@travetto/test 8.0.0-alpha.20 → 8.0.0-alpha.21

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 (51) hide show
  1. package/README.md +14 -20
  2. package/__index__.ts +9 -9
  3. package/package.json +7 -7
  4. package/src/assert/capture.ts +1 -2
  5. package/src/assert/check.ts +52 -25
  6. package/src/assert/types.ts +1 -1
  7. package/src/assert/util.ts +16 -12
  8. package/src/consumer/decorator.ts +2 -2
  9. package/src/consumer/enhancer.ts +3 -3
  10. package/src/consumer/registry-adapter.ts +3 -3
  11. package/src/consumer/registry-index.ts +6 -5
  12. package/src/consumer/types/cumulative.ts +6 -6
  13. package/src/consumer/types/delegating.ts +2 -2
  14. package/src/consumer/types/event.ts +2 -2
  15. package/src/consumer/types/exec.ts +3 -4
  16. package/src/consumer/types/json.ts +3 -4
  17. package/src/consumer/types/noop.ts +3 -3
  18. package/src/consumer/types/runnable.ts +4 -6
  19. package/src/consumer/types/summarizer.ts +2 -3
  20. package/src/consumer/types/tap-summary.ts +15 -20
  21. package/src/consumer/types/tap.ts +57 -29
  22. package/src/consumer/types/util.ts +8 -5
  23. package/src/consumer/types/xunit.ts +7 -6
  24. package/src/decorator/suite.ts +3 -3
  25. package/src/decorator/test.ts +6 -4
  26. package/src/execute/barrier.ts +15 -9
  27. package/src/execute/console.ts +3 -4
  28. package/src/execute/executor.ts +29 -25
  29. package/src/execute/phase.ts +1 -1
  30. package/src/execute/run.ts +39 -39
  31. package/src/execute/watcher.ts +12 -19
  32. package/src/fixture.ts +6 -7
  33. package/src/model/common.ts +1 -1
  34. package/src/model/error.ts +2 -2
  35. package/src/model/event.ts +14 -9
  36. package/src/model/suite.ts +2 -2
  37. package/src/model/test.ts +8 -5
  38. package/src/model/util.ts +24 -14
  39. package/src/registry/registry-adapter.ts +10 -13
  40. package/src/registry/registry-index.ts +13 -11
  41. package/src/worker/child.ts +13 -10
  42. package/src/worker/standard.ts +11 -14
  43. package/src/worker/types.ts +3 -7
  44. package/support/bin/run.ts +1 -1
  45. package/support/cli.test.ts +16 -14
  46. package/support/cli.test_child.ts +2 -2
  47. package/support/cli.test_diff.ts +5 -6
  48. package/support/cli.test_digest.ts +3 -4
  49. package/support/cli.test_direct.ts +5 -6
  50. package/support/cli.test_watch.ts +2 -3
  51. package/support/transformer.assert.ts +40 -32
@@ -1,13 +1,12 @@
1
- import type { SuiteResult } from '../../model/suite.ts';
2
1
  import type { TestEvent } from '../../model/event.ts';
3
- import type { SuitesSummary, TestConsumerShape } from '../types.ts';
2
+ import type { SuiteResult } from '../../model/suite.ts';
4
3
  import { TestModelUtil } from '../../model/util.ts';
4
+ import type { SuitesSummary, TestConsumerShape } from '../types.ts';
5
5
 
6
6
  /**
7
7
  * Test Result Collector, combines all results into a single Suite Result
8
8
  */
9
9
  export class TestResultsSummarizer implements TestConsumerShape {
10
-
11
10
  summary: SuitesSummary = {
12
11
  ...TestModelUtil.buildSummary(),
13
12
  suites: []
@@ -1,16 +1,14 @@
1
- import { Util, AsyncQueue } from '@travetto/runtime';
1
+ import { AsyncQueue, Util } from '@travetto/runtime';
2
2
  import { Terminal, TerminalUtil } from '@travetto/terminal';
3
3
 
4
4
  import type { TestEvent } from '../../model/event.ts';
5
+ import type { SuiteResult } from '../../model/suite.ts';
5
6
  import type { TestResult } from '../../model/test.ts';
6
-
7
- import type { SuitesSummary, TestConsumerShape, TestRunState } from '../types.ts';
7
+ import { TestModelUtil } from '../../model/util.ts';
8
8
  import { TestConsumer } from '../decorator.ts';
9
-
10
- import { TapEmitter } from './tap.ts';
11
9
  import { CONSOLE_ENHANCER, type TestResultsEnhancer } from '../enhancer.ts';
12
- import type { SuiteResult } from '../../model/suite.ts';
13
- import { TestModelUtil } from '../../model/util.ts';
10
+ import type { SuitesSummary, TestConsumerShape, TestRunState } from '../types.ts';
11
+ import { TapEmitter } from './tap.ts';
14
12
 
15
13
  type Result = {
16
14
  key: string;
@@ -23,7 +21,6 @@ type Result = {
23
21
  */
24
22
  @TestConsumer()
25
23
  export class TapSummaryEmitter implements TestConsumerShape {
26
-
27
24
  #timings = new Map<'test' | 'module' | 'file' | 'suite', Map<string, Result>>();
28
25
 
29
26
  #terminal: Terminal;
@@ -53,20 +50,16 @@ export class TapSummaryEmitter implements TestConsumerShape {
53
50
  foundModule.duration += suite.duration;
54
51
  foundModule.tests += testCount;
55
52
 
56
- const foundFile = this.#timings
57
- .getOrInsert('file', new Map<string, Result>())
58
- .getOrInsert(file, { key: file, duration: 0, tests: 0 });
53
+ const foundFile = this.#timings.getOrInsert('file', new Map<string, Result>()).getOrInsert(file, { key: file, duration: 0, tests: 0 });
59
54
 
60
55
  foundFile.duration += suite.duration;
61
56
  foundFile.tests += testCount;
62
57
 
63
- this.#timings
64
- .getOrInsert('suite', new Map<string, Result>())
65
- .set(suite.classId, {
66
- key: suite.classId,
67
- duration: suite.duration,
68
- tests: testCount
69
- });
58
+ this.#timings.getOrInsert('suite', new Map<string, Result>()).set(suite.classId, {
59
+ key: suite.classId,
60
+ duration: suite.duration,
61
+ tests: testCount
62
+ });
70
63
  }
71
64
 
72
65
  #renderTimings(): void {
@@ -77,7 +70,9 @@ export class TapSummaryEmitter implements TestConsumerShape {
77
70
  const top10 = [...results.values()].toSorted((a, b) => b.duration - a.duration).slice(0, count);
78
71
 
79
72
  for (const result of top10) {
80
- console.log(` * ${this.#enhancer.testName(result.key)} - ${this.#enhancer.total(result.duration)}ms / ${this.#enhancer.total(result.tests)} tests`);
73
+ console.log(
74
+ ` * ${this.#enhancer.testName(result.key)} - ${this.#enhancer.total(result.duration)}ms / ${this.#enhancer.total(result.tests)} tests`
75
+ );
81
76
  }
82
77
  this.#consumer.log('');
83
78
  }
@@ -101,7 +96,7 @@ export class TapSummaryEmitter implements TestConsumerShape {
101
96
  this.#progress = this.#terminal.streamToBottom(
102
97
  Util.mapAsyncIterable(
103
98
  this.#results,
104
- (value) => {
99
+ value => {
105
100
  TestModelUtil.countTestResult(total, [value]);
106
101
  const statusLine = `${total.failed} failed, ${total.errored} errored, ${total.skipped} skipped`;
107
102
  return {
@@ -1,13 +1,14 @@
1
1
  import path from 'node:path';
2
+
2
3
  import { stringify } from 'yaml';
3
4
 
4
- import { Terminal, StyleUtil } from '@travetto/terminal';
5
- import { TimeUtil, RuntimeIndex } from '@travetto/runtime';
5
+ import { RuntimeIndex, TimeUtil } from '@travetto/runtime';
6
+ import { StyleUtil, Terminal } from '@travetto/terminal';
6
7
 
7
8
  import type { TestEvent } from '../../model/event.ts';
8
- import type { SuitesSummary, TestConsumerShape } from '../types.ts';
9
9
  import { TestConsumer } from '../decorator.ts';
10
- import { type TestResultsEnhancer, CONSOLE_ENHANCER } from '../enhancer.ts';
10
+ import { CONSOLE_ENHANCER, type TestResultsEnhancer } from '../enhancer.ts';
11
+ import type { SuitesSummary, TestConsumerShape } from '../types.ts';
11
12
  import { TestConsumerUtil } from './util.ts';
12
13
 
13
14
  const SPACE = ' ';
@@ -23,10 +24,7 @@ export class TapEmitter implements TestConsumerShape {
23
24
  #options?: Record<string, unknown>;
24
25
  #start: number = 0;
25
26
 
26
- constructor(
27
- terminal = new Terminal(),
28
- enhancer: TestResultsEnhancer = CONSOLE_ENHANCER
29
- ) {
27
+ constructor(terminal = new Terminal(), enhancer: TestResultsEnhancer = CONSOLE_ENHANCER) {
30
28
  this.#terminal = terminal;
31
29
  this.#enhancer = enhancer;
32
30
  }
@@ -53,7 +51,10 @@ export class TapEmitter implements TestConsumerShape {
53
51
  logMeta(metadata: Record<string, unknown>): void {
54
52
  const lineLength = this.#terminal.width - 5;
55
53
  let body = stringify(metadata, { lineWidth: lineLength, indent: 2 });
56
- body = body.split('\n').map(line => ` ${line}`).join('\n');
54
+ body = body
55
+ .split('\n')
56
+ .map(line => ` ${line}`)
57
+ .join('\n');
57
58
  this.log(`---\n${this.#enhancer.objectInspect(body)}\n...`);
58
59
  }
59
60
 
@@ -71,7 +72,7 @@ export class TapEmitter implements TestConsumerShape {
71
72
  StyleUtil.link(suiteId, `file://${suiteSourceFile}#${test.suiteLineStart ?? 1}`),
72
73
  ' - ',
73
74
  StyleUtil.link(this.#enhancer.testName(test.methodName), `file://${testSourceFile}#${test.lineStart}`),
74
- ...test.description ? [`: ${this.#enhancer.testDescription(test.description)}`] : []
75
+ ...(test.description ? [`: ${this.#enhancer.testDescription(test.description)}`] : [])
75
76
  ].join('');
76
77
 
77
78
  this.log(`# ${header}`);
@@ -110,10 +111,17 @@ export class TapEmitter implements TestConsumerShape {
110
111
  // Track test result
111
112
  let status = `${this.#enhancer.testNumber(++this.#count)} `;
112
113
  switch (test.status) {
113
- case 'passed': `${this.#enhancer.success('ok')} ${status}`; break;
114
- case 'skipped': status += ' # SKIP'; break;
115
- case 'unknown': break;
116
- default: status = `${this.#enhancer.failure('not ok')} ${status}`; break;
114
+ case 'passed':
115
+ `${this.#enhancer.success('ok')} ${status}`;
116
+ break;
117
+ case 'skipped':
118
+ status += ' # SKIP';
119
+ break;
120
+ case 'unknown':
121
+ break;
122
+ default:
123
+ status = `${this.#enhancer.failure('not ok')} ${status}`;
124
+ break;
117
125
  }
118
126
  status += header;
119
127
 
@@ -156,20 +164,40 @@ export class TapEmitter implements TestConsumerShape {
156
164
 
157
165
  const allPassed = !summary.failed && !summary.errored;
158
166
 
159
- this.log([
160
- this.#enhancer[allPassed ? 'success' : 'failure']('Results'), SPACE,
161
- `${this.#enhancer.total(summary.passed)}/${this.#enhancer.total(summary.total)},`, SPACE,
162
- allPassed ? 'failed' : this.#enhancer.failure('failed'), SPACE,
163
- `${this.#enhancer.total(summary.failed)}`, SPACE,
164
- allPassed ? 'errored' : this.#enhancer.failure('errored'), SPACE,
165
- `${this.#enhancer.total(summary.errored)}`, SPACE,
166
- 'skipped', SPACE,
167
- this.#enhancer.total(summary.skipped), SPACE,
168
- '#', SPACE, '(Timings:', SPACE,
169
- 'Self=', TimeUtil.asClock(summary.selfDuration), ',', SPACE,
170
- 'Total=', TimeUtil.asClock(summary.duration), ',', SPACE,
171
- 'Clock=', TimeUtil.asClock(Date.now() - this.#start),
172
- ')',
173
- ].join(''));
167
+ this.log(
168
+ [
169
+ this.#enhancer[allPassed ? 'success' : 'failure']('Results'),
170
+ SPACE,
171
+ `${this.#enhancer.total(summary.passed)}/${this.#enhancer.total(summary.total)},`,
172
+ SPACE,
173
+ allPassed ? 'failed' : this.#enhancer.failure('failed'),
174
+ SPACE,
175
+ `${this.#enhancer.total(summary.failed)}`,
176
+ SPACE,
177
+ allPassed ? 'errored' : this.#enhancer.failure('errored'),
178
+ SPACE,
179
+ `${this.#enhancer.total(summary.errored)}`,
180
+ SPACE,
181
+ 'skipped',
182
+ SPACE,
183
+ this.#enhancer.total(summary.skipped),
184
+ SPACE,
185
+ '#',
186
+ SPACE,
187
+ '(Timings:',
188
+ SPACE,
189
+ 'Self=',
190
+ TimeUtil.asClock(summary.selfDuration),
191
+ ',',
192
+ SPACE,
193
+ 'Total=',
194
+ TimeUtil.asClock(summary.duration),
195
+ ',',
196
+ SPACE,
197
+ 'Clock=',
198
+ TimeUtil.asClock(Date.now() - this.#start),
199
+ ')'
200
+ ].join('')
201
+ );
174
202
  }
175
203
  }
@@ -1,5 +1,5 @@
1
- import util from 'node:util';
2
1
  import { AssertionError } from 'node:assert';
2
+ import util from 'node:util';
3
3
 
4
4
  import { TypedObject } from '@travetto/runtime';
5
5
 
@@ -11,9 +11,12 @@ export class TestConsumerUtil {
11
11
  if (error instanceof AssertionError) {
12
12
  return;
13
13
  } else if (error instanceof Error) {
14
- const stack = error.stack ?
15
- error.stack.split(/\n/).slice(0, verbose ? -1 : 5).join('\n') :
16
- error.message;
14
+ const stack = error.stack
15
+ ? error.stack
16
+ .split(/\n/)
17
+ .slice(0, verbose ? -1 : 5)
18
+ .join('\n')
19
+ : error.message;
17
20
  const subObject: Record<string, unknown> = {};
18
21
  for (const key of TypedObject.keys(error)) {
19
22
  if (key !== 'stack' && key !== 'message' && key !== 'name') {
@@ -25,4 +28,4 @@ export class TestConsumerUtil {
25
28
  return `${error}`;
26
29
  }
27
30
  }
28
- }
31
+ }
@@ -5,8 +5,8 @@ import { stringify } from 'yaml';
5
5
  import { RuntimeIndex } from '@travetto/runtime';
6
6
 
7
7
  import type { TestEvent } from '../../model/event.ts';
8
- import type { SuitesSummary, TestConsumerShape } from '../types.ts';
9
8
  import { TestConsumer } from '../decorator.ts';
9
+ import type { SuitesSummary, TestConsumerShape } from '../types.ts';
10
10
  import { TestConsumerUtil } from './util.ts';
11
11
 
12
12
  /**
@@ -37,7 +37,10 @@ export class XunitEmitter implements TestConsumerShape {
37
37
  }
38
38
  if (Object.keys(metadata).length) {
39
39
  let body = stringify(metadata);
40
- body = body.split('\n').map(line => ` ${line}`).join('\n');
40
+ body = body
41
+ .split('\n')
42
+ .map(line => ` ${line}`)
43
+ .join('\n');
41
44
  return `<![CDATA[\n${body}\n]]>`;
42
45
  } else {
43
46
  return '';
@@ -49,7 +52,6 @@ export class XunitEmitter implements TestConsumerShape {
49
52
  */
50
53
  onEvent(event: TestEvent): void {
51
54
  if (event.type === 'test' && event.phase === 'after') {
52
-
53
55
  const { test } = event;
54
56
 
55
57
  let name = `${test.methodName}`;
@@ -79,8 +81,7 @@ export class XunitEmitter implements TestConsumerShape {
79
81
  ${body}
80
82
  <system-out>${this.buildMeta({ log: groupedByLevel.log, info: groupedByLevel.info, debug: groupedByLevel.debug })}</system-out>
81
83
  <system-err>${this.buildMeta({ error: groupedByLevel.error, warn: groupedByLevel.warn })}</system-err>
82
- </testcase>`
83
- );
84
+ </testcase>`);
84
85
  } else if (event.type === 'suite' && event.phase === 'after') {
85
86
  const { suite } = event;
86
87
  const testBodies = this.#tests.slice(0);
@@ -121,4 +122,4 @@ export class XunitEmitter implements TestConsumerShape {
121
122
  </testsuites>
122
123
  `);
123
124
  }
124
- }
125
+ }
@@ -1,4 +1,4 @@
1
- import { castTo, type Class, type ClassInstance, getClass } from '@travetto/runtime';
1
+ import { type Class, type ClassInstance, castTo, getClass } from '@travetto/runtime';
2
2
 
3
3
  import type { SuiteConfig } from '../model/suite.ts';
4
4
  import { SuiteRegistryIndex } from '../registry/registry-index.ts';
@@ -18,7 +18,7 @@ export function Suite(description?: string | Partial<SuiteConfig>, ...rest: Part
18
18
  SuiteRegistryIndex.getForRegister(cls).register(
19
19
  ...(typeof description !== 'string' && description ? [description] : []),
20
20
  ...rest,
21
- ...(typeof description === 'string' ? [{ description }] : []),
21
+ ...(typeof description === 'string' ? [{ description }] : [])
22
22
  );
23
23
  return cls;
24
24
  };
@@ -76,4 +76,4 @@ export function AfterEach() {
76
76
  });
77
77
  return descriptor;
78
78
  };
79
- }
79
+ }
@@ -27,10 +27,12 @@ export function Test(...rest: Partial<TestConfig>[]): MethodDecorator;
27
27
  export function Test(description: string, ...rest: Partial<TestConfig>[]): MethodDecorator;
28
28
  export function Test(description?: string | Partial<TestConfig>, ...rest: Partial<TestConfig>[]): MethodDecorator {
29
29
  return (instance: ClassInstance, property: string, descriptor: PropertyDescriptor) => {
30
- SuiteRegistryIndex.getForRegister(getClass(instance)).registerTest(property, descriptor.value,
31
- ...(typeof description !== 'string' && description) ? [description] : [],
30
+ SuiteRegistryIndex.getForRegister(getClass(instance)).registerTest(
31
+ property,
32
+ descriptor.value,
33
+ ...(typeof description !== 'string' && description ? [description] : []),
32
34
  ...rest,
33
- ...(typeof description === 'string') ? [{ description }] : []
35
+ ...(typeof description === 'string' ? [{ description }] : [])
34
36
  );
35
37
  return descriptor;
36
38
  };
@@ -58,4 +60,4 @@ export function Timeout(ms: number): MethodDecorator {
58
60
  SuiteRegistryIndex.getForRegister(getClass(instance)).registerTest(property, descriptor.value, { timeout: ms });
59
61
  return descriptor;
60
62
  };
61
- }
63
+ }
@@ -1,5 +1,5 @@
1
- import { isPromise } from 'node:util/types';
2
1
  import { createHook, executionAsyncId } from 'node:async_hooks';
2
+ import { isPromise } from 'node:util/types';
3
3
 
4
4
  import { type TimeSpan, TimeUtil, Util } from '@travetto/runtime';
5
5
 
@@ -11,7 +11,7 @@ export class Barrier {
11
11
  /**
12
12
  * Track timeout
13
13
  */
14
- static timeout(duration: number | TimeSpan, operation: string = 'Operation'): { promise: Promise<void>, resolve: () => unknown } {
14
+ static timeout(duration: number | TimeSpan, operation: string = 'Operation'): { promise: Promise<void>; resolve: () => unknown } {
15
15
  const resolver = Promise.withResolvers<void>();
16
16
  const durationMs = TimeUtil.duration(duration, 'ms');
17
17
  let timeout: NodeJS.Timeout;
@@ -22,25 +22,31 @@ export class Barrier {
22
22
  timeout = setTimeout(() => resolver.reject(new TimeoutError(msg)), durationMs).unref();
23
23
  }
24
24
 
25
- resolver.promise.finally(() => { clearTimeout(timeout); });
25
+ resolver.promise.finally(() => {
26
+ clearTimeout(timeout);
27
+ });
26
28
  return resolver;
27
29
  }
28
30
 
29
31
  /**
30
32
  * Track uncaught error
31
33
  */
32
- static uncaughtErrorPromise(): { promise: Promise<void>, resolve: () => unknown } {
34
+ static uncaughtErrorPromise(): { promise: Promise<void>; resolve: () => unknown } {
33
35
  const uncaught = Promise.withResolvers<void>();
34
- const onError = (error: Error): void => { Util.queueMacroTask().then(() => uncaught.reject(error)); };
36
+ const onError = (error: Error): void => {
37
+ Util.queueMacroTask().then(() => uncaught.reject(error));
38
+ };
35
39
  UNCAUGHT_ERR_EVENTS.map(key => process.on(key, onError));
36
- uncaught.promise.finally(() => { UNCAUGHT_ERR_EVENTS.map(key => process.off(key, onError)); });
40
+ uncaught.promise.finally(() => {
41
+ UNCAUGHT_ERR_EVENTS.map(key => process.off(key, onError));
42
+ });
37
43
  return uncaught;
38
44
  }
39
45
 
40
46
  /**
41
47
  * Promise capturer
42
48
  */
43
- static capturePromises(): { start: () => Promise<void>, finish: () => Promise<void>, cleanup: () => void } {
49
+ static capturePromises(): { start: () => Promise<void>; finish: () => Promise<void>; cleanup: () => void } {
44
50
  const pending = new Map<number, Promise<unknown>>();
45
51
  let id: number = 0;
46
52
 
@@ -90,7 +96,7 @@ export class Barrier {
90
96
  let capturedError: Error | undefined;
91
97
  const opProm = operation().then(() => promises.finish());
92
98
 
93
- await Promise.race([opProm, uncaught.promise, timer.promise]).catch(error => capturedError ??= error);
99
+ await Promise.race([opProm, uncaught.promise, timer.promise]).catch(error => (capturedError ??= error));
94
100
 
95
101
  return capturedError;
96
102
  } finally {
@@ -99,4 +105,4 @@ export class Barrier {
99
105
  uncaught.resolve();
100
106
  }
101
107
  }
102
- }
108
+ }
@@ -1,6 +1,7 @@
1
1
  import util from 'node:util';
2
2
 
3
3
  import { type ConsoleEvent, type ConsoleListener, ConsoleManager } from '@travetto/runtime';
4
+
4
5
  import type { TestLog } from '../model/test.ts';
5
6
 
6
7
  /**
@@ -21,9 +22,7 @@ export class ConsoleCapture implements ConsoleListener {
21
22
  log({ args, scope: _, ...rest }: ConsoleEvent): void {
22
23
  this.out.push({
23
24
  ...rest,
24
- message: args
25
- .map((arg => typeof arg === 'string' ? arg : util.inspect(arg, false, 5)))
26
- .join(' ')
25
+ message: args.map(arg => (typeof arg === 'string' ? arg : util.inspect(arg, false, 5))).join(' ')
27
26
  });
28
27
  }
29
28
 
@@ -33,4 +32,4 @@ export class ConsoleCapture implements ConsoleListener {
33
32
  ConsoleManager.set(ConsoleCapture.#listener);
34
33
  return result;
35
34
  }
36
- }
35
+ }
@@ -1,17 +1,17 @@
1
- import { Env, TimeUtil, Runtime, castTo, classConstruct } from '@travetto/runtime';
2
1
  import { Registry } from '@travetto/registry';
2
+ import { castTo, classConstruct, Env, Runtime, TimeUtil } from '@travetto/runtime';
3
3
 
4
- import type { TestConfig, TestResult, TestRun } from '../model/test.ts';
5
- import type { SuiteConfig, SuiteResult } from '../model/suite.ts';
6
- import type { TestConsumerShape } from '../consumer/types.ts';
7
- import { AssertCheck } from '../assert/check.ts';
8
4
  import { AssertCapture } from '../assert/capture.ts';
9
- import { ConsoleCapture } from './console.ts';
10
- import { TestPhaseManager } from './phase.ts';
5
+ import { AssertCheck } from '../assert/check.ts';
11
6
  import { AssertUtil } from '../assert/util.ts';
12
- import { Barrier } from './barrier.ts';
13
- import { SuiteRegistryIndex } from '../registry/registry-index.ts';
7
+ import type { TestConsumerShape } from '../consumer/types.ts';
8
+ import type { SuiteConfig, SuiteResult } from '../model/suite.ts';
9
+ import type { TestConfig, TestResult, TestRun } from '../model/test.ts';
14
10
  import { TestModelUtil } from '../model/util.ts';
11
+ import { SuiteRegistryIndex } from '../registry/registry-index.ts';
12
+ import { Barrier } from './barrier.ts';
13
+ import { ConsoleCapture } from './console.ts';
14
+ import { TestPhaseManager } from './phase.ts';
15
15
 
16
16
  const TEST_TIMEOUT = TimeUtil.duration(Env.TRV_TEST_TIMEOUT.value || 5000, 'ms');
17
17
 
@@ -19,7 +19,6 @@ const TEST_TIMEOUT = TimeUtil.duration(Env.TRV_TEST_TIMEOUT.value || 5000, 'ms')
19
19
  * Support execution of the tests
20
20
  */
21
21
  export class TestExecutor {
22
-
23
22
  #consumer: TestConsumerShape;
24
23
 
25
24
  constructor(consumer: TestConsumerShape) {
@@ -57,16 +56,15 @@ export class TestExecutor {
57
56
  * Execute the test, capture output, assertions and promises
58
57
  */
59
58
  async executeTest(instance: unknown, test: TestConfig, suite: SuiteConfig, override?: Partial<TestResult>): Promise<TestResult> {
60
-
61
59
  const result = TestModelUtil.createTestResult(suite, test, override);
62
60
 
63
61
  // Mark test start
64
62
  this.#consumer.onEvent({ type: 'test', phase: 'before', test });
65
63
 
66
-
67
64
  // Emit every assertion as it occurs
68
65
  const getAssertions = AssertCapture.collector(test, item =>
69
- this.#consumer.onEvent({ type: 'assertion', phase: 'after', assertion: item }));
66
+ this.#consumer.onEvent({ type: 'assertion', phase: 'after', assertion: item })
67
+ );
70
68
 
71
69
  const consoleCapture = new ConsoleCapture().start(); // Capture all output from transpiled code
72
70
 
@@ -75,7 +73,9 @@ export class TestExecutor {
75
73
  if (result.error) {
76
74
  result.assertions.push(AssertUtil.generateAssertion({ suite, test, error: result.error }));
77
75
  }
78
- for (const item of result.assertions ?? []) { AssertCapture.add(item); }
76
+ for (const item of result.assertions ?? []) {
77
+ AssertCapture.add(item);
78
+ }
79
79
  } else {
80
80
  // Run method and get result
81
81
  const startTime = Date.now();
@@ -101,7 +101,6 @@ export class TestExecutor {
101
101
  * Execute an entire suite
102
102
  */
103
103
  async executeSuite(suite: SuiteConfig, tests: TestConfig[]): Promise<void> {
104
-
105
104
  const instance = classConstruct(suite.class);
106
105
 
107
106
  const shouldSkip = await this.#shouldSkip(suite, instance);
@@ -110,7 +109,8 @@ export class TestExecutor {
110
109
 
111
110
  if (shouldSkip) {
112
111
  this.#consumer.onEvent({
113
- phase: 'after', type: 'suite',
112
+ phase: 'after',
113
+ type: 'suite',
114
114
  suite: {
115
115
  ...result,
116
116
  status: 'skipped',
@@ -130,9 +130,7 @@ export class TestExecutor {
130
130
  const testResultOverrides: Record<string, Partial<TestResult>> = {};
131
131
 
132
132
  const validTestMethodNames = new Set(tests.map(t => t.methodName));
133
- const testConfigs = Object.fromEntries(
134
- Object.entries(suite.tests).filter(([key]) => validTestMethodNames.has(key))
135
- );
133
+ const testConfigs = Object.fromEntries(Object.entries(suite.tests).filter(([key]) => validTestMethodNames.has(key)));
136
134
 
137
135
  // Mark suite start
138
136
  this.#consumer.onEvent({ phase: 'before', type: 'suite', suite: { ...suite, tests: testConfigs } });
@@ -162,7 +160,7 @@ export class TestExecutor {
162
160
 
163
161
  try {
164
162
  // Handle BeforeEach
165
- testResultOverride.status || await manager.startPhase('each');
163
+ testResultOverride.status || (await manager.startPhase('each'));
166
164
  } catch (someError) {
167
165
  const testError = await manager.onError('each', someError);
168
166
  testResultOverride.error = testError;
@@ -174,9 +172,11 @@ export class TestExecutor {
174
172
 
175
173
  // Handle after each
176
174
  try {
177
- testResultOverride.status || await manager.endPhase('each');
175
+ testResultOverride.status || (await manager.endPhase('each'));
178
176
  } catch (testError) {
179
- if (!(testError instanceof Error)) { throw testError; };
177
+ if (!(testError instanceof Error)) {
178
+ throw testError;
179
+ }
180
180
  console.error('Failed to properly shutdown test', testError.message);
181
181
  }
182
182
 
@@ -189,7 +189,9 @@ export class TestExecutor {
189
189
  // Handle after all
190
190
  await manager.endPhase('all');
191
191
  } catch (suiteError) {
192
- if (!(suiteError instanceof Error)) { throw suiteError; };
192
+ if (!(suiteError instanceof Error)) {
193
+ throw suiteError;
194
+ }
193
195
  console.error('Failed to properly shutdown test', suiteError.message);
194
196
  }
195
197
 
@@ -210,7 +212,9 @@ export class TestExecutor {
210
212
  try {
211
213
  await Runtime.importFrom(run.import);
212
214
  } catch (error) {
213
- if (!(error instanceof Error)) { throw error; }
215
+ if (!(error instanceof Error)) {
216
+ throw error;
217
+ }
214
218
  const suite = TestModelUtil.createImportErrorSuiteResult(run);
215
219
  console.error(error);
216
220
  this.#consumer.onEvent({ type: 'suite', phase: 'after', suite });
@@ -235,4 +239,4 @@ export class TestExecutor {
235
239
  await this.executeSuite(suite, tests);
236
240
  }
237
241
  }
238
- }
242
+ }
@@ -60,7 +60,7 @@ export class TestPhaseManager {
60
60
  */
61
61
  async onError(phase: 'all' | 'each', error: unknown): Promise<Error> {
62
62
  if (!(error instanceof Error)) {
63
- await this.endPhase(phase).catch(() => { });
63
+ await this.endPhase(phase).catch(() => {});
64
64
  throw error;
65
65
  }
66
66
  return error;