@travetto/test 6.0.0-rc.2 → 6.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.
package/README.md CHANGED
@@ -122,6 +122,7 @@ The equivalences for all of the [assert](https://nodejs.org/api/assert.html) ope
122
122
  * `assert(a instanceof b)` as `assert.instanceOf(a, b)`
123
123
  * `assert(a.includes(b))` as `assert.ok(a.includes(b))`
124
124
  * `assert(/a/.test(b))` as `assert.ok(/a/.test(b))`
125
+
125
126
  In addition to the standard operations, there is support for throwing/rejecting errors (or the inverse). This is useful for testing error states or ensuring errors do not occur.
126
127
 
127
128
  ### Throws
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@travetto/test",
3
- "version": "6.0.0-rc.2",
3
+ "version": "6.0.0",
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": "^6.0.0-rc.2",
31
- "@travetto/runtime": "^6.0.0-rc.2",
32
- "@travetto/terminal": "^6.0.0-rc.2",
33
- "@travetto/worker": "^6.0.0-rc.2",
30
+ "@travetto/registry": "^6.0.0",
31
+ "@travetto/runtime": "^6.0.0",
32
+ "@travetto/terminal": "^6.0.0",
33
+ "@travetto/worker": "^6.0.0",
34
34
  "yaml": "^2.7.1"
35
35
  },
36
36
  "peerDependencies": {
37
- "@travetto/cli": "^6.0.0-rc.2",
38
- "@travetto/transformer": "^6.0.0-rc.3"
37
+ "@travetto/cli": "^6.0.0",
38
+ "@travetto/transformer": "^6.0.0"
39
39
  },
40
40
  "peerDependenciesMeta": {
41
41
  "@travetto/transformer": {
@@ -156,10 +156,11 @@ export class AssertCheck {
156
156
  });
157
157
  }
158
158
  } else if (typeof shouldThrow === 'function') {
159
+ const target = shouldThrow.name ? `("${shouldThrow.name}")` : '';
159
160
  try {
160
161
  const res = shouldThrow(err);
161
162
  if (res === false) {
162
- return new assert.AssertionError({ message: `Checking "${shouldThrow.name}" indicated an invalid error`, actual: err });
163
+ return new assert.AssertionError({ message: `Checking function ${target} indicated an invalid error`, actual: err });
163
164
  } else if (typeof res === 'string') {
164
165
  return new assert.AssertionError({ message: res, actual: err });
165
166
  }
@@ -167,7 +168,7 @@ export class AssertCheck {
167
168
  if (checkErr instanceof assert.AssertionError) {
168
169
  return checkErr;
169
170
  } else {
170
- return new assert.AssertionError({ message: `Checking "${shouldThrow.name}" threw an error`, actual: checkErr });
171
+ return new assert.AssertionError({ message: `Checking function ${target} threw an error`, actual: checkErr });
171
172
  }
172
173
  }
173
174
  }
@@ -105,7 +105,7 @@ export class AssertUtil {
105
105
  };
106
106
  const testResult: TestResult = {
107
107
  ...coreAll,
108
- status: 'failed', error, duration: 0, durationTotal: 0, assertions: [assert], output: {}
108
+ status: 'failed', error, duration: 0, durationTotal: 0, assertions: [assert], output: []
109
109
  };
110
110
  const test: TestConfig = {
111
111
  ...coreAll,
@@ -10,7 +10,7 @@ import { TestConsumer } from '../registry.ts';
10
10
  import { TestResultsEnhancer, CONSOLE_ENHANCER } from '../enhancer.ts';
11
11
 
12
12
  /**
13
- * TAP Format consumer
13
+ * TAP Format consumer
14
14
  */
15
15
  @TestConsumer()
16
16
  export class TapEmitter implements TestConsumerShape {
@@ -134,9 +134,13 @@ export class TapEmitter implements TestConsumerShape {
134
134
 
135
135
  // Track output
136
136
  if (test.output) {
137
+ const groupedByLevel: Record<string, string[]> = {};
138
+ for (const log of test.output) {
139
+ (groupedByLevel[log.level] ??= []).push(log.message);
140
+ }
137
141
  for (const key of ['log', 'info', 'error', 'debug', 'warn']) {
138
- if (test.output[key]) {
139
- this.logMeta({ [key]: test.output[key] });
142
+ if (groupedByLevel[key]) {
143
+ this.logMeta({ [key]: groupedByLevel[key].join('\n') });
140
144
  }
141
145
  }
142
146
  }
@@ -63,6 +63,11 @@ export class XunitEmitter implements TestConsumerShape {
63
63
  body = `<failure type="${assertErr.text}" message="${encodeURIComponent(assertErr.message!)}"><![CDATA[${assertErr.error!.stack}]]></failure>`;
64
64
  }
65
65
 
66
+ const groupedByLevel: Record<string, string[]> = {};
67
+ for (const log of test.output) {
68
+ (groupedByLevel[log.level] ??= []).push(log.message);
69
+ }
70
+
66
71
  this.#tests.push(`
67
72
  <testcase
68
73
  name="${name}"
@@ -70,8 +75,8 @@ export class XunitEmitter implements TestConsumerShape {
70
75
  classname="${test.classId}"
71
76
  >
72
77
  ${body}
73
- <system-out>${this.buildMeta({ log: test.output.log, info: test.output.info, debug: test.output.debug })}</system-out>
74
- <system-err>${this.buildMeta({ error: test.output.error, warn: test.output.warn })}</system-err>
78
+ <system-out>${this.buildMeta({ log: groupedByLevel.log, info: groupedByLevel.info, debug: groupedByLevel.debug })}</system-out>
79
+ <system-err>${this.buildMeta({ error: groupedByLevel.error, warn: groupedByLevel.warn })}</system-err>
75
80
  </testcase>`
76
81
  );
77
82
  } else if (e.type === 'suite' && e.phase === 'after') {
@@ -1,6 +1,7 @@
1
1
  import util from 'node:util';
2
2
 
3
3
  import { ConsoleEvent, ConsoleListener, ConsoleManager } from '@travetto/runtime';
4
+ import { TestLog } from '../model/test';
4
5
 
5
6
  /**
6
7
  * Console capturer. Hooks into the Console manager, and collects the
@@ -9,26 +10,28 @@ import { ConsoleEvent, ConsoleListener, ConsoleManager } from '@travetto/runtime
9
10
  export class ConsoleCapture implements ConsoleListener {
10
11
  static #listener: ConsoleListener = ConsoleManager.get();
11
12
 
12
- out: Record<string, string[]>;
13
+ out: TestLog[];
13
14
 
14
15
  start(): this {
15
- this.out = {};
16
+ this.out = [];
16
17
  ConsoleManager.set(this);
17
18
  return this;
18
19
  }
19
20
 
20
- log({ level, args }: ConsoleEvent): void {
21
- (this.out[level] = this.out[level] ?? []).push(
22
- args
21
+ log({ level, line, args }: ConsoleEvent): void {
22
+ this.out.push({
23
+ line,
24
+ level,
25
+ message: args
23
26
  .map((x => typeof x === 'string' ? x : util.inspect(x, false, 5)))
24
27
  .join(' ')
25
- );
28
+ });
26
29
  }
27
30
 
28
- end(): Record<string, string> {
29
- const result = this.out ?? {};
30
- this.out = {};
31
+ end(): TestLog[] {
32
+ const result = this.out ?? [];
33
+ this.out = [];
31
34
  ConsoleManager.set(ConsoleCapture.#listener);
32
- return Object.fromEntries(Object.entries(result).map(([k, v]) => [k, v.join('\n')]));
35
+ return result;
33
36
  }
34
37
  }
@@ -82,7 +82,7 @@ export class TestExecutor {
82
82
  // Mark test start
83
83
  this.#consumer.onEvent({ type: 'test', phase: 'before', test });
84
84
  result.skipped++;
85
- this.#consumer.onEvent({ type: 'test', phase: 'after', test: { ...test, assertions: [], duration: 0, durationTotal: 0, output: {}, status: 'skipped' } });
85
+ this.#consumer.onEvent({ type: 'test', phase: 'after', test: { ...test, assertions: [], duration: 0, durationTotal: 0, output: [], status: 'skipped' } });
86
86
  }
87
87
 
88
88
  /**
@@ -126,7 +126,7 @@ export class TestExecutor {
126
126
  assertions: [],
127
127
  duration: 0,
128
128
  durationTotal: 0,
129
- output: {},
129
+ output: [],
130
130
  };
131
131
 
132
132
  // Emit every assertion as it occurs
package/src/model/test.ts CHANGED
@@ -1,7 +1,9 @@
1
- import type { Class, TimeSpan } from '@travetto/runtime';
1
+ import type { Class, ConsoleEvent, TimeSpan } from '@travetto/runtime';
2
+
2
3
  import { Skip, TestCore } from './common.ts';
3
4
 
4
5
  export type ThrowableError = string | RegExp | Class<Error> | ((e: Error | string) => boolean | void | undefined);
6
+ export type TestLog = { level: ConsoleEvent['level'], line: number, message: string };
5
7
 
6
8
  /**
7
9
  * Specific configuration for a test
@@ -106,7 +108,7 @@ export interface TestResult extends TestCore {
106
108
  /**
107
109
  * Logging output
108
110
  */
109
- output: Record<string, string>;
111
+ output: TestLog[];
110
112
  }
111
113
 
112
114
  /**