fix(tstest): Improve file range filtering and summary logging by skipping test files outside the specified range and reporting them in the final summary.
This commit is contained in:
parent
e0d8ede450
commit
763dc89f59
@ -1,5 +1,13 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2025-05-23 - 1.10.1 - fix(tstest)
|
||||||
|
Improve file range filtering and summary logging by skipping test files outside the specified range and reporting them in the final summary.
|
||||||
|
|
||||||
|
- Introduce runSingleTestOrSkip to check file index against startFrom/stopAt values.
|
||||||
|
- Log skipped files with appropriate messages and add them to the summary.
|
||||||
|
- Update the logger to include total skipped files in the test summary.
|
||||||
|
- Add permission settings in .claude/settings.local.json to support new operations.
|
||||||
|
|
||||||
## 2025-05-23 - 1.10.0 - feat(cli)
|
## 2025-05-23 - 1.10.0 - feat(cli)
|
||||||
Add --startFrom and --stopAt options to filter test files by range
|
Add --startFrom and --stopAt options to filter test files by range
|
||||||
|
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@git.zone/tstest',
|
name: '@git.zone/tstest',
|
||||||
version: '1.10.0',
|
version: '1.10.1',
|
||||||
description: 'a test utility to run tests that match test/**/*.ts'
|
description: 'a test utility to run tests that match test/**/*.ts'
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import { TsTestLogger } from './tstest.logging.js';
|
|||||||
|
|
||||||
export class TapCombinator {
|
export class TapCombinator {
|
||||||
tapParserStore: TapParser[] = [];
|
tapParserStore: TapParser[] = [];
|
||||||
|
skippedFiles: string[] = [];
|
||||||
private logger: TsTestLogger;
|
private logger: TsTestLogger;
|
||||||
|
|
||||||
constructor(logger: TsTestLogger) {
|
constructor(logger: TsTestLogger) {
|
||||||
@ -19,10 +20,14 @@ export class TapCombinator {
|
|||||||
addTapParser(tapParserArg: TapParser) {
|
addTapParser(tapParserArg: TapParser) {
|
||||||
this.tapParserStore.push(tapParserArg);
|
this.tapParserStore.push(tapParserArg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
addSkippedFile(filename: string) {
|
||||||
|
this.skippedFiles.push(filename);
|
||||||
|
}
|
||||||
|
|
||||||
evaluate() {
|
evaluate() {
|
||||||
// Call the logger's summary method
|
// Call the logger's summary method with skipped files
|
||||||
this.logger.summary();
|
this.logger.summary(this.skippedFiles);
|
||||||
|
|
||||||
// Check for failures
|
// Check for failures
|
||||||
let failGlobal = false;
|
let failGlobal = false;
|
||||||
|
@ -39,26 +39,9 @@ export class TsTest {
|
|||||||
|
|
||||||
async run() {
|
async run() {
|
||||||
const testGroups = await this.testDir.getTestFileGroups();
|
const testGroups = await this.testDir.getTestFileGroups();
|
||||||
let allFiles = [...testGroups.serial, ...Object.values(testGroups.parallelGroups).flat()];
|
const allFiles = [...testGroups.serial, ...Object.values(testGroups.parallelGroups).flat()];
|
||||||
|
|
||||||
// Apply file range filtering if specified
|
// Log test discovery - always show full count
|
||||||
if (this.startFromFile !== null || this.stopAtFile !== null) {
|
|
||||||
const startIndex = this.startFromFile ? this.startFromFile - 1 : 0; // Convert to 0-based index
|
|
||||||
const endIndex = this.stopAtFile ? this.stopAtFile : allFiles.length;
|
|
||||||
allFiles = allFiles.slice(startIndex, endIndex);
|
|
||||||
|
|
||||||
// Filter the serial and parallel groups based on remaining files
|
|
||||||
testGroups.serial = testGroups.serial.filter(file => allFiles.includes(file));
|
|
||||||
Object.keys(testGroups.parallelGroups).forEach(groupName => {
|
|
||||||
testGroups.parallelGroups[groupName] = testGroups.parallelGroups[groupName].filter(file => allFiles.includes(file));
|
|
||||||
// Remove empty groups
|
|
||||||
if (testGroups.parallelGroups[groupName].length === 0) {
|
|
||||||
delete testGroups.parallelGroups[groupName];
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Log test discovery
|
|
||||||
this.logger.testDiscovery(
|
this.logger.testDiscovery(
|
||||||
allFiles.length,
|
allFiles.length,
|
||||||
this.testDir.testPath,
|
this.testDir.testPath,
|
||||||
@ -71,7 +54,7 @@ export class TsTest {
|
|||||||
// Execute serial tests first
|
// Execute serial tests first
|
||||||
for (const fileNameArg of testGroups.serial) {
|
for (const fileNameArg of testGroups.serial) {
|
||||||
fileIndex++;
|
fileIndex++;
|
||||||
await this.runSingleTest(fileNameArg, fileIndex, allFiles.length, tapCombinator);
|
await this.runSingleTestOrSkip(fileNameArg, fileIndex, allFiles.length, tapCombinator);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute parallel groups sequentially
|
// Execute parallel groups sequentially
|
||||||
@ -85,7 +68,7 @@ export class TsTest {
|
|||||||
// Run all tests in this group in parallel
|
// Run all tests in this group in parallel
|
||||||
const parallelPromises = groupFiles.map(async (fileNameArg) => {
|
const parallelPromises = groupFiles.map(async (fileNameArg) => {
|
||||||
fileIndex++;
|
fileIndex++;
|
||||||
return this.runSingleTest(fileNameArg, fileIndex, allFiles.length, tapCombinator);
|
return this.runSingleTestOrSkip(fileNameArg, fileIndex, allFiles.length, tapCombinator);
|
||||||
});
|
});
|
||||||
|
|
||||||
await Promise.all(parallelPromises);
|
await Promise.all(parallelPromises);
|
||||||
@ -96,6 +79,24 @@ export class TsTest {
|
|||||||
tapCombinator.evaluate();
|
tapCombinator.evaluate();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async runSingleTestOrSkip(fileNameArg: string, fileIndex: number, totalFiles: number, tapCombinator: TapCombinator) {
|
||||||
|
// Check if this file should be skipped based on range
|
||||||
|
if (this.startFromFile !== null && fileIndex < this.startFromFile) {
|
||||||
|
this.logger.testFileSkipped(fileNameArg, fileIndex, totalFiles, `before start range (${this.startFromFile})`);
|
||||||
|
tapCombinator.addSkippedFile(fileNameArg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.stopAtFile !== null && fileIndex > this.stopAtFile) {
|
||||||
|
this.logger.testFileSkipped(fileNameArg, fileIndex, totalFiles, `after stop range (${this.stopAtFile})`);
|
||||||
|
tapCombinator.addSkippedFile(fileNameArg);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// File is in range, run it
|
||||||
|
await this.runSingleTest(fileNameArg, fileIndex, totalFiles, tapCombinator);
|
||||||
|
}
|
||||||
|
|
||||||
private async runSingleTest(fileNameArg: string, fileIndex: number, totalFiles: number, tapCombinator: TapCombinator) {
|
private async runSingleTest(fileNameArg: string, fileIndex: number, totalFiles: number, tapCombinator: TapCombinator) {
|
||||||
switch (true) {
|
switch (true) {
|
||||||
case process.env.CI && fileNameArg.includes('.nonci.'):
|
case process.env.CI && fileNameArg.includes('.nonci.'):
|
||||||
|
@ -30,8 +30,10 @@ export interface TestSummary {
|
|||||||
totalTests: number;
|
totalTests: number;
|
||||||
totalPassed: number;
|
totalPassed: number;
|
||||||
totalFailed: number;
|
totalFailed: number;
|
||||||
|
totalSkipped: number;
|
||||||
totalDuration: number;
|
totalDuration: number;
|
||||||
fileResults: TestFileResult[];
|
fileResults: TestFileResult[];
|
||||||
|
skippedFiles: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export class TsTestLogger {
|
export class TsTestLogger {
|
||||||
@ -282,6 +284,19 @@ export class TsTestLogger {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Skipped test file
|
||||||
|
testFileSkipped(filename: string, index: number, total: number, reason: string) {
|
||||||
|
if (this.options.json) {
|
||||||
|
this.logJson({ event: 'fileSkipped', filename, index, total, reason });
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.options.quiet) return;
|
||||||
|
|
||||||
|
this.log(this.format(`\n⏭️ ${filename} (${index}/${total})`, 'yellow'));
|
||||||
|
this.log(this.format(` Skipped: ${reason}`, 'dim'));
|
||||||
|
}
|
||||||
|
|
||||||
// Browser console
|
// Browser console
|
||||||
browserConsole(message: string, level: string = 'log') {
|
browserConsole(message: string, level: string = 'log') {
|
||||||
if (this.options.json) {
|
if (this.options.json) {
|
||||||
@ -317,15 +332,17 @@ export class TsTestLogger {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Final summary
|
// Final summary
|
||||||
summary() {
|
summary(skippedFiles: string[] = []) {
|
||||||
const totalDuration = Date.now() - this.startTime;
|
const totalDuration = Date.now() - this.startTime;
|
||||||
const summary: TestSummary = {
|
const summary: TestSummary = {
|
||||||
totalFiles: this.fileResults.length,
|
totalFiles: this.fileResults.length + skippedFiles.length,
|
||||||
totalTests: this.fileResults.reduce((sum, r) => sum + r.total, 0),
|
totalTests: this.fileResults.reduce((sum, r) => sum + r.total, 0),
|
||||||
totalPassed: this.fileResults.reduce((sum, r) => sum + r.passed, 0),
|
totalPassed: this.fileResults.reduce((sum, r) => sum + r.passed, 0),
|
||||||
totalFailed: this.fileResults.reduce((sum, r) => sum + r.failed, 0),
|
totalFailed: this.fileResults.reduce((sum, r) => sum + r.failed, 0),
|
||||||
|
totalSkipped: skippedFiles.length,
|
||||||
totalDuration,
|
totalDuration,
|
||||||
fileResults: this.fileResults
|
fileResults: this.fileResults,
|
||||||
|
skippedFiles
|
||||||
};
|
};
|
||||||
|
|
||||||
if (this.options.json) {
|
if (this.options.json) {
|
||||||
@ -346,6 +363,9 @@ export class TsTestLogger {
|
|||||||
this.log(this.format(`│ Total Tests: ${summary.totalTests.toString().padStart(14)} │`, 'white'));
|
this.log(this.format(`│ Total Tests: ${summary.totalTests.toString().padStart(14)} │`, 'white'));
|
||||||
this.log(this.format(`│ Passed: ${summary.totalPassed.toString().padStart(14)} │`, 'green'));
|
this.log(this.format(`│ Passed: ${summary.totalPassed.toString().padStart(14)} │`, 'green'));
|
||||||
this.log(this.format(`│ Failed: ${summary.totalFailed.toString().padStart(14)} │`, summary.totalFailed > 0 ? 'red' : 'green'));
|
this.log(this.format(`│ Failed: ${summary.totalFailed.toString().padStart(14)} │`, summary.totalFailed > 0 ? 'red' : 'green'));
|
||||||
|
if (summary.totalSkipped > 0) {
|
||||||
|
this.log(this.format(`│ Skipped: ${summary.totalSkipped.toString().padStart(14)} │`, 'yellow'));
|
||||||
|
}
|
||||||
this.log(this.format(`│ Duration: ${totalDuration.toString().padStart(14)}ms │`, 'white'));
|
this.log(this.format(`│ Duration: ${totalDuration.toString().padStart(14)}ms │`, 'white'));
|
||||||
this.log(this.format('└────────────────────────────────┘', 'dim'));
|
this.log(this.format('└────────────────────────────────┘', 'dim'));
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user