@travetto/test 4.0.0-rc.0 → 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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/test",
3
- "version": "4.0.0-rc.0",
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": "^4.0.0-rc.0",
31
- "@travetto/registry": "^4.0.0-rc.0",
32
- "@travetto/terminal": "^4.0.0-rc.0",
33
- "@travetto/worker": "^4.0.0-rc.0",
34
- "@travetto/yaml": "^4.0.0-rc.0"
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": "^4.0.0-rc.0",
38
- "@travetto/transformer": "^4.0.0-rc.0"
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": {
@@ -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
@@ -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;
@@ -140,13 +140,15 @@ export class TestExecutor {
140
140
  // Run method and get result
141
141
  let error = await this.#executeTestMethod(test);
142
142
 
143
- if (error) {
143
+ if (!error) {
144
+ error = AssertCheck.checkError(test.shouldThrow, error); // Rewrite error
145
+ } else {
144
146
  if (error instanceof AssertionError) {
145
- // Pass
147
+ // Pass, do nothing
146
148
  } else if (error instanceof ExecutionError) { // Errors that are not expected
147
149
  AssertCheck.checkUnhandled(test, error);
148
- } else if (test.shouldThrow) { // Errors that are
149
- error = AssertCheck.checkError(test.shouldThrow!, error); // Rewrite error
150
+ } else if (test.shouldThrow) {
151
+ error = AssertCheck.checkError(test.shouldThrow, error); // Rewrite error
150
152
  } else if (error instanceof Error) {
151
153
  AssertCheck.checkUnhandled(test, error);
152
154
  }
@@ -1,3 +1,4 @@
1
+ import { spawn } from 'node:child_process';
1
2
  import { createReadStream } from 'node:fs';
2
3
  import readline from 'node:readline';
3
4
  import timers from 'node:timers/promises';
@@ -43,7 +44,7 @@ export class RunnerUtil {
43
44
  folder: f => f === 'test',
44
45
  file: f => f.role === 'test'
45
46
  })
46
- .filter(f => globs?.some(g => g.test(f.import)) ?? true);
47
+ .filter(f => globs?.some(g => g.test(f.sourceFile)) ?? true);
47
48
 
48
49
  const validFiles = files
49
50
  .map(f => this.isTestFile(f.sourceFile).then(valid => ({ file: f, valid })));
@@ -59,14 +60,12 @@ export class RunnerUtil {
59
60
  * @returns
60
61
  */
61
62
  static async getTestCount(patterns: string[]): Promise<number> {
62
- const proc = ExecUtil.spawn('npx', ['trv', 'test:count', ...patterns],
63
- {
64
- stdio: 'pipe',
65
- catchAsResult: true,
66
- env: { ...Env.FORCE_COLOR.export(0), ...Env.NO_COLOR.export(true) }
67
- }
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
68
  );
69
- const countRes = await proc.result;
70
69
  if (!countRes.valid) {
71
70
  throw new Error(countRes.stderr);
72
71
  }
@@ -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
  *
@@ -71,7 +78,7 @@ export class TestWatcher {
71
78
  }
72
79
  });
73
80
 
74
- process.send?.('ready');
81
+ process.send?.({ type: 'ready' });
75
82
 
76
83
  if (runAllOnStart) {
77
84
  for (const test of await RunnerUtil.getTestFiles()) {
@@ -1,7 +1,7 @@
1
1
  import { createWriteStream } from 'node:fs';
2
2
  import timers from 'node:timers/promises';
3
3
 
4
- import { ManifestFileUtil, RuntimeIndex } from '@travetto/manifest';
4
+ import { RuntimeContext } from '@travetto/manifest';
5
5
  import { ConsoleManager, Env, TimeUtil } from '@travetto/base';
6
6
  import { ChildCommChannel } from '@travetto/worker';
7
7
 
@@ -34,7 +34,8 @@ export class TestChildWorker extends ChildCommChannel<RunEvent> {
34
34
  */
35
35
  async activate(): Promise<void> {
36
36
  if (/\b@travetto[/]test\b/.test(Env.DEBUG.val ?? '')) {
37
- const stdout = createWriteStream(ManifestFileUtil.toolPath(RuntimeIndex, `test-worker.${process.pid}.log`), { flags: 'a' });
37
+ const file = RuntimeContext.toolPath(`test-worker.${process.pid}.log`);
38
+ const stdout = createWriteStream(file, { flags: 'a' });
38
39
  const c = new console.Console({ stdout, inspectOptions: { depth: 4, colors: false } });
39
40
  ConsoleManager.set({ onLog: (ev) => c[ev.level](process.pid, ...ev.args) });
40
41
  } else {
@@ -1,5 +1,7 @@
1
+ import { fork } from 'node:child_process';
2
+
1
3
  import { RuntimeIndex } from '@travetto/manifest';
2
- import { Env, ExecUtil } from '@travetto/base';
4
+ import { Env } from '@travetto/base';
3
5
  import { ParentCommChannel, Worker } from '@travetto/worker';
4
6
 
5
7
  import { Events, RunEvent } from './types';
@@ -39,12 +41,12 @@ export function buildStandardTestManager(consumer: TestConsumer): Worker<string>
39
41
  const cwd = RuntimeIndex.getModule(module)!.sourcePath;
40
42
 
41
43
  const channel = new ParentCommChannel<TestEvent & { error?: Error }>(
42
- ExecUtil.fork(
43
- RuntimeIndex.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
48
  env: {
49
+ ...process.env,
48
50
  ...Env.TRV_MANIFEST.export(RuntimeIndex.getModule(module)!.outputPath),
49
51
  ...Env.TRV_QUIET.export(true)
50
52
  },
@@ -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';
@@ -45,8 +45,6 @@ export class TestCommand implements CliCommandShape {
45
45
 
46
46
  if (mode === 'single' && !await this.isFirstFile(first)) {
47
47
  return { message: 'You must specify a proper test file to run in single mode', source: 'arg' };
48
- } else if (!/test\//.test(first)) {
49
- return { message: 'Only files in the test/ folder are permitted to be run', source: 'arg' };
50
48
  }
51
49
  }
52
50
 
@@ -1,6 +1,6 @@
1
1
  import { EventEmitter } from 'node:events';
2
2
 
3
- import { Env, ExecUtil } from '@travetto/base';
3
+ import { Env } from '@travetto/base';
4
4
  import { CliCommand } from '@travetto/cli';
5
5
 
6
6
  /** Test child worker target */
@@ -17,7 +17,7 @@ export class TestChildWorkerCommand {
17
17
  }
18
18
 
19
19
  async main(): Promise<void> {
20
- ExecUtil.exitOnDisconnect();
20
+ process.once('disconnect', () => process.exit());
21
21
  const { TestChildWorker } = await import('../src/worker/child.js');
22
22
  return new TestChildWorker().activate();
23
23
  }
@@ -1,4 +1,4 @@
1
- import { Env, ExecUtil } 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';
@@ -22,7 +22,7 @@ export class TestWatcherCommand {
22
22
  return;
23
23
  }
24
24
 
25
- ExecUtil.exitOnDisconnect();
25
+ process.once('disconnect', () => process.exit());
26
26
 
27
27
  try {
28
28
  const { TestWatcher } = await import('../src/execute/watcher.js');