fix(tapParser/logger): Fix test duration reporting and summary formatting in TAP parser and logger
This commit is contained in:
		| @@ -1,5 +1,13 @@ | |||||||
| # Changelog | # Changelog | ||||||
|  |  | ||||||
|  | ## 2025-05-26 - 2.3.1 - fix(tapParser/logger) | ||||||
|  | Fix test duration reporting and summary formatting in TAP parser and logger | ||||||
|  |  | ||||||
|  | - Introduce startTime in TapParser to capture the overall test duration | ||||||
|  | - Pass computed duration to logger methods in evaluateFinalResult for accurate timing | ||||||
|  | - Update summary output to format duration in a human-readable way (ms vs. s) | ||||||
|  | - Add local permission settings configuration to .claude/settings.local.json | ||||||
|  |  | ||||||
| ## 2025-05-26 - 2.3.0 - feat(cli) | ## 2025-05-26 - 2.3.0 - feat(cli) | ||||||
| Add '--version' option and warn against global tstest usage in the tstest project | Add '--version' option and warn against global tstest usage in the tstest project | ||||||
|  |  | ||||||
|   | |||||||
| @@ -3,6 +3,6 @@ | |||||||
|  */ |  */ | ||||||
| export const commitinfo = { | export const commitinfo = { | ||||||
|   name: '@git.zone/tstest', |   name: '@git.zone/tstest', | ||||||
|   version: '2.3.0', |   version: '2.3.1', | ||||||
|   description: 'a test utility to run tests that match test/**/*.ts' |   description: 'a test utility to run tests that match test/**/*.ts' | ||||||
| } | } | ||||||
|   | |||||||
| @@ -22,6 +22,7 @@ export class TapParser { | |||||||
|   private logger: TsTestLogger; |   private logger: TsTestLogger; | ||||||
|   private protocolParser: ProtocolParser; |   private protocolParser: ProtocolParser; | ||||||
|   private protocolVersion: string | null = null; |   private protocolVersion: string | null = null; | ||||||
|  |   private startTime: number; | ||||||
|  |  | ||||||
|   /** |   /** | ||||||
|    * the constructor for TapParser |    * the constructor for TapParser | ||||||
| @@ -29,6 +30,7 @@ export class TapParser { | |||||||
|   constructor(public fileName: string, logger?: TsTestLogger) { |   constructor(public fileName: string, logger?: TsTestLogger) { | ||||||
|     this.logger = logger; |     this.logger = logger; | ||||||
|     this.protocolParser = new ProtocolParser(); |     this.protocolParser = new ProtocolParser(); | ||||||
|  |     this.startTime = Date.now(); | ||||||
|   } |   } | ||||||
|    |    | ||||||
|   /** |   /** | ||||||
| @@ -480,6 +482,7 @@ export class TapParser { | |||||||
|  |  | ||||||
|   public async evaluateFinalResult() { |   public async evaluateFinalResult() { | ||||||
|     this.receivedTests = this.testStore.length; |     this.receivedTests = this.testStore.length; | ||||||
|  |     const duration = Date.now() - this.startTime; | ||||||
|  |  | ||||||
|     // check wether all tests ran |     // check wether all tests ran | ||||||
|     if (this.expectedTests === this.receivedTests) { |     if (this.expectedTests === this.receivedTests) { | ||||||
| @@ -494,23 +497,23 @@ export class TapParser { | |||||||
|     if (!this.expectedTests && this.receivedTests === 0) { |     if (!this.expectedTests && this.receivedTests === 0) { | ||||||
|       if (this.logger) { |       if (this.logger) { | ||||||
|         this.logger.error('No tests were defined. Therefore the testfile failed!'); |         this.logger.error('No tests were defined. Therefore the testfile failed!'); | ||||||
|         this.logger.testFileEnd(0, 1, 0); // Count as 1 failure |         this.logger.testFileEnd(0, 1, duration); // Count as 1 failure | ||||||
|       } |       } | ||||||
|     } else if (this.expectedTests !== this.receivedTests) { |     } else if (this.expectedTests !== this.receivedTests) { | ||||||
|       if (this.logger) { |       if (this.logger) { | ||||||
|         this.logger.error('The amount of received tests and expectedTests is unequal! Therefore the testfile failed'); |         this.logger.error('The amount of received tests and expectedTests is unequal! Therefore the testfile failed'); | ||||||
|         const errorCount = this.getErrorTests().length || 1; // At least 1 error |         const errorCount = this.getErrorTests().length || 1; // At least 1 error | ||||||
|         this.logger.testFileEnd(this.receivedTests - errorCount, errorCount, 0); |         this.logger.testFileEnd(this.receivedTests - errorCount, errorCount, duration); | ||||||
|       } |       } | ||||||
|     } else if (this.getErrorTests().length === 0) { |     } else if (this.getErrorTests().length === 0) { | ||||||
|       if (this.logger) { |       if (this.logger) { | ||||||
|         this.logger.tapOutput('All tests are successfull!!!'); |         this.logger.tapOutput('All tests are successfull!!!'); | ||||||
|         this.logger.testFileEnd(this.receivedTests, 0, 0); |         this.logger.testFileEnd(this.receivedTests, 0, duration); | ||||||
|       } |       } | ||||||
|     } else { |     } else { | ||||||
|       if (this.logger) { |       if (this.logger) { | ||||||
|         this.logger.tapOutput(`${this.getErrorTests().length} tests threw an error!!!`, true); |         this.logger.tapOutput(`${this.getErrorTests().length} tests threw an error!!!`, true); | ||||||
|         this.logger.testFileEnd(this.receivedTests - this.getErrorTests().length, this.getErrorTests().length, 0); |         this.logger.testFileEnd(this.receivedTests - this.getErrorTests().length, this.getErrorTests().length, duration); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|   | |||||||
| @@ -242,10 +242,12 @@ export class TsTestLogger { | |||||||
|      |      | ||||||
|     if (!this.options.quiet) { |     if (!this.options.quiet) { | ||||||
|       const total = passed + failed; |       const total = passed + failed; | ||||||
|  |       const durationStr = duration >= 1000 ? `${(duration / 1000).toFixed(1)}s` : `${duration}ms`; | ||||||
|  |        | ||||||
|       if (failed === 0) { |       if (failed === 0) { | ||||||
|         this.log(this.format(`   Summary: ${passed}/${total} PASSED`, 'green')); |         this.log(this.format(`   Summary: ${passed}/${total} PASSED in ${durationStr}`, 'green')); | ||||||
|       } else { |       } else { | ||||||
|         this.log(this.format(`   Summary: ${passed} passed, ${failed} failed of ${total} tests`, 'red')); |         this.log(this.format(`   Summary: ${passed} passed, ${failed} failed of ${total} tests in ${durationStr}`, 'red')); | ||||||
|       } |       } | ||||||
|     } |     } | ||||||
|      |      | ||||||
| @@ -392,10 +394,12 @@ export class TsTestLogger { | |||||||
|      |      | ||||||
|     if (this.options.quiet) { |     if (this.options.quiet) { | ||||||
|       const status = summary.totalFailed === 0 ? 'PASSED' : 'FAILED'; |       const status = summary.totalFailed === 0 ? 'PASSED' : 'FAILED'; | ||||||
|  |       const durationStr = totalDuration >= 1000 ? `${(totalDuration / 1000).toFixed(1)}s` : `${totalDuration}ms`; | ||||||
|  |        | ||||||
|       if (summary.totalFailed === 0) { |       if (summary.totalFailed === 0) { | ||||||
|         this.log(`\nSummary: ${summary.totalPassed}/${summary.totalTests} | ${totalDuration}ms | ${status}`); |         this.log(`\nSummary: ${summary.totalPassed}/${summary.totalTests} | ${durationStr} | ${status}`); | ||||||
|       } else { |       } else { | ||||||
|         this.log(`\nSummary: ${summary.totalPassed} passed, ${summary.totalFailed} failed of ${summary.totalTests} tests | ${totalDuration}ms | ${status}`); |         this.log(`\nSummary: ${summary.totalPassed} passed, ${summary.totalFailed} failed of ${summary.totalTests} tests | ${durationStr} | ${status}`); | ||||||
|       } |       } | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
| @@ -410,7 +414,8 @@ export class TsTestLogger { | |||||||
|     if (summary.totalSkipped > 0) { |     if (summary.totalSkipped > 0) { | ||||||
|       this.log(this.format(`│ Skipped:        ${summary.totalSkipped.toString().padStart(14)} │`, 'yellow')); |       this.log(this.format(`│ Skipped:        ${summary.totalSkipped.toString().padStart(14)} │`, 'yellow')); | ||||||
|     } |     } | ||||||
|     this.log(this.format(`│ Duration:       ${totalDuration.toString().padStart(14)}ms │`, 'white')); |     const durationStrFormatted = totalDuration >= 1000 ? `${(totalDuration / 1000).toFixed(1)}s` : `${totalDuration}ms`; | ||||||
|  |     this.log(this.format(`│ Duration:       ${durationStrFormatted.padStart(14)} │`, 'white')); | ||||||
|     this.log(this.format('└────────────────────────────────┘', 'dim')); |     this.log(this.format('└────────────────────────────────┘', 'dim')); | ||||||
|      |      | ||||||
|     // File results |     // File results | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user