@travetto/test 7.0.0-rc.2 → 7.0.0-rc.4
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/README.md +1 -2
- package/__index__.ts +1 -0
- package/package.json +7 -7
- package/src/assert/util.ts +1 -1
- package/src/communication.ts +66 -0
- package/src/consumer/registry-index.ts +7 -7
- package/src/consumer/types/cumulative.ts +90 -61
- package/src/consumer/types/delegating.ts +23 -20
- package/src/consumer/types/event.ts +11 -4
- package/src/consumer/types/exec.ts +12 -3
- package/src/consumer/types/runnable.ts +2 -1
- package/src/consumer/types/summarizer.ts +4 -2
- package/src/consumer/types/tap-summary.ts +5 -3
- package/src/consumer/types.ts +6 -2
- package/src/execute/executor.ts +23 -12
- package/src/execute/phase.ts +1 -1
- package/src/execute/run.ts +247 -0
- package/src/execute/types.ts +2 -17
- package/src/execute/watcher.ts +30 -56
- package/src/model/common.ts +4 -0
- package/src/model/event.ts +3 -1
- package/src/model/suite.ts +9 -20
- package/src/model/test.ts +47 -1
- package/src/model/util.ts +8 -0
- package/src/registry/registry-adapter.ts +4 -2
- package/src/registry/registry-index.ts +10 -11
- package/src/worker/child.ts +12 -12
- package/src/worker/standard.ts +27 -18
- package/src/worker/types.ts +9 -5
- package/support/bin/run.ts +6 -6
- package/support/cli.test.ts +20 -41
- package/support/cli.test_diff.ts +47 -0
- package/support/cli.test_digest.ts +2 -2
- package/support/cli.test_direct.ts +13 -12
- package/support/cli.test_watch.ts +1 -6
- package/src/execute/runner.ts +0 -87
- package/src/execute/util.ts +0 -108
|
@@ -61,7 +61,7 @@ export class SuiteRegistryAdapter implements RegistryAdapter<SuiteConfig> {
|
|
|
61
61
|
|
|
62
62
|
register(...data: Partial<SuiteConfig>[]): SuiteConfig {
|
|
63
63
|
if (!this.#config) {
|
|
64
|
-
const lines = describeFunction(this.#cls)
|
|
64
|
+
const { lines, hash } = describeFunction(this.#cls) ?? {};
|
|
65
65
|
this.#config = asFull<SuiteConfig>({
|
|
66
66
|
class: this.#cls,
|
|
67
67
|
classId: this.#cls.Ⲑid,
|
|
@@ -69,6 +69,7 @@ export class SuiteRegistryAdapter implements RegistryAdapter<SuiteConfig> {
|
|
|
69
69
|
import: Runtime.getImport(this.#cls),
|
|
70
70
|
lineStart: lines?.[0],
|
|
71
71
|
lineEnd: lines?.[1],
|
|
72
|
+
sourceHash: hash,
|
|
72
73
|
tests: {},
|
|
73
74
|
beforeAll: [],
|
|
74
75
|
beforeEach: [],
|
|
@@ -84,7 +85,7 @@ export class SuiteRegistryAdapter implements RegistryAdapter<SuiteConfig> {
|
|
|
84
85
|
const suite = this.register();
|
|
85
86
|
|
|
86
87
|
if (!(method in this.#config.tests)) {
|
|
87
|
-
const lines = describeFunction(this.#cls)?.methods?.[method]
|
|
88
|
+
const { lines, hash } = describeFunction(this.#cls)?.methods?.[method] ?? {};
|
|
88
89
|
const config = asFull<TestConfig>({
|
|
89
90
|
class: this.#cls,
|
|
90
91
|
tags: [],
|
|
@@ -93,6 +94,7 @@ export class SuiteRegistryAdapter implements RegistryAdapter<SuiteConfig> {
|
|
|
93
94
|
lineEnd: lines?.[1],
|
|
94
95
|
lineBodyStart: lines?.[2],
|
|
95
96
|
methodName: method,
|
|
97
|
+
sourceHash: hash,
|
|
96
98
|
});
|
|
97
99
|
this.#config.tests[method] = config;
|
|
98
100
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { AppError, Class, Runtime, describeFunction } from '@travetto/runtime';
|
|
2
|
-
import {
|
|
2
|
+
import { RegistryIndex, RegistryIndexStore, Registry } from '@travetto/registry';
|
|
3
3
|
|
|
4
4
|
import { SuiteConfig } from '../model/suite.ts';
|
|
5
5
|
import { TestConfig, TestRun } from '../model/test.ts';
|
|
@@ -21,11 +21,7 @@ export class SuiteRegistryIndex implements RegistryIndex {
|
|
|
21
21
|
return this.#instance.store.getForRegister(cls);
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
static
|
|
25
|
-
return this.#instance.store.has(cls);
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
static getTestConfig(cls: Class, method: Function): TestConfig | undefined {
|
|
24
|
+
static getTestConfig(cls: Class, method: Function | string): TestConfig | undefined {
|
|
29
25
|
return this.#instance.getTestConfig(cls, method);
|
|
30
26
|
}
|
|
31
27
|
|
|
@@ -41,11 +37,13 @@ export class SuiteRegistryIndex implements RegistryIndex {
|
|
|
41
37
|
return this.#instance.store.getClasses();
|
|
42
38
|
}
|
|
43
39
|
|
|
40
|
+
static hasConfig(cls: Class): boolean {
|
|
41
|
+
return this.#instance.store.has(cls);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
44
|
store = new RegistryIndexStore(SuiteRegistryAdapter);
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
// No-op for now
|
|
48
|
-
}
|
|
46
|
+
/** @private */ constructor(source: unknown) { Registry.validateConstructor(source); }
|
|
49
47
|
|
|
50
48
|
/**
|
|
51
49
|
* Find all valid tests (ignoring abstract)
|
|
@@ -109,10 +107,11 @@ export class SuiteRegistryIndex implements RegistryIndex {
|
|
|
109
107
|
/**
|
|
110
108
|
* Find a test configuration given class and optionally a method
|
|
111
109
|
*/
|
|
112
|
-
getTestConfig(cls: Class, method: Function): TestConfig | undefined {
|
|
110
|
+
getTestConfig(cls: Class, method: Function | string): TestConfig | undefined {
|
|
113
111
|
if (this.store.has(cls)) {
|
|
114
112
|
const config = this.getConfig(cls);
|
|
115
|
-
|
|
113
|
+
const methodName = typeof method === 'string' ? method : method.name;
|
|
114
|
+
return Object.values(config.tests).find(item => item.methodName === methodName);
|
|
116
115
|
}
|
|
117
116
|
}
|
|
118
117
|
}
|
package/src/worker/child.ts
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
import { createWriteStream } from 'node:fs';
|
|
2
2
|
|
|
3
|
-
import { ConsoleManager, Env,
|
|
3
|
+
import { ConsoleManager, Env, Runtime } from '@travetto/runtime';
|
|
4
4
|
import { IpcChannel } from '@travetto/worker';
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
import {
|
|
8
|
-
import { Events } from './types.ts';
|
|
6
|
+
import { RunUtil } from '../execute/run.ts';
|
|
7
|
+
import { TestWorkerEvents } from './types.ts';
|
|
9
8
|
import { TestRun } from '../model/test.ts';
|
|
9
|
+
import { CommunicationUtil } from '../communication.ts';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Child Worker for the Test Runner. Receives events as commands
|
|
@@ -25,7 +25,7 @@ export class TestChildWorker extends IpcChannel<TestRun> {
|
|
|
25
25
|
throw error;
|
|
26
26
|
}
|
|
27
27
|
// Mark as errored out
|
|
28
|
-
this.send(type,
|
|
28
|
+
this.send(type, CommunicationUtil.serializeToObject({ error }));
|
|
29
29
|
}
|
|
30
30
|
}
|
|
31
31
|
|
|
@@ -42,13 +42,13 @@ export class TestChildWorker extends IpcChannel<TestRun> {
|
|
|
42
42
|
ConsoleManager.set({ log: () => { } });
|
|
43
43
|
}
|
|
44
44
|
|
|
45
|
-
|
|
45
|
+
RunUtil.registerCleanup('worker');
|
|
46
46
|
|
|
47
47
|
// Listen for inbound requests
|
|
48
48
|
this.on('*', event => this.onCommand(event));
|
|
49
49
|
|
|
50
50
|
// Let parent know the child is ready for handling commands
|
|
51
|
-
this.send(
|
|
51
|
+
this.send(TestWorkerEvents.READY);
|
|
52
52
|
|
|
53
53
|
await this.#done.promise;
|
|
54
54
|
}
|
|
@@ -59,10 +59,10 @@ export class TestChildWorker extends IpcChannel<TestRun> {
|
|
|
59
59
|
async onCommand(event: TestRun & { type: string }): Promise<boolean> {
|
|
60
60
|
console.debug('on message', { ...event });
|
|
61
61
|
|
|
62
|
-
if (event.type ===
|
|
63
|
-
await this.#exec(() => this.onInitCommand(),
|
|
64
|
-
} else if (event.type ===
|
|
65
|
-
await this.#exec(() => this.onRunCommand(event),
|
|
62
|
+
if (event.type === TestWorkerEvents.INIT) { // On request to init, start initialization
|
|
63
|
+
await this.#exec(() => this.onInitCommand(), TestWorkerEvents.INIT_COMPLETE);
|
|
64
|
+
} else if (event.type === TestWorkerEvents.RUN) { // On request to run, start running
|
|
65
|
+
await this.#exec(() => this.onRunCommand(event), TestWorkerEvents.RUN_COMPLETE);
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
return false;
|
|
@@ -80,7 +80,7 @@ export class TestChildWorker extends IpcChannel<TestRun> {
|
|
|
80
80
|
console.debug('Running', { import: run.import });
|
|
81
81
|
|
|
82
82
|
try {
|
|
83
|
-
await
|
|
83
|
+
await RunUtil.runTests({ consumer: 'exec' }, run);
|
|
84
84
|
} finally {
|
|
85
85
|
this.#done.resolve();
|
|
86
86
|
}
|
package/src/worker/standard.ts
CHANGED
|
@@ -1,26 +1,26 @@
|
|
|
1
1
|
import { fork } from 'node:child_process';
|
|
2
2
|
|
|
3
|
-
import { Env, RuntimeIndex
|
|
3
|
+
import { Env, RuntimeIndex } from '@travetto/runtime';
|
|
4
4
|
import { IpcChannel } from '@travetto/worker';
|
|
5
5
|
|
|
6
|
-
import {
|
|
7
|
-
import { TestConsumerShape } from '../consumer/types.ts';
|
|
8
|
-
import { TestEvent } from '../model/event.ts';
|
|
9
|
-
import { TestRun } from '../model/test.ts';
|
|
6
|
+
import { TestWorkerEvents, type TestLogEvent } from './types.ts';
|
|
7
|
+
import type { TestConsumerShape } from '../consumer/types.ts';
|
|
8
|
+
import type { TestEvent, TestRemoveEvent } from '../model/event.ts';
|
|
9
|
+
import type { TestDiffInput, TestRun } from '../model/test.ts';
|
|
10
|
+
import { CommunicationUtil } from '../communication.ts';
|
|
10
11
|
|
|
11
|
-
const log = (message: string): void => {
|
|
12
|
-
|
|
12
|
+
const log = (message: string | TestLogEvent): void => {
|
|
13
|
+
const event: TestLogEvent = typeof message === 'string' ? { type: 'log', message } : message;
|
|
14
|
+
process.send ? process.send?.(event) : console.debug(event.message);
|
|
13
15
|
};
|
|
14
16
|
|
|
15
17
|
/**
|
|
16
18
|
* Produce a handler for the child worker
|
|
17
19
|
*/
|
|
18
|
-
export async function buildStandardTestManager(consumer: TestConsumerShape, run: TestRun): Promise<void> {
|
|
20
|
+
export async function buildStandardTestManager(consumer: TestConsumerShape, run: TestRun | TestDiffInput): Promise<void> {
|
|
19
21
|
log(`Worker Input ${JSON.stringify(run)}`);
|
|
20
|
-
log(`Worker Executing ${run.import}`);
|
|
21
22
|
|
|
22
|
-
const
|
|
23
|
-
const suiteMod = RuntimeIndex.getModule(module)!;
|
|
23
|
+
const suiteMod = RuntimeIndex.findModuleForArbitraryImport(run.import)!;
|
|
24
24
|
|
|
25
25
|
const channel = new IpcChannel<TestEvent & { error?: Error }>(
|
|
26
26
|
fork(
|
|
@@ -37,25 +37,34 @@ export async function buildStandardTestManager(consumer: TestConsumerShape, run:
|
|
|
37
37
|
)
|
|
38
38
|
);
|
|
39
39
|
|
|
40
|
-
await channel.once(
|
|
41
|
-
await channel.send(
|
|
42
|
-
await channel.once(
|
|
40
|
+
await channel.once(TestWorkerEvents.READY); // Wait for the child to be ready
|
|
41
|
+
await channel.send(TestWorkerEvents.INIT); // Initialize
|
|
42
|
+
await channel.once(TestWorkerEvents.INIT_COMPLETE); // Wait for complete
|
|
43
43
|
|
|
44
44
|
channel.on('*', async event => {
|
|
45
45
|
try {
|
|
46
|
-
|
|
46
|
+
const parsed: TestEvent | TestRemoveEvent | TestLogEvent = CommunicationUtil.deserializeFromObject(event);
|
|
47
|
+
if (parsed.type === 'log') {
|
|
48
|
+
log(parsed);
|
|
49
|
+
} else if (parsed.type === 'removeTest') {
|
|
50
|
+
log(`Received remove event ${JSON.stringify(event)}@${consumer.constructor.name}`);
|
|
51
|
+
await consumer.onRemoveEvent?.(parsed); // Forward remove events
|
|
52
|
+
} else {
|
|
53
|
+
await consumer.onEvent(parsed); // Forward standard events
|
|
54
|
+
}
|
|
47
55
|
} catch {
|
|
48
56
|
// Do nothing
|
|
49
57
|
}
|
|
50
58
|
});
|
|
51
59
|
|
|
52
60
|
// Listen for child to complete
|
|
53
|
-
const complete = channel.once(
|
|
61
|
+
const complete = channel.once(TestWorkerEvents.RUN_COMPLETE);
|
|
54
62
|
// Start test
|
|
55
|
-
channel.send(
|
|
63
|
+
channel.send(TestWorkerEvents.RUN, run);
|
|
56
64
|
|
|
57
65
|
// Wait for complete
|
|
58
|
-
const
|
|
66
|
+
const completedEvent = await complete;
|
|
67
|
+
const result: { error?: unknown } = await CommunicationUtil.deserializeFromObject(completedEvent);
|
|
59
68
|
|
|
60
69
|
// Kill on complete
|
|
61
70
|
await channel.destroy();
|
package/src/worker/types.ts
CHANGED
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
import { TestEvent } from '../model/event.ts';
|
|
2
|
-
import { TestRun } from '../model/test.ts';
|
|
1
|
+
import { TestEvent, TestRemoveEvent } from '../model/event.ts';
|
|
3
2
|
|
|
4
3
|
/**
|
|
5
4
|
* Test Run Event Keys
|
|
6
5
|
*/
|
|
7
|
-
export const
|
|
6
|
+
export const TestWorkerEvents = {
|
|
8
7
|
RUN: 'run',
|
|
9
8
|
RUN_COMPLETE: 'runComplete',
|
|
10
9
|
INIT: 'init',
|
|
@@ -12,12 +11,17 @@ export const Events = {
|
|
|
12
11
|
READY: 'ready'
|
|
13
12
|
};
|
|
14
13
|
|
|
15
|
-
export type
|
|
14
|
+
export type TestRunEvent = { type: 'runTest', import: string };
|
|
15
|
+
|
|
16
|
+
export const isTestRunEvent = (event: unknown): event is TestRunEvent =>
|
|
17
|
+
typeof event === 'object' && !!event && 'type' in event && event.type === 'runTest';
|
|
18
|
+
|
|
19
|
+
|
|
16
20
|
export type TestReadyEvent = { type: 'ready' };
|
|
17
21
|
export type TestLogEvent = { type: 'log', message: string };
|
|
18
22
|
|
|
19
23
|
export type TestWatchEvent =
|
|
20
24
|
TestEvent |
|
|
21
|
-
|
|
25
|
+
TestRemoveEvent |
|
|
22
26
|
TestReadyEvent |
|
|
23
27
|
TestLogEvent;
|
package/support/bin/run.ts
CHANGED
|
@@ -2,20 +2,20 @@ import { getClass, Runtime } from '@travetto/runtime';
|
|
|
2
2
|
import { SchemaRegistryIndex } from '@travetto/schema';
|
|
3
3
|
|
|
4
4
|
import { TestConsumerRegistryIndex } from '../../src/consumer/registry-index.ts';
|
|
5
|
-
import type {
|
|
5
|
+
import type { TestConsumerConfig } from '../../src/execute/types.ts';
|
|
6
|
+
import type { TestRunInput } from '../../src/model/test.ts';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Run tests given the input state
|
|
9
10
|
* @param state
|
|
10
11
|
*/
|
|
11
|
-
export async function runTests(state:
|
|
12
|
-
const {
|
|
13
|
-
const { Runner } = await import('../../src/execute/runner.ts');
|
|
12
|
+
export async function runTests(state: TestConsumerConfig, input: TestRunInput): Promise<void> {
|
|
13
|
+
const { RunUtil } = await import('../../src/execute/run.ts');
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
RunUtil.registerCleanup('runner');
|
|
16
16
|
|
|
17
17
|
try {
|
|
18
|
-
const result = await
|
|
18
|
+
const result = await RunUtil.runTests(state, input);
|
|
19
19
|
process.exitCode = result ? 0 : 1;
|
|
20
20
|
} catch (error) {
|
|
21
21
|
console.error('Test Worker Failed', { error });
|
package/support/cli.test.ts
CHANGED
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { EventEmitter } from 'node:events';
|
|
2
|
-
import fs from 'node:fs/promises';
|
|
3
|
-
import path from 'node:path';
|
|
4
2
|
|
|
5
|
-
import { Env } from '@travetto/runtime';
|
|
6
|
-
import { CliCommandShape, CliCommand,
|
|
3
|
+
import { Env, RuntimeIndex } from '@travetto/runtime';
|
|
4
|
+
import { CliCommandShape, CliCommand, CliUtil } from '@travetto/cli';
|
|
7
5
|
import { WorkPool } from '@travetto/worker';
|
|
8
6
|
import { Max, Min } from '@travetto/schema';
|
|
9
7
|
|
|
@@ -20,11 +18,8 @@ export class TestCommand implements CliCommandShape {
|
|
|
20
18
|
@Min(1) @Max(WorkPool.MAX_SIZE)
|
|
21
19
|
concurrency: number = WorkPool.DEFAULT_SIZE;
|
|
22
20
|
|
|
23
|
-
/** Test run mode */
|
|
24
|
-
mode: 'single' | 'standard' = 'standard';
|
|
25
|
-
|
|
26
21
|
/**
|
|
27
|
-
* Tags to target or exclude
|
|
22
|
+
* Tags to target or exclude when using globs
|
|
28
23
|
* @alias env.TRV_TEST_TAGS
|
|
29
24
|
*/
|
|
30
25
|
tags?: string[];
|
|
@@ -44,46 +39,30 @@ export class TestCommand implements CliCommandShape {
|
|
|
44
39
|
Env.TRV_LOG_TIME.clear();
|
|
45
40
|
}
|
|
46
41
|
|
|
47
|
-
isFirstFile(first: string): Promise<boolean> {
|
|
48
|
-
return fs.stat(path.resolve(first ?? '')).then(stat => stat.isFile(), () => false);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
async resolvedMode(first: string, rest: string[]): Promise<string> {
|
|
52
|
-
return (await this.isFirstFile(first)) && rest.length === 0 ? 'single' : this.mode;
|
|
53
|
-
}
|
|
54
|
-
|
|
55
42
|
async preValidate(): Promise<void> {
|
|
56
43
|
const { selectConsumer } = await import('./bin/run.ts');
|
|
57
44
|
await selectConsumer(this);
|
|
58
45
|
}
|
|
59
46
|
|
|
60
|
-
async validate(first: string = '**/*', rest: string[]): Promise<CliValidationError | undefined> {
|
|
61
|
-
const mode = await this.resolvedMode(first, rest);
|
|
62
|
-
|
|
63
|
-
if (mode === 'single' && !await this.isFirstFile(first)) {
|
|
64
|
-
return { message: 'You must specify a proper test file to run in single mode', source: 'arg' };
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
47
|
async main(first: string = '**/*', globs: string[] = []): Promise<void> {
|
|
69
48
|
const { runTests } = await import('./bin/run.ts');
|
|
70
49
|
|
|
71
|
-
const
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
50
|
+
const importPath = RuntimeIndex.getFromImportOrSource(first)?.import;
|
|
51
|
+
|
|
52
|
+
return runTests(
|
|
53
|
+
{
|
|
54
|
+
concurrency: this.concurrency,
|
|
55
|
+
consumer: this.format,
|
|
56
|
+
consumerOptions: CliUtil.readExtendedOptions(this.formatOptions),
|
|
57
|
+
},
|
|
58
|
+
importPath ? {
|
|
59
|
+
import: importPath,
|
|
60
|
+
classId: globs[0],
|
|
61
|
+
methodNames: globs.slice(1),
|
|
62
|
+
} : {
|
|
63
|
+
globs: [first, ...globs],
|
|
64
|
+
tags: this.tags,
|
|
65
|
+
}
|
|
66
|
+
);
|
|
88
67
|
}
|
|
89
68
|
}
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { Env, JSONUtil, RuntimeIndex } from '@travetto/runtime';
|
|
2
|
+
import { CliCommand, CliUtil } from '@travetto/cli';
|
|
3
|
+
import { IsPrivate } from '@travetto/schema';
|
|
4
|
+
|
|
5
|
+
import { runTests, selectConsumer } from './bin/run.ts';
|
|
6
|
+
import type { TestDiffSource } from '../src/model/test.ts';
|
|
7
|
+
|
|
8
|
+
/** Direct test invocation */
|
|
9
|
+
@CliCommand()
|
|
10
|
+
@IsPrivate()
|
|
11
|
+
export class TestDiffCommand {
|
|
12
|
+
|
|
13
|
+
format: string = 'tap';
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Format options
|
|
17
|
+
* @alias o
|
|
18
|
+
*/
|
|
19
|
+
formatOptions?: string[];
|
|
20
|
+
|
|
21
|
+
async preValidate(): Promise<void> {
|
|
22
|
+
await selectConsumer(this);
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
preMain(): void {
|
|
26
|
+
Env.TRV_ROLE.set('test');
|
|
27
|
+
Env.TRV_ENV.set('test');
|
|
28
|
+
Env.TRV_LOG_PLAIN.set(true);
|
|
29
|
+
Env.TRV_LOG_TIME.clear();
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
async main(importOrFile: string, diff: string): Promise<void> {
|
|
33
|
+
const diffSource: TestDiffSource = await JSONUtil.readFile(diff);
|
|
34
|
+
const importPath = RuntimeIndex.getFromImportOrSource(importOrFile)?.import!;
|
|
35
|
+
|
|
36
|
+
return runTests(
|
|
37
|
+
{
|
|
38
|
+
consumer: this.format,
|
|
39
|
+
consumerOptions: CliUtil.readExtendedOptions(this.formatOptions),
|
|
40
|
+
},
|
|
41
|
+
{
|
|
42
|
+
import: importPath,
|
|
43
|
+
diffSource
|
|
44
|
+
}
|
|
45
|
+
);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
@@ -4,7 +4,7 @@ import { Registry } from '@travetto/registry';
|
|
|
4
4
|
import { IsPrivate } from '@travetto/schema';
|
|
5
5
|
|
|
6
6
|
import { SuiteRegistryIndex } from '../src/registry/registry-index.ts';
|
|
7
|
-
import {
|
|
7
|
+
import { RunUtil } from '../src/execute/run.ts';
|
|
8
8
|
|
|
9
9
|
@CliCommand()
|
|
10
10
|
@IsPrivate()
|
|
@@ -19,7 +19,7 @@ export class TestDigestCommand {
|
|
|
19
19
|
|
|
20
20
|
async main(globs: string[] = ['**/*']) {
|
|
21
21
|
// Load all tests
|
|
22
|
-
for await (const imp of await
|
|
22
|
+
for await (const imp of await RunUtil.getTestImports(globs)) {
|
|
23
23
|
try {
|
|
24
24
|
await Runtime.importFrom(imp);
|
|
25
25
|
} catch (error) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Env } from '@travetto/runtime';
|
|
2
|
-
import { CliCommand } from '@travetto/cli';
|
|
1
|
+
import { Env, RuntimeIndex } from '@travetto/runtime';
|
|
2
|
+
import { CliCommand, CliUtil } from '@travetto/cli';
|
|
3
3
|
import { IsPrivate } from '@travetto/schema';
|
|
4
4
|
|
|
5
5
|
import { runTests, selectConsumer } from './bin/run.ts';
|
|
@@ -9,7 +9,6 @@ import { runTests, selectConsumer } from './bin/run.ts';
|
|
|
9
9
|
@IsPrivate()
|
|
10
10
|
export class TestDirectCommand {
|
|
11
11
|
|
|
12
|
-
@IsPrivate()
|
|
13
12
|
format: string = 'tap';
|
|
14
13
|
|
|
15
14
|
/**
|
|
@@ -30,17 +29,19 @@ export class TestDirectCommand {
|
|
|
30
29
|
}
|
|
31
30
|
|
|
32
31
|
main(importOrFile: string, clsId?: string, methodsNames: string[] = []): Promise<void> {
|
|
33
|
-
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
return runTests(
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
32
|
+
// Resolve to import
|
|
33
|
+
const importPath = RuntimeIndex.getFromImportOrSource(importOrFile)?.import!;
|
|
34
|
+
|
|
35
|
+
return runTests(
|
|
36
|
+
{
|
|
37
|
+
consumer: this.format,
|
|
38
|
+
consumerOptions: CliUtil.readExtendedOptions(this.formatOptions),
|
|
39
|
+
},
|
|
40
|
+
{
|
|
41
|
+
import: importPath,
|
|
41
42
|
classId: clsId,
|
|
42
43
|
methodNames: methodsNames,
|
|
43
44
|
}
|
|
44
|
-
|
|
45
|
+
);
|
|
45
46
|
}
|
|
46
47
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { Env } from '@travetto/runtime';
|
|
2
|
-
import { CliCommand
|
|
2
|
+
import { CliCommand } from '@travetto/cli';
|
|
3
3
|
|
|
4
4
|
import { selectConsumer } from './bin/run.ts';
|
|
5
5
|
|
|
@@ -18,14 +18,9 @@ export class TestWatcherCommand {
|
|
|
18
18
|
|
|
19
19
|
preMain(): void {
|
|
20
20
|
Env.TRV_ROLE.set('test');
|
|
21
|
-
Env.TRV_DYNAMIC.set(true);
|
|
22
21
|
}
|
|
23
22
|
|
|
24
23
|
async main(): Promise<void> {
|
|
25
|
-
if (await CliUtil.runWithRestart(this, true)) {
|
|
26
|
-
return;
|
|
27
|
-
}
|
|
28
|
-
|
|
29
24
|
try {
|
|
30
25
|
const { TestWatcher } = await import('../src/execute/watcher.ts');
|
|
31
26
|
await TestWatcher.watch(this.format, this.mode === 'all');
|
package/src/execute/runner.ts
DELETED
|
@@ -1,87 +0,0 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
|
|
3
|
-
import { TimeUtil, Runtime, RuntimeIndex } from '@travetto/runtime';
|
|
4
|
-
import { WorkPool } from '@travetto/worker';
|
|
5
|
-
|
|
6
|
-
import { buildStandardTestManager } from '../worker/standard.ts';
|
|
7
|
-
import { RunnableTestConsumer } from '../consumer/types/runnable.ts';
|
|
8
|
-
import { TestRun } from '../model/test.ts';
|
|
9
|
-
|
|
10
|
-
import { TestExecutor } from './executor.ts';
|
|
11
|
-
import { RunnerUtil } from './util.ts';
|
|
12
|
-
import { RunState } from './types.ts';
|
|
13
|
-
import { TestConsumerRegistryIndex } from '../consumer/registry-index.ts';
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* Test Runner
|
|
17
|
-
*/
|
|
18
|
-
export class Runner {
|
|
19
|
-
|
|
20
|
-
#state: RunState;
|
|
21
|
-
|
|
22
|
-
constructor(state: RunState) {
|
|
23
|
-
this.#state = state;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
/**
|
|
27
|
-
* Run all files
|
|
28
|
-
*/
|
|
29
|
-
async runFiles(globs?: string[]): Promise<boolean> {
|
|
30
|
-
const target = await TestConsumerRegistryIndex.getInstance(this.#state);
|
|
31
|
-
const consumer = new RunnableTestConsumer(target);
|
|
32
|
-
const tests = await RunnerUtil.getTestDigest(globs, this.#state.tags);
|
|
33
|
-
const testRuns = RunnerUtil.getTestRuns(tests)
|
|
34
|
-
.toSorted((a, b) => a.runId!.localeCompare(b.runId!));
|
|
35
|
-
|
|
36
|
-
await consumer.onStart({ testCount: tests.length });
|
|
37
|
-
await WorkPool.run(
|
|
38
|
-
run => buildStandardTestManager(consumer, run),
|
|
39
|
-
testRuns,
|
|
40
|
-
{
|
|
41
|
-
idleTimeoutMillis: TimeUtil.asMillis(10, 's'),
|
|
42
|
-
min: 1,
|
|
43
|
-
max: this.#state.concurrency
|
|
44
|
-
});
|
|
45
|
-
|
|
46
|
-
return consumer.summarizeAsBoolean();
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/**
|
|
50
|
-
* Run a single file
|
|
51
|
-
*/
|
|
52
|
-
async runSingle(run: TestRun): Promise<boolean> {
|
|
53
|
-
run.import =
|
|
54
|
-
RuntimeIndex.getFromImport(run.import)?.import ??
|
|
55
|
-
RuntimeIndex.getFromSource(path.resolve(run.import))?.import!;
|
|
56
|
-
|
|
57
|
-
const entry = RuntimeIndex.getFromImport(run.import)!;
|
|
58
|
-
|
|
59
|
-
if (entry.module !== Runtime.main.name) {
|
|
60
|
-
RuntimeIndex.reinitForModule(entry.module);
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const target = await TestConsumerRegistryIndex.getInstance(this.#state);
|
|
64
|
-
|
|
65
|
-
const consumer = new RunnableTestConsumer(target)
|
|
66
|
-
.withTransformer(event => {
|
|
67
|
-
// Copy run metadata to event
|
|
68
|
-
event.metadata = run.metadata;
|
|
69
|
-
return event;
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
await consumer.onStart({});
|
|
73
|
-
await new TestExecutor(consumer).execute(run);
|
|
74
|
-
return consumer.summarizeAsBoolean();
|
|
75
|
-
}
|
|
76
|
-
|
|
77
|
-
/**
|
|
78
|
-
* Run the runner, based on the inputs passed to the constructor
|
|
79
|
-
*/
|
|
80
|
-
async run(): Promise<boolean | undefined> {
|
|
81
|
-
if ('import' in this.#state.target) {
|
|
82
|
-
return await this.runSingle(this.#state.target);
|
|
83
|
-
} else {
|
|
84
|
-
return await this.runFiles(this.#state.target.globs);
|
|
85
|
-
}
|
|
86
|
-
}
|
|
87
|
-
}
|