@travetto/test 5.0.14 → 5.0.15

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
@@ -208,7 +208,7 @@ class SimpleTest {
208
208
  await assert.rejects(() => {
209
209
  throw new Error('Big Error');
210
210
  }, (err: Error) =>
211
- err.message.startsWith('Big') && err.message.length > 4 ? undefined : err
211
+ err.message.startsWith('Big') && err.message.length > 4
212
212
  );
213
213
  }
214
214
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/test",
3
- "version": "5.0.14",
3
+ "version": "5.0.15",
4
4
  "description": "Declarative test framework",
5
5
  "keywords": [
6
6
  "unit-testing",
@@ -27,14 +27,14 @@
27
27
  "directory": "module/test"
28
28
  },
29
29
  "dependencies": {
30
- "@travetto/registry": "^5.0.12",
31
- "@travetto/runtime": "^5.0.12",
32
- "@travetto/terminal": "^5.0.14",
33
- "@travetto/worker": "^5.0.14",
30
+ "@travetto/registry": "^5.0.13",
31
+ "@travetto/runtime": "^5.0.13",
32
+ "@travetto/terminal": "^5.0.15",
33
+ "@travetto/worker": "^5.0.15",
34
34
  "yaml": "^2.6.0"
35
35
  },
36
36
  "peerDependencies": {
37
- "@travetto/cli": "^5.0.15",
37
+ "@travetto/cli": "^5.0.16",
38
38
  "@travetto/transformer": "^5.0.10"
39
39
  },
40
40
  "peerDependenciesMeta": {
@@ -1,4 +1,5 @@
1
1
  import assert from 'node:assert';
2
+ import { isPromise } from 'node:util/types';
2
3
 
3
4
  import { AppError, Class, castTo, castKey, asConstructable } from '@travetto/runtime';
4
5
 
@@ -12,6 +13,8 @@ type StringFields<T> = {
12
13
  (T[K] extends string ? K : never)
13
14
  }[Extract<keyof T, string>];
14
15
 
16
+ const isClass = (e: unknown): e is Class => e === Error || e === AppError || Object.getPrototypeOf(e) !== Object.getPrototypeOf(Function);
17
+
15
18
  /**
16
19
  * Check assertion
17
20
  */
@@ -124,46 +127,48 @@ export class AssertCheck {
124
127
  static checkError(shouldThrow: ThrowableError | undefined, err: Error | string | undefined): Error | undefined {
125
128
  if (!shouldThrow) { // If we shouldn't be throwing anything, we are good
126
129
  return;
127
- }
128
- // If should throw is a string or a regexp
129
- if (typeof shouldThrow === 'string' || shouldThrow instanceof RegExp) {
130
- const actual = `${err instanceof Error ? `'${err.message}'` : (err ? `'${err}'` : 'nothing')}`;
131
-
132
- // If a string, check if error exists, and then see if the string is included in the message
133
- if (typeof shouldThrow === 'string' && (!err || !(err instanceof Error ? err.message : err).includes(shouldThrow))) {
130
+ } else if (!err) {
131
+ return new assert.AssertionError({ message: 'Expected to throw an error, but got nothing' });
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}'`;
134
135
  return new assert.AssertionError({
135
136
  message: `Expected error containing text '${shouldThrow}', but got ${actual}`,
136
137
  actual,
137
138
  expected: shouldThrow
138
139
  });
139
140
  }
140
- // If a regexp, check if error exists, and then test the error message against the regex
141
- if (shouldThrow instanceof RegExp && (!err || !shouldThrow.test(typeof err === 'string' ? err : err.message))) {
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
144
  return new assert.AssertionError({
143
145
  message: `Expected error with message matching '${shouldThrow.source}', but got ${actual}`,
144
146
  actual,
145
147
  expected: shouldThrow.source
146
148
  });
147
149
  }
148
- // If passing in a constructor
149
- } else if (shouldThrow === Error ||
150
- shouldThrow === AppError ||
151
- Object.getPrototypeOf(shouldThrow) !== Object.getPrototypeOf(Function)
152
- ) { // if not simple function, treat as class
153
- if (!err || !(err instanceof shouldThrow)) {
150
+ } else if (isClass(shouldThrow)) {
151
+ if (!(err instanceof shouldThrow)) {
154
152
  return new assert.AssertionError({
155
- message: `Expected to throw ${shouldThrow.name}, but got ${err ?? 'nothing'}`,
153
+ message: `Expected to throw ${shouldThrow.name}, but got ${err}`,
156
154
  actual: (err ?? 'nothing'),
157
155
  expected: shouldThrow.name
158
156
  });
159
157
  }
160
- } else {
161
- // Else treat as a simple function to build an error or not
162
- const res = shouldThrow(err);
163
- if (res && !(res instanceof Error)) {
164
- return new AppError(`Invalid check, "${shouldThrow.name}" should return an Error or undefined`, { category: 'data' });
165
- } else {
166
- return res;
158
+ } else if (typeof shouldThrow === 'function') {
159
+ try {
160
+ const res = shouldThrow(err);
161
+ if (res === false) {
162
+ return new assert.AssertionError({ message: `Checking "${shouldThrow.name}" indicated an invalid error`, actual: err });
163
+ } else if (typeof res === 'string') {
164
+ return new assert.AssertionError({ message: res, actual: err });
165
+ }
166
+ } catch (checkErr) {
167
+ if (checkErr instanceof assert.AssertionError) {
168
+ return checkErr;
169
+ } else {
170
+ return new assert.AssertionError({ message: `Checking "${shouldThrow.name}" threw an error`, actual: checkErr });
171
+ }
167
172
  }
168
173
  }
169
174
  }
@@ -171,7 +176,8 @@ export class AssertCheck {
171
176
  static #onError(
172
177
  positive: boolean,
173
178
  message: string | undefined,
174
- err: unknown, missed: Error | undefined,
179
+ err: unknown,
180
+ missed: Error | undefined,
175
181
  shouldThrow: ThrowableError | undefined,
176
182
  assertion: CaptureAssert
177
183
  ): void {
@@ -182,7 +188,7 @@ export class AssertCheck {
182
188
  throw err;
183
189
  }
184
190
  if (positive) {
185
- missed = new AppError('Error thrown, but expected no errors');
191
+ missed = new assert.AssertionError({ message: 'Error thrown, but expected no errors' });
186
192
  missed.stack = err.stack;
187
193
  }
188
194
 
@@ -216,7 +222,7 @@ export class AssertCheck {
216
222
  if (typeof shouldThrow === 'function') {
217
223
  shouldThrow = shouldThrow.name;
218
224
  }
219
- throw (missed = new AppError(`No error thrown, but expected ${shouldThrow ?? 'an error'}`));
225
+ throw (missed = new assert.AssertionError({ message: `No error thrown, but expected ${shouldThrow ?? 'an error'}`, expected: shouldThrow ?? 'an error' }));
220
226
  }
221
227
  } catch (err) {
222
228
  this.#onError(positive, message, err, missed, shouldThrow, assertion);
@@ -243,7 +249,7 @@ export class AssertCheck {
243
249
  let missed: Error | undefined;
244
250
 
245
251
  try {
246
- if ('then' in action) {
252
+ if (isPromise(action)) {
247
253
  await action;
248
254
  } else {
249
255
  await action();
@@ -252,7 +258,7 @@ export class AssertCheck {
252
258
  if (typeof shouldThrow === 'function') {
253
259
  shouldThrow = shouldThrow.name;
254
260
  }
255
- throw (missed = new AppError(`No error thrown, but expected ${shouldThrow ?? 'an error'} `));
261
+ throw (missed = new assert.AssertionError({ message: `No error thrown, but expected ${shouldThrow ?? 'an error'}`, expected: shouldThrow ?? 'an error' }));
256
262
  }
257
263
  } catch (err) {
258
264
  this.#onError(positive, message, err, missed, shouldThrow, assertion);
@@ -1,7 +1,7 @@
1
1
  import { ClassInstance } from '@travetto/runtime';
2
2
 
3
3
  import { SuiteRegistry } from '../registry/suite';
4
- import { TestConfig } from '../model/test';
4
+ import { TestConfig, ThrowableError } from '../model/test';
5
5
 
6
6
  /**
7
7
  * The `@AssertCheck` indicates that a function's assert calls should be transformed
@@ -39,7 +39,7 @@ export function Test(description?: string | Partial<TestConfig>, ...rest: Partia
39
39
  * Marks a method as should throw to indicate a lack of throwing is a problem
40
40
  * @param state The parameters to use for checking if the response is valid
41
41
  */
42
- export function ShouldThrow(state: TestConfig['shouldThrow']): MethodDecorator {
42
+ export function ShouldThrow(state: ThrowableError): MethodDecorator {
43
43
  return (inst: ClassInstance, prop: string | symbol, descriptor: PropertyDescriptor) => {
44
44
  SuiteRegistry.registerField(inst.constructor, descriptor.value, { shouldThrow: state });
45
45
  return descriptor;
package/src/model/test.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import type { Class, TimeSpan } from '@travetto/runtime';
2
2
  import { Skip, TestCore } from './common';
3
3
 
4
- export type ThrowableError = string | RegExp | Function;
4
+ export type ThrowableError = string | RegExp | Class<Error> | ((e: Error | string) => boolean | void | undefined);
5
5
 
6
6
  /**
7
7
  * Specific configuration for a test