@travetto/test 7.0.0-rc.1 → 7.0.0-rc.3

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 (46) hide show
  1. package/README.md +7 -8
  2. package/__index__.ts +1 -0
  3. package/package.json +7 -7
  4. package/src/assert/check.ts +46 -46
  5. package/src/assert/util.ts +31 -31
  6. package/src/communication.ts +66 -0
  7. package/src/consumer/registry-index.ts +11 -11
  8. package/src/consumer/types/cumulative.ts +91 -62
  9. package/src/consumer/types/delegating.ts +30 -27
  10. package/src/consumer/types/event.ts +11 -4
  11. package/src/consumer/types/exec.ts +12 -3
  12. package/src/consumer/types/runnable.ts +4 -3
  13. package/src/consumer/types/summarizer.ts +12 -10
  14. package/src/consumer/types/tap-summary.ts +22 -20
  15. package/src/consumer/types/tap.ts +15 -15
  16. package/src/consumer/types/xunit.ts +15 -15
  17. package/src/consumer/types.ts +6 -2
  18. package/src/decorator/suite.ts +2 -2
  19. package/src/decorator/test.ts +6 -4
  20. package/src/execute/barrier.ts +8 -8
  21. package/src/execute/console.ts +1 -1
  22. package/src/execute/executor.ts +32 -21
  23. package/src/execute/phase.ts +7 -7
  24. package/src/execute/run.ts +247 -0
  25. package/src/execute/types.ts +2 -17
  26. package/src/execute/watcher.ts +33 -60
  27. package/src/fixture.ts +2 -2
  28. package/src/model/common.ts +4 -0
  29. package/src/model/event.ts +3 -1
  30. package/src/model/suite.ts +10 -21
  31. package/src/model/test.ts +48 -2
  32. package/src/model/util.ts +8 -0
  33. package/src/registry/registry-adapter.ts +23 -21
  34. package/src/registry/registry-index.ts +25 -25
  35. package/src/worker/child.ts +21 -21
  36. package/src/worker/standard.ts +28 -19
  37. package/src/worker/types.ts +9 -5
  38. package/support/bin/run.ts +10 -10
  39. package/support/cli.test.ts +20 -41
  40. package/support/cli.test_diff.ts +47 -0
  41. package/support/cli.test_digest.ts +7 -7
  42. package/support/cli.test_direct.ts +13 -12
  43. package/support/cli.test_watch.ts +3 -8
  44. package/support/transformer.assert.ts +12 -12
  45. package/src/execute/runner.ts +0 -87
  46. package/src/execute/util.ts +0 -108
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
  }
@@ -231,8 +231,7 @@ Usage: test [options] [first:string] [globs...:string]
231
231
  Options:
232
232
  -f, --format <string> Output format for test results (default: "tap")
233
233
  -c, --concurrency <number> Number of tests to run concurrently (default: 9)
234
- -m, --mode <single|standard> Test run mode (default: "standard")
235
- -t, --tags <string> Tags to target or exclude
234
+ -t, --tags <string> Tags to target or exclude when using globs
236
235
  -o, --format-options <string> Format options
237
236
  -h, --help display help for command
238
237
  ```
package/__index__.ts CHANGED
@@ -4,6 +4,7 @@ export * from './src/decorator/test.ts';
4
4
  export * from './src/model/suite.ts';
5
5
  export * from './src/model/test.ts';
6
6
  export * from './src/model/event.ts';
7
+ export * from './src/model/util.ts';
7
8
  export * from './src/registry/registry-index.ts';
8
9
  export * from './src/registry/registry-adapter.ts';
9
10
  export * from './src/fixture.ts';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/test",
3
- "version": "7.0.0-rc.1",
3
+ "version": "7.0.0-rc.3",
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.1",
31
- "@travetto/runtime": "^7.0.0-rc.1",
32
- "@travetto/terminal": "^7.0.0-rc.1",
33
- "@travetto/worker": "^7.0.0-rc.1",
30
+ "@travetto/registry": "^7.0.0-rc.3",
31
+ "@travetto/runtime": "^7.0.0-rc.3",
32
+ "@travetto/terminal": "^7.0.0-rc.3",
33
+ "@travetto/worker": "^7.0.0-rc.3",
34
34
  "yaml": "^2.8.1"
35
35
  },
36
36
  "peerDependencies": {
37
- "@travetto/cli": "^7.0.0-rc.1",
38
- "@travetto/transformer": "^7.0.0-rc.1"
37
+ "@travetto/cli": "^7.0.0-rc.3",
38
+ "@travetto/transformer": "^7.0.0-rc.3"
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;
@@ -96,7 +96,7 @@ export class AssertUtil {
96
96
 
97
97
  const msg = error.message.split(/\n/)[0];
98
98
 
99
- const core = { import: imp, classId: suite.classId, methodName };
99
+ const core = { import: imp, classId: suite.classId, methodName, sourceHash: suite.sourceHash };
100
100
  const coreAll = { ...core, description: msg, lineStart: line, lineEnd: line, lineBodyStart: line };
101
101
 
102
102
  const assert: Assertion = {
@@ -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
  }
@@ -0,0 +1,66 @@
1
+ import { AppError, hasToJSON, JSONUtil } from '@travetto/runtime';
2
+
3
+ /**
4
+ * Tools for communication serialization/deserialization especially with errors
5
+ */
6
+ export class CommunicationUtil {
7
+
8
+ /**
9
+ * Serialize to JSON
10
+ */
11
+ static serialize<T>(out: T): string {
12
+ return JSON.stringify(out, function (key, value) {
13
+ const objectValue = this[key];
14
+ if (objectValue && objectValue instanceof Error) {
15
+ return {
16
+ $: true,
17
+ ...hasToJSON(objectValue) ? objectValue.toJSON() : objectValue,
18
+ name: objectValue.name,
19
+ message: objectValue.message,
20
+ stack: objectValue.stack,
21
+ };
22
+ } else if (typeof value === 'bigint') {
23
+ return `${value.toString()}$n`;
24
+ } else {
25
+ return value;
26
+ }
27
+ });
28
+ }
29
+
30
+ /**
31
+ * Serialize to a standard object, instead of a string
32
+ */
33
+ static serializeToObject<R = Record<string, unknown>, T = unknown>(out: T): R {
34
+ return JSONUtil.parseSafe(this.serialize(out));
35
+ }
36
+
37
+ /**
38
+ * Deserialize from JSON
39
+ */
40
+ static deserialize<T = unknown>(input: string): T {
41
+ return JSONUtil.parseSafe(input, function (key, value) {
42
+ if (value && typeof value === 'object' && '$' in value) {
43
+ const error = AppError.fromJSON(value) ?? new Error();
44
+ if (!(error instanceof AppError)) {
45
+ const { $: _, ...rest } = value;
46
+ Object.assign(error, rest);
47
+ }
48
+ error.message = value.message;
49
+ error.stack = value.stack;
50
+ error.name = value.name;
51
+ return error;
52
+ } else if (typeof value === 'string' && /^\d+[$]n$/.test(value)) {
53
+ return BigInt(value.split('$')[0]);
54
+ } else {
55
+ return value;
56
+ }
57
+ });
58
+ }
59
+
60
+ /**
61
+ * Deserialize from a standard object, instead of a string
62
+ */
63
+ static deserializeFromObject<R = unknown, T = R>(input: T): R {
64
+ return this.deserialize<R>(JSON.stringify(input));
65
+ }
66
+ }
@@ -2,7 +2,7 @@ import { RuntimeIndex, type Class } from '@travetto/runtime';
2
2
  import { Registry, RegistryIndex, RegistryIndexStore } from '@travetto/registry';
3
3
 
4
4
  import type { TestConsumerShape } from './types.ts';
5
- import type { RunState } from '../execute/types.ts';
5
+ import type { TestConsumerConfig } from '../execute/types.ts';
6
6
  import { TestConsumerRegistryAdapter } from './registry-adapter.ts';
7
7
 
8
8
  /**
@@ -25,33 +25,33 @@ export class TestConsumerRegistryIndex implements RegistryIndex {
25
25
 
26
26
  /**
27
27
  * Get a consumer instance that supports summarization
28
- * @param consumer The consumer identifier or the actual consumer
28
+ * @param consumerConfig The consumer configuration
29
29
  */
30
- static getInstance(state: Pick<RunState, 'consumer' | 'consumerOptions'>): Promise<TestConsumerShape> {
31
- return this.#instance.getInstance(state);
30
+ static getInstance(consumerConfig: TestConsumerConfig): Promise<TestConsumerShape> {
31
+ return this.#instance.getInstance(consumerConfig);
32
32
  }
33
33
 
34
34
  #initialized: Promise<void>;
35
35
  store = new RegistryIndexStore(TestConsumerRegistryAdapter);
36
36
 
37
+ /** @private */ constructor(source: unknown) { Registry.validateConstructor(source); }
38
+
37
39
  /**
38
40
  * Manual initialization when running outside of the bootstrap process
39
41
  */
40
42
  async #init(): Promise<void> {
41
43
  const allFiles = RuntimeIndex.find({
42
- module: m => m.name === '@travetto/test',
43
- file: f => f.relativeFile.startsWith('src/consumer/types/')
44
+ module: mod => mod.name === '@travetto/test',
45
+ file: file => file.relativeFile.startsWith('src/consumer/types/')
44
46
  });
45
- for (const f of allFiles) {
46
- await import(f.outputFile);
47
+ for (const file of allFiles) {
48
+ await import(file.outputFile);
47
49
  }
48
50
  for (const cls of this.store.getClasses()) {
49
51
  this.store.finalize(cls);
50
52
  }
51
53
  }
52
54
 
53
- process(): void { }
54
-
55
55
  /**
56
56
  * Get types
57
57
  */
@@ -69,7 +69,7 @@ export class TestConsumerRegistryIndex implements RegistryIndex {
69
69
  * Get a consumer instance that supports summarization
70
70
  * @param consumer The consumer identifier or the actual consumer
71
71
  */
72
- async getInstance(state: Pick<RunState, 'consumer' | 'consumerOptions'>): Promise<TestConsumerShape> {
72
+ async getInstance(state: Pick<TestConsumerConfig, 'consumer' | 'consumerOptions'>): Promise<TestConsumerShape> {
73
73
  await (this.#initialized ??= this.#init());
74
74
  for (const cls of this.store.getClasses()) {
75
75
  const adapter = this.store.get(cls);