@git.zone/tstest 2.6.2 → 2.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/tstest.classes.runtime.bun.js +3 -1
- package/dist_ts/tstest.classes.runtime.deno.js +12 -1
- package/dist_ts/tstest.classes.runtime.docker.d.ts +42 -0
- package/dist_ts/tstest.classes.runtime.docker.js +199 -0
- package/dist_ts/tstest.classes.runtime.parser.d.ts +28 -0
- package/dist_ts/tstest.classes.runtime.parser.js +59 -2
- package/dist_ts/tstest.classes.testdirectory.js +10 -4
- package/dist_ts/tstest.classes.tstest.d.ts +6 -0
- package/dist_ts/tstest.classes.tstest.js +27 -3
- package/package.json +3 -2
- package/readme.md +123 -0
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/tstest.classes.runtime.bun.ts +3 -0
- package/ts/tstest.classes.runtime.deno.ts +12 -0
- package/ts/tstest.classes.runtime.docker.ts +251 -0
- package/ts/tstest.classes.runtime.parser.ts +79 -1
- package/ts/tstest.classes.testdirectory.ts +13 -5
- package/ts/tstest.classes.tstest.ts +40 -2
|
@@ -29,7 +29,7 @@ export interface ParserConfig {
|
|
|
29
29
|
|
|
30
30
|
const KNOWN_RUNTIMES: Set<string> = new Set(['node', 'chromium', 'deno', 'bun']);
|
|
31
31
|
const KNOWN_MODIFIERS: Set<string> = new Set(['nonci']);
|
|
32
|
-
const VALID_EXTENSIONS: Set<string> = new Set(['ts', 'tsx', 'mts', 'cts']);
|
|
32
|
+
const VALID_EXTENSIONS: Set<string> = new Set(['ts', 'tsx', 'mts', 'cts', 'sh']);
|
|
33
33
|
const ALL_RUNTIMES: Runtime[] = ['node', 'chromium', 'deno', 'bun'];
|
|
34
34
|
|
|
35
35
|
// Legacy mappings for backwards compatibility
|
|
@@ -228,3 +228,81 @@ export function getLegacyMigrationTarget(fileName: string): string | null {
|
|
|
228
228
|
|
|
229
229
|
return parts.join('.');
|
|
230
230
|
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Docker test file information
|
|
234
|
+
*/
|
|
235
|
+
export interface DockerTestFileInfo {
|
|
236
|
+
baseName: string;
|
|
237
|
+
variant: string;
|
|
238
|
+
isDockerTest: true;
|
|
239
|
+
original: string;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/**
|
|
243
|
+
* Check if a filename matches the Docker test pattern: *.{variant}.docker.sh
|
|
244
|
+
* Examples: test.latest.docker.sh, test.integration.npmci.docker.sh
|
|
245
|
+
*/
|
|
246
|
+
export function isDockerTestFile(fileName: string): boolean {
|
|
247
|
+
// Must end with .docker.sh
|
|
248
|
+
if (!fileName.endsWith('.docker.sh')) {
|
|
249
|
+
return false;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
// Extract filename from path if needed
|
|
253
|
+
const name = fileName.split('/').pop() || fileName;
|
|
254
|
+
|
|
255
|
+
// Must have at least 3 parts: [baseName, variant, docker, sh]
|
|
256
|
+
const parts = name.split('.');
|
|
257
|
+
return parts.length >= 4 && parts[parts.length - 2] === 'docker' && parts[parts.length - 1] === 'sh';
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
/**
|
|
261
|
+
* Parse a Docker test filename to extract variant and base name
|
|
262
|
+
* Pattern: test.{baseName}.{variant}.docker.sh
|
|
263
|
+
* Examples:
|
|
264
|
+
* - test.latest.docker.sh -> { baseName: 'test', variant: 'latest' }
|
|
265
|
+
* - test.integration.npmci.docker.sh -> { baseName: 'test.integration', variant: 'npmci' }
|
|
266
|
+
*/
|
|
267
|
+
export function parseDockerTestFilename(filePath: string): DockerTestFileInfo {
|
|
268
|
+
// Extract just the filename from the path
|
|
269
|
+
const fileName = filePath.split('/').pop() || filePath;
|
|
270
|
+
const original = fileName;
|
|
271
|
+
|
|
272
|
+
if (!isDockerTestFile(fileName)) {
|
|
273
|
+
throw new Error(`Not a valid Docker test file: "${fileName}". Expected pattern: *.{variant}.docker.sh`);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
// Remove .docker.sh suffix
|
|
277
|
+
const withoutSuffix = fileName.slice(0, -10); // Remove '.docker.sh'
|
|
278
|
+
const tokens = withoutSuffix.split('.');
|
|
279
|
+
|
|
280
|
+
if (tokens.length === 0) {
|
|
281
|
+
throw new Error(`Invalid Docker test file: empty basename in "${fileName}"`);
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
// Last token before .docker.sh is the variant
|
|
285
|
+
const variant = tokens[tokens.length - 1];
|
|
286
|
+
|
|
287
|
+
// Everything else is the base name
|
|
288
|
+
const baseName = tokens.slice(0, -1).join('.');
|
|
289
|
+
|
|
290
|
+
return {
|
|
291
|
+
baseName: baseName || 'test',
|
|
292
|
+
variant,
|
|
293
|
+
isDockerTest: true,
|
|
294
|
+
original,
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/**
|
|
299
|
+
* Map a Docker variant to its corresponding Dockerfile path
|
|
300
|
+
* "latest" -> "Dockerfile"
|
|
301
|
+
* Other variants -> "Dockerfile_{variant}"
|
|
302
|
+
*/
|
|
303
|
+
export function mapVariantToDockerfile(variant: string, baseDir: string): string {
|
|
304
|
+
if (variant === 'latest') {
|
|
305
|
+
return `${baseDir}/Dockerfile`;
|
|
306
|
+
}
|
|
307
|
+
return `${baseDir}/Dockerfile_${variant}`;
|
|
308
|
+
}
|
|
@@ -74,12 +74,20 @@ export class TestDirectory {
|
|
|
74
74
|
case TestExecutionMode.DIRECTORY:
|
|
75
75
|
// Directory mode - now recursive with ** pattern
|
|
76
76
|
const dirPath = plugins.path.join(this.cwd, this.testPath);
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
const
|
|
80
|
-
|
|
77
|
+
|
|
78
|
+
// Search for both TypeScript test files and Docker shell test files
|
|
79
|
+
const tsPattern = '**/test*.ts';
|
|
80
|
+
const dockerPattern = '**/*.docker.sh';
|
|
81
|
+
|
|
82
|
+
const [tsFiles, dockerFiles] = await Promise.all([
|
|
83
|
+
plugins.smartfile.fs.listFileTree(dirPath, tsPattern),
|
|
84
|
+
plugins.smartfile.fs.listFileTree(dirPath, dockerPattern),
|
|
85
|
+
]);
|
|
86
|
+
|
|
87
|
+
const allTestFiles = [...tsFiles, ...dockerFiles];
|
|
88
|
+
|
|
81
89
|
this.testfileArray = await Promise.all(
|
|
82
|
-
|
|
90
|
+
allTestFiles.map(async (filePath) => {
|
|
83
91
|
const absolutePath = plugins.path.isAbsolute(filePath)
|
|
84
92
|
? filePath
|
|
85
93
|
: plugins.path.join(dirPath, filePath);
|
|
@@ -11,12 +11,13 @@ import { TsTestLogger } from './tstest.logging.js';
|
|
|
11
11
|
import type { LogOptions } from './tstest.logging.js';
|
|
12
12
|
|
|
13
13
|
// Runtime adapters
|
|
14
|
-
import { parseTestFilename } from './tstest.classes.runtime.parser.js';
|
|
14
|
+
import { parseTestFilename, isDockerTestFile, parseDockerTestFilename } from './tstest.classes.runtime.parser.js';
|
|
15
15
|
import { RuntimeAdapterRegistry } from './tstest.classes.runtime.adapter.js';
|
|
16
16
|
import { NodeRuntimeAdapter } from './tstest.classes.runtime.node.js';
|
|
17
17
|
import { ChromiumRuntimeAdapter } from './tstest.classes.runtime.chromium.js';
|
|
18
18
|
import { DenoRuntimeAdapter } from './tstest.classes.runtime.deno.js';
|
|
19
19
|
import { BunRuntimeAdapter } from './tstest.classes.runtime.bun.js';
|
|
20
|
+
import { DockerRuntimeAdapter } from './tstest.classes.runtime.docker.js';
|
|
20
21
|
|
|
21
22
|
export class TsTest {
|
|
22
23
|
public testDir: TestDirectory;
|
|
@@ -37,6 +38,7 @@ export class TsTest {
|
|
|
37
38
|
public tsbundleInstance = new plugins.tsbundle.TsBundle();
|
|
38
39
|
|
|
39
40
|
public runtimeRegistry = new RuntimeAdapterRegistry();
|
|
41
|
+
public dockerAdapter: DockerRuntimeAdapter | null = null;
|
|
40
42
|
|
|
41
43
|
constructor(cwdArg: string, testPathArg: string, executionModeArg: TestExecutionMode, logOptions: LogOptions = {}, tags: string[] = [], startFromFile: number | null = null, stopAtFile: number | null = null, timeoutSeconds: number | null = null) {
|
|
42
44
|
this.executionMode = executionModeArg;
|
|
@@ -60,6 +62,14 @@ export class TsTest {
|
|
|
60
62
|
this.runtimeRegistry.register(
|
|
61
63
|
new BunRuntimeAdapter(this.logger, this.smartshellInstance, this.timeoutSeconds, this.filterTags)
|
|
62
64
|
);
|
|
65
|
+
|
|
66
|
+
// Initialize Docker adapter
|
|
67
|
+
this.dockerAdapter = new DockerRuntimeAdapter(
|
|
68
|
+
this.logger,
|
|
69
|
+
this.smartshellInstance,
|
|
70
|
+
this.timeoutSeconds,
|
|
71
|
+
cwdArg
|
|
72
|
+
);
|
|
63
73
|
}
|
|
64
74
|
|
|
65
75
|
/**
|
|
@@ -211,8 +221,14 @@ export class TsTest {
|
|
|
211
221
|
}
|
|
212
222
|
|
|
213
223
|
private async runSingleTest(fileNameArg: string, fileIndex: number, totalFiles: number, tapCombinator: TapCombinator) {
|
|
214
|
-
// Parse the filename to determine runtimes and modifiers
|
|
215
224
|
const fileName = plugins.path.basename(fileNameArg);
|
|
225
|
+
|
|
226
|
+
// Check if this is a Docker test file
|
|
227
|
+
if (isDockerTestFile(fileName)) {
|
|
228
|
+
return await this.runDockerTest(fileNameArg, fileIndex, totalFiles, tapCombinator);
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
// Parse the filename to determine runtimes and modifiers (for TypeScript tests)
|
|
216
232
|
const parsed = parseTestFilename(fileName, { strictUnknownRuntime: false });
|
|
217
233
|
|
|
218
234
|
// Check for nonci modifier in CI environment
|
|
@@ -258,6 +274,28 @@ export class TsTest {
|
|
|
258
274
|
}
|
|
259
275
|
}
|
|
260
276
|
|
|
277
|
+
/**
|
|
278
|
+
* Execute a Docker test file
|
|
279
|
+
*/
|
|
280
|
+
private async runDockerTest(
|
|
281
|
+
fileNameArg: string,
|
|
282
|
+
fileIndex: number,
|
|
283
|
+
totalFiles: number,
|
|
284
|
+
tapCombinator: TapCombinator
|
|
285
|
+
): Promise<void> {
|
|
286
|
+
if (!this.dockerAdapter) {
|
|
287
|
+
this.logger.tapOutput(cs('❌ Docker adapter not initialized', 'red'));
|
|
288
|
+
return;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
try {
|
|
292
|
+
const tapParser = await this.dockerAdapter.run(fileNameArg, fileIndex, totalFiles);
|
|
293
|
+
tapCombinator.addTapParser(tapParser);
|
|
294
|
+
} catch (error) {
|
|
295
|
+
this.logger.tapOutput(cs(`❌ Docker test failed: ${error.message}`, 'red'));
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
|
|
261
299
|
public async runInNode(fileNameArg: string, index: number, total: number): Promise<TapParser> {
|
|
262
300
|
this.logger.testFileStart(fileNameArg, 'node.js', index, total);
|
|
263
301
|
const tapParser = new TapParser(fileNameArg + ':node', this.logger);
|