@travetto/test 6.0.0-rc.1 → 6.0.0-rc.2

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.
Files changed (43) hide show
  1. package/__index__.ts +11 -9
  2. package/package.json +8 -8
  3. package/src/assert/capture.ts +1 -1
  4. package/src/assert/check.ts +4 -4
  5. package/src/assert/util.ts +2 -2
  6. package/src/consumer/registry.ts +6 -4
  7. package/src/consumer/types/cumulative.ts +6 -6
  8. package/src/consumer/types/delegating.ts +2 -2
  9. package/src/consumer/types/event.ts +6 -5
  10. package/src/consumer/types/exec.ts +5 -5
  11. package/src/consumer/types/json.ts +3 -4
  12. package/src/consumer/types/noop.ts +3 -4
  13. package/src/consumer/types/runnable.ts +4 -4
  14. package/src/consumer/types/summarizer.ts +3 -3
  15. package/src/consumer/types/tap-summary.ts +10 -9
  16. package/src/consumer/types/tap.ts +39 -12
  17. package/src/consumer/types/xunit.ts +3 -3
  18. package/src/consumer/types.ts +2 -2
  19. package/src/decorator/suite.ts +2 -2
  20. package/src/decorator/test.ts +2 -2
  21. package/src/execute/barrier.ts +3 -3
  22. package/src/execute/console.ts +2 -2
  23. package/src/execute/executor.ts +17 -17
  24. package/src/execute/phase.ts +3 -3
  25. package/src/execute/runner.ts +8 -8
  26. package/src/execute/types.ts +1 -1
  27. package/src/execute/util.ts +3 -3
  28. package/src/execute/watcher.ts +8 -7
  29. package/src/model/event.ts +2 -2
  30. package/src/model/suite.ts +2 -2
  31. package/src/model/test.ts +1 -1
  32. package/src/registry/suite.ts +2 -2
  33. package/src/worker/child.ts +6 -7
  34. package/src/worker/standard.ts +10 -11
  35. package/src/worker/types.ts +2 -2
  36. package/support/bin/run.ts +5 -6
  37. package/support/cli.test.ts +2 -3
  38. package/support/cli.test_child.ts +1 -1
  39. package/support/cli.test_digest.ts +2 -2
  40. package/support/cli.test_direct.ts +1 -1
  41. package/support/cli.test_watch.ts +2 -2
  42. package/support/transformer.assert.ts +7 -6
  43. package/src/consumer/serialize.ts +0 -61
package/__index__.ts CHANGED
@@ -1,9 +1,11 @@
1
- import type { } from './src/trv';
2
- export * from './src/decorator/suite';
3
- export * from './src/decorator/test';
4
- export * from './src/model/suite';
5
- export * from './src/model/test';
6
- export * from './src/model/event';
7
- export * from './src/registry/suite';
8
- export * from './src/fixture';
9
- export * from './src/consumer/types';
1
+ import type { } from './src/trv.d.ts';
2
+ export * from './src/decorator/suite.ts';
3
+ export * from './src/decorator/test.ts';
4
+ export * from './src/model/suite.ts';
5
+ export * from './src/model/test.ts';
6
+ export * from './src/model/event.ts';
7
+ export * from './src/registry/suite.ts';
8
+ export * from './src/fixture.ts';
9
+ export * from './src/consumer/types.ts';
10
+ export * from './src/execute/error.ts';
11
+ export { TestWatchEvent } from './src/worker/types.ts';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/test",
3
- "version": "6.0.0-rc.1",
3
+ "version": "6.0.0-rc.2",
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/registry": "^6.0.0-rc.1",
31
- "@travetto/runtime": "^6.0.0-rc.1",
32
- "@travetto/terminal": "^6.0.0-rc.1",
33
- "@travetto/worker": "^6.0.0-rc.1",
34
- "yaml": "^2.7.0"
30
+ "@travetto/registry": "^6.0.0-rc.2",
31
+ "@travetto/runtime": "^6.0.0-rc.2",
32
+ "@travetto/terminal": "^6.0.0-rc.2",
33
+ "@travetto/worker": "^6.0.0-rc.2",
34
+ "yaml": "^2.7.1"
35
35
  },
36
36
  "peerDependencies": {
37
- "@travetto/cli": "^6.0.0-rc.1",
38
- "@travetto/transformer": "^6.0.0-rc.1"
37
+ "@travetto/cli": "^6.0.0-rc.2",
38
+ "@travetto/transformer": "^6.0.0-rc.3"
39
39
  },
40
40
  "peerDependenciesMeta": {
41
41
  "@travetto/transformer": {
@@ -1,6 +1,6 @@
1
1
  import { EventEmitter } from 'node:events';
2
2
 
3
- import { Assertion, TestConfig } from '../model/test';
3
+ import { Assertion, TestConfig } from '../model/test.ts';
4
4
 
5
5
  export interface CaptureAssert extends Partial<Assertion> {
6
6
  module?: [string, string];
@@ -3,10 +3,10 @@ import { isPromise } from 'node:util/types';
3
3
 
4
4
  import { AppError, Class, castTo, castKey, asConstructable } from '@travetto/runtime';
5
5
 
6
- import { ThrowableError, TestConfig, Assertion } from '../model/test';
7
- import { AssertCapture, CaptureAssert } from './capture';
8
- import { AssertUtil } from './util';
9
- import { ASSERT_FN_OPERATOR, OP_MAPPING } from './types';
6
+ import { ThrowableError, TestConfig, Assertion } from '../model/test.ts';
7
+ import { AssertCapture, CaptureAssert } from './capture.ts';
8
+ import { AssertUtil } from './util.ts';
9
+ import { ASSERT_FN_OPERATOR, OP_MAPPING } from './types.ts';
10
10
 
11
11
  type StringFields<T> = {
12
12
  [K in Extract<keyof T, string>]:
@@ -3,8 +3,8 @@ import path from 'node:path';
3
3
 
4
4
  import { asFull, Class, hasFunction, Runtime, RuntimeIndex } from '@travetto/runtime';
5
5
 
6
- import { TestConfig, Assertion, TestResult } from '../model/test';
7
- import { SuiteConfig, SuiteFailure, SuiteResult } from '../model/suite';
6
+ import { TestConfig, Assertion, TestResult } from '../model/test.ts';
7
+ import { SuiteConfig, SuiteFailure, SuiteResult } from '../model/suite.ts';
8
8
 
9
9
  const isCleanable = hasFunction<{ toClean(): unknown }>('toClean');
10
10
 
@@ -1,7 +1,9 @@
1
- import path from 'path';
1
+ import path from 'node:path';
2
+
2
3
  import { classConstruct, describeFunction, type Class } from '@travetto/runtime';
3
- import type { TestConsumerShape } from './types';
4
- import type { RunState } from '../execute/types';
4
+
5
+ import type { TestConsumerShape } from './types.ts';
6
+ import type { RunState } from '../execute/types.ts';
5
7
 
6
8
  /**
7
9
  * Test Results Handler Registry
@@ -13,7 +15,7 @@ class $TestConsumerRegistry {
13
15
  * Manual initialization when running outside of the bootstrap process
14
16
  */
15
17
  async manualInit(): Promise<void> {
16
- await import('./types/all');
18
+ await import('./types/all.ts');
17
19
  }
18
20
 
19
21
  /**
@@ -2,12 +2,12 @@ import { existsSync } from 'node:fs';
2
2
 
3
3
  import { type Class, RuntimeIndex } from '@travetto/runtime';
4
4
 
5
- import type { TestConsumerShape } from '../types';
6
- import type { TestEvent } from '../../model/event';
7
- import type { TestResult } from '../../model/test';
8
- import type { SuiteResult } from '../../model/suite';
9
- import { SuiteRegistry } from '../../registry/suite';
10
- import { DelegatingConsumer } from './delegating';
5
+ import type { TestConsumerShape } from '../types.ts';
6
+ import type { TestEvent } from '../../model/event.ts';
7
+ import type { TestResult } from '../../model/test.ts';
8
+ import type { SuiteResult } from '../../model/suite.ts';
9
+ import { SuiteRegistry } from '../../registry/suite.ts';
10
+ import { DelegatingConsumer } from './delegating.ts';
11
11
 
12
12
  /**
13
13
  * Cumulative Summary consumer
@@ -1,5 +1,5 @@
1
- import type { SuitesSummary, TestConsumerShape, TestRunState } from '../types';
2
- import type { TestEvent } from '../../model/event';
1
+ import type { SuitesSummary, TestConsumerShape, TestRunState } from '../types.ts';
2
+ import type { TestEvent } from '../../model/event.ts';
3
3
 
4
4
  /**
5
5
  * Delegating event consumer
@@ -1,9 +1,10 @@
1
1
  import { Writable } from 'node:stream';
2
2
 
3
- import type { TestEvent } from '../../model/event';
4
- import type { TestConsumerShape } from '../types';
5
- import { SerializeUtil } from '../serialize';
6
- import { TestConsumer } from '../registry';
3
+ import { Util } from '@travetto/runtime';
4
+
5
+ import type { TestEvent } from '../../model/event.ts';
6
+ import type { TestConsumerShape } from '../types.ts';
7
+ import { TestConsumer } from '../registry.ts';
7
8
 
8
9
  /**
9
10
  * Streams all test events a JSON payload, in an nd-json format
@@ -17,6 +18,6 @@ export class EventStreamer implements TestConsumerShape {
17
18
  }
18
19
 
19
20
  onEvent(event: TestEvent): void {
20
- this.#stream.write(`${SerializeUtil.serializeToJSON(event)}\n`);
21
+ this.#stream.write(`${Util.serializeToJSON(event)}\n`);
21
22
  }
22
23
  }
@@ -1,9 +1,9 @@
1
1
  import { IpcChannel } from '@travetto/worker';
2
+ import { Util } from '@travetto/runtime';
2
3
 
3
- import type { TestEvent } from '../../model/event';
4
- import type { TestConsumerShape } from '../types';
5
- import { SerializeUtil } from '../serialize';
6
- import { TestConsumer } from '../registry';
4
+ import type { TestEvent } from '../../model/event.ts';
5
+ import type { TestConsumerShape } from '../types.ts';
6
+ import { TestConsumer } from '../registry.ts';
7
7
 
8
8
  /**
9
9
  * Triggers each event as an IPC command to a parent process
@@ -11,6 +11,6 @@ import { TestConsumer } from '../registry';
11
11
  @TestConsumer()
12
12
  export class ExecutionEmitter extends IpcChannel<TestEvent> implements TestConsumerShape {
13
13
  onEvent(event: TestEvent): void {
14
- this.send(event.type, JSON.parse(SerializeUtil.serializeToJSON(event)));
14
+ this.send(event.type, JSON.parse(Util.serializeToJSON(event)));
15
15
  }
16
16
  }
@@ -1,8 +1,7 @@
1
1
  import type { Writable } from 'node:stream';
2
2
 
3
- import type { TestEvent } from '../../model/event';
4
- import type { SuitesSummary } from '../types';
5
- import { TestConsumer } from '../registry';
3
+ import type { SuitesSummary } from '../types.ts';
4
+ import { TestConsumer } from '../registry.ts';
6
5
 
7
6
  /**
8
7
  * Returns the entire result set as a single JSON document
@@ -16,7 +15,7 @@ export class JSONEmitter {
16
15
  this.#stream = stream;
17
16
  }
18
17
 
19
- onEvent(event: TestEvent): void { }
18
+ onEvent(): void { }
20
19
 
21
20
  onSummary(summary: SuitesSummary): void {
22
21
  this.#stream.write(JSON.stringify(summary, undefined, 2));
@@ -1,11 +1,10 @@
1
- import type { TestEvent } from '../../model/event';
2
- import type { TestConsumerShape } from '../types';
3
- import { TestConsumer } from '../registry';
1
+ import type { TestConsumerShape } from '../types.ts';
2
+ import { TestConsumer } from '../registry.ts';
4
3
 
5
4
  /**
6
5
  * Does nothing consumer
7
6
  */
8
7
  @TestConsumer()
9
8
  export class NoopConsumer implements TestConsumerShape {
10
- onEvent(event: TestEvent): void { }
9
+ onEvent(): void { }
11
10
  }
@@ -1,7 +1,7 @@
1
- import type { TestConsumerShape } from '../types';
2
- import { TestResultsSummarizer } from './summarizer';
3
- import type { TestEvent } from '../../model/event';
4
- import { DelegatingConsumer } from './delegating';
1
+ import type { TestConsumerShape } from '../types.ts';
2
+ import { TestResultsSummarizer } from './summarizer.ts';
3
+ import type { TestEvent } from '../../model/event.ts';
4
+ import { DelegatingConsumer } from './delegating.ts';
5
5
 
6
6
  /**
7
7
  * Test consumer with support for multiple nested consumers, and summarization
@@ -1,6 +1,6 @@
1
- import type { SuiteResult } from '../../model/suite';
2
- import type { TestEvent } from '../../model/event';
3
- import type { SuitesSummary, TestConsumerShape } from '../types';
1
+ import type { SuiteResult } from '../../model/suite.ts';
2
+ import type { TestEvent } from '../../model/event.ts';
3
+ import type { SuitesSummary, TestConsumerShape } from '../types.ts';
4
4
 
5
5
  /**
6
6
  * Test Result Collector, combines all results into a single Suite Result
@@ -1,14 +1,14 @@
1
1
  import { Util, AsyncQueue } from '@travetto/runtime';
2
2
  import { StyleUtil, Terminal, TerminalUtil } from '@travetto/terminal';
3
3
 
4
- import type { TestEvent } from '../../model/event';
5
- import type { TestResult } from '../../model/test';
4
+ import type { TestEvent } from '../../model/event.ts';
5
+ import type { TestResult } from '../../model/test.ts';
6
6
 
7
- import type { SuitesSummary, TestConsumerShape, TestRunState } from '../types';
8
- import { TestConsumer } from '../registry';
7
+ import type { SuitesSummary, TestConsumerShape, TestRunState } from '../types.ts';
8
+ import { TestConsumer } from '../registry.ts';
9
9
 
10
- import { TapEmitter } from './tap';
11
- import { CONSOLE_ENHANCER, TestResultsEnhancer } from '../enhancer';
10
+ import { TapEmitter } from './tap.ts';
11
+ import { CONSOLE_ENHANCER, TestResultsEnhancer } from '../enhancer.ts';
12
12
 
13
13
  type Result = {
14
14
  key: string;
@@ -44,6 +44,7 @@ export class TapSummaryEmitter implements TestConsumerShape {
44
44
 
45
45
  setOptions(options?: Record<string, unknown>): Promise<void> | void {
46
46
  this.#options = options;
47
+ this.#consumer.setOptions(options);
47
48
  }
48
49
 
49
50
  async onStart(state: TestRunState): Promise<void> {
@@ -57,7 +58,7 @@ export class TapSummaryEmitter implements TestConsumerShape {
57
58
  this.#progress = this.#terminal.streamToBottom(
58
59
  Util.mapAsyncItr(
59
60
  this.#results,
60
- (value, idx) => {
61
+ (value) => {
61
62
  failed += (value.status === 'failed' ? 1 : 0);
62
63
  skipped += (value.status === 'skipped' ? 1 : 0);
63
64
  completed += (value.status !== 'skipped' ? 1 : 0);
@@ -122,9 +123,9 @@ export class TapSummaryEmitter implements TestConsumerShape {
122
123
  if (this.#options?.timings) {
123
124
  const count = +(this.#options?.count ?? 5);
124
125
  await this.#consumer.log('\n---');
125
- for (const [title, results] of [...this.#timings.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {
126
+ for (const [title, results] of [...this.#timings.entries()].toSorted((a, b) => a[0].localeCompare(b[0]))) {
126
127
  await this.#consumer.log(`${this.#enhancer.suiteName(`Top ${count} slowest ${title}s`)}: `);
127
- const top10 = [...results.values()].sort((a, b) => b.duration - a.duration).slice(0, count);
128
+ const top10 = [...results.values()].toSorted((a, b) => b.duration - a.duration).slice(0, count);
128
129
 
129
130
  for (const x of top10) {
130
131
  console.log(` * ${this.#enhancer.testName(x.key)} - ${this.#enhancer.total(x.duration)}ms / ${this.#enhancer.total(x.tests)} tests`);
@@ -1,13 +1,13 @@
1
+ import path from 'node:path';
1
2
  import { stringify } from 'yaml';
2
3
 
3
4
  import { Terminal } from '@travetto/terminal';
4
- import { TimeUtil, Runtime, RuntimeIndex, hasToJSON } from '@travetto/runtime';
5
+ import { TimeUtil, RuntimeIndex, hasToJSON } from '@travetto/runtime';
5
6
 
6
- import type { TestEvent } from '../../model/event';
7
- import type { SuitesSummary, TestConsumerShape } from '../types';
8
- import { TestConsumer } from '../registry';
9
- import { SerializeUtil } from '../serialize';
10
- import { TestResultsEnhancer, CONSOLE_ENHANCER } from '../enhancer';
7
+ import type { TestEvent } from '../../model/event.ts';
8
+ import type { SuitesSummary, TestConsumerShape } from '../types.ts';
9
+ import { TestConsumer } from '../registry.ts';
10
+ import { TestResultsEnhancer, CONSOLE_ENHANCER } from '../enhancer.ts';
11
11
 
12
12
  /**
13
13
  * TAP Format consumer
@@ -18,6 +18,7 @@ export class TapEmitter implements TestConsumerShape {
18
18
  #enhancer: TestResultsEnhancer;
19
19
  #terminal: Terminal;
20
20
  #start: number;
21
+ #options?: Record<string, unknown>;
21
22
 
22
23
  constructor(
23
24
  terminal = new Terminal(),
@@ -27,6 +28,11 @@ export class TapEmitter implements TestConsumerShape {
27
28
  this.#enhancer = enhancer;
28
29
  }
29
30
 
31
+ setOptions(options?: Record<string, unknown>): Promise<void> | void {
32
+ this.#options = options;
33
+ }
34
+
35
+
30
36
  log(message: string): void {
31
37
  this.#terminal.writer.writeLine(message).commit();
32
38
  }
@@ -49,6 +55,24 @@ export class TapEmitter implements TestConsumerShape {
49
55
  this.log(`---\n${this.#enhancer.objectInspect(body)}\n...`);
50
56
  }
51
57
 
58
+ /**
59
+ * Error to string
60
+ * @param error
61
+ */
62
+ errorToString(err?: Error): string | undefined {
63
+ if (err && err.name !== 'AssertionError') {
64
+ if (err instanceof Error) {
65
+ let out = JSON.stringify(hasToJSON(err) ? err.toJSON() : err, null, 2);
66
+ if (this.#options?.verbose && err.stack) {
67
+ out = `${out}\n${err.stack}`;
68
+ }
69
+ return out;
70
+ } else {
71
+ return `${err}`;
72
+ }
73
+ }
74
+ }
75
+
52
76
  /**
53
77
  * Listen for each event
54
78
  */
@@ -67,7 +91,7 @@ export class TapEmitter implements TestConsumerShape {
67
91
  let subCount = 0;
68
92
  for (const asrt of test.assertions) {
69
93
  const text = asrt.message ? `${asrt.text} (${this.#enhancer.failure(asrt.message)})` : asrt.text;
70
- const pth = RuntimeIndex.getFromImport(asrt.import)!.sourceFile.replace(Runtime.mainSourcePath, '.');
94
+ const pth = `./${path.relative(process.cwd(), RuntimeIndex.getFromImport(asrt.import)!.sourceFile)}`;
71
95
  let subMessage = [
72
96
  this.#enhancer.assertNumber(++subCount),
73
97
  '-',
@@ -101,10 +125,10 @@ export class TapEmitter implements TestConsumerShape {
101
125
  this.log(status);
102
126
 
103
127
  // Handle error
104
- if (test.status === 'failed') {
105
- if (test.error && test.error.name !== 'AssertionError') {
106
- const err = SerializeUtil.deserializeError(test.error);
107
- this.logMeta({ error: hasToJSON(err) ? err.toJSON() : err });
128
+ if (test.status === 'failed' && test.error) {
129
+ const msg = this.errorToString(test.error);
130
+ if (msg) {
131
+ this.logMeta({ error: msg });
108
132
  }
109
133
  }
110
134
 
@@ -128,7 +152,10 @@ export class TapEmitter implements TestConsumerShape {
128
152
  if (summary.errors.length) {
129
153
  this.log('---\n');
130
154
  for (const err of summary.errors) {
131
- this.log(this.#enhancer.failure(hasToJSON(err) ? JSON.stringify(err.toJSON(), null, 2) : `${err}`));
155
+ const msg = this.errorToString(err);
156
+ if (msg) {
157
+ this.log(this.#enhancer.failure(msg));
158
+ }
132
159
  }
133
160
  }
134
161
 
@@ -4,9 +4,9 @@ import { stringify } from 'yaml';
4
4
 
5
5
  import { RuntimeIndex } from '@travetto/runtime';
6
6
 
7
- import type { TestEvent } from '../../model/event';
8
- import type { SuitesSummary, TestConsumerShape } from '../types';
9
- import { TestConsumer } from '../registry';
7
+ import type { TestEvent } from '../../model/event.ts';
8
+ import type { SuitesSummary, TestConsumerShape } from '../types.ts';
9
+ import { TestConsumer } from '../registry.ts';
10
10
 
11
11
  /**
12
12
  * Xunit consumer, compatible with JUnit formatters
@@ -1,5 +1,5 @@
1
- import { TestEvent } from '../model/event';
2
- import { Counts, SuiteResult } from '../model/suite';
1
+ import { TestEvent } from '../model/event.ts';
2
+ import { Counts, SuiteResult } from '../model/suite.ts';
3
3
 
4
4
  /**
5
5
  * All suite results
@@ -1,7 +1,7 @@
1
1
  import { castTo, Class, ClassInstance, describeFunction } from '@travetto/runtime';
2
2
 
3
- import { SuiteRegistry } from '../registry/suite';
4
- import { SuiteConfig } from '../model/suite';
3
+ import { SuiteRegistry } from '../registry/suite.ts';
4
+ import { SuiteConfig } from '../model/suite.ts';
5
5
 
6
6
  export type SuitePhase = 'beforeAll' | 'beforeEach' | 'afterAll' | 'afterEach';
7
7
 
@@ -1,7 +1,7 @@
1
1
  import { ClassInstance } from '@travetto/runtime';
2
2
 
3
- import { SuiteRegistry } from '../registry/suite';
4
- import { TestConfig, ThrowableError } from '../model/test';
3
+ import { SuiteRegistry } from '../registry/suite.ts';
4
+ import { TestConfig, ThrowableError } from '../model/test.ts';
5
5
 
6
6
  /**
7
7
  * The `@AssertCheck` indicates that a function's assert calls should be transformed
@@ -3,7 +3,7 @@ import { createHook, executionAsyncId } from 'node:async_hooks';
3
3
 
4
4
  import { TimeSpan, TimeUtil, Util } from '@travetto/runtime';
5
5
 
6
- import { ExecutionError, TimeoutError } from './error';
6
+ import { ExecutionError, TimeoutError } from './error.ts';
7
7
 
8
8
  const UNCAUGHT_ERR_EVENTS = ['unhandledRejection', 'uncaughtException'] as const;
9
9
 
@@ -12,7 +12,7 @@ export class Barrier {
12
12
  * Track timeout
13
13
  */
14
14
  static timeout(duration: number | TimeSpan, op: string = 'Operation'): { promise: Promise<void>, resolve: () => unknown } {
15
- const resolver = Util.resolvablePromise();
15
+ const resolver = Promise.withResolvers<void>();
16
16
  const durationMs = TimeUtil.asMillis(duration);
17
17
  let timeout: NodeJS.Timeout;
18
18
  if (!durationMs) {
@@ -30,7 +30,7 @@ export class Barrier {
30
30
  * Track uncaught error
31
31
  */
32
32
  static uncaughtErrorPromise(): { promise: Promise<void>, resolve: () => unknown } {
33
- const uncaught = Util.resolvablePromise<void>();
33
+ const uncaught = Promise.withResolvers<void>();
34
34
  const onError = (err: Error): void => { Util.queueMacroTask().then(() => uncaught.reject(err)); };
35
35
  UNCAUGHT_ERR_EVENTS.map(k => process.on(k, onError));
36
36
  uncaught.promise.finally(() => { UNCAUGHT_ERR_EVENTS.map(k => process.off(k, onError)); });
@@ -26,9 +26,9 @@ export class ConsoleCapture implements ConsoleListener {
26
26
  }
27
27
 
28
28
  end(): Record<string, string> {
29
- const ret = this.out ?? {};
29
+ const result = this.out ?? {};
30
30
  this.out = {};
31
31
  ConsoleManager.set(ConsoleCapture.#listener);
32
- return Object.fromEntries(Object.entries(ret).map(([k, v]) => [k, v.join('\n')]));
32
+ return Object.fromEntries(Object.entries(result).map(([k, v]) => [k, v.join('\n')]));
33
33
  }
34
34
  }
@@ -2,17 +2,17 @@ import { AssertionError } from 'node:assert';
2
2
 
3
3
  import { Env, TimeUtil, Runtime, castTo } from '@travetto/runtime';
4
4
 
5
- import { SuiteRegistry } from '../registry/suite';
6
- import { TestConfig, TestResult, TestRun } from '../model/test';
7
- import { SuiteConfig, SuiteFailure, SuiteResult } from '../model/suite';
8
- import { TestConsumer } from '../consumer/types';
9
- import { AssertCheck } from '../assert/check';
10
- import { AssertCapture } from '../assert/capture';
11
- import { ConsoleCapture } from './console';
12
- import { TestPhaseManager } from './phase';
13
- import { AssertUtil } from '../assert/util';
14
- import { Barrier } from './barrier';
15
- import { ExecutionError } from './error';
5
+ import { SuiteRegistry } from '../registry/suite.ts';
6
+ import { TestConfig, TestResult, TestRun } from '../model/test.ts';
7
+ import { SuiteConfig, SuiteFailure, SuiteResult } from '../model/suite.ts';
8
+ import { TestConsumerShape } from '../consumer/types.ts';
9
+ import { AssertCheck } from '../assert/check.ts';
10
+ import { AssertCapture } from '../assert/capture.ts';
11
+ import { ConsoleCapture } from './console.ts';
12
+ import { TestPhaseManager } from './phase.ts';
13
+ import { AssertUtil } from '../assert/util.ts';
14
+ import { Barrier } from './barrier.ts';
15
+ import { ExecutionError } from './error.ts';
16
16
 
17
17
  const TEST_TIMEOUT = TimeUtil.fromValue(Env.TRV_TEST_TIMEOUT.val) ?? 5000;
18
18
 
@@ -21,9 +21,9 @@ const TEST_TIMEOUT = TimeUtil.fromValue(Env.TRV_TEST_TIMEOUT.val) ?? 5000;
21
21
  */
22
22
  export class TestExecutor {
23
23
 
24
- #consumer: TestConsumer;
24
+ #consumer: TestConsumerShape;
25
25
 
26
- constructor(consumer: TestConsumer) {
26
+ constructor(consumer: TestConsumerShape) {
27
27
  this.#consumer = consumer;
28
28
  }
29
29
 
@@ -211,13 +211,13 @@ export class TestExecutor {
211
211
  await mgr.startPhase('each');
212
212
 
213
213
  // Run test
214
- const ret = await this.executeTest(test);
215
- result[ret.status]++;
216
- result.tests.push(ret);
214
+ const testResult = await this.executeTest(test);
215
+ result[testResult.status]++;
216
+ result.tests.push(testResult);
217
217
 
218
218
  // Handle after each
219
219
  await mgr.endPhase('each');
220
- ret.durationTotal = Date.now() - testStart;
220
+ testResult.durationTotal = Date.now() - testStart;
221
221
  }
222
222
 
223
223
  // Handle after all
@@ -1,8 +1,8 @@
1
1
  import { Env, TimeUtil } from '@travetto/runtime';
2
2
 
3
- import { SuiteConfig, SuiteFailure, SuiteResult } from '../model/suite';
4
- import { AssertUtil } from '../assert/util';
5
- import { Barrier } from './barrier';
3
+ import { SuiteConfig, SuiteFailure, SuiteResult } from '../model/suite.ts';
4
+ import { AssertUtil } from '../assert/util.ts';
5
+ import { Barrier } from './barrier.ts';
6
6
 
7
7
  class TestBreakout extends Error {
8
8
  source?: Error;
@@ -3,14 +3,14 @@ import path from 'node:path';
3
3
  import { TimeUtil, Runtime, RuntimeIndex } from '@travetto/runtime';
4
4
  import { WorkPool } from '@travetto/worker';
5
5
 
6
- import { buildStandardTestManager } from '../worker/standard';
7
- import { RunnableTestConsumer } from '../consumer/types/runnable';
8
- import { TestRun } from '../model/test';
6
+ import { buildStandardTestManager } from '../worker/standard.ts';
7
+ import { RunnableTestConsumer } from '../consumer/types/runnable.ts';
8
+ import { TestRun } from '../model/test.ts';
9
9
 
10
- import { TestExecutor } from './executor';
11
- import { RunnerUtil } from './util';
12
- import { RunState } from './types';
13
- import { TestConsumerRegistry } from '../consumer/registry';
10
+ import { TestExecutor } from './executor.ts';
11
+ import { RunnerUtil } from './util.ts';
12
+ import { RunState } from './types.ts';
13
+ import { TestConsumerRegistry } from '../consumer/registry.ts';
14
14
 
15
15
  /**
16
16
  * Test Runner
@@ -31,7 +31,7 @@ export class Runner {
31
31
  const consumer = new RunnableTestConsumer(target);
32
32
  const tests = await RunnerUtil.getTestDigest(globs, this.#state.tags);
33
33
  const testRuns = RunnerUtil.getTestRuns(tests)
34
- .sort((a, b) => a.runId!.localeCompare(b.runId!));
34
+ .toSorted((a, b) => a.runId!.localeCompare(b.runId!));
35
35
 
36
36
  await consumer.onStart({ testCount: tests.length });
37
37
  await WorkPool.run(
@@ -1,4 +1,4 @@
1
- import { TestRun } from '../model/test';
1
+ import { TestRun } from '../model/test.ts';
2
2
 
3
3
  /**
4
4
  * Run state
@@ -5,7 +5,7 @@ import readline from 'node:readline/promises';
5
5
  import path from 'node:path';
6
6
 
7
7
  import { Env, ExecUtil, ShutdownManager, Util, RuntimeIndex, Runtime } from '@travetto/runtime';
8
- import { TestConfig, TestRun } from '../model/test';
8
+ import { TestConfig, TestRun } from '../model/test.ts';
9
9
 
10
10
  /**
11
11
  * Simple Test Utilities
@@ -88,8 +88,8 @@ export class RunnerUtil {
88
88
  ) :
89
89
  ((): boolean => true);
90
90
 
91
- const res: TestConfig[] = countRes.valid ? JSON.parse(countRes.stdout) : [];
92
- return res.filter(testFilter);
91
+ const parsed: TestConfig[] = countRes.valid ? JSON.parse(countRes.stdout) : [];
92
+ return parsed.filter(testFilter);
93
93
  }
94
94
 
95
95
  /**
@@ -2,13 +2,14 @@ import { RootRegistry, MethodSource } from '@travetto/registry';
2
2
  import { WorkPool } from '@travetto/worker';
3
3
  import { AsyncQueue, Runtime, RuntimeIndex, castTo, describeFunction } from '@travetto/runtime';
4
4
 
5
- import { SuiteRegistry } from '../registry/suite';
6
- import { buildStandardTestManager } from '../worker/standard';
7
- import { TestConsumerRegistry } from '../consumer/registry';
8
- import { CumulativeSummaryConsumer } from '../consumer/types/cumulative';
9
- import { TestRun } from '../model/test';
10
- import { RunnerUtil } from './util';
11
- import { TestReadyEvent, TestRemovedEvent } from '../worker/types';
5
+ import { SuiteRegistry } from '../registry/suite.ts';
6
+ import { buildStandardTestManager } from '../worker/standard.ts';
7
+ import { TestConsumerRegistry } from '../consumer/registry.ts';
8
+ import { CumulativeSummaryConsumer } from '../consumer/types/cumulative.ts';
9
+ import { TestRun } from '../model/test.ts';
10
+ import { RunnerUtil } from './util.ts';
11
+ import { TestReadyEvent, TestRemovedEvent } from '../worker/types.ts';
12
+
12
13
  /**
13
14
  * Test Watcher.
14
15
  *
@@ -1,5 +1,5 @@
1
- import { Assertion, TestConfig, TestResult } from './test';
2
- import { SuiteConfig, SuiteResult } from './suite';
1
+ import { Assertion, TestConfig, TestResult } from './test.ts';
2
+ import { SuiteConfig, SuiteResult } from './suite.ts';
3
3
 
4
4
  /**
5
5
  * Targets
@@ -1,7 +1,7 @@
1
1
  import type { Class } from '@travetto/runtime';
2
2
 
3
- import { Assertion, TestConfig, TestResult } from './test';
4
- import { Skip, SuiteCore } from './common';
3
+ import { Assertion, TestConfig, TestResult } from './test.ts';
4
+ import { Skip, SuiteCore } from './common.ts';
5
5
 
6
6
  /**
7
7
  * Suite configuration
package/src/model/test.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { Class, TimeSpan } from '@travetto/runtime';
2
- import { Skip, TestCore } from './common';
2
+ import { Skip, TestCore } from './common.ts';
3
3
 
4
4
  export type ThrowableError = string | RegExp | Class<Error> | ((e: Error | string) => boolean | void | undefined);
5
5
 
@@ -1,8 +1,8 @@
1
1
  import { Class, Runtime, classConstruct, describeFunction, asFull } from '@travetto/runtime';
2
2
  import { MetadataRegistry } from '@travetto/registry';
3
3
 
4
- import { SuiteConfig } from '../model/suite';
5
- import { TestConfig, TestRun } from '../model/test';
4
+ import { SuiteConfig } from '../model/suite.ts';
5
+ import { TestConfig, TestRun } from '../model/test.ts';
6
6
 
7
7
  /**
8
8
  * Test Suite registry
@@ -3,11 +3,10 @@ import { createWriteStream } from 'node:fs';
3
3
  import { ConsoleManager, Env, Util, Runtime } from '@travetto/runtime';
4
4
  import { IpcChannel } from '@travetto/worker';
5
5
 
6
- import { SerializeUtil } from '../consumer/serialize';
7
- import { RunnerUtil } from '../execute/util';
8
- import { Runner } from '../execute/runner';
9
- import { Events } from './types';
10
- import { TestRun } from '../model/test';
6
+ import { RunnerUtil } from '../execute/util.ts';
7
+ import { Runner } from '../execute/runner.ts';
8
+ import { Events } from './types.ts';
9
+ import { TestRun } from '../model/test.ts';
11
10
 
12
11
  /**
13
12
  * Child Worker for the Test Runner. Receives events as commands
@@ -15,7 +14,7 @@ import { TestRun } from '../model/test';
15
14
  */
16
15
  export class TestChildWorker extends IpcChannel<TestRun> {
17
16
 
18
- #done = Util.resolvablePromise();
17
+ #done = Promise.withResolvers<void>();
19
18
 
20
19
  async #exec(op: () => Promise<unknown>, type: string): Promise<void> {
21
20
  try {
@@ -26,7 +25,7 @@ export class TestChildWorker extends IpcChannel<TestRun> {
26
25
  throw err;
27
26
  }
28
27
  // Mark as errored out
29
- this.send(type, { error: SerializeUtil.serializeError(err) });
28
+ this.send(type, JSON.parse(Util.serializeToJSON({ error: err })));
30
29
  }
31
30
  }
32
31
 
@@ -1,13 +1,12 @@
1
1
  import { fork } from 'node:child_process';
2
2
 
3
- import { Env, RuntimeIndex } from '@travetto/runtime';
3
+ import { Env, RuntimeIndex, Util } from '@travetto/runtime';
4
4
  import { IpcChannel } from '@travetto/worker';
5
5
 
6
- import { Events, TestLogEvent } from './types';
7
- import { TestConsumerShape } from '../consumer/types';
8
- import { SerializeUtil } from '../consumer/serialize';
9
- import { TestEvent } from '../model/event';
10
- import { TestRun } from '../model/test';
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';
11
10
 
12
11
  const log = (message: string): void => {
13
12
  process.send?.({ type: 'log', message } satisfies TestLogEvent);
@@ -25,7 +24,7 @@ export async function buildStandardTestManager(consumer: TestConsumerShape, run:
25
24
 
26
25
  const channel = new IpcChannel<TestEvent & { error?: Error }>(
27
26
  fork(
28
- RuntimeIndex.resolveFileImport('@travetto/cli/support/entry.trv'), ['test:child'],
27
+ RuntimeIndex.resolveFileImport('@travetto/cli/support/entry.trv.ts'), ['test:child'],
29
28
  {
30
29
  cwd: suiteMod.sourcePath,
31
30
  env: {
@@ -44,7 +43,7 @@ export async function buildStandardTestManager(consumer: TestConsumerShape, run:
44
43
 
45
44
  channel.on('*', async ev => {
46
45
  try {
47
- await consumer.onEvent(ev); // Connect the consumer with the event stream from the child
46
+ await consumer.onEvent(Util.deserializeFromJson(JSON.stringify(ev))); // Connect the consumer with the event stream from the child
48
47
  } catch {
49
48
  // Do nothing
50
49
  }
@@ -56,7 +55,7 @@ export async function buildStandardTestManager(consumer: TestConsumerShape, run:
56
55
  channel.send(Events.RUN, run);
57
56
 
58
57
  // Wait for complete
59
- const { error } = await complete;
58
+ const result = await complete.then(ev => Util.deserializeFromJson<typeof ev>(JSON.stringify(ev)));
60
59
 
61
60
  // Kill on complete
62
61
  await channel.destroy();
@@ -64,7 +63,7 @@ export async function buildStandardTestManager(consumer: TestConsumerShape, run:
64
63
  log(`Worker Finished ${run.import}`);
65
64
 
66
65
  // If we received an error, throw it
67
- if (error) {
68
- throw SerializeUtil.deserializeError(error);
66
+ if (result.error) {
67
+ throw result.error;
69
68
  }
70
69
  }
@@ -1,5 +1,5 @@
1
- import { TestEvent } from '../model/event';
2
- import { TestRun } from '../model/test';
1
+ import { TestEvent } from '../model/event.ts';
2
+ import { TestRun } from '../model/test.ts';
3
3
 
4
4
  /**
5
5
  * Test Run Event Keys
@@ -1,17 +1,16 @@
1
1
  import { castTo, Runtime } from '@travetto/runtime';
2
- import { AllViewSymbol } from '@travetto/schema/src/internal/types';
3
2
  import { SchemaRegistry } from '@travetto/schema';
4
3
 
5
- import { TestConsumerRegistry } from '../../src/consumer/registry';
6
- import type { RunState } from '../../src/execute/types';
4
+ import { TestConsumerRegistry } from '../../src/consumer/registry.ts';
5
+ import type { RunState } from '../../src/execute/types.ts';
7
6
 
8
7
  /**
9
8
  * Run tests given the input state
10
9
  * @param opts
11
10
  */
12
11
  export async function runTests(opts: RunState): Promise<void> {
13
- const { RunnerUtil } = await import('../../src/execute/util');
14
- const { Runner } = await import('../../src/execute/runner');
12
+ const { RunnerUtil } = await import('../../src/execute/util.ts');
13
+ const { Runner } = await import('../../src/execute/runner.ts');
15
14
 
16
15
  RunnerUtil.registerCleanup('runner');
17
16
 
@@ -36,7 +35,7 @@ export async function selectConsumer(inst: { format?: string }) {
36
35
 
37
36
  const cls = inst.constructor;
38
37
 
39
- SchemaRegistry.get(castTo(cls)).views[AllViewSymbol].schema.format.enum = {
38
+ SchemaRegistry.get(castTo(cls)).totalView.schema.format.enum = {
40
39
  message: `{path} is only allowed to be "${types.join('" or "')}"`,
41
40
  values: types
42
41
  };
@@ -7,8 +7,6 @@ import { CliCommandShape, CliCommand, CliValidationError } from '@travetto/cli';
7
7
  import { WorkPool } from '@travetto/worker';
8
8
  import { Max, Min } from '@travetto/schema';
9
9
 
10
- import { selectConsumer } from './bin/run';
11
-
12
10
  /**
13
11
  * Launch test framework and execute tests
14
12
  */
@@ -55,6 +53,7 @@ export class TestCommand implements CliCommandShape {
55
53
  }
56
54
 
57
55
  async preValidate(): Promise<void> {
56
+ const { selectConsumer } = await import('./bin/run.ts');
58
57
  await selectConsumer(this);
59
58
  }
60
59
 
@@ -67,7 +66,7 @@ export class TestCommand implements CliCommandShape {
67
66
  }
68
67
 
69
68
  async main(first: string = '**/*', globs: string[] = []): Promise<void> {
70
- const { runTests } = await import('./bin/run');
69
+ const { runTests } = await import('./bin/run.ts');
71
70
 
72
71
  const isFirst = await this.isFirstFile(first);
73
72
  const isSingle = this.mode === 'single' || (isFirst && globs.length === 0);
@@ -18,7 +18,7 @@ export class TestChildWorkerCommand {
18
18
 
19
19
  async main(): Promise<void> {
20
20
  process.once('disconnect', () => process.exit());
21
- const { TestChildWorker } = await import('../src/worker/child');
21
+ const { TestChildWorker } = await import('../src/worker/child.ts');
22
22
  return new TestChildWorker().activate();
23
23
  }
24
24
  }
@@ -1,8 +1,8 @@
1
1
  import { CliCommand } from '@travetto/cli';
2
2
  import { Env, Runtime, describeFunction } from '@travetto/runtime';
3
3
 
4
- import { SuiteRegistry } from '../src/registry/suite';
5
- import { RunnerUtil } from '../src/execute/util';
4
+ import { SuiteRegistry } from '../src/registry/suite.ts';
5
+ import { RunnerUtil } from '../src/execute/util.ts';
6
6
 
7
7
  @CliCommand({ hidden: true })
8
8
  export class TestDigestCommand {
@@ -1,7 +1,7 @@
1
1
  import { Env } from '@travetto/runtime';
2
2
  import { CliCommand } from '@travetto/cli';
3
3
 
4
- import { runTests, selectConsumer } from './bin/run';
4
+ import { runTests, selectConsumer } from './bin/run.ts';
5
5
 
6
6
  /** Direct test invocation */
7
7
  @CliCommand({ hidden: true })
@@ -1,7 +1,7 @@
1
1
  import { Env } from '@travetto/runtime';
2
2
  import { CliCommand, CliUtil } from '@travetto/cli';
3
3
 
4
- import { selectConsumer } from './bin/run';
4
+ import { selectConsumer } from './bin/run.ts';
5
5
 
6
6
  /**
7
7
  * Invoke the test watcher
@@ -27,7 +27,7 @@ export class TestWatcherCommand {
27
27
  }
28
28
 
29
29
  try {
30
- const { TestWatcher } = await import('../src/execute/watcher');
30
+ const { TestWatcher } = await import('../src/execute/watcher.ts');
31
31
  await TestWatcher.watch(this.format, this.mode === 'all');
32
32
  } catch (err) {
33
33
  console.error(err);
@@ -48,8 +48,8 @@ const METHODS: Record<string, Function[]> = {
48
48
 
49
49
  const OP_TOKEN_TO_NAME = new Map<number, keyof typeof OPTOKEN_ASSERT>();
50
50
 
51
- const AssertSymbol = Symbol.for('@travetto/test:assert');
52
- const IsTestSymbol = Symbol.for('@travetto/test:valid');
51
+ const AssertSymbol = Symbol();
52
+ const IsTestSymbol = Symbol();
53
53
 
54
54
  /**
55
55
  * Assert transformation state
@@ -137,7 +137,7 @@ export class AssertTransformer {
137
137
  */
138
138
  static initState(state: TransformerState & AssertState): void {
139
139
  if (!state[AssertSymbol]) {
140
- const asrt = state.importFile('@travetto/test/src/assert/check').ident;
140
+ const asrt = state.importFile('@travetto/test/src/assert/check.ts').ident;
141
141
  state[AssertSymbol] = {
142
142
  assert: asrt,
143
143
  assertCheck: CoreUtil.createAccess(state.factory, asrt, ASSERT_UTIL, 'check'),
@@ -154,7 +154,7 @@ export class AssertTransformer {
154
154
  this.initState(state);
155
155
 
156
156
  const first = CoreUtil.firstArgument(node);
157
- const firstText = first!.getText();
157
+ const firstText = first?.getText() ?? node.getText();
158
158
 
159
159
  cmd.args = cmd.args.filter(x => x !== undefined && x !== null);
160
160
  const check = state.factory.createCallExpression(state[AssertSymbol]!.assertCheck, undefined, state.factory.createNodeArray([
@@ -252,7 +252,6 @@ export class AssertTransformer {
252
252
  * Determine which type of check to perform
253
253
  */
254
254
  static getCommand(state: TransformerState, args: Args): Command | undefined {
255
-
256
255
  const comp = args[0]!;
257
256
  const message = args.length === 2 ? args[1] : undefined;
258
257
 
@@ -303,7 +302,9 @@ export class AssertTransformer {
303
302
  const fn = exp.name.escapedText.toString();
304
303
  if (ident.escapedText === ASSERT_CMD) {
305
304
  // Look for reject/throw
306
- if (/^(doesNot)?(Throw|Reject)s?$/i.test(fn)) {
305
+ if (fn === 'fail') {
306
+ node = this.doAssert(state, node, { fn: 'fail', args: node.arguments.slice() });
307
+ } else if (/^(doesNot)?(Throw|Reject)s?$/i.test(fn)) {
307
308
  node = this.doThrows(state, node, fn, [...node.arguments]);
308
309
  } else {
309
310
  const sub = { ...this.getCommand(state, node.arguments)!, fn };
@@ -1,61 +0,0 @@
1
- import { AppError, hasToJSON } from '@travetto/runtime';
2
- import { TestEvent, } from '../model/event';
3
-
4
- export type SerializedError = { [K in keyof Error]: Error[K] extends Function ? never : Error[K] } & { $: true };
5
-
6
- function isError(e: unknown): e is SerializedError {
7
- return !!e && (typeof e === 'object') && '$' in e;
8
- }
9
-
10
- export class SerializeUtil {
11
-
12
- /**
13
- * Prepare error for transmission
14
- */
15
- static serializeError(e: Error | SerializedError): SerializedError;
16
- static serializeError(e: undefined): undefined;
17
- static serializeError(e: Error | SerializedError | undefined): SerializedError | undefined {
18
- if (!e) {
19
- return;
20
- }
21
-
22
- return {
23
- $: true,
24
- ...hasToJSON(e) ? e.toJSON() : e,
25
- name: e.name,
26
- message: e.message,
27
- stack: e.stack?.replace(/.*\[ERR_ASSERTION\]:\s*/, ''),
28
- };
29
- }
30
-
31
- /**
32
- * Reconstitute the error, post serialization
33
- */
34
- static deserializeError(e: Error | SerializedError): Error;
35
- static deserializeError(e: undefined): undefined;
36
- static deserializeError(e: Error | SerializedError | undefined): Error | undefined {
37
- if (isError(e)) {
38
- const err = AppError.fromJSON(e) ?? new Error();
39
- if (!(err instanceof AppError)) {
40
- const { $: _, ...rest } = e;
41
- Object.assign(err, rest);
42
- }
43
- err.message = e.message;
44
- err.stack = e.stack;
45
- err.name = e.name;
46
- return err;
47
- } else {
48
- return e;
49
- }
50
- }
51
-
52
- /**
53
- * Serialize to JSON
54
- */
55
- static serializeToJSON(out: TestEvent): string {
56
- return JSON.stringify(out, (_, v) =>
57
- v instanceof Error ? this.serializeError(v) :
58
- typeof v === 'bigint' ? v.toString() : v
59
- );
60
- }
61
- }