@travetto/test 7.0.0-rc.0 → 7.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.
package/README.md CHANGED
@@ -21,7 +21,7 @@ This module provides unit testing functionality that integrates with the framewo
21
21
  **Note**: All tests should be under the `**/*` folders. The pattern for tests is defined as as a standard glob using [Node](https://nodejs.org)'s built in globbing support.
22
22
 
23
23
  ## Definition
24
- A test suite is a collection of individual tests. All test suites are classes with the [@Suite](https://github.com/travetto/travetto/tree/main/module/test/src/decorator/suite.ts#L14) decorator. Tests are defined as methods on the suite class, using the [@Test](https://github.com/travetto/travetto/tree/main/module/test/src/decorator/test.ts#L23) decorator. All tests intrinsically support `async`/`await`.
24
+ A test suite is a collection of individual tests. All test suites are classes with the [@Suite](https://github.com/travetto/travetto/tree/main/module/test/src/decorator/suite.ts#L14) decorator. Tests are defined as methods on the suite class, using the [@Test](https://github.com/travetto/travetto/tree/main/module/test/src/decorator/test.ts#L25) decorator. All tests intrinsically support `async`/`await`.
25
25
 
26
26
  A simple example would be:
27
27
 
@@ -35,14 +35,14 @@ import { Suite, Test } from '@travetto/test';
35
35
  class SimpleTest {
36
36
 
37
37
  #complexService: {
38
- doLongOp(): Promise<number>;
38
+ doLongOperation(): Promise<number>;
39
39
  getText(): string;
40
40
  };
41
41
 
42
42
  @Test()
43
43
  async test1() {
44
- const val = await this.#complexService.doLongOp();
45
- assert(val === 5);
44
+ const value = await this.#complexService.doLongOperation();
45
+ assert(value === 5);
46
46
  }
47
47
 
48
48
  @Test()
@@ -212,8 +212,8 @@ class SimpleTest {
212
212
 
213
213
  await assert.rejects(() => {
214
214
  throw new Error('Big Error');
215
- }, (err: Error) =>
216
- err.message.startsWith('Big') && err.message.length > 4
215
+ }, (error: Error) =>
216
+ error.message.startsWith('Big') && error.message.length > 4
217
217
  );
218
218
  }
219
219
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/test",
3
- "version": "7.0.0-rc.0",
3
+ "version": "7.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": "^7.0.0-rc.0",
31
- "@travetto/runtime": "^7.0.0-rc.0",
32
- "@travetto/terminal": "^7.0.0-rc.0",
33
- "@travetto/worker": "^7.0.0-rc.0",
30
+ "@travetto/registry": "^7.0.0-rc.2",
31
+ "@travetto/runtime": "^7.0.0-rc.2",
32
+ "@travetto/terminal": "^7.0.0-rc.2",
33
+ "@travetto/worker": "^7.0.0-rc.2",
34
34
  "yaml": "^2.8.1"
35
35
  },
36
36
  "peerDependencies": {
37
- "@travetto/cli": "^7.0.0-rc.0",
38
- "@travetto/transformer": "^7.0.0-rc.0"
37
+ "@travetto/cli": "^7.0.0-rc.2",
38
+ "@travetto/transformer": "^7.0.0-rc.2"
39
39
  },
40
40
  "peerDependenciesMeta": {
41
41
  "@travetto/transformer": {
@@ -13,7 +13,7 @@ type StringFields<T> = {
13
13
  (T[K] extends string ? K : never)
14
14
  }[Extract<keyof T, string>];
15
15
 
16
- const isClass = (e: unknown): e is Class => e === Error || e === AppError || Object.getPrototypeOf(e) !== Object.getPrototypeOf(Function);
16
+ const isClass = (input: unknown): input is Class => input === Error || input === AppError || Object.getPrototypeOf(input) !== Object.getPrototypeOf(Function);
17
17
 
18
18
  /**
19
19
  * Check assertion
@@ -35,7 +35,7 @@ export class AssertCheck {
35
35
  };
36
36
 
37
37
  // Invert check for negative
38
- const assertFn = positive ? assert : (x: unknown, msg?: string): unknown => assert(!x, msg);
38
+ const assertFn = positive ? assert : (value: unknown, msg?: string): unknown => assert(!value, msg);
39
39
 
40
40
  // Check fn to call
41
41
  if (fn === 'fail') {
@@ -102,36 +102,36 @@ export class AssertCheck {
102
102
 
103
103
  // Pushing on not error
104
104
  AssertCapture.add(assertion);
105
- } catch (err) {
105
+ } catch (error) {
106
106
  // On error, produce the appropriate error message
107
- if (err instanceof assert.AssertionError) {
107
+ if (error instanceof assert.AssertionError) {
108
108
  if (!assertion.message) {
109
109
  assertion.message = (OP_MAPPING[fn] ?? '{state} be {expected}');
110
110
  }
111
111
  assertion.message = assertion.message
112
- .replace(/[{]([A-Za-z]+)[}]/g, (a, k: StringFields<Assertion>) => common[k] || assertion[k]!)
112
+ .replace(/[{]([A-Za-z]+)[}]/g, (a, key: StringFields<Assertion>) => common[key] || assertion[key]!)
113
113
  .replace(/not not/g, ''); // Handle double negatives
114
- assertion.error = err;
115
- err.message = assertion.message;
114
+ assertion.error = error;
115
+ error.message = assertion.message;
116
116
  AssertCapture.add(assertion);
117
117
  }
118
- throw err;
118
+ throw error;
119
119
  }
120
120
  }
121
121
 
122
122
  /**
123
123
  * Check a given error
124
124
  * @param shouldThrow Should the test throw anything
125
- * @param err The provided error
125
+ * @param error The provided error
126
126
  */
127
- static checkError(shouldThrow: ThrowableError | undefined, err: Error | string | undefined): Error | undefined {
127
+ static checkError(shouldThrow: ThrowableError | undefined, error: Error | string | undefined): Error | undefined {
128
128
  if (!shouldThrow) { // If we shouldn't be throwing anything, we are good
129
129
  return;
130
- } else if (!err) {
130
+ } else if (!error) {
131
131
  return new assert.AssertionError({ message: 'Expected to throw an error, but got nothing' });
132
132
  } else if (typeof shouldThrow === 'string') {
133
- if (!(err instanceof Error ? err.message : err).includes(shouldThrow)) {
134
- const actual = err instanceof Error ? `'${err.message}'` : `'${err}'`;
133
+ if (!(error instanceof Error ? error.message : error).includes(shouldThrow)) {
134
+ const actual = error instanceof Error ? `'${error.message}'` : `'${error}'`;
135
135
  return new assert.AssertionError({
136
136
  message: `Expected error containing text '${shouldThrow}', but got ${actual}`,
137
137
  actual,
@@ -139,8 +139,8 @@ export class AssertCheck {
139
139
  });
140
140
  }
141
141
  } else if (shouldThrow instanceof RegExp) {
142
- if (!shouldThrow.test(typeof err === 'string' ? err : err.message)) {
143
- const actual = err instanceof Error ? `'${err.message}'` : `'${err}'`;
142
+ if (!shouldThrow.test(typeof error === 'string' ? error : error.message)) {
143
+ const actual = error instanceof Error ? `'${error.message}'` : `'${error}'`;
144
144
  return new assert.AssertionError({
145
145
  message: `Expected error with message matching '${shouldThrow.source}', but got ${actual}`,
146
146
  actual,
@@ -148,27 +148,27 @@ export class AssertCheck {
148
148
  });
149
149
  }
150
150
  } else if (isClass(shouldThrow)) {
151
- if (!(err instanceof shouldThrow)) {
151
+ if (!(error instanceof shouldThrow)) {
152
152
  return new assert.AssertionError({
153
- message: `Expected to throw ${shouldThrow.name}, but got ${err}`,
154
- actual: (err ?? 'nothing'),
153
+ message: `Expected to throw ${shouldThrow.name}, but got ${error}`,
154
+ actual: (error ?? 'nothing'),
155
155
  expected: shouldThrow.name
156
156
  });
157
157
  }
158
158
  } else if (typeof shouldThrow === 'function') {
159
159
  const target = shouldThrow.name ? `("${shouldThrow.name}")` : '';
160
160
  try {
161
- const res = shouldThrow(err);
162
- if (res === false) {
163
- return new assert.AssertionError({ message: `Checking function ${target} indicated an invalid error`, actual: err });
164
- } else if (typeof res === 'string') {
165
- return new assert.AssertionError({ message: res, actual: err });
161
+ const result = shouldThrow(error);
162
+ if (result === false) {
163
+ return new assert.AssertionError({ message: `Checking function ${target} indicated an invalid error`, actual: error });
164
+ } else if (typeof result === 'string') {
165
+ return new assert.AssertionError({ message: result, actual: error });
166
166
  }
167
- } catch (checkErr) {
168
- if (checkErr instanceof assert.AssertionError) {
169
- return checkErr;
167
+ } catch (checkError) {
168
+ if (checkError instanceof assert.AssertionError) {
169
+ return checkError;
170
170
  } else {
171
- return new assert.AssertionError({ message: `Checking function ${target} threw an error`, actual: checkErr });
171
+ return new assert.AssertionError({ message: `Checking function ${target} threw an error`, actual: checkError });
172
172
  }
173
173
  }
174
174
  }
@@ -177,26 +177,26 @@ export class AssertCheck {
177
177
  static #onError(
178
178
  positive: boolean,
179
179
  message: string | undefined,
180
- err: unknown,
180
+ error: unknown,
181
181
  missed: Error | undefined,
182
182
  shouldThrow: ThrowableError | undefined,
183
183
  assertion: CaptureAssert
184
184
  ): void {
185
- if (!(err instanceof Error)) {
186
- err = new Error(`${err}`);
185
+ if (!(error instanceof Error)) {
186
+ error = new Error(`${error}`);
187
187
  }
188
- if (!(err instanceof Error)) {
189
- throw err;
188
+ if (!(error instanceof Error)) {
189
+ throw error;
190
190
  }
191
191
  if (positive) {
192
192
  missed = new assert.AssertionError({ message: 'Error thrown, but expected no errors' });
193
- missed.stack = err.stack;
193
+ missed.stack = error.stack;
194
194
  }
195
195
 
196
- const resolvedErr = (missed && err) ?? this.checkError(shouldThrow, err);
197
- if (resolvedErr) {
198
- assertion.message = message || missed?.message || resolvedErr.message;
199
- throw (assertion.error = resolvedErr);
196
+ const resolvedError = (missed && error) ?? this.checkError(shouldThrow, error);
197
+ if (resolvedError) {
198
+ assertion.message = message || missed?.message || resolvedError.message;
199
+ throw (assertion.error = resolvedError);
200
200
  }
201
201
  }
202
202
 
@@ -225,8 +225,8 @@ export class AssertCheck {
225
225
  }
226
226
  throw (missed = new assert.AssertionError({ message: `No error thrown, but expected ${shouldThrow ?? 'an error'}`, expected: shouldThrow ?? 'an error' }));
227
227
  }
228
- } catch (err) {
229
- this.#onError(positive, message, err, missed, shouldThrow, assertion);
228
+ } catch (error) {
229
+ this.#onError(positive, message, error, missed, shouldThrow, assertion);
230
230
  } finally {
231
231
  AssertCapture.add(assertion);
232
232
  }
@@ -261,8 +261,8 @@ export class AssertCheck {
261
261
  }
262
262
  throw (missed = new assert.AssertionError({ message: `No error thrown, but expected ${shouldThrow ?? 'an error'}`, expected: shouldThrow ?? 'an error' }));
263
263
  }
264
- } catch (err) {
265
- this.#onError(positive, message, err, missed, shouldThrow, assertion);
264
+ } catch (error) {
265
+ this.#onError(positive, message, error, missed, shouldThrow, assertion);
266
266
  } finally {
267
267
  AssertCapture.add(assertion);
268
268
  }
@@ -271,8 +271,8 @@ export class AssertCheck {
271
271
  /**
272
272
  * Look for any unhandled exceptions
273
273
  */
274
- static checkUnhandled(test: TestConfig, err: Error | assert.AssertionError): void {
275
- let line = AssertUtil.getPositionOfError(err, test.sourceImport ?? test.import).line;
274
+ static checkUnhandled(test: TestConfig, error: Error | assert.AssertionError): void {
275
+ let line = AssertUtil.getPositionOfError(error, test.sourceImport ?? test.import).line;
276
276
  if (line === 1) {
277
277
  line = test.lineStart;
278
278
  }
@@ -281,9 +281,9 @@ export class AssertCheck {
281
281
  import: test.import,
282
282
  line,
283
283
  operator: 'throws',
284
- error: err,
285
- message: err.message,
286
- text: ('operator' in err ? err.operator : '') || '(uncaught)'
284
+ error,
285
+ message: error.message,
286
+ text: ('operator' in error ? error.operator : '') || '(uncaught)'
287
287
  });
288
288
  }
289
289
  }
@@ -15,53 +15,53 @@ export class AssertUtil {
15
15
  /**
16
16
  * Clean a value for displaying in the output
17
17
  */
18
- static cleanValue(val: unknown): unknown {
19
- switch (typeof val) {
20
- case 'number': case 'boolean': case 'bigint': case 'string': case 'undefined': return val;
18
+ static cleanValue(value: unknown): unknown {
19
+ switch (typeof value) {
20
+ case 'number': case 'boolean': case 'bigint': case 'string': case 'undefined': return value;
21
21
  case 'object': {
22
- if (isCleanable(val)) {
23
- return val.toClean();
24
- } else if (val === null || val.constructor === Object || Array.isArray(val) || val instanceof Date) {
25
- return JSON.stringify(val);
22
+ if (isCleanable(value)) {
23
+ return value.toClean();
24
+ } else if (value === null || value.constructor === Object || Array.isArray(value) || value instanceof Date) {
25
+ return JSON.stringify(value);
26
26
  }
27
27
  break;
28
28
  }
29
29
  case 'function': {
30
- if (val.Ⲑid || !val.constructor) {
31
- return val.name;
30
+ if (value.Ⲑid || !value.constructor) {
31
+ return value.name;
32
32
  }
33
33
  break;
34
34
  }
35
35
  }
36
- return util.inspect(val, false, 1).replace(/\n/g, ' ');
36
+ return util.inspect(value, false, 1).replace(/\n/g, ' ');
37
37
  }
38
38
 
39
39
  /**
40
40
  * Determine file location for a given error and the stack trace
41
41
  */
42
- static getPositionOfError(err: Error, imp: string): { import: string, line: number } {
43
- const cwd = Runtime.mainSourcePath;
44
- const lines = (err.stack ?? new Error().stack!)
42
+ static getPositionOfError(error: Error, importLocation: string): { import: string, line: number } {
43
+ const workingDirectory = Runtime.mainSourcePath;
44
+ const lines = (error.stack ?? new Error().stack!)
45
45
  .replace(/[\\/]/g, '/')
46
46
  .split('\n')
47
47
  // Exclude node_modules, target self
48
- .filter(x => x.includes(cwd) && (!x.includes('node_modules') || x.includes('/support/')));
48
+ .filter(lineText => lineText.includes(workingDirectory) && (!lineText.includes('node_modules') || lineText.includes('/support/')));
49
49
 
50
- const filename = RuntimeIndex.getFromImport(imp)?.sourceFile!;
50
+ const filename = RuntimeIndex.getFromImport(importLocation)?.sourceFile!;
51
51
 
52
- let best = lines.filter(x => x.includes(filename))[0];
52
+ let best = lines.filter(lineText => lineText.includes(filename))[0];
53
53
 
54
54
  if (!best) {
55
- [best] = lines.filter(x => x.includes(`${cwd}/test`));
55
+ [best] = lines.filter(lineText => lineText.includes(`${workingDirectory}/test`));
56
56
  }
57
57
 
58
58
  if (!best) {
59
- return { import: imp, line: 1 };
59
+ return { import: importLocation, line: 1 };
60
60
  }
61
61
 
62
62
  const pth = best.trim().split(/\s+/g).slice(1).pop()!;
63
63
  if (!pth) {
64
- return { import: imp, line: 1 };
64
+ return { import: importLocation, line: 1 };
65
65
  }
66
66
 
67
67
  const [file, lineNo] = pth
@@ -74,21 +74,21 @@ export class AssertUtil {
74
74
  line = -1;
75
75
  }
76
76
 
77
- const outFileParts = file.split(cwd.replace(/^[A-Za-z]:/, ''));
77
+ const outFileParts = file.split(workingDirectory.replace(/^[A-Za-z]:/, ''));
78
78
 
79
79
  const outFile = outFileParts.length > 1 ? outFileParts[1].replace(/^[\/]/, '') : filename;
80
80
 
81
- const res = { import: RuntimeIndex.getFromSource(outFile)?.import!, line };
81
+ const result = { import: RuntimeIndex.getFromSource(outFile)?.import!, line };
82
82
 
83
- return res;
83
+ return result;
84
84
  }
85
85
 
86
86
  /**
87
87
  * Generate a suite error given a suite config, and an error
88
88
  */
89
89
  static generateSuiteFailure(suite: SuiteConfig, methodName: string, error: Error): SuiteFailure {
90
- const { import: imp, ...pos } = this.getPositionOfError(error, suite.import);
91
- let line = pos.line;
90
+ const { import: imp, ...rest } = this.getPositionOfError(error, suite.import);
91
+ let line = rest.line;
92
92
 
93
93
  if (line === 1 && suite.lineStart) {
94
94
  line = suite.lineStart;
@@ -118,13 +118,13 @@ export class AssertUtil {
118
118
  /**
119
119
  * Define import failure as a SuiteFailure object
120
120
  */
121
- static gernerateImportFailure(imp: string, err: Error): SuiteFailure {
122
- const name = path.basename(imp);
123
- const classId = `${RuntimeIndex.getFromImport(imp)?.id}#${name}`;
121
+ static gernerateImportFailure(importLocation: string, error: Error): SuiteFailure {
122
+ const name = path.basename(importLocation);
123
+ const classId = `${RuntimeIndex.getFromImport(importLocation)?.id}#${name}`;
124
124
  const suite = asFull<SuiteConfig & SuiteResult>({
125
- class: asFull<Class>({ name }), classId, duration: 0, lineStart: 1, lineEnd: 1, import: imp
125
+ class: asFull<Class>({ name }), classId, duration: 0, lineStart: 1, lineEnd: 1, import: importLocation
126
126
  });
127
- err.message = err.message.replaceAll(Runtime.mainSourcePath, '.');
128
- return this.generateSuiteFailure(suite, 'require', err);
127
+ error.message = error.message.replaceAll(Runtime.mainSourcePath, '.');
128
+ return this.generateSuiteFailure(suite, 'require', error);
129
129
  }
130
130
  }
@@ -39,11 +39,11 @@ export class TestConsumerRegistryIndex implements RegistryIndex {
39
39
  */
40
40
  async #init(): Promise<void> {
41
41
  const allFiles = RuntimeIndex.find({
42
- module: m => m.name === '@travetto/test',
43
- file: f => f.relativeFile.startsWith('src/consumer/types/')
42
+ module: mod => mod.name === '@travetto/test',
43
+ file: file => file.relativeFile.startsWith('src/consumer/types/')
44
44
  });
45
- for (const f of allFiles) {
46
- await import(f.outputFile);
45
+ for (const file of allFiles) {
46
+ await import(file.outputFile);
47
47
  }
48
48
  for (const cls of this.store.getClasses()) {
49
49
  this.store.finalize(cls);
@@ -30,7 +30,7 @@ export class CumulativeSummaryConsumer extends DelegatingConsumer {
30
30
  // Was only loading to verify existence (TODO: double-check)
31
31
  if (existsSync(RuntimeIndex.getFromImport(test.import)!.sourceFile)) {
32
32
  (this.#state[test.classId] ??= {})[test.methodName] = test.status;
33
- const SuiteCls = SuiteRegistryIndex.getClasses().find(x => x.Ⲑid === test.classId);
33
+ const SuiteCls = SuiteRegistryIndex.getClasses().find(cls => cls.Ⲑid === test.classId);
34
34
  return SuiteCls ? this.computeTotal(SuiteCls) : this.removeClass(test.classId);
35
35
  } else {
36
36
  return this.removeClass(test.classId);
@@ -52,10 +52,10 @@ export class CumulativeSummaryConsumer extends DelegatingConsumer {
52
52
  */
53
53
  computeTotal(cls: Class): SuiteResult {
54
54
  const suite = SuiteRegistryIndex.getConfig(cls);
55
- const total = Object.values(suite.tests).reduce((acc, x) => {
56
- const status = this.#state[x.classId][x.methodName] ?? 'unknown';
57
- acc[status] += 1;
58
- return acc;
55
+ const total = Object.values(suite.tests).reduce((map, config) => {
56
+ const status = this.#state[config.classId][config.methodName] ?? 'unknown';
57
+ map[status] += 1;
58
+ return map;
59
59
  }, { skipped: 0, passed: 0, failed: 0, unknown: 0 });
60
60
 
61
61
  return {
@@ -76,17 +76,17 @@ export class CumulativeSummaryConsumer extends DelegatingConsumer {
76
76
  * Listen for event, process the full event, and if the event is an after test,
77
77
  * send a full suite summary
78
78
  */
79
- onEventDone(e: TestEvent): void {
79
+ onEventDone(event: TestEvent): void {
80
80
  try {
81
- if (e.type === 'test' && e.phase === 'after') {
81
+ if (event.type === 'test' && event.phase === 'after') {
82
82
  this.onEvent({
83
83
  type: 'suite',
84
84
  phase: 'after',
85
- suite: this.summarizeSuite(e.test),
85
+ suite: this.summarizeSuite(event.test),
86
86
  });
87
87
  }
88
- } catch (err) {
89
- console.warn('Summarization Error', { error: err });
88
+ } catch (error) {
89
+ console.warn('Summarization Error', { error });
90
90
  }
91
91
  }
92
92
  }
@@ -6,53 +6,53 @@ import type { TestEvent } from '../../model/event.ts';
6
6
  */
7
7
  export abstract class DelegatingConsumer implements TestConsumerShape {
8
8
  #consumers: TestConsumerShape[];
9
- #transformer?: (ev: TestEvent) => typeof ev;
10
- #filter?: (ev: TestEvent) => boolean;
9
+ #transformer?: (event: TestEvent) => typeof event;
10
+ #filter?: (event: TestEvent) => boolean;
11
11
 
12
12
  constructor(consumers: TestConsumerShape[]) {
13
13
  this.#consumers = consumers;
14
- for (const c of consumers) {
15
- c.onEvent = c.onEvent.bind(c);
14
+ for (const consumer of consumers) {
15
+ consumer.onEvent = consumer.onEvent.bind(consumer);
16
16
  }
17
17
  }
18
18
 
19
- withTransformer(transformer: (ev: TestEvent) => typeof ev): this {
19
+ withTransformer(transformer: (event: TestEvent) => typeof event): this {
20
20
  this.#transformer = transformer;
21
21
  return this;
22
22
  }
23
23
 
24
- withFilter(filter: (ev: TestEvent) => boolean): this {
24
+ withFilter(filter: (event: TestEvent) => boolean): this {
25
25
  this.#filter = filter;
26
26
  return this;
27
27
  }
28
28
 
29
29
  async onStart(state: TestRunState): Promise<void> {
30
- for (const c of this.#consumers) {
31
- await c.onStart?.(state);
30
+ for (const consumer of this.#consumers) {
31
+ await consumer.onStart?.(state);
32
32
  }
33
33
  }
34
34
 
35
- onEvent(e: TestEvent): void {
35
+ onEvent(event: TestEvent): void {
36
36
  if (this.#transformer) {
37
- e = this.#transformer(e);
37
+ event = this.#transformer(event);
38
38
  }
39
- if (this.#filter?.(e) === false) {
39
+ if (this.#filter?.(event) === false) {
40
40
  return;
41
41
  }
42
- for (const c of this.#consumers) {
43
- c.onEvent(e);
42
+ for (const consumer of this.#consumers) {
43
+ consumer.onEvent(event);
44
44
  }
45
45
 
46
- this.onEventDone?.(e);
46
+ this.onEventDone?.(event);
47
47
  }
48
48
 
49
49
  async summarize(summary?: SuitesSummary): Promise<void> {
50
50
  if (summary) {
51
- for (const c of this.#consumers) {
52
- await c.onSummary?.(summary);
51
+ for (const consumer of this.#consumers) {
52
+ await consumer.onSummary?.(summary);
53
53
  }
54
54
  }
55
55
  }
56
56
 
57
- onEventDone?(e: TestEvent): void;
57
+ onEventDone?(event: TestEvent): void;
58
58
  }
@@ -12,11 +12,11 @@ export class RunnableTestConsumer extends DelegatingConsumer {
12
12
 
13
13
  constructor(...consumers: TestConsumerShape[]) {
14
14
  super(consumers);
15
- this.#results = consumers.find(x => !!x.onSummary) ? new TestResultsSummarizer() : undefined;
15
+ this.#results = consumers.find(consumer => !!consumer.onSummary) ? new TestResultsSummarizer() : undefined;
16
16
  }
17
17
 
18
- onEventDone(e: TestEvent): void {
19
- this.#results?.onEvent(e);
18
+ onEventDone(event: TestEvent): void {
19
+ this.#results?.onEvent(event);
20
20
  }
21
21
 
22
22
  async summarizeAsBoolean(): Promise<boolean> {
@@ -17,21 +17,21 @@ export class TestResultsSummarizer implements TestConsumerShape {
17
17
  errors: []
18
18
  };
19
19
 
20
- #merge(src: SuiteResult): void {
21
- this.summary.suites.push(src);
22
- this.summary.failed += src.failed;
23
- this.summary.passed += src.passed;
24
- this.summary.skipped += src.skipped;
25
- this.summary.duration += src.duration;
26
- this.summary.total += (src.failed + src.passed + src.skipped);
20
+ #merge(result: SuiteResult): void {
21
+ this.summary.suites.push(result);
22
+ this.summary.failed += result.failed;
23
+ this.summary.passed += result.passed;
24
+ this.summary.skipped += result.skipped;
25
+ this.summary.duration += result.duration;
26
+ this.summary.total += (result.failed + result.passed + result.skipped);
27
27
  }
28
28
 
29
29
  /**
30
30
  * Merge all test results into a single Suite Result
31
31
  */
32
- onEvent(e: TestEvent): void {
33
- if (e.phase === 'after' && e.type === 'suite') {
34
- this.#merge(e.suite);
32
+ onEvent(event: TestEvent): void {
33
+ if (event.phase === 'after' && event.type === 'suite') {
34
+ this.#merge(event.suite);
35
35
  }
36
36
  }
37
37
  }
@@ -56,7 +56,7 @@ export class TapSummaryEmitter implements TestConsumerShape {
56
56
  const success = StyleUtil.getStyle({ text: '#e5e5e5', background: '#026020' }); // White on dark green
57
57
  const fail = StyleUtil.getStyle({ text: '#e5e5e5', background: '#8b0000' }); // White on dark red
58
58
  this.#progress = this.#terminal.streamToBottom(
59
- Util.mapAsyncItr(
59
+ Util.mapAsyncIterable(
60
60
  this.#results,
61
61
  (value) => {
62
62
  failed += (value.status === 'failed' ? 1 : 0);
@@ -70,22 +70,22 @@ export class TapSummaryEmitter implements TestConsumerShape {
70
70
  );
71
71
  }
72
72
 
73
- onEvent(ev: TestEvent): void {
74
- if (ev.type === 'test' && ev.phase === 'after') {
75
- const { test } = ev;
73
+ onEvent(event: TestEvent): void {
74
+ if (event.type === 'test' && event.phase === 'after') {
75
+ const { test } = event;
76
76
  this.#results.add(test);
77
77
  if (test.status === 'failed') {
78
- this.#consumer.onEvent(ev);
78
+ this.#consumer.onEvent(event);
79
79
  }
80
80
  const tests = this.#timings.get('test')!;
81
- tests.set(`${ev.test.classId}/${ev.test.methodName}`, {
82
- key: `${ev.test.classId}/${ev.test.methodName}`,
81
+ tests.set(`${event.test.classId}/${event.test.methodName}`, {
82
+ key: `${event.test.classId}/${event.test.methodName}`,
83
83
  duration: test.duration,
84
84
  tests: 1
85
85
  });
86
- } else if (ev.type === 'suite' && ev.phase === 'after') {
87
- const [module] = ev.suite.classId.split(/:/);
88
- const [file] = ev.suite.classId.split(/#/);
86
+ } else if (event.type === 'suite' && event.phase === 'after') {
87
+ const [module] = event.suite.classId.split(/:/);
88
+ const [file] = event.suite.classId.split(/#/);
89
89
 
90
90
  const modules = this.#timings.get('module')!;
91
91
  const files = this.#timings.get('file')!;
@@ -99,16 +99,16 @@ export class TapSummaryEmitter implements TestConsumerShape {
99
99
  files.set(file, { key: file, duration: 0, tests: 0 });
100
100
  }
101
101
 
102
- suites.set(ev.suite.classId, {
103
- key: ev.suite.classId,
104
- duration: ev.suite.duration,
105
- tests: ev.suite.tests.length
102
+ suites.set(event.suite.classId, {
103
+ key: event.suite.classId,
104
+ duration: event.suite.duration,
105
+ tests: event.suite.tests.length
106
106
  });
107
107
 
108
- files.get(file)!.duration += ev.suite.duration;
109
- files.get(file)!.tests += ev.suite.tests.length;
110
- modules.get(module)!.duration += ev.suite.duration;
111
- modules.get(module)!.tests += ev.suite.tests.length;
108
+ files.get(file)!.duration += event.suite.duration;
109
+ files.get(file)!.tests += event.suite.tests.length;
110
+ modules.get(module)!.duration += event.suite.duration;
111
+ modules.get(module)!.tests += event.suite.tests.length;
112
112
  }
113
113
  }
114
114
 
@@ -127,8 +127,8 @@ export class TapSummaryEmitter implements TestConsumerShape {
127
127
  await this.#consumer.log(`${this.#enhancer.suiteName(`Top ${count} slowest ${title}s`)}: `);
128
128
  const top10 = [...results.values()].toSorted((a, b) => b.duration - a.duration).slice(0, count);
129
129
 
130
- for (const x of top10) {
131
- console.log(` * ${this.#enhancer.testName(x.key)} - ${this.#enhancer.total(x.duration)}ms / ${this.#enhancer.total(x.tests)} tests`);
130
+ for (const result of top10) {
131
+ console.log(` * ${this.#enhancer.testName(result.key)} - ${this.#enhancer.total(result.duration)}ms / ${this.#enhancer.total(result.tests)} tests`);
132
132
  }
133
133
  await this.#consumer.log('');
134
134
  }