@travetto/test 3.4.3 → 4.0.0-rc.1

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 CHANGED
@@ -27,7 +27,7 @@ A simple example would be:
27
27
 
28
28
  **Code: Example Test Suite**
29
29
  ```typescript
30
- import assert from 'assert';
30
+ import assert from 'node:assert';
31
31
 
32
32
  import { Suite, Test } from '@travetto/test';
33
33
 
@@ -58,7 +58,7 @@ A common aspect of the tests themselves are the assertions that are made. [Node
58
58
 
59
59
  **Code: Example assertion for deep comparison**
60
60
  ```typescript
61
- import assert from 'assert';
61
+ import assert from 'node:assert';
62
62
 
63
63
  import { Suite, Test } from '@travetto/test';
64
64
 
@@ -81,13 +81,13 @@ Object.defineProperty(exports, "__esModule", { value: true });
81
81
  const tslib_1 = require("tslib");
82
82
  const Ⲑ_util_1 = tslib_1.__importStar(require("@travetto/test/src/execute/util.js"));
83
83
  const Ⲑ_check_1 = tslib_1.__importStar(require("@travetto/test/src/assert/check.js"));
84
- const Ⲑ_root_index_1 = tslib_1.__importStar(require("@travetto/manifest/src/root-index.js"));
84
+ const Ⲑ_runtime_1 = tslib_1.__importStar(require("@travetto/manifest/src/runtime.js"));
85
85
  const Ⲑ_decorator_1 = tslib_1.__importStar(require("@travetto/registry/src/decorator.js"));
86
86
  var ᚕf = "@travetto/test/doc/assert-example.js";
87
- const assert_1 = tslib_1.__importDefault(require("assert"));
87
+ const node_assert_1 = tslib_1.__importDefault(require("node:assert"));
88
88
  const test_1 = require("@travetto/test");
89
89
  let SimpleTest = class SimpleTest {
90
- static Ⲑinit = Ⲑ_root_index_1.RootIndex.registerFunction(SimpleTest, ᚕf, 1887908328, { test: { hash: 102834457 } }, false, false);
90
+ static Ⲑinit = Ⲑ_runtime_1.RuntimeIndex.registerFunction(SimpleTest, ᚕf, 1887908328, { test: { hash: 102834457 } }, false, false);
91
91
  async test() {
92
92
  if (Ⲑ_util_1.RunnerUtil.tryDebugger)
93
93
  debugger;
@@ -131,7 +131,7 @@ In addition to the standard operations, there is support for throwing/rejecting
131
131
 
132
132
  **Code: Throws vs Does Not Throw**
133
133
  ```typescript
134
- import assert from 'assert';
134
+ import assert from 'node:assert';
135
135
 
136
136
  import { Suite, Test } from '@travetto/test';
137
137
 
@@ -157,7 +157,7 @@ class SimpleTest {
157
157
 
158
158
  **Code: Rejects vs Does Not Reject**
159
159
  ```typescript
160
- import assert from 'assert';
160
+ import assert from 'node:assert';
161
161
 
162
162
  import { Suite, Test } from '@travetto/test';
163
163
 
@@ -186,7 +186,7 @@ Additionally, the `throws`/`rejects` assertions take in a secondary parameter to
186
186
 
187
187
  **Code: Example of different Error matching paradigms**
188
188
  ```typescript
189
- import assert from 'assert';
189
+ import assert from 'node:assert';
190
190
 
191
191
  import { Suite, Test } from '@travetto/test';
192
192
 
package/__index__.ts CHANGED
@@ -1,3 +1,4 @@
1
+ /// <reference path="./src/trv.d.ts" />
1
2
  export * from './src/decorator/suite';
2
3
  export * from './src/decorator/test';
3
4
  export * from './src/model/suite';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/test",
3
- "version": "3.4.3",
3
+ "version": "4.0.0-rc.1",
4
4
  "description": "Declarative test framework",
5
5
  "keywords": [
6
6
  "unit-testing",
@@ -27,15 +27,15 @@
27
27
  "directory": "module/test"
28
28
  },
29
29
  "dependencies": {
30
- "@travetto/base": "^3.4.2",
31
- "@travetto/registry": "^3.4.2",
32
- "@travetto/terminal": "^3.4.0",
33
- "@travetto/worker": "^3.4.2",
34
- "@travetto/yaml": "^3.4.2"
30
+ "@travetto/base": "^4.0.0-rc.1",
31
+ "@travetto/registry": "^4.0.0-rc.1",
32
+ "@travetto/terminal": "^4.0.0-rc.1",
33
+ "@travetto/worker": "^4.0.0-rc.1",
34
+ "@travetto/yaml": "^4.0.0-rc.1"
35
35
  },
36
36
  "peerDependencies": {
37
- "@travetto/cli": "^3.4.7",
38
- "@travetto/transformer": "^3.4.2"
37
+ "@travetto/cli": "^4.0.0-rc.1",
38
+ "@travetto/transformer": "^4.0.0-rc.1"
39
39
  },
40
40
  "peerDependenciesMeta": {
41
41
  "@travetto/transformer": {
@@ -1,4 +1,4 @@
1
- import { EventEmitter } from 'events';
1
+ import { EventEmitter } from 'node:events';
2
2
 
3
3
  import { Assertion, TestConfig } from '../model/test';
4
4
 
@@ -1,6 +1,6 @@
1
- import assert from 'assert';
1
+ import assert from 'node:assert';
2
2
 
3
- import { RootIndex } from '@travetto/manifest';
3
+ import { RuntimeIndex } from '@travetto/manifest';
4
4
  import { ObjectUtil, AppError, ClassInstance, Class } from '@travetto/base';
5
5
 
6
6
  import { ThrowableError, TestConfig, Assertion } from '../model/test';
@@ -30,7 +30,7 @@ export class AssertCheck {
30
30
  * @param args The arguments passed in
31
31
  */
32
32
  static check(assertion: CaptureAssert, positive: boolean, ...args: unknown[]): void {
33
- assertion.file = RootIndex.getSourceFile(assertion.file);
33
+ assertion.file = RuntimeIndex.getSourceFile(assertion.file);
34
34
 
35
35
  let fn = assertion.operator;
36
36
  assertion.operator = ASSERT_FN_OPERATOR[fn];
@@ -115,7 +115,7 @@ export class AssertCheck {
115
115
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
116
116
  case 'greaterThanEqual': assertFn((actual as number) >= (expected as number), message); break;
117
117
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
118
- case 'ok': assertFn.apply(null, args as [unknown, string]); break; // eslint-disable-line prefer-spread
118
+ case 'ok': assertFn(...args as [unknown, string]); break; // eslint-disable-line prefer-spread
119
119
  default:
120
120
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
121
121
  if (fn && assert[fn as keyof typeof assert]) { // Assert call
@@ -161,11 +161,19 @@ export class AssertCheck {
161
161
 
162
162
  // If a string, check if error exists, and then see if the string is included in the message
163
163
  if (typeof shouldThrow === 'string' && (!err || !(err instanceof Error ? err.message : err).includes(shouldThrow))) {
164
- return new assert.AssertionError({ message: `Expected error containing text '${shouldThrow}', but got ${actual}` });
164
+ return new assert.AssertionError({
165
+ message: `Expected error containing text '${shouldThrow}', but got ${actual}`,
166
+ actual,
167
+ expected: shouldThrow
168
+ });
165
169
  }
166
170
  // If a regexp, check if error exists, and then test the error message against the regex
167
171
  if (shouldThrow instanceof RegExp && (!err || !shouldThrow.test(typeof err === 'string' ? err : err.message))) {
168
- return new assert.AssertionError({ message: `Expected error with message matching '${shouldThrow.source}', but got ${actual} ` });
172
+ return new assert.AssertionError({
173
+ message: `Expected error with message matching '${shouldThrow.source}', but got ${actual}`,
174
+ actual,
175
+ expected: shouldThrow.source
176
+ });
169
177
  }
170
178
  // If passing in a constructor
171
179
  } else if (shouldThrow === Error ||
@@ -173,7 +181,11 @@ export class AssertCheck {
173
181
  Object.getPrototypeOf(shouldThrow) !== Object.getPrototypeOf(Function)
174
182
  ) { // if not simple function, treat as class
175
183
  if (!err || !(err instanceof shouldThrow)) {
176
- return new assert.AssertionError({ message: `Expected to throw ${shouldThrow.name}, but got ${err ?? 'nothing'} ` });
184
+ return new assert.AssertionError({
185
+ message: `Expected to throw ${shouldThrow.name}, but got ${err ?? 'nothing'}`,
186
+ actual: (err ?? 'nothing'),
187
+ expected: shouldThrow.name
188
+ });
177
189
  }
178
190
  } else {
179
191
  // Else treat as a simple function to build an error or not
@@ -227,7 +239,7 @@ export class AssertCheck {
227
239
  ): void {
228
240
  let missed: Error | undefined;
229
241
 
230
- assertion.file = RootIndex.getSourceFile(assertion.file);
242
+ assertion.file = RuntimeIndex.getSourceFile(assertion.file);
231
243
 
232
244
  try {
233
245
  action();
@@ -261,7 +273,7 @@ export class AssertCheck {
261
273
  ): Promise<void> {
262
274
  let missed: Error | undefined;
263
275
 
264
- assertion.file = RootIndex.getSourceFile(assertion.file);
276
+ assertion.file = RuntimeIndex.getSourceFile(assertion.file);
265
277
 
266
278
  try {
267
279
  if ('then' in action) {
@@ -1,6 +1,6 @@
1
- import util from 'util';
1
+ import util from 'node:util';
2
2
 
3
- import { path, RootIndex } from '@travetto/manifest';
3
+ import { path, RuntimeIndex, RuntimeContext } from '@travetto/manifest';
4
4
  import { Class, ClassInstance, ObjectUtil } from '@travetto/base';
5
5
 
6
6
  import { TestConfig, Assertion, TestResult } from '../model/test';
@@ -41,7 +41,7 @@ export class AssertUtil {
41
41
  * Determine file location for a given error and the stack trace
42
42
  */
43
43
  static getPositionOfError(err: Error, filename: string): { file: string, line: number } {
44
- const cwd = RootIndex.mainModule.sourcePath;
44
+ const cwd = RuntimeIndex.mainModule.sourcePath;
45
45
  const lines = path.toPosix(err.stack ?? new Error().stack!)
46
46
  .split('\n')
47
47
  // Exclude node_modules, target self
@@ -94,7 +94,7 @@ export class AssertUtil {
94
94
 
95
95
  const msg = error.message.split(/\n/)[0];
96
96
 
97
- const core = { file, classId: suite.classId, methodName, module: RootIndex.manifest.mainModule };
97
+ const core = { file, classId: suite.classId, methodName, module: RuntimeContext.main.name };
98
98
  const coreAll = { ...core, description: msg, lines: { start: line, end: line, codeStart: line } };
99
99
 
100
100
  const assert: Assertion = {
@@ -1,18 +1,18 @@
1
- import { GlobalTerminal } from '@travetto/terminal';
1
+ import { StyleUtil } from '@travetto/terminal';
2
2
 
3
- export const CONSOLE_ENHANCER = GlobalTerminal.palette({
4
- assertDescription: 'lightGray',
5
- testDescription: 'white',
6
- success: 'green',
7
- failure: 'red',
8
- assertNumber: 'brightCyan',
9
- testNumber: 'dodgerBlue',
10
- assertFile: 'lightGreen',
11
- assertLine: 'lightYellow',
12
- objectInspect: 'magenta',
13
- suiteName: 'yellow',
14
- testName: 'cyan',
15
- total: 'white'
3
+ export const CONSOLE_ENHANCER = StyleUtil.getPalette({
4
+ assertDescription: '#d3d3d3', // light gray
5
+ testDescription: '#e5e5e5', // White
6
+ success: '#00cd00', // Green
7
+ failure: '#cd0000', // Red
8
+ assertNumber: '#00ffff', // Bright cyan
9
+ testNumber: '#1e90ff', // dodger blue
10
+ assertFile: '#90e90', // lightGreen
11
+ assertLine: '#ffffe0', // light yellow
12
+ objectInspect: '#cd00cd', // Magenta
13
+ suiteName: '#cdcd00', // Yellow
14
+ testName: '#00cdcd', // Cyan
15
+ total: '#e5e5e5', // White
16
16
  });
17
17
 
18
18
  export type TestResultsEnhancer = typeof CONSOLE_ENHANCER;
@@ -28,8 +28,8 @@ export class ErrorUtil {
28
28
  if (ObjectUtil.hasToJSON(e)) {
29
29
  Object.assign(error, e.toJSON());
30
30
  }
31
- error.message ??= e.message;
32
- error.stack ??= e.stack;
31
+ error.message ||= e.message;
32
+ error.stack ??= e.stack?.replace(/.*\[ERR_ASSERTION\]:\s*/, '');
33
33
  }
34
34
 
35
35
  return error;
@@ -1,4 +1,4 @@
1
- import { existsSync } from 'fs';
1
+ import { existsSync } from 'node:fs';
2
2
 
3
3
  import { Class } from '@travetto/base';
4
4
 
@@ -1,4 +1,4 @@
1
- import { Writable } from 'stream';
1
+ import { Writable } from 'node:stream';
2
2
 
3
3
  import { TestEvent } from '../../model/event';
4
4
  import { TestConsumer } from '../types';
@@ -1,4 +1,4 @@
1
- import { Writable } from 'stream';
1
+ import { Writable } from 'node:stream';
2
2
 
3
3
  import { TestEvent } from '../../model/event';
4
4
  import { SuitesSummary, TestConsumer } from '../types';
@@ -1,5 +1,6 @@
1
- import { GlobalTerminal, TermStyleInput, Terminal } from '@travetto/terminal';
2
- import { ManualAsyncIterator } from '@travetto/worker';
1
+ import { Util } from '@travetto/base';
2
+ import { StyleUtil, Terminal, TerminalUtil } from '@travetto/terminal';
3
+ import { WorkQueue } from '@travetto/worker';
3
4
 
4
5
  import { TestEvent } from '../../model/event';
5
6
  import { TestResult } from '../../model/test';
@@ -15,35 +16,12 @@ import { TapEmitter } from './tap';
15
16
  @Consumable('tap-streamed')
16
17
  export class TapStreamedEmitter implements TestConsumer {
17
18
 
18
- static makeProgressBar(term: Terminal, total: number): (t: TestResult, idx: number) => string {
19
- let failed = 0;
20
- const palette: TermStyleInput[] = [
21
- { text: 'white', background: 'darkGreen' },
22
- { text: 'white', background: 'darkRed' }
23
- ];
24
- const styles = palette.map(s => GlobalTerminal.colorer(s));
25
-
26
- return (t: TestResult, idx: number): string => {
27
- if (t.status === 'failed') {
28
- failed += 1;
29
- }
30
- const i = idx + 1;
31
- const digits = total.toString().length;
32
- const paddedI = `${i}`.padStart(digits);
33
- const paddedFailed = `${failed}`.padStart(digits);
34
- const line = `Tests ${paddedI}/${total} [${paddedFailed} failed] -- ${t.classId}`.padEnd(term.width);
35
- const pos = Math.trunc(line.length * (i / total));
36
- const colorer = styles[Math.min(failed, styles.length - 1)];
37
- return `${colorer(line.substring(0, pos))}${line.substring(pos)}`;
38
- };
39
- }
40
-
41
19
  #terminal: Terminal;
42
- #results = new ManualAsyncIterator<TestResult>();
20
+ #results = new WorkQueue<TestResult>();
43
21
  #progress: Promise<unknown> | undefined;
44
22
  #consumer: TapEmitter;
45
23
 
46
- constructor(terminal: Terminal = new Terminal({ output: process.stderr })) {
24
+ constructor(terminal: Terminal = new Terminal(process.stderr)) {
47
25
  this.#terminal = terminal;
48
26
  this.#consumer = new TapEmitter(this.#terminal);
49
27
  }
@@ -51,9 +29,19 @@ export class TapStreamedEmitter implements TestConsumer {
51
29
  async onStart(state: TestRunState): Promise<void> {
52
30
  this.#consumer.onStart();
53
31
 
54
- this.#progress = this.#terminal.streamToPosition(this.#results,
55
- TapStreamedEmitter.makeProgressBar(this.#terminal, state.testCount ?? 0),
56
- { position: 'bottom', minDelay: 100 }
32
+ let failed = 0;
33
+ const succ = StyleUtil.getStyle({ text: '#e5e5e5', background: '#026020' }); // White on dark green
34
+ const fail = StyleUtil.getStyle({ text: '#e5e5e5', background: '#8b0000' }); // White on dark red
35
+ this.#progress = this.#terminal.streamToBottom(
36
+ Util.mapAsyncItr(
37
+ this.#results,
38
+ (value, idx) => {
39
+ failed += (value.status === 'failed' ? 1 : 0);
40
+ return { value: `Tests %idx/%total [${failed} failed] -- ${value.classId}`, total: state.testCount, idx };
41
+ },
42
+ TerminalUtil.progressBarUpdater(this.#terminal, { style: () => ({ complete: failed ? fail : succ }) })
43
+ ),
44
+ { minDelay: 100 }
57
45
  );
58
46
  }
59
47
 
@@ -1,5 +1,5 @@
1
- import { RootIndex } from '@travetto/manifest';
2
- import { GlobalTerminal, Terminal } from '@travetto/terminal';
1
+ import { RuntimeIndex } from '@travetto/manifest';
2
+ import { Terminal } from '@travetto/terminal';
3
3
  import { ObjectUtil, TimeUtil } from '@travetto/base';
4
4
  import { YamlUtil } from '@travetto/yaml';
5
5
 
@@ -20,7 +20,7 @@ export class TapEmitter implements TestConsumer {
20
20
  #start: number;
21
21
 
22
22
  constructor(
23
- terminal = new Terminal({ output: process.stdout }),
23
+ terminal = new Terminal(),
24
24
  enhancer: TestResultsEnhancer = CONSOLE_ENHANCER
25
25
  ) {
26
26
  this.#terminal = terminal;
@@ -28,7 +28,7 @@ export class TapEmitter implements TestConsumer {
28
28
  }
29
29
 
30
30
  log(message: string): void {
31
- this.#terminal.writeLines(message);
31
+ this.#terminal.writer.writeLine(message).commit();
32
32
  }
33
33
 
34
34
  /**
@@ -43,7 +43,7 @@ export class TapEmitter implements TestConsumer {
43
43
  * Output supplemental data (e.g. logs)
44
44
  */
45
45
  logMeta(obj: Record<string, unknown>): void {
46
- const lineLength = GlobalTerminal.width - 5;
46
+ const lineLength = this.#terminal.width - 5;
47
47
  let body = YamlUtil.serialize(obj, { wordwrap: lineLength });
48
48
  body = body.split('\n').map(x => ` ${x}`).join('\n');
49
49
  this.log(`---\n${this.#enhancer.objectInspect(body)}\n...`);
@@ -71,7 +71,7 @@ export class TapEmitter implements TestConsumer {
71
71
  this.#enhancer.assertNumber(++subCount),
72
72
  '-',
73
73
  this.#enhancer.assertDescription(text),
74
- `${this.#enhancer.assertFile(asrt.file.replace(RootIndex.mainModule.sourcePath, '.'))}:${this.#enhancer.assertLine(asrt.line)}`
74
+ `${this.#enhancer.assertFile(asrt.file.replace(RuntimeIndex.mainModule.sourcePath, '.'))}:${this.#enhancer.assertLine(asrt.line)}`
75
75
  ].join(' ');
76
76
 
77
77
  if (asrt.error) {
@@ -1,4 +1,4 @@
1
- import { Writable } from 'stream';
1
+ import { Writable } from 'node:stream';
2
2
 
3
3
  import { YamlUtil } from '@travetto/yaml';
4
4
 
@@ -1,4 +1,4 @@
1
- import { RootIndex } from '@travetto/manifest';
1
+ import { RuntimeIndex } from '@travetto/manifest';
2
2
  import { Class, ClassInstance } from '@travetto/base';
3
3
 
4
4
  import { SuiteRegistry } from '../registry/suite';
@@ -27,7 +27,7 @@ export function Suite(description?: string | Partial<SuiteConfig>, ...rest: Part
27
27
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
28
28
  const decorator = ((target: Class) => {
29
29
  const cfg = { description: descriptionString, ...extra };
30
- if (RootIndex.getFunctionMetadata(target)?.abstract) {
30
+ if (RuntimeIndex.getFunctionMetadata(target)?.abstract) {
31
31
  cfg.skip = true;
32
32
  }
33
33
  SuiteRegistry.register(target, cfg);
@@ -1,5 +1,5 @@
1
1
  import { ClassInstance } from '@travetto/base';
2
- import { RootIndex } from '@travetto/manifest';
2
+ import { RuntimeIndex } from '@travetto/manifest';
3
3
 
4
4
  import { SuiteRegistry } from '../registry/suite';
5
5
  import { TestConfig } from '../model/test';
@@ -32,7 +32,7 @@ export function Test(description?: string | Partial<TestConfig>, ...rest: Partia
32
32
  return (inst: ClassInstance, prop: string | symbol, descriptor: PropertyDescriptor) => {
33
33
  SuiteRegistry.registerField(inst.constructor, descriptor.value, {
34
34
  ...extra,
35
- file: RootIndex.getFunctionMetadata(inst.constructor)!.source,
35
+ file: RuntimeIndex.getFunctionMetadata(inst.constructor)!.source,
36
36
  description: descriptionString
37
37
  });
38
38
  return descriptor;
@@ -1,4 +1,4 @@
1
- import util from 'util';
1
+ import util from 'node:util';
2
2
 
3
3
  import { ConsoleEvent, ConsoleManager } from '@travetto/base';
4
4
 
@@ -1,7 +1,8 @@
1
- import timers from 'timers/promises';
1
+ import timers from 'node:timers/promises';
2
+ import { AssertionError } from 'node:assert';
2
3
 
3
- import { path, RootIndex } from '@travetto/manifest';
4
- import { TimeUtil, Util } from '@travetto/base';
4
+ import { path, RuntimeIndex, RuntimeContext } from '@travetto/manifest';
5
+ import { Env, Util } from '@travetto/base';
5
6
  import { Barrier, ExecutionError } from '@travetto/worker';
6
7
 
7
8
  import { SuiteRegistry } from '../registry/suite';
@@ -15,7 +16,7 @@ import { TestPhaseManager } from './phase';
15
16
  import { PromiseCapture } from './promise';
16
17
  import { AssertUtil } from '../assert/util';
17
18
 
18
- const TEST_TIMEOUT = TimeUtil.getEnvTime('TRV_TEST_TIMEOUT', '5s');
19
+ const TEST_TIMEOUT = Env.TRV_TEST_TIMEOUT.time ?? 5000;
19
20
 
20
21
  /**
21
22
  * Support execution of the tests
@@ -68,10 +69,10 @@ export class TestExecutor {
68
69
  */
69
70
  static failFile(consumer: TestConsumer, file: string, err: Error): void {
70
71
  const name = path.basename(file);
71
- const classId = RootIndex.getId(file, name);
72
+ const classId = RuntimeIndex.getId(file, name);
72
73
  // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
73
74
  const suite = { class: { name }, classId, duration: 0, lines: { start: 1, end: 1 }, file, } as SuiteConfig & SuiteResult;
74
- err.message = err.message.replaceAll(RootIndex.mainModule.sourcePath, '.');
75
+ err.message = err.message.replaceAll(RuntimeIndex.mainModule.sourcePath, '.');
75
76
  const res = AssertUtil.generateSuiteError(suite, 'require', err);
76
77
  consumer.onEvent({ type: 'suite', phase: 'before', suite });
77
78
  consumer.onEvent({ type: 'test', phase: 'before', test: res.testConfig });
@@ -109,7 +110,7 @@ export class TestExecutor {
109
110
 
110
111
  const result: TestResult = {
111
112
  methodName: test.methodName,
112
- module: RootIndex.manifest.mainModule,
113
+ module: RuntimeContext.main.name,
113
114
  description: test.description,
114
115
  classId: test.classId,
115
116
  lines: { ...test.lines },
@@ -139,11 +140,17 @@ export class TestExecutor {
139
140
  // Run method and get result
140
141
  let error = await this.#executeTestMethod(test);
141
142
 
142
- if (error) {
143
- if (error instanceof ExecutionError) { // Errors that are not expected
143
+ if (!error) {
144
+ error = AssertCheck.checkError(test.shouldThrow, error); // Rewrite error
145
+ } else {
146
+ if (error instanceof AssertionError) {
147
+ // Pass, do nothing
148
+ } else if (error instanceof ExecutionError) { // Errors that are not expected
149
+ AssertCheck.checkUnhandled(test, error);
150
+ } else if (test.shouldThrow) {
151
+ error = AssertCheck.checkError(test.shouldThrow, error); // Rewrite error
152
+ } else if (error instanceof Error) {
144
153
  AssertCheck.checkUnhandled(test, error);
145
- } else if (test.shouldThrow) { // Errors that are
146
- error = AssertCheck.checkError(test.shouldThrow!, error); // Rewrite error
147
154
  }
148
155
  }
149
156
 
@@ -254,7 +261,7 @@ export class TestExecutor {
254
261
 
255
262
  file = path.resolve(file);
256
263
 
257
- const entry = RootIndex.getEntry(file)!;
264
+ const entry = RuntimeIndex.getEntry(file)!;
258
265
 
259
266
  try {
260
267
  await import(entry.import);
@@ -1,5 +1,5 @@
1
1
  import { Barrier } from '@travetto/worker';
2
- import { TimeUtil } from '@travetto/base';
2
+ import { Env } from '@travetto/base';
3
3
 
4
4
  import { TestConsumer } from '../consumer/types';
5
5
  import { SuiteConfig, SuiteResult } from '../model/suite';
@@ -8,7 +8,7 @@ import { TestResult } from '../model/test';
8
8
 
9
9
  class TestBreakout extends Error { }
10
10
 
11
- const TEST_PHASE_TIMEOUT = TimeUtil.getEnvTime('TRV_TEST_PHASE_TIMEOUT', '15s');
11
+ const TEST_PHASE_TIMEOUT = Env.TRV_TEST_PHASE_TIMEOUT.time ?? 15000;
12
12
 
13
13
  /**
14
14
  * Test Phase Execution Manager.
@@ -1,6 +1,6 @@
1
1
  import { path } from '@travetto/manifest';
2
2
  import { TimeUtil } from '@travetto/base';
3
- import { WorkPool, IterableWorkSet } from '@travetto/worker';
3
+ import { WorkPool } from '@travetto/worker';
4
4
 
5
5
  import { buildStandardTestManager } from '../worker/standard';
6
6
  import { RunnableTestConsumer } from '../consumer/types/runnable';
@@ -34,17 +34,17 @@ export class Runner {
34
34
 
35
35
  console.debug('Running', { files, patterns: this.patterns });
36
36
 
37
- const manager = buildStandardTestManager;
38
-
39
- const pool = new WorkPool(manager(consumer), {
40
- idleTimeoutMillis: TimeUtil.timeToMs('10s'),
41
- min: 1,
42
- max: this.#state.concurrency
43
- });
44
-
45
37
  const testCount = await RunnerUtil.getTestCount(this.#state.args);
46
38
  await consumer.onStart({ testCount });
47
- await pool.process(new IterableWorkSet(files));
39
+ await WorkPool.run(
40
+ () => buildStandardTestManager(consumer),
41
+ files,
42
+ {
43
+ idleTimeoutMillis: TimeUtil.timeToMs('10s'),
44
+ min: 1,
45
+ max: this.#state.concurrency,
46
+ });
47
+
48
48
  return consumer.summarizeAsBoolean();
49
49
  }
50
50
 
@@ -1,8 +1,10 @@
1
- import { createReadStream } from 'fs';
2
- import readline from 'readline';
1
+ import { spawn } from 'node:child_process';
2
+ import { createReadStream } from 'node:fs';
3
+ import readline from 'node:readline';
4
+ import timers from 'node:timers/promises';
3
5
 
4
- import { ExecUtil, ShutdownManager, TimeUtil } from '@travetto/base';
5
- import { IndexedFile, RootIndex } from '@travetto/manifest';
6
+ import { Env, ExecUtil, ShutdownManager } from '@travetto/base';
7
+ import { IndexedFile, RuntimeIndex } from '@travetto/manifest';
6
8
 
7
9
  /**
8
10
  * Simple Test Utilities
@@ -12,7 +14,7 @@ export class RunnerUtil {
12
14
  * Add 50 ms to the shutdown to allow for buffers to output properly
13
15
  */
14
16
  static registerCleanup(scope: string): void {
15
- ShutdownManager.onShutdown(`test.${scope}.bufferOutput`, () => TimeUtil.wait(50));
17
+ ShutdownManager.onGracefulShutdown(() => timers.setTimeout(50), `test.${scope}.bufferOutput`);
16
18
  }
17
19
 
18
20
  /**
@@ -37,12 +39,12 @@ export class RunnerUtil {
37
39
  * Find all valid test files given the globs
38
40
  */
39
41
  static async getTestFiles(globs?: RegExp[]): Promise<IndexedFile[]> {
40
- const files = RootIndex.find({
42
+ const files = RuntimeIndex.find({
41
43
  module: m => m.roles.includes('test') || m.roles.includes('std'),
42
44
  folder: f => f === 'test',
43
45
  file: f => f.role === 'test'
44
46
  })
45
- .filter(f => globs?.some(g => g.test(f.import)) ?? true);
47
+ .filter(f => globs?.some(g => g.test(f.sourceFile)) ?? true);
46
48
 
47
49
  const validFiles = files
48
50
  .map(f => this.isTestFile(f.sourceFile).then(valid => ({ file: f, valid })));
@@ -58,8 +60,12 @@ export class RunnerUtil {
58
60
  * @returns
59
61
  */
60
62
  static async getTestCount(patterns: string[]): Promise<number> {
61
- const proc = ExecUtil.spawn('npx', ['trv', 'test:count', ...patterns], { stdio: 'pipe', catchAsResult: true, env: { FORCE_COLOR: '0', NO_COLOR: '1' } });
62
- const countRes = await proc.result;
63
+ const countRes = await ExecUtil.getResult(
64
+ spawn('npx', ['trv', 'test:count', ...patterns], {
65
+ env: { ...process.env, ...Env.FORCE_COLOR.export(0), ...Env.NO_COLOR.export(true) }
66
+ }),
67
+ { catch: true }
68
+ );
63
69
  if (!countRes.valid) {
64
70
  throw new Error(countRes.stderr);
65
71
  }
@@ -70,6 +76,6 @@ export class RunnerUtil {
70
76
  * Determine if we should invoke the debugger
71
77
  */
72
78
  static get tryDebugger(): boolean {
73
- return process.env.TRV_TEST_BREAK_ENTRY === '1';
79
+ return Env.TRV_TEST_BREAK_ENTRY.isTrue;
74
80
  }
75
81
  }
@@ -1,6 +1,6 @@
1
1
  import { RootRegistry, MethodSource } from '@travetto/registry';
2
- import { WorkPool, IterableWorkSet, ManualAsyncIterator } from '@travetto/worker';
3
- import { RootIndex } from '@travetto/manifest';
2
+ import { WorkPool, WorkQueue } from '@travetto/worker';
3
+ import { RuntimeIndex } from '@travetto/manifest';
4
4
  import { ObjectUtil } from '@travetto/base';
5
5
 
6
6
  import { SuiteRegistry } from '../registry/suite';
@@ -9,11 +9,18 @@ import { TestConsumerRegistry } from '../consumer/registry';
9
9
  import { CumulativeSummaryConsumer } from '../consumer/types/cumulative';
10
10
  import { RunEvent } from '../worker/types';
11
11
  import { RunnerUtil } from './util';
12
+ import { TestEvent } from '../model/event';
12
13
 
13
14
  function isRunEvent(ev: unknown): ev is RunEvent {
14
15
  return ObjectUtil.isPlainObject(ev) && 'type' in ev && typeof ev.type === 'string' && ev.type === 'run-test';
15
16
  }
16
17
 
18
+ export type TestWatchEvent =
19
+ TestEvent |
20
+ { type: 'removeTest', method: string, file: string, classId: string } |
21
+ { type: 'ready' } |
22
+ { type: 'log', message: string };
23
+
17
24
  /**
18
25
  * Test Watcher.
19
26
  *
@@ -27,22 +34,16 @@ export class TestWatcher {
27
34
  static async watch(format: string, runAllOnStart = true): Promise<void> {
28
35
  console.debug('Listening for changes');
29
36
 
30
- const itr = new ManualAsyncIterator<string>();
31
- const src = new IterableWorkSet(itr);
37
+ const itr = new WorkQueue<string>();
32
38
 
33
39
  await SuiteRegistry.init();
34
40
  SuiteRegistry.listen(RootRegistry);
35
41
 
36
42
  const consumer = new CumulativeSummaryConsumer(await TestConsumerRegistry.getInstance(format));
37
- const pool = new WorkPool(buildStandardTestManager(consumer), {
38
- idleTimeoutMillis: 120000,
39
- min: 2,
40
- max: WorkPool.DEFAULT_SIZE
41
- });
42
43
 
43
44
  new MethodSource(RootRegistry).on(e => {
44
45
  const [cls, method] = (e.prev ?? e.curr ?? []);
45
- if (!cls || RootIndex.getFunctionMetadata(cls)?.abstract) {
46
+ if (!cls || RuntimeIndex.getFunctionMetadata(cls)?.abstract) {
46
47
  return;
47
48
  }
48
49
  if (!method) {
@@ -60,7 +61,7 @@ export class TestWatcher {
60
61
  type: 'removeTest',
61
62
  method: method?.name,
62
63
  classId: cls?.Ⲑid,
63
- file: RootIndex.getFunctionMetadata(cls)?.source
64
+ file: RuntimeIndex.getFunctionMetadata(cls)?.source
64
65
  });
65
66
  }
66
67
  });
@@ -72,11 +73,12 @@ export class TestWatcher {
72
73
 
73
74
  process.on('message', ev => {
74
75
  if (isRunEvent(ev)) {
76
+ console.debug('Manually triggered', ev);
75
77
  itr.add([ev.file, ev.class, ev.method].filter(x => !!x).join('#'), true);
76
78
  }
77
79
  });
78
80
 
79
- process.send?.('ready');
81
+ process.send?.({ type: 'ready' });
80
82
 
81
83
  if (runAllOnStart) {
82
84
  for (const test of await RunnerUtil.getTestFiles()) {
@@ -85,6 +87,14 @@ export class TestWatcher {
85
87
  }
86
88
  }
87
89
 
88
- await pool.process(src);
90
+ await WorkPool.run(
91
+ () => buildStandardTestManager(consumer),
92
+ itr,
93
+ {
94
+ idleTimeoutMillis: 120000,
95
+ min: 2,
96
+ max: WorkPool.DEFAULT_SIZE
97
+ }
98
+ );
89
99
  }
90
100
  }
@@ -1,5 +1,5 @@
1
1
  import { Class, ConcreteClass } from '@travetto/base';
2
- import { RootIndex } from '@travetto/manifest';
2
+ import { RuntimeIndex, RuntimeContext } from '@travetto/manifest';
3
3
  import { MetadataRegistry } from '@travetto/registry';
4
4
 
5
5
  import { SuiteConfig } from '../model/suite';
@@ -14,15 +14,15 @@ class $SuiteRegistry extends MetadataRegistry<SuiteConfig, TestConfig> {
14
14
  * Find all valid tests (ignoring abstract)
15
15
  */
16
16
  getValidClasses(): Class[] {
17
- return this.getClasses().filter(c => !RootIndex.getFunctionMetadata(c)?.abstract);
17
+ return this.getClasses().filter(c => !RuntimeIndex.getFunctionMetadata(c)?.abstract);
18
18
  }
19
19
 
20
20
  createPending(cls: Class): Partial<SuiteConfig> {
21
21
  return {
22
22
  class: cls,
23
- module: RootIndex.manifest.mainModule,
23
+ module: RuntimeContext.main.name,
24
24
  classId: cls.Ⲑid,
25
- file: RootIndex.getFunctionMetadata(cls)!.source,
25
+ file: RuntimeIndex.getFunctionMetadata(cls)!.source,
26
26
  tests: [],
27
27
  beforeAll: [],
28
28
  beforeEach: [],
@@ -34,8 +34,8 @@ class $SuiteRegistry extends MetadataRegistry<SuiteConfig, TestConfig> {
34
34
  override createPendingField(cls: Class, fn: Function): Partial<TestConfig> {
35
35
  return {
36
36
  class: cls,
37
- module: RootIndex.manifest.mainModule,
38
- file: RootIndex.getFunctionMetadata(cls)!.source,
37
+ module: RuntimeContext.main.name,
38
+ file: RuntimeIndex.getFunctionMetadata(cls)!.source,
39
39
  methodName: fn.name
40
40
  };
41
41
  }
@@ -91,7 +91,7 @@ class $SuiteRegistry extends MetadataRegistry<SuiteConfig, TestConfig> {
91
91
  getRunParams(file: string, clsName?: string, method?: string): { suites: SuiteConfig[] } | { suite: SuiteConfig, test?: TestConfig } {
92
92
  if (clsName && /^\d+$/.test(clsName)) { // If we only have a line number
93
93
  const line = parseInt(clsName, 10);
94
- const suites = this.getValidClasses().filter(cls => RootIndex.getFunctionMetadata(cls)!.source === file).map(x => this.get(x)).filter(x => !x.skip);
94
+ const suites = this.getValidClasses().filter(cls => RuntimeIndex.getFunctionMetadata(cls)!.source === file).map(x => this.get(x)).filter(x => !x.skip);
95
95
  const suite = suites.find(x => x.lines && (line >= x.lines.start && line <= x.lines.end));
96
96
 
97
97
  if (suite) {
@@ -113,7 +113,7 @@ class $SuiteRegistry extends MetadataRegistry<SuiteConfig, TestConfig> {
113
113
  } else {
114
114
  const suites = this.getValidClasses()
115
115
  .map(x => this.get(x))
116
- .filter(x => !RootIndex.getFunctionMetadata(x.class)?.abstract); // Do not run abstract suites
116
+ .filter(x => !RuntimeIndex.getFunctionMetadata(x.class)?.abstract); // Do not run abstract suites
117
117
  return { suites };
118
118
  }
119
119
  }
package/src/trv.d.ts ADDED
@@ -0,0 +1,24 @@
1
+ import { TimeSpan } from '@travetto/base';
2
+
3
+ declare global {
4
+ interface TravettoEnv {
5
+ /**
6
+ * The default time to wait for each phase to finish.
7
+ * @default 15s
8
+ */
9
+ TRV_TEST_PHASE_TIMEOUT: TimeSpan | number;
10
+ /**
11
+ * The default time for a single test to finish.
12
+ * @default 5s
13
+ */
14
+ TRV_TEST_TIMEOUT: TimeSpan | number;
15
+ /**
16
+ * An additional wait for triggering test runs, useful for code that takes time to warm up
17
+ */
18
+ TRV_TEST_DELAY: TimeSpan | number;
19
+ /**
20
+ * Should the test break on the first line of debugging
21
+ */
22
+ TRV_TEST_BREAK_ENTRY: boolean;
23
+ }
24
+ }
@@ -1,7 +1,8 @@
1
- import { createWriteStream } from 'fs';
1
+ import { createWriteStream } from 'node:fs';
2
+ import timers from 'node:timers/promises';
2
3
 
3
- import { ManifestFileUtil, RootIndex } from '@travetto/manifest';
4
- import { ConsoleManager, TimeUtil } from '@travetto/base';
4
+ import { RuntimeContext } from '@travetto/manifest';
5
+ import { ConsoleManager, Env, TimeUtil } from '@travetto/base';
5
6
  import { ChildCommChannel } from '@travetto/worker';
6
7
 
7
8
  import { ErrorUtil } from '../consumer/error';
@@ -32,8 +33,9 @@ export class TestChildWorker extends ChildCommChannel<RunEvent> {
32
33
  * Start the worker
33
34
  */
34
35
  async activate(): Promise<void> {
35
- if (/\b@travetto[/]test\b/.test(process.env.DEBUG ?? '')) {
36
- const stdout = createWriteStream(ManifestFileUtil.toolPath(RootIndex, `test-worker.${process.pid}.log`), { flags: 'a' });
36
+ if (/\b@travetto[/]test\b/.test(Env.DEBUG.val ?? '')) {
37
+ const file = RuntimeContext.toolPath(`test-worker.${process.pid}.log`);
38
+ const stdout = createWriteStream(file, { flags: 'a' });
37
39
  const c = new console.Console({ stdout, inspectOptions: { depth: 4, colors: false } });
38
40
  ConsoleManager.set({ onLog: (ev) => c[ev.level](process.pid, ...ev.args) });
39
41
  } else {
@@ -48,7 +50,7 @@ export class TestChildWorker extends ChildCommChannel<RunEvent> {
48
50
  // Let parent know the child is ready for handling commands
49
51
  this.send(Events.READY);
50
52
 
51
- await TimeUtil.wait('10m');
53
+ await timers.setTimeout(TimeUtil.timeToMs('10m'));
52
54
  }
53
55
 
54
56
  /**
@@ -1,5 +1,7 @@
1
- import { RootIndex } from '@travetto/manifest';
2
- import { ExecUtil } from '@travetto/base';
1
+ import { fork } from 'node:child_process';
2
+
3
+ import { RuntimeIndex } from '@travetto/manifest';
4
+ import { Env } from '@travetto/base';
3
5
  import { ParentCommChannel, Worker } from '@travetto/worker';
4
6
 
5
7
  import { Events, RunEvent } from './types';
@@ -21,11 +23,11 @@ function buildEvent(ev: string): RunEvent {
21
23
  /**
22
24
  * Produce a handler for the child worker
23
25
  */
24
- export function buildStandardTestManager(consumer: TestConsumer): () => Worker<string> {
26
+ export function buildStandardTestManager(consumer: TestConsumer): Worker<string> {
25
27
  /**
26
28
  * Spawn a child
27
29
  */
28
- return () => ({
30
+ return {
29
31
  id: i += 1,
30
32
  active: true,
31
33
  async destroy(): Promise<void> { },
@@ -35,16 +37,19 @@ export function buildStandardTestManager(consumer: TestConsumer): () => Worker<s
35
37
 
36
38
  const event = buildEvent(file);
37
39
 
38
- const { module } = RootIndex.getEntry(event.file!)!;
39
- const cwd = RootIndex.getModule(module)!.sourcePath;
40
+ const { module } = RuntimeIndex.getEntry(event.file!)!;
41
+ const cwd = RuntimeIndex.getModule(module)!.sourcePath;
40
42
 
41
43
  const channel = new ParentCommChannel<TestEvent & { error?: Error }>(
42
- ExecUtil.fork(
43
- RootIndex.resolveFileImport('@travetto/cli/support/entry.trv'),
44
- ['test:child'],
44
+ fork(
45
+ RuntimeIndex.resolveFileImport('@travetto/cli/support/entry.trv'), ['test:child'],
45
46
  {
46
47
  cwd,
47
- env: { TRV_MANIFEST: RootIndex.getModule(module)!.outputPath, TRV_QUIET: '1' },
48
+ env: {
49
+ ...process.env,
50
+ ...Env.TRV_MANIFEST.export(RuntimeIndex.getModule(module)!.outputPath),
51
+ ...Env.TRV_QUIET.export(true)
52
+ },
48
53
  stdio: ['ignore', 'ignore', 2, 'ipc']
49
54
  }
50
55
  )
@@ -80,5 +85,5 @@ export function buildStandardTestManager(consumer: TestConsumer): () => Worker<s
80
85
  throw ErrorUtil.deserializeError(error);
81
86
  }
82
87
  },
83
- });
88
+ };
84
89
  }
@@ -1,15 +1,8 @@
1
- import { ShutdownManager, TimeUtil } from '@travetto/base';
1
+ import timers from 'node:timers/promises';
2
2
 
3
- import type { RunState } from '../../src/execute/types';
3
+ import { Env } from '@travetto/base';
4
4
 
5
- declare global {
6
- // eslint-disable-next-line @typescript-eslint/no-namespace
7
- namespace NodeJS {
8
- interface ProcessEnv {
9
- TRV_TEST_DELAY?: '2s';
10
- }
11
- }
12
- }
5
+ import type { RunState } from '../../src/execute/types';
13
6
 
14
7
  /**
15
8
  * Run tests given the input state
@@ -21,15 +14,13 @@ export async function runTests(opts: RunState): Promise<void> {
21
14
 
22
15
  RunnerUtil.registerCleanup('runner');
23
16
 
24
- if (process.env.TRV_TEST_DELAY) {
25
- await TimeUtil.wait(process.env.TRV_TEST_DELAY);
26
- }
17
+ await timers.setTimeout(Env.TRV_TEST_DELAY.time ?? 0);
27
18
 
28
19
  try {
29
20
  const res = await new Runner(opts).run();
30
- return ShutdownManager.exit(res ? 0 : 1);
21
+ process.exitCode = res ? 0 : 1;
31
22
  } catch (err) {
32
23
  console.error('Test Worker Failed', { error: err });
33
- return ShutdownManager.exit(1);
24
+ process.exitCode = 1;
34
25
  }
35
26
  }
@@ -1,2 +1,2 @@
1
- export type TestFormat = 'tap' | 'tap-streamed' | 'xunit' | 'event' | 'exec';
1
+ export type TestFormat = 'tap' | 'tap-streamed' | 'xunit' | 'event' | 'exec' | 'json';
2
2
  export type TestMode = 'single' | 'standard';
@@ -1,8 +1,8 @@
1
- import { EventEmitter } from 'events';
2
- import fs from 'fs/promises';
1
+ import { EventEmitter } from 'node:events';
2
+ import fs from 'node:fs/promises';
3
3
 
4
4
  import { path } from '@travetto/manifest';
5
- import { defineEnv } from '@travetto/base';
5
+ import { Env } from '@travetto/base';
6
6
  import { CliCommandShape, CliCommand, CliValidationError } from '@travetto/cli';
7
7
  import { WorkPool } from '@travetto/worker';
8
8
  import { Max, Min } from '@travetto/schema';
@@ -24,7 +24,11 @@ export class TestCommand implements CliCommandShape {
24
24
 
25
25
  preMain(): void {
26
26
  EventEmitter.defaultMaxListeners = 1000;
27
- defineEnv({ envName: 'test' });
27
+ Env.TRV_ROLE.set('test');
28
+ Env.TRV_ENV.set('test');
29
+ Env.DEBUG.set(false);
30
+ Env.TRV_LOG_PLAIN.set(true);
31
+ Env.TRV_LOG_TIME.clear();
28
32
  }
29
33
 
30
34
  isFirstFile(first: string): Promise<boolean> {
@@ -41,8 +45,6 @@ export class TestCommand implements CliCommandShape {
41
45
 
42
46
  if (mode === 'single' && !await this.isFirstFile(first)) {
43
47
  return { message: 'You must specify a proper test file to run in single mode', source: 'arg' };
44
- } else if (!/test\//.test(first)) {
45
- return { message: 'Only files in the test/ folder are permitted to be run', source: 'arg' };
46
48
  }
47
49
  }
48
50
 
@@ -1,6 +1,6 @@
1
- import { EventEmitter } from 'events';
1
+ import { EventEmitter } from 'node:events';
2
2
 
3
- import { defineEnv, ShutdownManager } from '@travetto/base';
3
+ import { Env } from '@travetto/base';
4
4
  import { CliCommand } from '@travetto/cli';
5
5
 
6
6
  /** Test child worker target */
@@ -8,15 +8,16 @@ import { CliCommand } from '@travetto/cli';
8
8
  export class TestChildWorkerCommand {
9
9
  preMain(): void {
10
10
  EventEmitter.defaultMaxListeners = 1000;
11
- process.env.FORCE_COLOR = '0';
12
- defineEnv({ envName: 'test' });
11
+ Env.TRV_ROLE.set('test');
12
+ Env.TRV_ENV.set('test');
13
+ Env.DEBUG.set(false);
14
+ Env.FORCE_COLOR.set(false);
15
+ Env.TRV_LOG_PLAIN.set(true);
16
+ Env.TRV_LOG_TIME.clear();
13
17
  }
14
18
 
15
19
  async main(): Promise<void> {
16
- if (process.send) {
17
- // Shutdown when ipc bridge is closed
18
- process.on('disconnect', () => ShutdownManager.execute());
19
- }
20
+ process.once('disconnect', () => process.exit());
20
21
  const { TestChildWorker } = await import('../src/worker/child.js');
21
22
  return new TestChildWorker().activate();
22
23
  }
@@ -1,6 +1,6 @@
1
1
  import { CliCommand } from '@travetto/cli';
2
- import { RootIndex } from '@travetto/manifest';
3
- import { defineEnv } from '@travetto/base';
2
+ import { RuntimeIndex } from '@travetto/manifest';
3
+ import { Env } from '@travetto/base';
4
4
 
5
5
  import { SuiteRegistry } from '../src/registry/suite';
6
6
  import { RunnerUtil } from '../src/execute/util';
@@ -9,7 +9,8 @@ import { RunnerUtil } from '../src/execute/util';
9
9
  export class TestCountCommand {
10
10
 
11
11
  preMain(): void {
12
- defineEnv({ debug: false, envName: 'test' });
12
+ Env.TRV_ROLE.set('test');
13
+ Env.DEBUG.set(false);
13
14
  }
14
15
 
15
16
  async main(patterns: string[]) {
@@ -30,7 +31,7 @@ export class TestCountCommand {
30
31
  const suites = SuiteRegistry.getClasses();
31
32
  const total = suites
32
33
  .map(c => SuiteRegistry.get(c))
33
- .filter(c => !RootIndex.getFunctionMetadata(c.class)?.abstract)
34
+ .filter(c => !RuntimeIndex.getFunctionMetadata(c.class)?.abstract)
34
35
  .reduce((acc, c) => acc + (c.tests?.length ?? 0), 0);
35
36
 
36
37
  console.log(total);
@@ -1,4 +1,4 @@
1
- import { defineEnv } from '@travetto/base';
1
+ import { Env } from '@travetto/base';
2
2
  import { CliCommand } from '@travetto/cli';
3
3
 
4
4
  import { runTests } from './bin/run';
@@ -11,7 +11,10 @@ export class TestDirectCommand {
11
11
  format: TestFormat = 'tap';
12
12
 
13
13
  preMain(): void {
14
- defineEnv({ envName: 'test' });
14
+ Env.TRV_ROLE.set('test');
15
+ Env.TRV_ENV.set('test');
16
+ Env.TRV_LOG_PLAIN.set(true);
17
+ Env.TRV_LOG_TIME.clear();
15
18
  }
16
19
 
17
20
  main(file: string, args: string[]): Promise<void> {
@@ -1,4 +1,4 @@
1
- import { defineEnv } from '@travetto/base';
1
+ import { Env } from '@travetto/base';
2
2
  import { CliCommand, CliUtil } from '@travetto/cli';
3
3
 
4
4
  import { TestFormat } from './bin/types';
@@ -13,7 +13,8 @@ export class TestWatcherCommand {
13
13
  mode: 'all' | 'change' = 'all';
14
14
 
15
15
  preMain(): void {
16
- defineEnv({ envName: 'test', dynamic: true });
16
+ Env.TRV_ROLE.set('test');
17
+ Env.TRV_DYNAMIC.set(true);
17
18
  }
18
19
 
19
20
  async main(): Promise<void> {
@@ -21,10 +22,7 @@ export class TestWatcherCommand {
21
22
  return;
22
23
  }
23
24
 
24
- // Quit on parent disconnect
25
- if (process.send) {
26
- process.on('disconnect', () => process.exit(0));
27
- }
25
+ process.once('disconnect', () => process.exit());
28
26
 
29
27
  try {
30
28
  const { TestWatcher } = await import('../src/execute/watcher.js');