@travetto/test 5.0.0-rc.8 → 5.0.0-rc.9

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/test",
3
- "version": "5.0.0-rc.8",
3
+ "version": "5.0.0-rc.9",
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/runtime": "^5.0.0-rc.8",
31
- "@travetto/registry": "^5.0.0-rc.8",
32
- "@travetto/terminal": "^5.0.0-rc.8",
33
- "@travetto/worker": "^5.0.0-rc.8",
30
+ "@travetto/runtime": "^5.0.0-rc.9",
31
+ "@travetto/registry": "^5.0.0-rc.9",
32
+ "@travetto/terminal": "^5.0.0-rc.9",
33
+ "@travetto/worker": "^5.0.0-rc.9",
34
34
  "yaml": "^2.4.5"
35
35
  },
36
36
  "peerDependencies": {
37
- "@travetto/cli": "^5.0.0-rc.8",
38
- "@travetto/transformer": "^5.0.0-rc.5"
37
+ "@travetto/cli": "^5.0.0-rc.9",
38
+ "@travetto/transformer": "^5.0.0-rc.6"
39
39
  },
40
40
  "peerDependenciesMeta": {
41
41
  "@travetto/transformer": {
@@ -26,15 +26,15 @@ class $AssertCapture {
26
26
 
27
27
  // Emit and collect, every assertion as it occurs
28
28
  const handler = (a: CaptureAssert): void => {
29
- const assrt: Assertion = {
29
+ const asrt: Assertion = {
30
30
  ...a,
31
31
  import: a.import ?? a.module!.join('/'),
32
32
  classId: test.classId,
33
33
  methodName: test.methodName
34
34
  };
35
- assertions.push(assrt);
35
+ assertions.push(asrt);
36
36
  if (listener) {
37
- listener(assrt);
37
+ listener(asrt);
38
38
  }
39
39
  };
40
40
 
@@ -1,6 +1,6 @@
1
1
  import assert from 'node:assert';
2
2
 
3
- import { AppError, ClassInstance, Class } from '@travetto/runtime';
3
+ import { AppError, Class, castTo, castKey, asConstructable } from '@travetto/runtime';
4
4
 
5
5
  import { ThrowableError, TestConfig, Assertion } from '../model/test';
6
6
  import { AssertCapture, CaptureAssert } from './capture';
@@ -34,36 +34,35 @@ export class AssertCheck {
34
34
  // Invert check for negative
35
35
  const assertFn = positive ? assert : (x: unknown, msg?: string): unknown => assert(!x, msg);
36
36
 
37
- /* eslint-disable @typescript-eslint/consistent-type-assertions */
38
37
  // Check fn to call
39
38
  if (fn === 'fail') {
40
39
  if (args.length > 1) {
41
- [assertion.actual, assertion.expected, assertion.message, assertion.operator] = args as [unknown, unknown, string, string];
40
+ [assertion.actual, assertion.expected, assertion.message, assertion.operator] = castTo(args);
42
41
  } else {
43
- [assertion.message] = args as [string];
42
+ [assertion.message] = castTo(args);
44
43
  }
45
44
  } else if (/throw|reject/i.test(fn)) {
46
45
  assertion.operator = fn;
47
46
  if (typeof args[1] !== 'string') {
48
- [, assertion.expected, assertion.message] = args as [unknown, unknown, string];
47
+ [, assertion.expected, assertion.message] = castTo(args);
49
48
  } else {
50
- [, assertion.message] = args as [unknown, string];
49
+ [, assertion.message] = castTo(args);
51
50
  }
52
51
  } else if (fn === 'ok' || fn === 'assert') {
53
52
  fn = assertion.operator = 'ok';
54
- [assertion.actual, assertion.message] = args as [unknown, string];
53
+ [assertion.actual, assertion.message] = castTo(args);
55
54
  assertion.expected = { toClean: (): string => positive ? 'truthy' : 'falsy' };
56
55
  common.state = 'should be';
57
56
  } else if (fn === 'includes') {
58
57
  assertion.operator = fn;
59
- [assertion.actual, assertion.expected, assertion.message] = args as [unknown, unknown, string];
58
+ [assertion.actual, assertion.expected, assertion.message] = castTo(args);
60
59
  } else if (fn === 'instanceof') {
61
60
  assertion.operator = fn;
62
- [assertion.actual, assertion.expected, assertion.message] = args as [unknown, unknown, string];
63
- assertion.actual = (assertion.actual as ClassInstance)?.constructor;
61
+ [assertion.actual, assertion.expected, assertion.message] = castTo(args);
62
+ assertion.actual = asConstructable(assertion.actual)?.constructor;
64
63
  } else { // Handle unknown
65
64
  assertion.operator = fn ?? '';
66
- [assertion.actual, assertion.expected, assertion.message] = args as [unknown, unknown, string];
65
+ [assertion.actual, assertion.expected, assertion.message] = castTo(args);
67
66
  }
68
67
 
69
68
  try {
@@ -76,25 +75,25 @@ export class AssertCheck {
76
75
  assertion.expected = AssertUtil.cleanValue(assertion.expected);
77
76
  }
78
77
 
79
- const [actual, expected, message] = args as [unknown, unknown, string];
78
+ const [actual, expected, message]: [unknown, unknown, string] = castTo(args);
80
79
 
81
80
  // Actually run the assertion
82
81
  switch (fn) {
83
- case 'includes': assertFn((actual as unknown[]).includes(expected), message); break;
84
- case 'test': assertFn((expected as RegExp).test(actual as string), message); break;
85
- case 'instanceof': assertFn(actual instanceof (expected as Class), message); break;
86
- case 'in': assertFn((actual as string) in (expected as object), message); break;
87
- case 'lessThan': assertFn((actual as number) < (expected as number), message); break;
88
- case 'lessThanEqual': assertFn((actual as number) <= (expected as number), message); break;
89
- case 'greaterThan': assertFn((actual as number) > (expected as number), message); break;
90
- case 'greaterThanEqual': assertFn((actual as number) >= (expected as number), message); break;
91
- case 'ok': assertFn(...args as [unknown, string]); break;
82
+ case 'includes': assertFn(castTo<unknown[]>(actual).includes(expected), message); break;
83
+ case 'test': assertFn(castTo<RegExp>(expected).test(castTo(actual)), message); break;
84
+ case 'instanceof': assertFn(actual instanceof castTo<Class>(expected), message); break;
85
+ case 'in': assertFn(castTo<string>(actual) in castTo<object>(expected), message); break;
86
+ case 'lessThan': assertFn(castTo<number>(actual) < castTo<number>(expected), message); break;
87
+ case 'lessThanEqual': assertFn(castTo<number>(actual) <= castTo<number>(expected), message); break;
88
+ case 'greaterThan': assertFn(castTo<number>(actual) > castTo<number>(expected), message); break;
89
+ case 'greaterThanEqual': assertFn(castTo<number>(actual) >= castTo<number>(expected), message); break;
90
+ case 'ok': assertFn(...castTo<Parameters<typeof assertFn>>(args)); break;
92
91
  default:
93
- if (fn && assert[fn as keyof typeof assert]) { // Assert call
92
+ if (fn && assert[castKey<typeof assert>(fn)]) { // Assert call
94
93
  if (/not/i.test(fn)) {
95
94
  common.state = 'should not';
96
95
  }
97
- assert[fn as 'ok'].apply(null, args as [boolean, string | undefined]);
96
+ assert[castTo<'ok'>(fn)].apply(null, castTo(args));
98
97
  }
99
98
  }
100
99
 
@@ -115,7 +114,6 @@ export class AssertCheck {
115
114
  }
116
115
  throw err;
117
116
  }
118
- /* eslint-enable @typescript-eslint/consistent-type-assertions */
119
117
  }
120
118
 
121
119
  /**
@@ -6,8 +6,7 @@ import { TestConfig, Assertion, TestResult } from '../model/test';
6
6
  import { SuiteConfig } from '../model/suite';
7
7
 
8
8
  function isCleanable(o: unknown): o is { toClean(): unknown } {
9
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
10
- return !!o && !!(o as { toClean: unknown }).toClean;
9
+ return !!o && typeof o === 'object' && 'toClean' in o && typeof o.toClean === 'function';
11
10
  }
12
11
 
13
12
  /**
@@ -35,7 +34,6 @@ export class AssertUtil {
35
34
  break;
36
35
  }
37
36
  }
38
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
39
37
  return util.inspect(val, false, 1).replace(/\n/g, ' ');
40
38
  }
41
39
 
@@ -14,9 +14,9 @@ export class ErrorUtil {
14
14
  /**
15
15
  * Prepare error for transmission
16
16
  */
17
- static serializeError(e: Error | SerializedError): SerializedError;
17
+ static serializeError(e: Error | SerializedError): Error;
18
18
  static serializeError(e: undefined): undefined;
19
- static serializeError(e: Error | SerializedError | undefined): SerializedError | undefined {
19
+ static serializeError(e: Error | SerializedError | undefined): Error | undefined {
20
20
  let error: SerializedError | undefined;
21
21
 
22
22
  if (e) {
@@ -66,13 +66,11 @@ export class ErrorUtil {
66
66
  if (out.phase === 'after') {
67
67
  if (out.type === 'test') {
68
68
  if (out.test.error) {
69
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
70
- out.test.error = this.serializeError(out.test.error) as Error;
69
+ out.test.error = this.serializeError(out.test.error);
71
70
  }
72
71
  } else if (out.type === 'assertion') {
73
72
  if (out.assertion.error) {
74
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
75
- out.assertion.error = this.serializeError(out.assertion.error) as Error;
73
+ out.assertion.error = this.serializeError(out.assertion.error);
76
74
  }
77
75
  }
78
76
  }
@@ -1,4 +1,4 @@
1
- import type { Class, ConcreteClass } from '@travetto/runtime';
1
+ import { classConstruct, type Class } from '@travetto/runtime';
2
2
  import { TestConsumer } from './types';
3
3
 
4
4
  /**
@@ -45,8 +45,7 @@ class $TestConsumerRegistry {
45
45
  await this.manualInit();
46
46
 
47
47
  return typeof consumer === 'string' ?
48
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
49
- new ((this.get(consumer) ?? this.#primary) as ConcreteClass)() :
48
+ classConstruct(this.get(consumer) ?? this.#primary) :
50
49
  consumer;
51
50
  }
52
51
  }
@@ -30,7 +30,7 @@ export class TapStreamedEmitter implements TestConsumer {
30
30
  this.#consumer.onStart();
31
31
 
32
32
  let failed = 0;
33
- const succ = StyleUtil.getStyle({ text: '#e5e5e5', background: '#026020' }); // White on dark green
33
+ const success = StyleUtil.getStyle({ text: '#e5e5e5', background: '#026020' }); // White on dark green
34
34
  const fail = StyleUtil.getStyle({ text: '#e5e5e5', background: '#8b0000' }); // White on dark red
35
35
  this.#progress = this.#terminal.streamToBottom(
36
36
  Util.mapAsyncItr(
@@ -39,7 +39,7 @@ export class TapStreamedEmitter implements TestConsumer {
39
39
  failed += (value.status === 'failed' ? 1 : 0);
40
40
  return { value: `Tests %idx/%total [${failed} failed] -- ${value.classId}`, total: state.testCount, idx };
41
41
  },
42
- TerminalUtil.progressBarUpdater(this.#terminal, { style: () => ({ complete: failed ? fail : succ }) })
42
+ TerminalUtil.progressBarUpdater(this.#terminal, { style: () => ({ complete: failed ? fail : success }) })
43
43
  ),
44
44
  { minDelay: 100 }
45
45
  );
@@ -1,4 +1,4 @@
1
- import { Class, ClassInstance, describeFunction } from '@travetto/runtime';
1
+ import { castTo, Class, ClassInstance, describeFunction } from '@travetto/runtime';
2
2
 
3
3
  import { SuiteRegistry } from '../registry/suite';
4
4
  import { SuiteConfig } from '../model/suite';
@@ -23,17 +23,16 @@ export function Suite(description?: string | Partial<SuiteConfig>, ...rest: Part
23
23
  Object.assign(extra, r);
24
24
  }
25
25
 
26
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
27
- const decorator = ((target: Class) => {
26
+ const dec = (target: Class): typeof target => {
28
27
  const cfg = { description: descriptionString, ...extra };
29
28
  if (describeFunction(target).abstract) {
30
29
  cfg.skip = true;
31
30
  }
32
31
  SuiteRegistry.register(target, cfg);
33
32
  return target;
34
- }) as ClassDecorator;
33
+ };
35
34
 
36
- return decorator;
35
+ return castTo(dec);
37
36
  }
38
37
 
39
38
  function listener(phase: SuitePhase) {
@@ -1,7 +1,7 @@
1
1
  import { AssertionError } from 'node:assert';
2
2
  import path from 'node:path';
3
3
 
4
- import { Env, TimeUtil, Runtime, RuntimeIndex } from '@travetto/runtime';
4
+ import { Env, TimeUtil, Runtime, RuntimeIndex, castTo, asFull, Class } from '@travetto/runtime';
5
5
  import { Barrier, ExecutionError } from '@travetto/worker';
6
6
 
7
7
  import { SuiteRegistry } from '../registry/suite';
@@ -39,8 +39,7 @@ export class TestExecutor {
39
39
 
40
40
  try {
41
41
  await pCap.run(() =>
42
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
43
- (suite.instance as Record<string, Function>)[test.methodName]()
42
+ castTo<Record<string, Function>>(suite.instance)[test.methodName]()
44
43
  );
45
44
  } finally {
46
45
  process.env = env; // Restore
@@ -68,8 +67,7 @@ export class TestExecutor {
68
67
  static failFile(consumer: TestConsumer, imp: string, err: Error): void {
69
68
  const name = path.basename(imp);
70
69
  const classId = `${RuntimeIndex.getFromImport(imp)?.id}○${name}`;
71
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
72
- const suite = { class: { name }, classId, duration: 0, lineStart: 1, lineEnd: 1, import: imp, } as SuiteConfig & SuiteResult;
70
+ const suite = asFull<SuiteConfig & SuiteResult>({ class: asFull<Class>({ name }), classId, duration: 0, lineStart: 1, lineEnd: 1, import: imp, });
73
71
  err.message = err.message.replaceAll(Runtime.mainSourcePath, '.');
74
72
  const res = AssertUtil.generateSuiteError(suite, 'require', err);
75
73
  consumer.onEvent({ type: 'suite', phase: 'before', suite });
@@ -127,11 +125,11 @@ export class TestExecutor {
127
125
  }
128
126
 
129
127
  // Emit every assertion as it occurs
130
- const getAssertions = AssertCapture.collector(test, assrt =>
128
+ const getAssertions = AssertCapture.collector(test, asrt =>
131
129
  consumer.onEvent({
132
130
  type: 'assertion',
133
131
  phase: 'after',
134
- assertion: assrt
132
+ assertion: asrt
135
133
  })
136
134
  );
137
135
 
@@ -1,4 +1,5 @@
1
1
  import { createHook, executionAsyncId } from 'node:async_hooks';
2
+ import { isPromise } from 'node:util/types';
2
3
 
3
4
  import { ExecutionError } from '@travetto/worker';
4
5
  import { Util } from '@travetto/runtime';
@@ -11,9 +12,8 @@ export class PromiseCapturer {
11
12
  #id: number = 0;
12
13
 
13
14
  #init(id: number, type: string, triggerId: number, resource: unknown): void {
14
- if (this.#id && type === 'PROMISE' && triggerId === this.#id) {
15
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
16
- this.#pending.set(id, resource as Promise<unknown>);
15
+ if (this.#id && type === 'PROMISE' && triggerId === this.#id && isPromise(resource)) {
16
+ this.#pending.set(id, resource);
17
17
  }
18
18
  }
19
19
 
@@ -1,4 +1,4 @@
1
- import { Class, ConcreteClass, Runtime, describeFunction } from '@travetto/runtime';
1
+ import { Class, Runtime, classConstruct, describeFunction, asFull } from '@travetto/runtime';
2
2
  import { MetadataRegistry } from '@travetto/registry';
3
3
 
4
4
  import { SuiteConfig } from '../model/suite';
@@ -57,8 +57,7 @@ class $SuiteRegistry extends MetadataRegistry<SuiteConfig, TestConfig> {
57
57
  * a full projection of all listeners and tests.
58
58
  */
59
59
  onInstallFinalize<T>(cls: Class<T>): SuiteConfig {
60
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
61
- const config = this.getOrCreatePending(cls) as SuiteConfig;
60
+ const config = asFull(this.getOrCreatePending(cls));
62
61
  const tests = [...this.pendingFields.get(cls.Ⲑid)!.values()];
63
62
 
64
63
  const parent = this.getParentClass(cls);
@@ -75,10 +74,8 @@ class $SuiteRegistry extends MetadataRegistry<SuiteConfig, TestConfig> {
75
74
  })));
76
75
  }
77
76
 
78
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
79
- config.instance = new (config.class as ConcreteClass)();
80
- // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
81
- config.tests = tests as TestConfig[];
77
+ config.instance = classConstruct(config.class);
78
+ config.tests = tests!.map(x => asFull(x));
82
79
 
83
80
  if (!config.description) {
84
81
  config.description = config.classId;
@@ -137,12 +137,12 @@ export class AssertTransformer {
137
137
  */
138
138
  static initState(state: TransformerState & AssertState): void {
139
139
  if (!state[AssertⲐ]) {
140
- const assrt = state.importFile('@travetto/test/src/assert/check').ident;
140
+ const asrt = state.importFile('@travetto/test/src/assert/check').ident;
141
141
  state[AssertⲐ] = {
142
- assert: assrt,
143
- assertCheck: CoreUtil.createAccess(state.factory, assrt, ASSERT_UTIL, 'check'),
144
- checkThrow: CoreUtil.createAccess(state.factory, assrt, ASSERT_UTIL, 'checkThrow'),
145
- checkThrowAsync: CoreUtil.createAccess(state.factory, assrt, ASSERT_UTIL, 'checkThrowAsync'),
142
+ assert: asrt,
143
+ assertCheck: CoreUtil.createAccess(state.factory, asrt, ASSERT_UTIL, 'check'),
144
+ checkThrow: CoreUtil.createAccess(state.factory, asrt, ASSERT_UTIL, 'checkThrow'),
145
+ checkThrowAsync: CoreUtil.createAccess(state.factory, asrt, ASSERT_UTIL, 'checkThrowAsync'),
146
146
  };
147
147
  }
148
148
  }
@@ -153,7 +153,7 @@ export class AssertTransformer {
153
153
  static doAssert(state: TransformerState & AssertState, node: ts.CallExpression, cmd: Command): ts.CallExpression {
154
154
  this.initState(state);
155
155
 
156
- const first = CoreUtil.getArgument<ts.CallExpression>(node);
156
+ const first = CoreUtil.firstArgument(node);
157
157
  const firstText = first!.getText();
158
158
 
159
159
  cmd.args = cmd.args.filter(x => x !== undefined && x !== null);
@@ -175,8 +175,8 @@ export class AssertTransformer {
175
175
  * Convert `assert.(throws|rejects|doesNotThrow|doesNotReject)` to the appropriate structure
176
176
  */
177
177
  static doThrows(state: TransformerState & AssertState, node: ts.CallExpression, key: string, args: ts.Expression[]): ts.CallExpression {
178
- const first = CoreUtil.getArgument<ts.CallExpression>(node);
179
- const firstText = first!.getText();
178
+ const first = CoreUtil.firstArgument(node)!;
179
+ const firstText = first.getText();
180
180
 
181
181
  this.initState(state);
182
182
  return state.factory.createCallExpression(