@@ -3,6 +3,7 @@ const path = require('path')
33const mkdirp = require ( 'mkdirp' )
44const crypto = require ( 'crypto' )
55const { template } = require ( '../utils' )
6+ const { getMachineInfo } = require ( '../command/info' )
67
78const event = require ( '../event' )
89const output = require ( '../output' )
@@ -329,10 +330,10 @@ module.exports = function (config) {
329330 }
330331
331332 // Get system information
332- const systemInfo = await getSystemInfo ( )
333+ const systemInfo = await getMachineInfo ( )
333334
334335 const html = template ( getHtmlTemplate ( ) , {
335- title : ' CodeceptJS Test Report' ,
336+ title : ` CodeceptJS Test Report v ${ Codecept . version ( ) } ` ,
336337 timestamp : data . endTime . toISOString ( ) ,
337338 duration : formatDuration ( data . duration ) ,
338339 stats : JSON . stringify ( data . stats ) ,
@@ -348,7 +349,6 @@ module.exports = function (config) {
348349 failuresDisplay : data . failures && data . failures . length > 0 ? 'block' : 'none' ,
349350 codeceptVersion : Codecept . version ( ) ,
350351 systemInfoHtml : generateSystemInfoHtml ( systemInfo ) ,
351- codeceptLogo : getCodeceptLogo ( ) ,
352352 } )
353353
354354 fs . writeFileSync ( reportPath , html )
@@ -402,7 +402,7 @@ module.exports = function (config) {
402402 return tests
403403 . map ( test => {
404404 const statusClass = test . state || 'unknown'
405- const feature = test . isBdd && test . feature ? test . feature . name : ( test . parent ?. title || 'Unknown Feature' )
405+ const feature = test . isBdd && test . feature ? test . feature . name : test . parent ?. title || 'Unknown Feature'
406406 const steps = config . showSteps && test . steps ? ( test . isBdd ? generateBddStepsHtml ( test . steps ) : generateStepsHtml ( test . steps ) ) : ''
407407 const featureDetails = test . isBdd && test . feature ? generateBddFeatureHtml ( test . feature ) : ''
408408 const hooks = test . hooks && test . hooks . length > 0 ? generateHooksHtml ( test . hooks ) : ''
@@ -506,8 +506,7 @@ module.exports = function (config) {
506506 if ( ! feature ) return ''
507507
508508 const description = feature . description ? `<div class="feature-description">${ escapeHtml ( feature . description ) } </div>` : ''
509- const featureTags = feature . tags && feature . tags . length > 0 ?
510- `<div class="feature-tags">${ feature . tags . map ( tag => `<span class="feature-tag">${ escapeHtml ( tag ) } </span>` ) . join ( '' ) } </div>` : ''
509+ const featureTags = feature . tags && feature . tags . length > 0 ? `<div class="feature-tags">${ feature . tags . map ( tag => `<span class="feature-tag">${ escapeHtml ( tag ) } </span>` ) . join ( '' ) } </div>` : ''
511510
512511 return `
513512 <div class="bdd-feature-section">
@@ -677,6 +676,48 @@ module.exports = function (config) {
677676 return unsafe . replace ( / & / g, '&' ) . replace ( / < / g, '<' ) . replace ( / > / g, '>' ) . replace ( / " / g, '"' ) . replace ( / ' / g, ''' )
678677 }
679678
679+ function generateSystemInfoHtml ( systemInfo ) {
680+ if ( ! systemInfo ) return ''
681+
682+ const formatInfo = ( key , value ) => {
683+ if ( Array . isArray ( value ) && value . length > 1 ) {
684+ return `<div class="info-item"><span class="info-key">${ key } :</span> <span class="info-value">${ escapeHtml ( value [ 1 ] ) } </span></div>`
685+ } else if ( typeof value === 'string' && value !== 'N/A' && value !== 'undefined' ) {
686+ return `<div class="info-item"><span class="info-key">${ key } :</span> <span class="info-value">${ escapeHtml ( value ) } </span></div>`
687+ }
688+ return ''
689+ }
690+
691+ const infoItems = [
692+ formatInfo ( 'Node.js' , systemInfo . nodeInfo ) ,
693+ formatInfo ( 'OS' , systemInfo . osInfo ) ,
694+ formatInfo ( 'CPU' , systemInfo . cpuInfo ) ,
695+ formatInfo ( 'Chrome' , systemInfo . chromeInfo ) ,
696+ formatInfo ( 'Edge' , systemInfo . edgeInfo ) ,
697+ formatInfo ( 'Firefox' , systemInfo . firefoxInfo ) ,
698+ formatInfo ( 'Safari' , systemInfo . safariInfo ) ,
699+ formatInfo ( 'Playwright Browsers' , systemInfo . playwrightBrowsers ) ,
700+ ]
701+ . filter ( item => item )
702+ . join ( '' )
703+
704+ if ( ! infoItems ) return ''
705+
706+ return `
707+ <section class="system-info-section">
708+ <div class="system-info-header" onclick="toggleSystemInfo()">
709+ <h3>Environment Information</h3>
710+ <span class="toggle-icon">▼</span>
711+ </div>
712+ <div class="system-info-content" id="systemInfoContent">
713+ <div class="system-info-grid">
714+ ${ infoItems }
715+ </div>
716+ </div>
717+ </section>
718+ `
719+ }
720+
680721 function getHtmlTemplate ( ) {
681722 return `
682723<!DOCTYPE html>
@@ -697,6 +738,8 @@ module.exports = function (config) {
697738 </header>
698739
699740 <main class="report-content">
741+ {{systemInfoHtml}}
742+
700743 <section class="stats-section">
701744 <h2>Test Statistics</h2>
702745 {{statsHtml}}
@@ -830,7 +873,7 @@ body {
830873 padding: 0 1rem;
831874}
832875
833- .stats-section, .tests-section, .failures-section, .retries-section, .filters-section, .history-section {
876+ .stats-section, .tests-section, .failures-section, .retries-section, .filters-section, .history-section, .system-info-section {
834877 background: white;
835878 margin-bottom: 2rem;
836879 border-radius: 8px;
@@ -1352,6 +1395,82 @@ body {
13521395 display: none !important;
13531396}
13541397
1398+ /* System Info Section */
1399+ .system-info-section {
1400+ background: white;
1401+ margin-bottom: 2rem;
1402+ border-radius: 8px;
1403+ box-shadow: 0 2px 4px rgba(0,0,0,0.1);
1404+ overflow: hidden;
1405+ }
1406+
1407+ .system-info-header {
1408+ background: #2c3e50;
1409+ color: white;
1410+ padding: 1rem;
1411+ cursor: pointer;
1412+ display: flex;
1413+ justify-content: space-between;
1414+ align-items: center;
1415+ transition: background-color 0.2s;
1416+ }
1417+
1418+ .system-info-header:hover {
1419+ background: #34495e;
1420+ }
1421+
1422+ .system-info-header h3 {
1423+ margin: 0;
1424+ font-size: 1.2rem;
1425+ }
1426+
1427+ .toggle-icon {
1428+ font-size: 1rem;
1429+ transition: transform 0.3s ease;
1430+ }
1431+
1432+ .toggle-icon.rotated {
1433+ transform: rotate(-180deg);
1434+ }
1435+
1436+ .system-info-content {
1437+ display: none;
1438+ padding: 1.5rem;
1439+ background: #f8f9fa;
1440+ border-top: 1px solid #e9ecef;
1441+ }
1442+
1443+ .system-info-content.visible {
1444+ display: block;
1445+ }
1446+
1447+ .system-info-grid {
1448+ display: grid;
1449+ grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
1450+ gap: 1rem;
1451+ }
1452+
1453+ .info-item {
1454+ padding: 0.75rem;
1455+ background: white;
1456+ border-radius: 6px;
1457+ border-left: 4px solid #3498db;
1458+ box-shadow: 0 1px 3px rgba(0,0,0,0.1);
1459+ }
1460+
1461+ .info-key {
1462+ font-weight: bold;
1463+ color: #2c3e50;
1464+ display: inline-block;
1465+ min-width: 100px;
1466+ }
1467+
1468+ .info-value {
1469+ color: #34495e;
1470+ font-family: 'Courier New', monospace;
1471+ font-size: 0.9rem;
1472+ }
1473+
13551474/* BDD/Gherkin specific styles */
13561475.bdd-test {
13571476 border-left: 4px solid #8e44ad;
@@ -1501,6 +1620,19 @@ function closeImageModal() {
15011620 modal.style.display = 'none';
15021621}
15031622
1623+ function toggleSystemInfo() {
1624+ const content = document.getElementById('systemInfoContent');
1625+ const icon = document.querySelector('.toggle-icon');
1626+
1627+ if (content.classList.contains('visible')) {
1628+ content.classList.remove('visible');
1629+ icon.classList.remove('rotated');
1630+ } else {
1631+ content.classList.add('visible');
1632+ icon.classList.add('rotated');
1633+ }
1634+ }
1635+
15041636// Filter functionality
15051637function applyFilters() {
15061638 const statusFilter = Array.from(document.getElementById('statusFilter').selectedOptions).map(opt => opt.value);
0 commit comments