@travetto/test 8.0.0-alpha.9 → 8.0.0

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 (52) hide show
  1. package/README.md +23 -21
  2. package/__index__.ts +9 -9
  3. package/package.json +20 -20
  4. package/src/assert/capture.ts +4 -5
  5. package/src/assert/check.ts +53 -26
  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 +28 -25
  21. package/src/consumer/types/tap.ts +68 -40
  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 +38 -38
  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 +25 -15
  39. package/src/registry/registry-adapter.ts +10 -13
  40. package/src/registry/registry-index.ts +13 -11
  41. package/src/trv.d.ts +2 -2
  42. package/src/worker/child.ts +13 -10
  43. package/src/worker/standard.ts +11 -14
  44. package/src/worker/types.ts +3 -7
  45. package/support/bin/run.ts +1 -1
  46. package/support/cli.test.ts +20 -15
  47. package/support/cli.test_child.ts +8 -3
  48. package/support/cli.test_diff.ts +11 -7
  49. package/support/cli.test_digest.ts +10 -4
  50. package/support/cli.test_direct.ts +11 -7
  51. package/support/cli.test_watch.ts +6 -4
  52. package/support/transformer.assert.ts +51 -43
@@ -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;
@@ -1,21 +1,21 @@
1
1
  import { createReadStream } from 'node:fs';
2
2
  import fs from 'node:fs/promises';
3
- import readline from 'node:readline/promises';
4
3
  import path from 'node:path';
4
+ import readline from 'node:readline/promises';
5
5
 
6
- import { Env, ExecUtil, Util, RuntimeIndex, Runtime, TimeUtil, JSONUtil, describeFunction } from '@travetto/runtime';
7
- import { WorkPool } from '@travetto/worker';
8
6
  import { Registry } from '@travetto/registry';
7
+ import { describeFunction, Env, ExecUtil, JSONUtil, Runtime, RuntimeIndex, TimeUtil, Util } from '@travetto/runtime';
8
+ import { WorkPool } from '@travetto/worker';
9
9
 
10
- import type { TestConfig, TestRunInput, TestRun, TestGlobInput, TestDiffInput } from '../model/test.ts';
11
- import type { TestRemoveEvent } from '../model/event.ts';
10
+ import { TestConsumerRegistryIndex } from '../consumer/registry-index.ts';
12
11
  import type { TestConsumerShape } from '../consumer/types.ts';
13
12
  import { RunnableTestConsumer } from '../consumer/types/runnable.ts';
14
- import type { TestConsumerConfig } from './types.ts';
15
- import { TestConsumerRegistryIndex } from '../consumer/registry-index.ts';
16
- import { TestExecutor } from './executor.ts';
17
- import { buildStandardTestManager } from '../worker/standard.ts';
13
+ import type { TestRemoveEvent } from '../model/event.ts';
14
+ import type { TestConfig, TestDiffInput, TestGlobInput, TestRun, TestRunInput } from '../model/test.ts';
18
15
  import { SuiteRegistryIndex } from '../registry/registry-index.ts';
16
+ import { buildStandardTestManager } from '../worker/standard.ts';
17
+ import { TestExecutor } from './executor.ts';
18
+ import type { TestConsumerConfig } from './types.ts';
19
19
 
20
20
  type RunState = {
21
21
  runs: TestRun[];
@@ -26,7 +26,6 @@ type RunState = {
26
26
  * Test Utilities for Running
27
27
  */
28
28
  export class RunUtil {
29
-
30
29
  /**
31
30
  * Determine if a given file path is a valid test file
32
31
  */
@@ -47,7 +46,7 @@ export class RunUtil {
47
46
  /**
48
47
  * Find all valid test files given the globs
49
48
  */
50
- static async* getTestImports(globs?: string[]): AsyncIterable<string> {
49
+ static async *getTestImports(globs?: string[]): AsyncIterable<string> {
51
50
  const all = RuntimeIndex.find({
52
51
  module: module => module.roles.includes('test') || module.roles.includes('std'),
53
52
  folder: folder => folder === 'test',
@@ -60,7 +59,7 @@ export class RunUtil {
60
59
  for await (const item of fs.glob(globs)) {
61
60
  const source = Runtime.workspaceRelative(path.resolve(item));
62
61
  const match = allFiles.get(source);
63
- if (match && await this.isTestFile(match.sourceFile)) {
62
+ if (match && (await this.isTestFile(match.sourceFile))) {
64
63
  yield match.import;
65
64
  }
66
65
  }
@@ -80,7 +79,7 @@ export class RunUtil {
80
79
  static async resolveGlobInput({ globs, tags, metadata }: TestGlobInput): Promise<TestRun[]> {
81
80
  const digestProcess = await ExecUtil.getResult(
82
81
  ExecUtil.spawnPackageCommand('trv', ['test:digest', '-o', 'json', ...globs], {
83
- env: { ...process.env, ...Env.FORCE_COLOR.export(0), ...Env.NO_COLOR.export(true) },
82
+ env: { ...process.env, ...Env.FORCE_COLOR.export(0), ...Env.NO_COLOR.export(true) }
84
83
  }),
85
84
  { catch: true }
86
85
  );
@@ -89,20 +88,20 @@ export class RunUtil {
89
88
  throw new Error(digestProcess.stderr);
90
89
  }
91
90
 
92
- const testFilter = tags?.length ?
93
- Util.allowDeny<string, [TestConfig]>(
94
- tags,
95
- rule => rule,
96
- (rule, core) => core.tags?.includes(rule) ?? false
97
- ) :
98
- ((): boolean => true);
91
+ const testFilter = tags?.length
92
+ ? Util.allowDeny<string, [TestConfig]>(
93
+ tags,
94
+ rule => rule,
95
+ (rule, core) => core.tags?.includes(rule) ?? false
96
+ )
97
+ : (): boolean => true;
99
98
 
100
99
  const parsed: TestConfig[] = JSONUtil.fromUTF8(digestProcess.stdout);
101
100
 
102
101
  const events = parsed.filter(testFilter).reduce((runs, test) => {
103
- runs.getOrInsert(test.classId,
104
- { import: test.import, classId: test.classId, methodNames: [], runId: Util.uuid(), metadata }
105
- ).methodNames!.push(test.methodName);
102
+ runs
103
+ .getOrInsert(test.classId, { import: test.import, classId: test.classId, methodNames: [], runId: Util.uuid(), metadata })
104
+ .methodNames!.push(test.methodName);
106
105
  return runs;
107
106
  }, new Map<string, TestRun>());
108
107
 
@@ -141,18 +140,22 @@ export class RunUtil {
141
140
  // Looking at Diff
142
141
  for (const [clsId, config] of Object.entries(diff)) {
143
142
  const local = classes[clsId];
144
- if (!local) { // Removed classes
143
+ if (!local) {
144
+ // Removed classes
145
145
  removeTest(clsId);
146
- } else if (local.sourceHash !== config.sourceHash) { // Class changed or added
146
+ } else if (local.sourceHash !== config.sourceHash) {
147
+ // Class changed or added
147
148
  // Methods to run, defaults to newly added
148
149
  const methods: string[] = Object.keys(local.tests ?? {}).filter(key => !config.methods[key]);
149
150
  let didRemove = false;
150
151
  for (const key of Object.keys(config.methods)) {
151
152
  const localMethod = local.tests?.[key];
152
- if (!localMethod) { // Test is removed
153
+ if (!localMethod) {
154
+ // Test is removed
153
155
  removeTest(clsId, key);
154
156
  didRemove = true;
155
- } else if (localMethod.sourceHash !== config.methods[key]) { // Method changed or added
157
+ } else if (localMethod.sourceHash !== config.methods[key]) {
158
+ // Method changed or added
156
159
  methods.push(key);
157
160
  }
158
161
  }
@@ -162,7 +165,8 @@ export class RunUtil {
162
165
  }
163
166
  }
164
167
 
165
- if (runs.length === 0 && removes.length === 0) { // Re-run entire file, classes unchanged
168
+ if (runs.length === 0 && removes.length === 0) {
169
+ // Re-run entire file, classes unchanged
166
170
  addRun(undefined);
167
171
  }
168
172
 
@@ -225,17 +229,13 @@ export class RunUtil {
225
229
  if (runs.length === 1) {
226
230
  await new TestExecutor(consumer).execute(runs[0], true);
227
231
  } else {
228
- await WorkPool.run(
229
- run => buildStandardTestManager(consumer, run),
230
- runs,
231
- {
232
- idleTimeoutMillis: TimeUtil.duration('10s', 'ms'),
233
- min: 1,
234
- max: consumerConfig.concurrency
235
- }
236
- );
232
+ await WorkPool.run(run => buildStandardTestManager(consumer, run), runs, {
233
+ idleTimeoutMillis: TimeUtil.duration('10s', 'ms'),
234
+ min: 1,
235
+ max: consumerConfig.concurrency
236
+ });
237
237
  }
238
238
 
239
239
  return consumer.summarizeAsBoolean();
240
240
  }
241
- }
241
+ }
@@ -1,14 +1,14 @@
1
1
  import { ManifestModuleUtil } from '@travetto/manifest';
2
2
  import { Registry } from '@travetto/registry';
3
- import { WorkPool } from '@travetto/worker';
4
3
  import { AsyncQueue, TimeUtil, WatchUtil } from '@travetto/runtime';
4
+ import { WorkPool } from '@travetto/worker';
5
5
 
6
- import { buildStandardTestManager } from '../worker/standard.ts';
7
6
  import { TestConsumerRegistryIndex } from '../consumer/registry-index.ts';
8
7
  import { CumulativeSummaryConsumer } from '../consumer/types/cumulative.ts';
9
8
  import type { TestDiffInput, TestRun } from '../model/test.ts';
10
- import { RunUtil } from './run.ts';
9
+ import { buildStandardTestManager } from '../worker/standard.ts';
11
10
  import { isTestRunEvent, type TestReadyEvent } from '../worker/types.ts';
11
+ import { RunUtil } from './run.ts';
12
12
 
13
13
  /**
14
14
  * Test Watcher.
@@ -16,7 +16,6 @@ import { isTestRunEvent, type TestReadyEvent } from '../worker/types.ts';
16
16
  * Runs all tests on startup, and then listens for changes to run tests again
17
17
  */
18
18
  export class TestWatcher {
19
-
20
19
  /**
21
20
  * Start watching all test files
22
21
  */
@@ -28,13 +27,11 @@ export class TestWatcher {
28
27
  const events: (TestRun | TestDiffInput)[] = [];
29
28
 
30
29
  if (runAllOnStart) {
31
- events.push(...await RunUtil.resolveGlobInput({ globs: [] }));
30
+ events.push(...(await RunUtil.resolveGlobInput({ globs: [] })));
32
31
  }
33
32
 
34
33
  const queue = new AsyncQueue(events);
35
- const consumer = new CumulativeSummaryConsumer(
36
- await TestConsumerRegistryIndex.getInstance({ consumer: format })
37
- );
34
+ const consumer = new CumulativeSummaryConsumer(await TestConsumerRegistryIndex.getInstance({ consumer: format }));
38
35
 
39
36
  process.on('message', event => {
40
37
  if (isTestRunEvent(event)) {
@@ -44,19 +41,15 @@ export class TestWatcher {
44
41
 
45
42
  process.send?.({ type: 'ready' } satisfies TestReadyEvent);
46
43
 
47
- const queueProcessor = WorkPool.run(
48
- buildStandardTestManager.bind(null, consumer),
49
- queue,
50
- {
51
- idleTimeoutMillis: TimeUtil.duration('2m', 'ms'),
52
- min: 2,
53
- max: WorkPool.DEFAULT_SIZE
54
- }
55
- );
44
+ const queueProcessor = WorkPool.run(buildStandardTestManager.bind(null, consumer), queue, {
45
+ idleTimeoutMillis: TimeUtil.duration('2m', 'ms'),
46
+ min: 2,
47
+ max: WorkPool.DEFAULT_SIZE
48
+ });
56
49
 
57
50
  await WatchUtil.watchCompilerEvents('change', event => {
58
51
  const fileType = ManifestModuleUtil.getFileType(event.file);
59
- if ((fileType === 'ts' || fileType === 'js')) {
52
+ if (fileType === 'ts' || fileType === 'js') {
60
53
  if (event.action === 'delete') {
61
54
  consumer.removeTest(event.import);
62
55
  } else {
@@ -69,4 +62,4 @@ export class TestWatcher {
69
62
  // Cleanup
70
63
  await queueProcessor;
71
64
  }
72
- }
65
+ }
package/src/fixture.ts CHANGED
@@ -2,11 +2,10 @@ import { FileLoader, Runtime } from '@travetto/runtime';
2
2
 
3
3
  export class TestFixtures extends FileLoader {
4
4
  constructor(modules: string[] = []) {
5
- super([
6
- '@#test/fixtures',
7
- '@#support/fixtures',
8
- ...modules.flat().map(module => `${module}#support/fixtures`),
9
- '@@#support/fixtures'
10
- ].map(value => Runtime.modulePath(value)));
5
+ super(
6
+ ['@#test/fixtures', '@#support/fixtures', ...modules.flat().map(module => `${module}#support/fixtures`), '@@#support/fixtures'].map(
7
+ value => Runtime.modulePath(value)
8
+ )
9
+ );
11
10
  }
12
- }
11
+ }
@@ -47,4 +47,4 @@ export interface TestCore extends SuiteCore {
47
47
  * For extended suites, this is where the test is declared
48
48
  */
49
49
  declarationImport?: string;
50
- }
50
+ }
@@ -3,9 +3,9 @@ import { RuntimeError } from '@travetto/runtime';
3
3
  /**
4
4
  * Represents an execution error
5
5
  */
6
- export class TestExecutionError extends RuntimeError { }
6
+ export class TestExecutionError extends RuntimeError {}
7
7
 
8
8
  /**
9
9
  * Timeout execution error
10
10
  */
11
- export class TimeoutError extends TestExecutionError { }
11
+ export class TimeoutError extends TestExecutionError {}
@@ -1,5 +1,5 @@
1
- import type { Assertion, TestConfig, TestResult } from './test.ts';
2
1
  import type { SuiteConfig, SuiteResult } from './suite.ts';
2
+ import type { Assertion, TestConfig, TestResult } from './test.ts';
3
3
 
4
4
  /**
5
5
  * Targets
@@ -11,17 +11,22 @@ export type EventEntity = 'test' | 'suite' | 'assertion';
11
11
  */
12
12
  export type EventPhase = 'before' | 'after';
13
13
 
14
- type EventTpl<T extends EventEntity, P extends EventPhase, V extends {}> =
15
- { type: T, phase: P, metadata?: Record<string, unknown> } & V;
14
+ type EventTpl<T extends EventEntity, P extends EventPhase, V extends {}> = { type: T; phase: P; metadata?: Record<string, unknown> } & V;
16
15
 
17
- export type TestRemoveEvent = { type: 'removeTest', import: string, classId?: string, methodName?: string, metadata?: Record<string, unknown> };
16
+ export type TestRemoveEvent = {
17
+ type: 'removeTest';
18
+ import: string;
19
+ classId?: string;
20
+ methodName?: string;
21
+ metadata?: Record<string, unknown>;
22
+ };
18
23
 
19
24
  /**
20
25
  * Different test event shapes
21
26
  */
22
27
  export type TestEvent =
23
- EventTpl<'assertion', 'after', { assertion: Assertion }> |
24
- EventTpl<'test', 'before', { test: TestConfig }> |
25
- EventTpl<'test', 'after', { test: TestResult }> |
26
- EventTpl<'suite', 'before', { suite: SuiteConfig }> |
27
- EventTpl<'suite', 'after', { suite: SuiteResult }>;
28
+ | EventTpl<'assertion', 'after', { assertion: Assertion }>
29
+ | EventTpl<'test', 'before', { test: TestConfig }>
30
+ | EventTpl<'test', 'after', { test: TestResult }>
31
+ | EventTpl<'suite', 'before', { suite: SuiteConfig }>
32
+ | EventTpl<'suite', 'after', { suite: SuiteResult }>;
@@ -1,7 +1,7 @@
1
1
  import type { Any, Class } from '@travetto/runtime';
2
2
 
3
- import type { TestConfig, TestResult, TestStatus } from './test.ts';
4
3
  import type { Skip, SuiteCore } from './common.ts';
4
+ import type { TestConfig, TestResult, TestStatus } from './test.ts';
5
5
 
6
6
  export type SuitePhase = 'beforeAll' | 'beforeEach' | 'afterAll' | 'afterEach';
7
7
 
@@ -63,4 +63,4 @@ export interface SuiteResult extends ResultsSummary, SuiteCore {
63
63
  * Overall status
64
64
  */
65
65
  status: TestStatus;
66
- }
66
+ }
package/src/model/test.ts CHANGED
@@ -5,10 +5,13 @@ import type { Skip, TestCore } from './common.ts';
5
5
  export type ThrowableError = string | RegExp | Class<Error> | ((error: Error | string) => boolean | void | undefined);
6
6
  export type TestLog = Omit<ConsoleEvent, 'args' | 'scope'> & { message: string };
7
7
 
8
- export type TestDiffSource = Record<string, {
9
- sourceHash: number;
10
- methods: Record<string, number>;
11
- }>;
8
+ export type TestDiffSource = Record<
9
+ string,
10
+ {
11
+ sourceHash: number;
12
+ methods: Record<string, number>;
13
+ }
14
+ >;
12
15
 
13
16
  export type TestStatus = 'passed' | 'skipped' | 'errored' | 'failed' | 'unknown';
14
17
 
@@ -184,4 +187,4 @@ export type TestGlobInput = {
184
187
  metadata?: Record<string, unknown>;
185
188
  };
186
189
 
187
- export type TestRunInput = TestRun | TestDiffInput | TestGlobInput;
190
+ export type TestRunInput = TestRun | TestDiffInput | TestGlobInput;
package/src/model/util.ts CHANGED
@@ -8,11 +8,16 @@ import type { TestConfig, TestResult, TestRun, TestStatus } from './test.ts';
8
8
  export class TestModelUtil {
9
9
  static computeTestStatus(summary: ResultsSummary): TestStatus {
10
10
  switch (true) {
11
- case summary.errored > 0: return 'errored';
12
- case summary.failed > 0: return 'failed';
13
- case summary.skipped > 0: return 'skipped';
14
- case summary.unknown > 0: return 'unknown';
15
- default: return 'passed';
11
+ case summary.errored > 0:
12
+ return 'errored';
13
+ case summary.failed > 0:
14
+ return 'failed';
15
+ case summary.skipped > 0:
16
+ return 'skipped';
17
+ case summary.unknown > 0:
18
+ return 'unknown';
19
+ default:
20
+ return 'passed';
16
21
  }
17
22
  }
18
23
 
@@ -24,13 +29,12 @@ export class TestModelUtil {
24
29
  for (const test of tests) {
25
30
  summary[test.status] += 1;
26
31
  summary.total += 1;
27
- summary.selfDuration += (test.selfDuration ?? 0);
28
- summary.duration += (test.duration ?? 0);
32
+ summary.selfDuration += test.selfDuration ?? 0;
33
+ summary.duration += test.duration ?? 0;
29
34
  }
30
35
  return summary;
31
36
  }
32
37
 
33
-
34
38
  /**
35
39
  * An empty suite result based on a suite config
36
40
  */
@@ -81,17 +85,23 @@ export class TestModelUtil {
81
85
  const common = { classId, duration: 0, lineStart: 1, lineEnd: 1, import: run.import } as const;
82
86
  return asFull<SuiteResult>({
83
87
  ...common,
84
- status: 'errored', errored: 1,
88
+ status: 'errored',
89
+ errored: 1,
85
90
  tests: {
86
- impport: asFull<TestResult>({
91
+ import: asFull<TestResult>({
87
92
  ...common,
88
93
  status: 'errored',
89
- assertions: [{
90
- ...common, line: common.lineStart,
91
- methodName: 'import', operator: 'import', text: `Failed to import ${run.import}`,
92
- }]
94
+ assertions: [
95
+ {
96
+ ...common,
97
+ line: common.lineStart,
98
+ methodName: 'import',
99
+ operator: 'import',
100
+ text: `Failed to import ${run.import}`
101
+ }
102
+ ]
93
103
  })
94
104
  }
95
105
  });
96
106
  }
97
- }
107
+ }
@@ -1,5 +1,5 @@
1
1
  import type { RegistryAdapter } from '@travetto/registry';
2
- import { RuntimeError, asFull, type Class, describeFunction, Runtime, safeAssign } from '@travetto/runtime';
2
+ import { asFull, type Class, describeFunction, Runtime, RuntimeError, safeAssign } from '@travetto/runtime';
3
3
  import { SchemaRegistryIndex } from '@travetto/schema';
4
4
 
5
5
  import type { SuiteConfig } from '../model/suite.ts';
@@ -8,7 +8,7 @@ import type { TestConfig } from '../model/test.ts';
8
8
  function combineClasses(baseConfig: SuiteConfig, ...subConfig: Partial<SuiteConfig>[]): SuiteConfig {
9
9
  for (const config of subConfig) {
10
10
  if (config.tags) {
11
- baseConfig.tags = [...new Set([...baseConfig.tags ?? [], ...config.tags])];
11
+ baseConfig.tags = [...new Set([...(baseConfig.tags ?? []), ...config.tags])];
12
12
  }
13
13
  baseConfig.skip = config.skip ?? baseConfig.skip;
14
14
 
@@ -22,7 +22,7 @@ function combineClasses(baseConfig: SuiteConfig, ...subConfig: Partial<SuiteConf
22
22
  ...test,
23
23
  class: baseConfig.class,
24
24
  classId: baseConfig.classId,
25
- import: baseConfig.import,
25
+ import: baseConfig.import
26
26
  };
27
27
  }
28
28
  }
@@ -31,7 +31,7 @@ function combineClasses(baseConfig: SuiteConfig, ...subConfig: Partial<SuiteConf
31
31
  }
32
32
 
33
33
  function combineWithParent(baseConfig: SuiteConfig, parentConfig: SuiteConfig): SuiteConfig {
34
- baseConfig.tags = [...parentConfig.tags ?? [], ...baseConfig.tags ?? []];
34
+ baseConfig.tags = [...(parentConfig.tags ?? []), ...(baseConfig.tags ?? [])];
35
35
  baseConfig.skip = baseConfig.skip ?? parentConfig.skip;
36
36
  baseConfig.phaseHandlers = [...(parentConfig.phaseHandlers ?? []), ...(baseConfig.phaseHandlers ?? [])];
37
37
  for (const [key, test] of Object.entries(parentConfig.tests ?? {})) {
@@ -39,7 +39,7 @@ function combineWithParent(baseConfig: SuiteConfig, parentConfig: SuiteConfig):
39
39
  ...test,
40
40
  class: baseConfig.class,
41
41
  classId: baseConfig.classId,
42
- import: baseConfig.import,
42
+ import: baseConfig.import
43
43
  };
44
44
  }
45
45
  return baseConfig;
@@ -50,10 +50,7 @@ function combineMethods(suite: SuiteConfig, baseConfig: TestConfig, ...subConfig
50
50
  baseConfig.import = suite.import;
51
51
  for (const config of subConfig) {
52
52
  safeAssign(baseConfig, config, {
53
- tags: [
54
- ...baseConfig.tags ?? [],
55
- ...config.tags ?? []
56
- ]
53
+ tags: [...(baseConfig.tags ?? []), ...(config.tags ?? [])]
57
54
  });
58
55
  }
59
56
  return baseConfig;
@@ -80,7 +77,7 @@ export class SuiteRegistryAdapter implements RegistryAdapter<SuiteConfig> {
80
77
  lineEnd: lines?.[1],
81
78
  sourceHash: hash,
82
79
  tests: {},
83
- phaseHandlers: [],
80
+ phaseHandlers: []
84
81
  });
85
82
  }
86
83
  combineClasses(this.#config, ...data);
@@ -102,7 +99,7 @@ export class SuiteRegistryAdapter implements RegistryAdapter<SuiteConfig> {
102
99
  lineEnd: lines?.[1],
103
100
  lineBodyStart: lines?.[2],
104
101
  methodName: method,
105
- sourceHash: hash,
102
+ sourceHash: hash
106
103
  });
107
104
  this.#config.tests[method] = config;
108
105
  }
@@ -118,7 +115,7 @@ export class SuiteRegistryAdapter implements RegistryAdapter<SuiteConfig> {
118
115
  }
119
116
 
120
117
  for (const test of Object.values(this.#config.tests)) {
121
- test.tags = [...new Set([...test.tags ?? [], ...this.#config.tags ?? []])];
118
+ test.tags = [...new Set([...(test.tags ?? []), ...(this.#config.tags ?? [])])];
122
119
  test.description ||= SchemaRegistryIndex.get(this.#cls).getMethod(test.methodName).description;
123
120
  }
124
121
  }
@@ -134,4 +131,4 @@ export class SuiteRegistryAdapter implements RegistryAdapter<SuiteConfig> {
134
131
  }
135
132
  return test;
136
133
  }
137
- }
134
+ }