Skip to content

Commit 0974d07

Browse files
committed
improve cli reporter
1 parent a5c9184 commit 0974d07

File tree

1 file changed

+93
-46
lines changed

1 file changed

+93
-46
lines changed

lib/workers.js

Lines changed: 93 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -234,6 +234,7 @@ class Workers extends EventEmitter {
234234
this.setMaxListeners(50)
235235
this.codecept = initializeCodecept(config.testConfig, config.options)
236236
this.options = config.options || {}
237+
this.config = config
237238
this.errors = []
238239
this.numberOfWorkers = 0
239240
this.closedWorkers = 0
@@ -683,73 +684,119 @@ class Workers extends EventEmitter {
683684
* @private
684685
*/
685686
_printEnhancedWorkersSummary(result, testsByFeature, testsByWorker) {
686-
// Calculate accurate stats from actual test objects instead of relying on Container stats
687-
// which may not aggregate correctly in all scenarios
688-
let actualPassed = 0
689-
let actualFailed = 0
690-
let actualPending = 0
691-
692-
result.tests.forEach(test => {
693-
if (test.state === 'passed') actualPassed++
694-
else if (test.state === 'failed') actualFailed++
695-
else if (test.state === 'pending' || test.state === 'skipped') actualPending++
696-
})
697-
698-
const actualTotal = result.tests.length
699-
const actualFailedHooks = result.stats?.failedHooks || 0
687+
const stats = result.stats
700688

701689
// Use result.duration (wall-clock time) instead of stats.duration (which gets overwritten)
702-
const duration = result.duration || result.stats?.duration || 0
690+
const duration = result.duration || stats.duration || 0
691+
const separator = '═'.repeat(82)
692+
const subSeparator = '─'.repeat(82)
693+
694+
// Determine strategy
695+
let strategy = 'test'
696+
if (this.isPoolMode) {
697+
strategy = 'pool'
698+
} else if (this.config && this.config.by === 'suite') {
699+
strategy = 'suite'
700+
}
701+
703702
output.print()
704-
output.print(output.styles.bold('-- TEST SUMMARY:'))
703+
output.print(separator)
704+
output.print(output.styles.bold(' 📊 ENHANCED SUMMARY'))
705+
output.print(separator)
706+
output.print()
707+
708+
// Print overall metrics first - use stats for backward compatibility with existing tests
709+
output.print(output.styles.bold('OVERALL METRICS'))
710+
output.print(subSeparator)
711+
const totalTests = stats.tests || 0
712+
const passRate = totalTests > 0 ? Math.round((stats.passes / totalTests) * 100) : 0
713+
const failRate = totalTests > 0 ? Math.round((stats.failures / totalTests) * 100) : 0
714+
const pendingRate = totalTests > 0 ? Math.round((stats.pending / totalTests) * 100) : 0
715+
716+
output.print(`Total Tests: ${totalTests}`)
717+
output.print(`${output.styles.success('✓')} Passed: ${output.styles.success(stats.passes)} (${passRate}%)`)
718+
if (stats.failures > 0) {
719+
output.print(`${output.styles.error('✗')} Failed: ${output.styles.error(stats.failures)} (${failRate}%)`)
720+
}
721+
if (stats.pending > 0) {
722+
output.print(`⊘ Pending: ${stats.pending} (${pendingRate}%)`)
723+
}
724+
if (stats.failedHooks > 0) {
725+
output.print(`${output.styles.error('✗')} Failed Hooks: ${output.styles.error(stats.failedHooks)}`)
726+
}
727+
output.print(`Duration: ${ms(duration)}`)
728+
output.print(`Strategy: ${strategy}`)
729+
output.print(separator)
705730
output.print()
706731

707732
// Print tests grouped by feature
708733
if (Object.keys(testsByFeature).length > 0) {
709-
output.print(output.styles.bold('Results by Feature:'))
734+
output.print(output.styles.bold('BY FEATURE'))
735+
output.print(subSeparator)
710736
Object.entries(testsByFeature).forEach(([featureName, data]) => {
711-
const totalTests = data.tests.length
712-
const passRate = totalTests > 0 ? Math.round((data.passed / totalTests) * 100) : 0
713-
const status = data.failed > 0 ? output.styles.error('✗') : output.styles.success('✓')
714-
output.print(` ${status} ${output.styles.bold(featureName)}`)
715-
output.print(` Passed: ${output.styles.success(data.passed)} | Failed: ${output.styles.error(data.failed)} | Skipped: ${data.skipped} | Pass Rate: ${passRate}%`)
737+
const totalFeatureTests = data.tests.length
738+
const featurePassRate = totalFeatureTests > 0 ? Math.round((data.passed / totalFeatureTests) * 100) : 0
739+
const featureDuration = data.tests.reduce((acc, test) => acc + (test.duration || 0), 0)
740+
741+
output.print(`📁 ${output.styles.bold(featureName)}`)
742+
743+
const parts = [` Total: ${totalFeatureTests}`]
744+
if (data.passed > 0) {
745+
parts.push(`${output.styles.success('✓')} Passed: ${data.passed} (${featurePassRate}%)`)
746+
}
747+
if (data.failed > 0) {
748+
const failRate = Math.round((data.failed / totalFeatureTests) * 100)
749+
parts.push(`${output.styles.error('✗')} Failed: ${data.failed} (${failRate}%)`)
750+
}
751+
if (data.skipped > 0) {
752+
const skipRate = Math.round((data.skipped / totalFeatureTests) * 100)
753+
parts.push(`⊘ Pending: ${data.skipped} (${skipRate}%)`)
754+
}
755+
parts.push(`Duration: ${ms(featureDuration)}`)
756+
757+
output.print(` ${parts.join(' | ')}`)
758+
output.print()
716759
})
760+
output.print(separator)
717761
output.print()
718762
}
719763

720764
// Print worker statistics
721765
if (Object.keys(testsByWorker).length > 1) {
722-
output.print(output.styles.bold('Results by Worker:'))
766+
output.print(output.styles.bold('BY WORKER'))
767+
output.print(subSeparator)
723768
Object.entries(testsByWorker)
724769
.sort((a, b) => parseInt(a[0]) - parseInt(b[0]))
725770
.forEach(([workerIndex, data]) => {
726-
const totalTests = data.tests.length
727-
const passRate = totalTests > 0 ? Math.round((data.passed / totalTests) * 100) : 0
728-
const status = data.failed > 0 ? output.styles.error('✗') : output.styles.success('✓')
729-
output.print(` ${status} Worker ${workerIndex}`)
730-
output.print(` Tests: ${totalTests} | Passed: ${output.styles.success(data.passed)} | Failed: ${output.styles.error(data.failed)} | Pass Rate: ${passRate}%`)
771+
const totalWorkerTests = data.tests.length
772+
const workerPassRate = totalWorkerTests > 0 ? Math.round((data.passed / totalWorkerTests) * 100) : 0
773+
const workerDuration = data.tests.reduce((acc, test) => acc + (test.duration || 0), 0)
774+
775+
output.print(`👷 Worker ${workerIndex}`)
776+
777+
const parts = [` Total: ${totalWorkerTests}`]
778+
if (data.passed > 0) {
779+
parts.push(`${output.styles.success('✓')} Passed: ${data.passed} (${workerPassRate}%)`)
780+
}
781+
if (data.failed > 0) {
782+
const failRate = Math.round((data.failed / totalWorkerTests) * 100)
783+
parts.push(`${output.styles.error('✗')} Failed: ${data.failed} (${failRate}%)`)
784+
}
785+
if (data.skipped > 0) {
786+
const skipRate = Math.round((data.skipped / totalWorkerTests) * 100)
787+
parts.push(`⊘ Pending: ${data.skipped} (${skipRate}%)`)
788+
}
789+
parts.push(`Duration: ${ms(workerDuration)}`)
790+
791+
output.print(` ${parts.join(' | ')}`)
792+
output.print()
731793
})
794+
output.print(separator)
732795
output.print()
733796
}
734797

735-
// Print overall metrics using accurate counts from test objects
736-
output.print(output.styles.bold('Overall Metrics:'))
737-
const passRate = actualTotal > 0 ? Math.round((actualPassed / actualTotal) * 100) : 0
738-
const failRate = actualTotal > 0 ? Math.round((actualFailed / actualTotal) * 100) : 0
739-
output.print(` Total Tests: ${actualTotal}`)
740-
output.print(` Passed: ${output.styles.success(actualPassed)} (${passRate}%)`)
741-
output.print(` Failed: ${output.styles.error(actualFailed)} (${failRate}%)`)
742-
output.print(` Skipped: ${actualPending}`)
743-
if (actualFailedHooks > 0) {
744-
output.print(` Failed Hooks: ${output.styles.error(actualFailedHooks)}`)
745-
}
746-
output.print(` Duration: ${ms(duration)}`)
747-
output.print(` Workers: ${this.numberOfWorkers}`)
748-
output.print(` Strategy: ${this.isPoolMode ? 'pool' : 'test/suite'}`)
749-
output.print()
750-
751-
// Print the classic result line with accurate counts
752-
output.result(actualPassed, actualFailed, actualPending, ms(duration), actualFailedHooks)
798+
// Print the classic result line using stats for backward compatibility
799+
output.result(stats.passes, stats.failures, stats.pending, ms(duration), stats.failedHooks)
753800
}
754801
}
755802

0 commit comments

Comments
 (0)