feat(cli): Add --startFrom and --stopAt options to filter test files by range
This commit is contained in:
parent
83b324b09f
commit
27c950c1a1
@ -1,5 +1,13 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2025-05-23 - 1.10.0 - feat(cli)
|
||||||
|
Add --startFrom and --stopAt options to filter test files by range
|
||||||
|
|
||||||
|
- Introduced CLI options --startFrom and --stopAt in ts/index.ts for selective test execution
|
||||||
|
- Added validation to ensure provided range values are positive and startFrom is not greater than stopAt
|
||||||
|
- Propagated file range filtering into test grouping in tstest.classes.tstest.ts, applying the range filter across serial and parallel groups
|
||||||
|
- Updated usage messages to include the new options
|
||||||
|
|
||||||
## 2025-05-23 - 1.9.4 - fix(docs)
|
## 2025-05-23 - 1.9.4 - fix(docs)
|
||||||
Update documentation and configuration for legal notices and CI permissions. This commit adds a new local settings file for tool permissions, refines the legal and trademark sections in the readme, and improves glob test files with clearer log messages.
|
Update documentation and configuration for legal notices and CI permissions. This commit adds a new local settings file for tool permissions, refines the legal and trademark sections in the readme, and improves glob test files with clearer log messages.
|
||||||
|
|
||||||
|
@ -3,6 +3,6 @@
|
|||||||
*/
|
*/
|
||||||
export const commitinfo = {
|
export const commitinfo = {
|
||||||
name: '@git.zone/tstest',
|
name: '@git.zone/tstest',
|
||||||
version: '1.9.4',
|
version: '1.10.0',
|
||||||
description: 'a test utility to run tests that match test/**/*.ts'
|
description: 'a test utility to run tests that match test/**/*.ts'
|
||||||
}
|
}
|
||||||
|
55
ts/index.ts
55
ts/index.ts
@ -13,6 +13,8 @@ export const runCli = async () => {
|
|||||||
const logOptions: LogOptions = {};
|
const logOptions: LogOptions = {};
|
||||||
let testPath: string | null = null;
|
let testPath: string | null = null;
|
||||||
let tags: string[] = [];
|
let tags: string[] = [];
|
||||||
|
let startFromFile: number | null = null;
|
||||||
|
let stopAtFile: number | null = null;
|
||||||
|
|
||||||
// Parse options
|
// Parse options
|
||||||
for (let i = 0; i < args.length; i++) {
|
for (let i = 0; i < args.length; i++) {
|
||||||
@ -42,6 +44,32 @@ export const runCli = async () => {
|
|||||||
tags = args[++i].split(',');
|
tags = args[++i].split(',');
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case '--startFrom':
|
||||||
|
if (i + 1 < args.length) {
|
||||||
|
const value = parseInt(args[++i], 10);
|
||||||
|
if (isNaN(value) || value < 1) {
|
||||||
|
console.error('Error: --startFrom must be a positive integer');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
startFromFile = value;
|
||||||
|
} else {
|
||||||
|
console.error('Error: --startFrom requires a number argument');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '--stopAt':
|
||||||
|
if (i + 1 < args.length) {
|
||||||
|
const value = parseInt(args[++i], 10);
|
||||||
|
if (isNaN(value) || value < 1) {
|
||||||
|
console.error('Error: --stopAt must be a positive integer');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
stopAtFile = value;
|
||||||
|
} else {
|
||||||
|
console.error('Error: --stopAt requires a number argument');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
if (!arg.startsWith('-')) {
|
if (!arg.startsWith('-')) {
|
||||||
testPath = arg;
|
testPath = arg;
|
||||||
@ -49,16 +77,24 @@ export const runCli = async () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Validate test file range options
|
||||||
|
if (startFromFile !== null && stopAtFile !== null && startFromFile > stopAtFile) {
|
||||||
|
console.error('Error: --startFrom cannot be greater than --stopAt');
|
||||||
|
process.exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
if (!testPath) {
|
if (!testPath) {
|
||||||
console.error('You must specify a test directory/file/pattern as argument. Please try again.');
|
console.error('You must specify a test directory/file/pattern as argument. Please try again.');
|
||||||
console.error('\nUsage: tstest <path> [options]');
|
console.error('\nUsage: tstest <path> [options]');
|
||||||
console.error('\nOptions:');
|
console.error('\nOptions:');
|
||||||
console.error(' --quiet, -q Minimal output');
|
console.error(' --quiet, -q Minimal output');
|
||||||
console.error(' --verbose, -v Verbose output');
|
console.error(' --verbose, -v Verbose output');
|
||||||
console.error(' --no-color Disable colored output');
|
console.error(' --no-color Disable colored output');
|
||||||
console.error(' --json Output results as JSON');
|
console.error(' --json Output results as JSON');
|
||||||
console.error(' --logfile Write logs to .nogit/testlogs/[testfile].log');
|
console.error(' --logfile Write logs to .nogit/testlogs/[testfile].log');
|
||||||
console.error(' --tags Run only tests with specified tags (comma-separated)');
|
console.error(' --tags <tags> Run only tests with specified tags (comma-separated)');
|
||||||
|
console.error(' --startFrom <n> Start running from test file number n');
|
||||||
|
console.error(' --stopAt <n> Stop running at test file number n');
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -73,6 +109,11 @@ export const runCli = async () => {
|
|||||||
executionMode = TestExecutionMode.DIRECTORY;
|
executionMode = TestExecutionMode.DIRECTORY;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tsTestInstance = new TsTest(process.cwd(), testPath, executionMode, logOptions, tags);
|
const tsTestInstance = new TsTest(process.cwd(), testPath, executionMode, logOptions, tags, startFromFile, stopAtFile);
|
||||||
await tsTestInstance.run();
|
await tsTestInstance.run();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Execute CLI when this file is run directly
|
||||||
|
if (import.meta.url === `file://${process.argv[1]}`) {
|
||||||
|
runCli();
|
||||||
|
}
|
||||||
|
@ -16,6 +16,8 @@ export class TsTest {
|
|||||||
public executionMode: TestExecutionMode;
|
public executionMode: TestExecutionMode;
|
||||||
public logger: TsTestLogger;
|
public logger: TsTestLogger;
|
||||||
public filterTags: string[];
|
public filterTags: string[];
|
||||||
|
public startFromFile: number | null;
|
||||||
|
public stopAtFile: number | null;
|
||||||
|
|
||||||
public smartshellInstance = new plugins.smartshell.Smartshell({
|
public smartshellInstance = new plugins.smartshell.Smartshell({
|
||||||
executor: 'bash',
|
executor: 'bash',
|
||||||
@ -26,16 +28,35 @@ export class TsTest {
|
|||||||
|
|
||||||
public tsbundleInstance = new plugins.tsbundle.TsBundle();
|
public tsbundleInstance = new plugins.tsbundle.TsBundle();
|
||||||
|
|
||||||
constructor(cwdArg: string, testPathArg: string, executionModeArg: TestExecutionMode, logOptions: LogOptions = {}, tags: string[] = []) {
|
constructor(cwdArg: string, testPathArg: string, executionModeArg: TestExecutionMode, logOptions: LogOptions = {}, tags: string[] = [], startFromFile: number | null = null, stopAtFile: number | null = null) {
|
||||||
this.executionMode = executionModeArg;
|
this.executionMode = executionModeArg;
|
||||||
this.testDir = new TestDirectory(cwdArg, testPathArg, executionModeArg);
|
this.testDir = new TestDirectory(cwdArg, testPathArg, executionModeArg);
|
||||||
this.logger = new TsTestLogger(logOptions);
|
this.logger = new TsTestLogger(logOptions);
|
||||||
this.filterTags = tags;
|
this.filterTags = tags;
|
||||||
|
this.startFromFile = startFromFile;
|
||||||
|
this.stopAtFile = stopAtFile;
|
||||||
}
|
}
|
||||||
|
|
||||||
async run() {
|
async run() {
|
||||||
const testGroups = await this.testDir.getTestFileGroups();
|
const testGroups = await this.testDir.getTestFileGroups();
|
||||||
const allFiles = [...testGroups.serial, ...Object.values(testGroups.parallelGroups).flat()];
|
let allFiles = [...testGroups.serial, ...Object.values(testGroups.parallelGroups).flat()];
|
||||||
|
|
||||||
|
// Apply file range filtering if specified
|
||||||
|
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
|
// Log test discovery
|
||||||
this.logger.testDiscovery(
|
this.logger.testDiscovery(
|
||||||
|
Loading…
x
Reference in New Issue
Block a user