@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.
@@ -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)?.lines;
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]?.lines;
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 { ChangeEvent, RegistryIndex, RegistryIndexStore, Registry } from '@travetto/registry';
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 has(cls: Class): boolean {
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
- process(_events: ChangeEvent<Class>[]): void {
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
- return Object.values(config.tests).find(item => item.methodName === method.name);
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
  }
@@ -1,12 +1,12 @@
1
1
  import { createWriteStream } from 'node:fs';
2
2
 
3
- import { ConsoleManager, Env, Util, Runtime } from '@travetto/runtime';
3
+ import { ConsoleManager, Env, Runtime } from '@travetto/runtime';
4
4
  import { IpcChannel } from '@travetto/worker';
5
5
 
6
- import { RunnerUtil } from '../execute/util.ts';
7
- import { Runner } from '../execute/runner.ts';
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, JSON.parse(Util.serializeToJSON({ error })));
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
- RunnerUtil.registerCleanup('worker');
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(Events.READY);
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 === Events.INIT) { // On request to init, start initialization
63
- await this.#exec(() => this.onInitCommand(), Events.INIT_COMPLETE);
64
- } else if (event.type === Events.RUN) { // On request to run, start running
65
- await this.#exec(() => this.onRunCommand(event), Events.RUN_COMPLETE);
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 new Runner({ consumer: 'exec', target: run }).run();
83
+ await RunUtil.runTests({ consumer: 'exec' }, run);
84
84
  } finally {
85
85
  this.#done.resolve();
86
86
  }
@@ -1,26 +1,26 @@
1
1
  import { fork } from 'node:child_process';
2
2
 
3
- import { Env, RuntimeIndex, Util } from '@travetto/runtime';
3
+ import { Env, RuntimeIndex } from '@travetto/runtime';
4
4
  import { IpcChannel } from '@travetto/worker';
5
5
 
6
- import { Events, TestLogEvent } from './types.ts';
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
- process.send?.({ type: 'log', message } satisfies TestLogEvent);
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 { module } = RuntimeIndex.getFromImport(run.import)!;
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(Events.READY); // Wait for the child to be ready
41
- await channel.send(Events.INIT); // Initialize
42
- await channel.once(Events.INIT_COMPLETE); // Wait for complete
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
- await consumer.onEvent(Util.deserializeFromJson(JSON.stringify(event))); // Connect the consumer with the event stream from the child
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(Events.RUN_COMPLETE);
61
+ const complete = channel.once(TestWorkerEvents.RUN_COMPLETE);
54
62
  // Start test
55
- channel.send(Events.RUN, run);
63
+ channel.send(TestWorkerEvents.RUN, run);
56
64
 
57
65
  // Wait for complete
58
- const result = await complete.then(event => Util.deserializeFromJson<typeof event>(JSON.stringify(event)));
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();
@@ -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 Events = {
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 TestRemovedEvent = { type: 'removeTest', method?: string } & TestRun;
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
- TestRemovedEvent |
25
+ TestRemoveEvent |
22
26
  TestReadyEvent |
23
27
  TestLogEvent;
@@ -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 { RunState } from '../../src/execute/types.ts';
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: RunState): Promise<void> {
12
- const { RunnerUtil } = await import('../../src/execute/util.ts');
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
- RunnerUtil.registerCleanup('runner');
15
+ RunUtil.registerCleanup('runner');
16
16
 
17
17
  try {
18
- const result = await new Runner(state).run();
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 });
@@ -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, CliValidationError } from '@travetto/cli';
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 isFirst = await this.isFirstFile(first);
72
- const isSingle = this.mode === 'single' || (isFirst && globs.length === 0);
73
- const options = Object.fromEntries((this.formatOptions ?? [])?.map(option => [...option.split(':'), true]));
74
-
75
- return runTests({
76
- concurrency: this.concurrency,
77
- consumer: this.format,
78
- consumerOptions: options,
79
- tags: this.tags,
80
- target: isSingle ?
81
- {
82
- import: first,
83
- classId: globs[0],
84
- methodNames: globs.slice(1),
85
- } :
86
- { globs: [first, ...globs], }
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 { RunnerUtil } from '../src/execute/util.ts';
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 RunnerUtil.getTestImports(globs)) {
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 options = Object.fromEntries((this.formatOptions ?? [])?.map(option => [...option.split(':'), true]));
35
-
36
- return runTests({
37
- consumer: this.format,
38
- consumerOptions: options,
39
- target: {
40
- import: importOrFile,
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, CliUtil } from '@travetto/cli';
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');
@@ -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
- }