Compare commits

..

5 Commits

7 changed files with 1697 additions and 434 deletions

View File

@@ -1,5 +1,35 @@
# Changelog # Changelog
## 2025-08-16 - 2.3.3 - fix(dependencies)
Bump dependency versions and add local Claude settings
- Bumped devDependency @git.zone/tsbuild ^2.6.3 → ^2.6.4
- Updated @git.zone/tsbundle ^2.2.5 → ^2.5.1
- Updated @push.rocks/consolecolor ^2.0.2 → ^2.0.3
- Updated @push.rocks/qenv ^6.1.0 → ^6.1.3
- Updated @push.rocks/smartchok ^1.0.34 → ^1.1.1
- Updated @push.rocks/smartenv ^5.0.12 → ^5.0.13
- Updated @push.rocks/smartfile ^11.2.3 → ^11.2.5
- Updated @push.rocks/smarts3 ^2.2.5 → ^2.2.6
- Updated @push.rocks/smartshell ^3.2.3 → ^3.2.4
- Updated ws ^8.18.2 → ^8.18.3
- Added .claude/settings.local.json for local Claude permissions and tooling (local-only configuration)
## 2025-07-24 - 2.3.2 - fix(tapbundle)
Fix TypeScript IDE warning about tapTools parameter possibly being undefined
- Changed ITestFunction from interface with optional parameter to union type
- Updated test runner to handle both function signatures (with and without tapTools)
- Resolves IDE warnings while maintaining backward compatibility
## 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

View File

@@ -1,6 +1,6 @@
{ {
"name": "@git.zone/tstest", "name": "@git.zone/tstest",
"version": "2.3.0", "version": "2.3.3",
"private": false, "private": false,
"description": "a test utility to run tests that match test/**/*.ts", "description": "a test utility to run tests that match test/**/*.ts",
"exports": { "exports": {
@@ -24,34 +24,34 @@
"buildDocs": "tsdoc" "buildDocs": "tsdoc"
}, },
"devDependencies": { "devDependencies": {
"@git.zone/tsbuild": "^2.6.3", "@git.zone/tsbuild": "^2.6.4",
"@types/node": "^22.15.21" "@types/node": "^22.15.21"
}, },
"dependencies": { "dependencies": {
"@api.global/typedserver": "^3.0.74", "@api.global/typedserver": "^3.0.74",
"@git.zone/tsbundle": "^2.2.5", "@git.zone/tsbundle": "^2.5.1",
"@git.zone/tsrun": "^1.3.3", "@git.zone/tsrun": "^1.3.3",
"@push.rocks/consolecolor": "^2.0.2", "@push.rocks/consolecolor": "^2.0.3",
"@push.rocks/qenv": "^6.1.0", "@push.rocks/qenv": "^6.1.3",
"@push.rocks/smartbrowser": "^2.0.8", "@push.rocks/smartbrowser": "^2.0.8",
"@push.rocks/smartchok": "^1.0.34", "@push.rocks/smartchok": "^1.1.1",
"@push.rocks/smartcrypto": "^2.0.4", "@push.rocks/smartcrypto": "^2.0.4",
"@push.rocks/smartdelay": "^3.0.5", "@push.rocks/smartdelay": "^3.0.5",
"@push.rocks/smartenv": "^5.0.12", "@push.rocks/smartenv": "^5.0.13",
"@push.rocks/smartexpect": "^2.5.0", "@push.rocks/smartexpect": "^2.5.0",
"@push.rocks/smartfile": "^11.2.3", "@push.rocks/smartfile": "^11.2.5",
"@push.rocks/smartjson": "^5.0.20", "@push.rocks/smartjson": "^5.0.20",
"@push.rocks/smartlog": "^3.1.8", "@push.rocks/smartlog": "^3.1.8",
"@push.rocks/smartmongo": "^2.0.12", "@push.rocks/smartmongo": "^2.0.12",
"@push.rocks/smartpath": "^5.0.18", "@push.rocks/smartpath": "^5.0.18",
"@push.rocks/smartpromise": "^4.2.3", "@push.rocks/smartpromise": "^4.2.3",
"@push.rocks/smartrequest": "^2.1.0", "@push.rocks/smartrequest": "^2.1.0",
"@push.rocks/smarts3": "^2.2.5", "@push.rocks/smarts3": "^2.2.6",
"@push.rocks/smartshell": "^3.2.3", "@push.rocks/smartshell": "^3.2.4",
"@push.rocks/smarttime": "^4.1.1", "@push.rocks/smarttime": "^4.1.1",
"@types/ws": "^8.18.1", "@types/ws": "^8.18.1",
"figures": "^6.1.0", "figures": "^6.1.0",
"ws": "^8.18.2" "ws": "^8.18.3"
}, },
"files": [ "files": [
"ts/**/*", "ts/**/*",

2041
pnpm-lock.yaml generated

File diff suppressed because it is too large Load Diff

View File

@@ -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.3',
description: 'a test utility to run tests that match test/**/*.ts' description: 'a test utility to run tests that match test/**/*.ts'
} }

View File

@@ -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);
} }
} }
} }

View File

@@ -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

View File

@@ -11,9 +11,9 @@ import { HrtMeasurement } from '@push.rocks/smarttime';
// interfaces // interfaces
export type TTestStatus = 'success' | 'error' | 'pending' | 'errorAfterSuccess' | 'timeout' | 'skipped'; export type TTestStatus = 'success' | 'error' | 'pending' | 'errorAfterSuccess' | 'timeout' | 'skipped';
export interface ITestFunction<T> { export type ITestFunction<T> =
(tapTools?: TapTools): Promise<T>; | ((tapTools: TapTools) => Promise<T>)
} | (() => Promise<T>);
export class TapTest<T = unknown> { export class TapTest<T = unknown> {
public description: string; public description: string;
@@ -173,7 +173,9 @@ export class TapTest<T = unknown> {
} }
// Run the test function with potential timeout // Run the test function with potential timeout
const testPromise = this.testFunction(this.tapTools); const testPromise = this.testFunction.length === 0
? (this.testFunction as () => Promise<T>)()
: (this.testFunction as (tapTools: TapTools) => Promise<T>)(this.tapTools);
const testReturnValue = timeoutPromise const testReturnValue = timeoutPromise
? await Promise.race([testPromise, timeoutPromise]) ? await Promise.race([testPromise, timeoutPromise])
: await testPromise; : await testPromise;