@travetto/test 5.0.15 → 5.0.17
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/LICENSE +1 -1
- package/README.md +13 -12
- package/package.json +8 -8
- package/src/assert/util.ts +1 -1
- package/src/consumer/registry.ts +31 -22
- package/src/consumer/serialize.ts +0 -2
- package/src/consumer/types/all.ts +1 -1
- package/src/consumer/types/cumulative.ts +6 -6
- package/src/consumer/types/delegating.ts +5 -5
- package/src/consumer/types/event.ts +5 -5
- package/src/consumer/types/{execution.ts → exec.ts} +5 -5
- package/src/consumer/types/json.ts +6 -6
- package/src/consumer/types/noop.ts +5 -5
- package/src/consumer/types/runnable.ts +3 -10
- package/src/consumer/types/summarizer.ts +4 -4
- package/src/consumer/types/tap-streamed.ts +72 -6
- package/src/consumer/types/tap.ts +11 -7
- package/src/consumer/types/xunit.ts +6 -6
- package/src/consumer/types.ts +6 -2
- package/src/execute/runner.ts +6 -2
- package/src/execute/types.ts +4 -5
- package/src/execute/watcher.ts +6 -4
- package/src/worker/child.ts +1 -1
- package/support/bin/run.ts +23 -0
- package/support/cli.test.ts +21 -6
- package/support/cli.test_direct.ts +8 -5
- package/support/cli.test_watch.ts +6 -2
- package/support/transformer.assert.ts +11 -11
- package/support/bin/types.ts +0 -2
package/LICENSE
CHANGED
package/README.md
CHANGED
|
@@ -79,18 +79,18 @@ would translate to:
|
|
|
79
79
|
"use strict";
|
|
80
80
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
81
81
|
const tslib_1 = require("tslib");
|
|
82
|
-
const
|
|
83
|
-
const
|
|
84
|
-
const
|
|
85
|
-
var
|
|
82
|
+
const Δdebug = tslib_1.__importStar(require("@travetto/runtime/src/debug.js"));
|
|
83
|
+
const Δcheck = tslib_1.__importStar(require("@travetto/test/src/assert/check.js"));
|
|
84
|
+
const Δfunction = tslib_1.__importStar(require("@travetto/runtime/src/function.js"));
|
|
85
|
+
var mod_1 = ["@travetto/test", "doc/assert-example.ts"];
|
|
86
86
|
const node_assert_1 = tslib_1.__importDefault(require("node:assert"));
|
|
87
87
|
const test_1 = require("@travetto/test");
|
|
88
88
|
let SimpleTest = class SimpleTest {
|
|
89
|
-
static
|
|
89
|
+
static { Δfunction.registerFunction(SimpleTest, mod_1, { hash: 1887908328, lines: [5, 12] }, { test: { hash: 102834457, lines: [8, 11, 10] } }, false); }
|
|
90
90
|
async test() {
|
|
91
|
-
if (
|
|
91
|
+
if (Δdebug.tryDebugger)
|
|
92
92
|
debugger;
|
|
93
|
-
|
|
93
|
+
Δcheck.AssertCheck.check({ module: mod_1, line: 10, text: "{ size: 20, address: { state: 'VA' } }", operator: "deepStrictEqual" }, true, { size: 20, address: { state: 'VA' } }, {});
|
|
94
94
|
}
|
|
95
95
|
};
|
|
96
96
|
tslib_1.__decorate([
|
|
@@ -224,11 +224,12 @@ $ trv test --help
|
|
|
224
224
|
Usage: test [options] [first:string] [globs...:string]
|
|
225
225
|
|
|
226
226
|
Options:
|
|
227
|
-
-f, --format <string>
|
|
228
|
-
-c, --concurrency <number>
|
|
229
|
-
-m, --mode <single|standard>
|
|
230
|
-
-t, --tags <string>
|
|
231
|
-
-
|
|
227
|
+
-f, --format <string> Output format for test results (default: "tap")
|
|
228
|
+
-c, --concurrency <number> Number of tests to run concurrently (default: 9)
|
|
229
|
+
-m, --mode <single|standard> Test run mode (default: "standard")
|
|
230
|
+
-t, --tags <string> Tags to target or exclude
|
|
231
|
+
-o, --format-options <string> Format options
|
|
232
|
+
-h, --help display help for command
|
|
232
233
|
```
|
|
233
234
|
|
|
234
235
|
The regexes are the patterns of tests you want to run, and all tests must be found under the `test/` folder.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/test",
|
|
3
|
-
"version": "5.0.
|
|
3
|
+
"version": "5.0.17",
|
|
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": "^5.0.
|
|
31
|
-
"@travetto/runtime": "^5.0.
|
|
32
|
-
"@travetto/terminal": "^5.0.
|
|
33
|
-
"@travetto/worker": "^5.0.
|
|
34
|
-
"yaml": "^2.6.
|
|
30
|
+
"@travetto/registry": "^5.0.15",
|
|
31
|
+
"@travetto/runtime": "^5.0.15",
|
|
32
|
+
"@travetto/terminal": "^5.0.17",
|
|
33
|
+
"@travetto/worker": "^5.0.17",
|
|
34
|
+
"yaml": "^2.6.1"
|
|
35
35
|
},
|
|
36
36
|
"peerDependencies": {
|
|
37
|
-
"@travetto/cli": "^5.0.
|
|
38
|
-
"@travetto/transformer": "^5.0.
|
|
37
|
+
"@travetto/cli": "^5.0.18",
|
|
38
|
+
"@travetto/transformer": "^5.0.12"
|
|
39
39
|
},
|
|
40
40
|
"peerDependenciesMeta": {
|
|
41
41
|
"@travetto/transformer": {
|
package/src/assert/util.ts
CHANGED
|
@@ -120,7 +120,7 @@ export class AssertUtil {
|
|
|
120
120
|
*/
|
|
121
121
|
static gernerateImportFailure(imp: string, err: Error): SuiteFailure {
|
|
122
122
|
const name = path.basename(imp);
|
|
123
|
-
const classId = `${RuntimeIndex.getFromImport(imp)?.id}
|
|
123
|
+
const classId = `${RuntimeIndex.getFromImport(imp)?.id}#${name}`;
|
|
124
124
|
const suite = asFull<SuiteConfig & SuiteResult>({
|
|
125
125
|
class: asFull<Class>({ name }), classId, duration: 0, lineStart: 1, lineEnd: 1, import: imp
|
|
126
126
|
});
|
package/src/consumer/registry.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import
|
|
2
|
-
import {
|
|
1
|
+
import path from 'path';
|
|
2
|
+
import { classConstruct, describeFunction, RuntimeIndex, type Class } from '@travetto/runtime';
|
|
3
|
+
import type { TestConsumerShape } from './types';
|
|
4
|
+
import { RunState } from '../execute/types';
|
|
3
5
|
|
|
4
6
|
/**
|
|
5
7
|
* Test Results Handler Registry
|
|
6
8
|
*/
|
|
7
9
|
class $TestConsumerRegistry {
|
|
8
|
-
#registered = new Map<string, Class<
|
|
9
|
-
#primary: Class<TestConsumer>;
|
|
10
|
+
#registered = new Map<string, Class<TestConsumerShape>>();
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Manual initialization when running outside of the bootstrap process
|
|
@@ -15,38 +16,48 @@ class $TestConsumerRegistry {
|
|
|
15
16
|
await import('./types/all');
|
|
16
17
|
}
|
|
17
18
|
|
|
19
|
+
/**
|
|
20
|
+
* Import a specific path and load all consumers there
|
|
21
|
+
*/
|
|
22
|
+
async importConsumers(pth: string): Promise<void> {
|
|
23
|
+
await import((RuntimeIndex.getEntry(pth) ?? RuntimeIndex.getFromImport(pth))!.outputFile);
|
|
24
|
+
}
|
|
25
|
+
|
|
18
26
|
/**
|
|
19
27
|
* Add a new consumer
|
|
20
|
-
* @param type The consumer unique identifier
|
|
21
28
|
* @param cls The consumer class
|
|
22
|
-
* @param isDefault Set as the default consumer
|
|
23
29
|
*/
|
|
24
|
-
add(
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
this.#registered.set(type, cls);
|
|
30
|
+
add(cls: Class<TestConsumerShape>): void {
|
|
31
|
+
const desc = describeFunction(cls);
|
|
32
|
+
const key = desc.module?.includes('@travetto') ? path.basename(desc.modulePath) : desc.import;
|
|
33
|
+
this.#registered.set(key, cls);
|
|
29
34
|
}
|
|
30
35
|
|
|
31
36
|
/**
|
|
32
37
|
* Retrieve a registered consumer
|
|
33
38
|
* @param type The unique identifier
|
|
34
39
|
*/
|
|
35
|
-
get(type: string): Class<
|
|
40
|
+
get(type: string): Class<TestConsumerShape> {
|
|
36
41
|
return this.#registered.get(type)!;
|
|
37
42
|
}
|
|
38
43
|
|
|
44
|
+
/**
|
|
45
|
+
* Get types
|
|
46
|
+
*/
|
|
47
|
+
getTypes(): string[] {
|
|
48
|
+
return [...this.#registered.keys()];
|
|
49
|
+
}
|
|
50
|
+
|
|
39
51
|
/**
|
|
40
52
|
* Get a consumer instance that supports summarization
|
|
41
53
|
* @param consumer The consumer identifier or the actual consumer
|
|
42
54
|
*/
|
|
43
|
-
async getInstance(
|
|
55
|
+
async getInstance(state: Pick<RunState, 'consumer' | 'consumerOptions'>): Promise<TestConsumerShape> {
|
|
44
56
|
// TODO: Fix consumer registry init
|
|
45
57
|
await this.manualInit();
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
consumer;
|
|
58
|
+
const inst = classConstruct(this.get(state.consumer));
|
|
59
|
+
await inst.setOptions?.(state.consumerOptions ?? {});
|
|
60
|
+
return inst;
|
|
50
61
|
}
|
|
51
62
|
}
|
|
52
63
|
|
|
@@ -54,11 +65,9 @@ export const TestConsumerRegistry = new $TestConsumerRegistry();
|
|
|
54
65
|
|
|
55
66
|
/**
|
|
56
67
|
* Registers a class a valid test consumer
|
|
57
|
-
* @param type The unique identifier for the consumer
|
|
58
|
-
* @param isDefault Is this the default consumer. Last one wins
|
|
59
68
|
*/
|
|
60
|
-
export function
|
|
61
|
-
return function (cls: Class<
|
|
62
|
-
TestConsumerRegistry.add(
|
|
69
|
+
export function TestConsumer(): (cls: Class<TestConsumerShape>) => void {
|
|
70
|
+
return function (cls: Class<TestConsumerShape>): void {
|
|
71
|
+
TestConsumerRegistry.add(cls);
|
|
63
72
|
};
|
|
64
73
|
}
|
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { AppError, hasToJSON } from '@travetto/runtime';
|
|
2
|
-
|
|
3
2
|
import { TestEvent, } from '../model/event';
|
|
4
3
|
|
|
5
|
-
|
|
6
4
|
export type SerializedError = { [K in keyof Error]: Error[K] extends Function ? never : Error[K] } & { $: true };
|
|
7
5
|
|
|
8
6
|
function isError(e: unknown): e is SerializedError {
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
|
|
3
|
-
import { Class, RuntimeIndex } from '@travetto/runtime';
|
|
3
|
+
import { type Class, RuntimeIndex } from '@travetto/runtime';
|
|
4
4
|
|
|
5
|
-
import {
|
|
6
|
-
import { TestEvent } from '../../model/event';
|
|
7
|
-
import { TestResult } from '../../model/test';
|
|
8
|
-
import { SuiteResult } from '../../model/suite';
|
|
5
|
+
import type { TestConsumerShape } from '../types';
|
|
6
|
+
import type { TestEvent } from '../../model/event';
|
|
7
|
+
import type { TestResult } from '../../model/test';
|
|
8
|
+
import type { SuiteResult } from '../../model/suite';
|
|
9
9
|
import { SuiteRegistry } from '../../registry/suite';
|
|
10
10
|
import { DelegatingConsumer } from './delegating';
|
|
11
11
|
|
|
@@ -18,7 +18,7 @@ export class CumulativeSummaryConsumer extends DelegatingConsumer {
|
|
|
18
18
|
*/
|
|
19
19
|
#state: Record<string, Record<string, TestResult['status']>> = {};
|
|
20
20
|
|
|
21
|
-
constructor(target:
|
|
21
|
+
constructor(target: TestConsumerShape) {
|
|
22
22
|
super([target]);
|
|
23
23
|
}
|
|
24
24
|
|
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { SuitesSummary,
|
|
2
|
-
import { TestEvent } from '../../model/event';
|
|
1
|
+
import type { SuitesSummary, TestConsumerShape, TestRunState } from '../types';
|
|
2
|
+
import type { TestEvent } from '../../model/event';
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* Delegating event consumer
|
|
6
6
|
*/
|
|
7
|
-
export abstract class DelegatingConsumer implements
|
|
8
|
-
#consumers:
|
|
7
|
+
export abstract class DelegatingConsumer implements TestConsumerShape {
|
|
8
|
+
#consumers: TestConsumerShape[];
|
|
9
9
|
#transformer?: (ev: TestEvent) => typeof ev;
|
|
10
10
|
#filter?: (ev: TestEvent) => boolean;
|
|
11
11
|
|
|
12
|
-
constructor(consumers:
|
|
12
|
+
constructor(consumers: TestConsumerShape[]) {
|
|
13
13
|
this.#consumers = consumers;
|
|
14
14
|
for (const c of consumers) {
|
|
15
15
|
c.onEvent = c.onEvent.bind(c);
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { Writable } from 'node:stream';
|
|
2
2
|
|
|
3
|
-
import { TestEvent } from '../../model/event';
|
|
4
|
-
import {
|
|
3
|
+
import type { TestEvent } from '../../model/event';
|
|
4
|
+
import type { TestConsumerShape } from '../types';
|
|
5
5
|
import { SerializeUtil } from '../serialize';
|
|
6
|
-
import {
|
|
6
|
+
import { TestConsumer } from '../registry';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Streams all test events a JSON payload, in an nd-json format
|
|
10
10
|
*/
|
|
11
|
-
@
|
|
12
|
-
export class EventStreamer implements
|
|
11
|
+
@TestConsumer()
|
|
12
|
+
export class EventStreamer implements TestConsumerShape {
|
|
13
13
|
#stream: Writable;
|
|
14
14
|
|
|
15
15
|
constructor(stream: Writable = process.stdout) {
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { IpcChannel } from '@travetto/worker';
|
|
2
2
|
|
|
3
|
-
import { TestEvent } from '../../model/event';
|
|
4
|
-
import {
|
|
3
|
+
import type { TestEvent } from '../../model/event';
|
|
4
|
+
import type { TestConsumerShape } from '../types';
|
|
5
5
|
import { SerializeUtil } from '../serialize';
|
|
6
|
-
import {
|
|
6
|
+
import { TestConsumer } from '../registry';
|
|
7
7
|
|
|
8
8
|
/**
|
|
9
9
|
* Triggers each event as an IPC command to a parent process
|
|
10
10
|
*/
|
|
11
|
-
@
|
|
12
|
-
export class ExecutionEmitter extends IpcChannel<TestEvent> implements
|
|
11
|
+
@TestConsumer()
|
|
12
|
+
export class ExecutionEmitter extends IpcChannel<TestEvent> implements TestConsumerShape {
|
|
13
13
|
onEvent(event: TestEvent): void {
|
|
14
14
|
this.send(event.type, JSON.parse(SerializeUtil.serializeToJSON(event)));
|
|
15
15
|
}
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
import { Writable } from 'node:stream';
|
|
1
|
+
import type { Writable } from 'node:stream';
|
|
2
2
|
|
|
3
|
-
import { TestEvent } from '../../model/event';
|
|
4
|
-
import { SuitesSummary
|
|
5
|
-
import {
|
|
3
|
+
import type { TestEvent } from '../../model/event';
|
|
4
|
+
import type { SuitesSummary } from '../types';
|
|
5
|
+
import { TestConsumer } from '../registry';
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
8
|
* Returns the entire result set as a single JSON document
|
|
9
9
|
*/
|
|
10
|
-
@
|
|
11
|
-
export class JSONEmitter
|
|
10
|
+
@TestConsumer()
|
|
11
|
+
export class JSONEmitter {
|
|
12
12
|
|
|
13
13
|
#stream: Writable;
|
|
14
14
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { TestEvent } from '../../model/event';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
1
|
+
import type { TestEvent } from '../../model/event';
|
|
2
|
+
import type { TestConsumerShape } from '../types';
|
|
3
|
+
import { TestConsumer } from '../registry';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Does nothing consumer
|
|
7
7
|
*/
|
|
8
|
-
@
|
|
9
|
-
export class NoopConsumer implements
|
|
8
|
+
@TestConsumer()
|
|
9
|
+
export class NoopConsumer implements TestConsumerShape {
|
|
10
10
|
onEvent(event: TestEvent): void { }
|
|
11
11
|
}
|
|
@@ -1,23 +1,16 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { TestConsumerShape } from '../types';
|
|
2
2
|
import { TestResultsSummarizer } from './summarizer';
|
|
3
|
-
import {
|
|
4
|
-
import { TestEvent } from '../../model/event';
|
|
3
|
+
import type { TestEvent } from '../../model/event';
|
|
5
4
|
import { DelegatingConsumer } from './delegating';
|
|
6
5
|
|
|
7
6
|
/**
|
|
8
7
|
* Test consumer with support for multiple nested consumers, and summarization
|
|
9
8
|
*/
|
|
10
9
|
export class RunnableTestConsumer extends DelegatingConsumer {
|
|
11
|
-
/**
|
|
12
|
-
* Build a runnable test consumer given a format or a full consumer
|
|
13
|
-
*/
|
|
14
|
-
static async get(consumer: string | TestConsumer): Promise<RunnableTestConsumer> {
|
|
15
|
-
return new RunnableTestConsumer([await TestConsumerRegistry.getInstance(consumer)]);
|
|
16
|
-
}
|
|
17
10
|
|
|
18
11
|
#results?: TestResultsSummarizer;
|
|
19
12
|
|
|
20
|
-
constructor(consumers:
|
|
13
|
+
constructor(...consumers: TestConsumerShape[]) {
|
|
21
14
|
super(consumers);
|
|
22
15
|
this.#results = consumers.find(x => !!x.onSummary) ? new TestResultsSummarizer() : undefined;
|
|
23
16
|
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import { SuiteResult } from '../../model/suite';
|
|
2
|
-
import { TestEvent } from '../../model/event';
|
|
3
|
-
import { SuitesSummary,
|
|
1
|
+
import type { SuiteResult } from '../../model/suite';
|
|
2
|
+
import type { TestEvent } from '../../model/event';
|
|
3
|
+
import type { SuitesSummary, TestConsumerShape } from '../types';
|
|
4
4
|
|
|
5
5
|
/**
|
|
6
6
|
* Test Result Collector, combines all results into a single Suite Result
|
|
7
7
|
*/
|
|
8
|
-
export class TestResultsSummarizer implements
|
|
8
|
+
export class TestResultsSummarizer implements TestConsumerShape {
|
|
9
9
|
|
|
10
10
|
summary: SuitesSummary = {
|
|
11
11
|
passed: 0,
|
|
@@ -1,30 +1,48 @@
|
|
|
1
1
|
import { Util, AsyncQueue } from '@travetto/runtime';
|
|
2
2
|
import { StyleUtil, Terminal, TerminalUtil } from '@travetto/terminal';
|
|
3
3
|
|
|
4
|
-
import { TestEvent } from '../../model/event';
|
|
5
|
-
import { TestResult } from '../../model/test';
|
|
4
|
+
import type { TestEvent } from '../../model/event';
|
|
5
|
+
import type { TestResult } from '../../model/test';
|
|
6
6
|
|
|
7
|
-
import { SuitesSummary,
|
|
8
|
-
import {
|
|
7
|
+
import type { SuitesSummary, TestConsumerShape, TestRunState } from '../types';
|
|
8
|
+
import { TestConsumer } from '../registry';
|
|
9
9
|
|
|
10
10
|
import { TapEmitter } from './tap';
|
|
11
11
|
|
|
12
|
+
type Result = {
|
|
13
|
+
key: string;
|
|
14
|
+
duration: number;
|
|
15
|
+
tests: number;
|
|
16
|
+
};
|
|
17
|
+
|
|
12
18
|
/**
|
|
13
19
|
* Streamed summary results
|
|
14
20
|
*/
|
|
15
|
-
@
|
|
16
|
-
export class TapStreamedEmitter implements
|
|
21
|
+
@TestConsumer()
|
|
22
|
+
export class TapStreamedEmitter implements TestConsumerShape {
|
|
23
|
+
|
|
24
|
+
#timings = new Map([
|
|
25
|
+
['file', new Map<string, Result>()],
|
|
26
|
+
['module', new Map<string, Result>()],
|
|
27
|
+
['suite', new Map<string, Result>()],
|
|
28
|
+
['test', new Map<string, Result>()],
|
|
29
|
+
] as const);
|
|
17
30
|
|
|
18
31
|
#terminal: Terminal;
|
|
19
32
|
#results = new AsyncQueue<TestResult>();
|
|
20
33
|
#progress: Promise<unknown> | undefined;
|
|
21
34
|
#consumer: TapEmitter;
|
|
35
|
+
#options?: Record<string, unknown>;
|
|
22
36
|
|
|
23
37
|
constructor(terminal: Terminal = new Terminal(process.stderr)) {
|
|
24
38
|
this.#terminal = terminal;
|
|
25
39
|
this.#consumer = new TapEmitter(this.#terminal);
|
|
26
40
|
}
|
|
27
41
|
|
|
42
|
+
setOptions(options?: Record<string, unknown>): Promise<void> | void {
|
|
43
|
+
this.#options = options;
|
|
44
|
+
}
|
|
45
|
+
|
|
28
46
|
async onStart(state: TestRunState): Promise<void> {
|
|
29
47
|
this.#consumer.onStart();
|
|
30
48
|
|
|
@@ -55,6 +73,38 @@ export class TapStreamedEmitter implements TestConsumer {
|
|
|
55
73
|
if (test.status === 'failed') {
|
|
56
74
|
this.#consumer.onEvent(ev);
|
|
57
75
|
}
|
|
76
|
+
const tests = this.#timings.get('test')!;
|
|
77
|
+
tests.set(`${ev.test.classId}/${ev.test.methodName}`, {
|
|
78
|
+
key: `${ev.test.classId}/${ev.test.methodName}`,
|
|
79
|
+
duration: test.duration,
|
|
80
|
+
tests: 1
|
|
81
|
+
});
|
|
82
|
+
} else if (ev.type === 'suite' && ev.phase === 'after') {
|
|
83
|
+
const [module] = ev.suite.classId.split(/:/);
|
|
84
|
+
const [file] = ev.suite.classId.split(/#/);
|
|
85
|
+
|
|
86
|
+
const modules = this.#timings.get('module')!;
|
|
87
|
+
const files = this.#timings.get('file')!;
|
|
88
|
+
const suites = this.#timings.get('suite')!;
|
|
89
|
+
|
|
90
|
+
if (!modules!.has(module)) {
|
|
91
|
+
modules.set(module, { key: module, duration: 0, tests: 0 });
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (!files.has(file)) {
|
|
95
|
+
files.set(file, { key: file, duration: 0, tests: 0 });
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
suites.set(ev.suite.classId, {
|
|
99
|
+
key: ev.suite.classId,
|
|
100
|
+
duration: ev.suite.duration,
|
|
101
|
+
tests: ev.suite.tests.length
|
|
102
|
+
});
|
|
103
|
+
|
|
104
|
+
files.get(file)!.duration += ev.suite.duration;
|
|
105
|
+
files.get(file)!.tests += ev.suite.tests.length;
|
|
106
|
+
modules.get(module)!.duration += ev.suite.duration;
|
|
107
|
+
modules.get(module)!.tests += ev.suite.tests.length;
|
|
58
108
|
}
|
|
59
109
|
}
|
|
60
110
|
|
|
@@ -65,5 +115,21 @@ export class TapStreamedEmitter implements TestConsumer {
|
|
|
65
115
|
this.#results.close();
|
|
66
116
|
await this.#progress;
|
|
67
117
|
await this.#consumer.onSummary?.(summary);
|
|
118
|
+
|
|
119
|
+
const enhancer = this.#consumer.enhancer;
|
|
120
|
+
|
|
121
|
+
if (this.#options?.timings) {
|
|
122
|
+
const count = +(this.#options?.count ?? 5);
|
|
123
|
+
console.log('\n---');
|
|
124
|
+
for (const [title, results] of [...this.#timings.entries()].sort((a, b) => a[0].localeCompare(b[0]))) {
|
|
125
|
+
console.log(`${enhancer.suiteName(`Top ${count} slowest ${title}s`)}: `);
|
|
126
|
+
const top10 = [...results.values()].sort((a, b) => b.duration - a.duration).slice(0, count);
|
|
127
|
+
for (const x of top10) {
|
|
128
|
+
console.log(` * ${enhancer.testName(x.key)} - ${enhancer.total(x.duration)}ms / ${enhancer.total(x.tests)} tests`);
|
|
129
|
+
}
|
|
130
|
+
console.log();
|
|
131
|
+
}
|
|
132
|
+
console.log('...');
|
|
133
|
+
}
|
|
68
134
|
}
|
|
69
135
|
}
|
|
@@ -3,17 +3,17 @@ import { stringify } from 'yaml';
|
|
|
3
3
|
import { Terminal } from '@travetto/terminal';
|
|
4
4
|
import { TimeUtil, Runtime, RuntimeIndex, hasToJSON } from '@travetto/runtime';
|
|
5
5
|
|
|
6
|
-
import { TestEvent } from '../../model/event';
|
|
7
|
-
import { SuitesSummary,
|
|
8
|
-
import {
|
|
6
|
+
import type { TestEvent } from '../../model/event';
|
|
7
|
+
import type { SuitesSummary, TestConsumerShape } from '../types';
|
|
8
|
+
import { TestConsumer } from '../registry';
|
|
9
9
|
import { SerializeUtil } from '../serialize';
|
|
10
10
|
import { TestResultsEnhancer, CONSOLE_ENHANCER } from '../enhancer';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* TAP Format consumer
|
|
14
14
|
*/
|
|
15
|
-
@
|
|
16
|
-
export class TapEmitter implements
|
|
15
|
+
@TestConsumer()
|
|
16
|
+
export class TapEmitter implements TestConsumerShape {
|
|
17
17
|
#count = 0;
|
|
18
18
|
#enhancer: TestResultsEnhancer;
|
|
19
19
|
#terminal: Terminal;
|
|
@@ -27,6 +27,10 @@ export class TapEmitter implements TestConsumer {
|
|
|
27
27
|
this.#enhancer = enhancer;
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
get enhancer(): TestResultsEnhancer {
|
|
31
|
+
return this.#enhancer;
|
|
32
|
+
}
|
|
33
|
+
|
|
30
34
|
log(message: string): void {
|
|
31
35
|
this.#terminal.writer.writeLine(message).commit();
|
|
32
36
|
}
|
|
@@ -36,7 +40,7 @@ export class TapEmitter implements TestConsumer {
|
|
|
36
40
|
*/
|
|
37
41
|
onStart(): void {
|
|
38
42
|
this.#start = Date.now();
|
|
39
|
-
this.log(this.#enhancer.suiteName('TAP version
|
|
43
|
+
this.log(this.#enhancer.suiteName('TAP version 14')!);
|
|
40
44
|
}
|
|
41
45
|
|
|
42
46
|
/**
|
|
@@ -44,7 +48,7 @@ export class TapEmitter implements TestConsumer {
|
|
|
44
48
|
*/
|
|
45
49
|
logMeta(obj: Record<string, unknown>): void {
|
|
46
50
|
const lineLength = this.#terminal.width - 5;
|
|
47
|
-
let body = stringify(obj, { lineWidth: lineLength });
|
|
51
|
+
let body = stringify(obj, { lineWidth: lineLength, indent: 2 });
|
|
48
52
|
body = body.split('\n').map(x => ` ${x}`).join('\n');
|
|
49
53
|
this.log(`---\n${this.#enhancer.objectInspect(body)}\n...`);
|
|
50
54
|
}
|
|
@@ -1,18 +1,18 @@
|
|
|
1
|
-
import { Writable } from 'node:stream';
|
|
1
|
+
import type { Writable } from 'node:stream';
|
|
2
2
|
|
|
3
3
|
import { stringify } from 'yaml';
|
|
4
4
|
|
|
5
5
|
import { RuntimeIndex } from '@travetto/runtime';
|
|
6
6
|
|
|
7
|
-
import { TestEvent } from '../../model/event';
|
|
8
|
-
import { SuitesSummary,
|
|
9
|
-
import {
|
|
7
|
+
import type { TestEvent } from '../../model/event';
|
|
8
|
+
import type { SuitesSummary, TestConsumerShape } from '../types';
|
|
9
|
+
import { TestConsumer } from '../registry';
|
|
10
10
|
|
|
11
11
|
/**
|
|
12
12
|
* Xunit consumer, compatible with JUnit formatters
|
|
13
13
|
*/
|
|
14
|
-
@
|
|
15
|
-
export class XunitEmitter implements
|
|
14
|
+
@TestConsumer()
|
|
15
|
+
export class XunitEmitter implements TestConsumerShape {
|
|
16
16
|
#tests: string[] = [];
|
|
17
17
|
#suites: string[] = [];
|
|
18
18
|
#stream: Writable;
|
package/src/consumer/types.ts
CHANGED
|
@@ -24,9 +24,13 @@ export type TestRunState = {
|
|
|
24
24
|
};
|
|
25
25
|
|
|
26
26
|
/**
|
|
27
|
-
* A test
|
|
27
|
+
* A test consumer shape
|
|
28
28
|
*/
|
|
29
|
-
export interface
|
|
29
|
+
export interface TestConsumerShape {
|
|
30
|
+
/**
|
|
31
|
+
* Set options
|
|
32
|
+
*/
|
|
33
|
+
setOptions?(options?: Record<string, unknown>): Promise<void> | void;
|
|
30
34
|
/**
|
|
31
35
|
* Listen for start of the test run
|
|
32
36
|
*/
|
package/src/execute/runner.ts
CHANGED
|
@@ -10,6 +10,7 @@ import { TestRun } from '../model/test';
|
|
|
10
10
|
import { TestExecutor } from './executor';
|
|
11
11
|
import { RunnerUtil } from './util';
|
|
12
12
|
import { RunState } from './types';
|
|
13
|
+
import { TestConsumerRegistry } from '../consumer/registry';
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Test Runner
|
|
@@ -26,7 +27,8 @@ export class Runner {
|
|
|
26
27
|
* Run all files
|
|
27
28
|
*/
|
|
28
29
|
async runFiles(globs?: string[]): Promise<boolean> {
|
|
29
|
-
const
|
|
30
|
+
const target = await TestConsumerRegistry.getInstance(this.#state);
|
|
31
|
+
const consumer = new RunnableTestConsumer(target);
|
|
30
32
|
const tests = await RunnerUtil.getTestDigest(globs, this.#state.tags);
|
|
31
33
|
const testRuns = RunnerUtil.getTestRuns(tests)
|
|
32
34
|
.sort((a, b) => a.runId!.localeCompare(b.runId!));
|
|
@@ -58,7 +60,9 @@ export class Runner {
|
|
|
58
60
|
RuntimeIndex.reinitForModule(entry.module);
|
|
59
61
|
}
|
|
60
62
|
|
|
61
|
-
const
|
|
63
|
+
const target = await TestConsumerRegistry.getInstance(this.#state);
|
|
64
|
+
|
|
65
|
+
const consumer = new RunnableTestConsumer(target)
|
|
62
66
|
.withTransformer(e => {
|
|
63
67
|
// Copy run metadata to event
|
|
64
68
|
e.metadata = run.metadata;
|
package/src/execute/types.ts
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import { TestConsumer } from '../consumer/types';
|
|
2
1
|
import { TestRun } from '../model/test';
|
|
3
2
|
|
|
4
3
|
/**
|
|
@@ -6,13 +5,13 @@ import { TestRun } from '../model/test';
|
|
|
6
5
|
*/
|
|
7
6
|
export interface RunState {
|
|
8
7
|
/**
|
|
9
|
-
*
|
|
8
|
+
* Test result consumer
|
|
10
9
|
*/
|
|
11
|
-
|
|
10
|
+
consumer: string;
|
|
12
11
|
/**
|
|
13
|
-
*
|
|
12
|
+
* Test result consumer options?
|
|
14
13
|
*/
|
|
15
|
-
|
|
14
|
+
consumerOptions?: Record<string, unknown>;
|
|
16
15
|
/**
|
|
17
16
|
* Number of test suites to run concurrently, when mode is not single
|
|
18
17
|
*/
|
package/src/execute/watcher.ts
CHANGED
|
@@ -34,7 +34,9 @@ export class TestWatcher {
|
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
const itr = new AsyncQueue(events);
|
|
37
|
-
const consumer = new CumulativeSummaryConsumer(
|
|
37
|
+
const consumer = new CumulativeSummaryConsumer(
|
|
38
|
+
await TestConsumerRegistry.getInstance({ consumer: format })
|
|
39
|
+
)
|
|
38
40
|
.withFilter(x => x.metadata?.partial !== true || x.type !== 'suite');
|
|
39
41
|
|
|
40
42
|
new MethodSource(RootRegistry).on(e => {
|
|
@@ -42,8 +44,9 @@ export class TestWatcher {
|
|
|
42
44
|
if (!cls || describeFunction(cls).abstract) {
|
|
43
45
|
return;
|
|
44
46
|
}
|
|
47
|
+
const classId = cls.Ⲑid;
|
|
45
48
|
if (!method) {
|
|
46
|
-
consumer.removeClass(
|
|
49
|
+
consumer.removeClass(classId);
|
|
47
50
|
return;
|
|
48
51
|
}
|
|
49
52
|
const conf = SuiteRegistry.getByClassAndMethod(cls, method)!;
|
|
@@ -60,13 +63,12 @@ export class TestWatcher {
|
|
|
60
63
|
type: 'removeTest',
|
|
61
64
|
methodNames: method?.name ? [method.name!] : undefined!,
|
|
62
65
|
method: method?.name,
|
|
63
|
-
classId
|
|
66
|
+
classId,
|
|
64
67
|
import: Runtime.getImport(cls)
|
|
65
68
|
} satisfies TestRemovedEvent);
|
|
66
69
|
}
|
|
67
70
|
});
|
|
68
71
|
|
|
69
|
-
|
|
70
72
|
// If a file is changed, but doesn't emit classes, re-run whole file
|
|
71
73
|
RootRegistry.onNonClassChanges(imp => itr.add({ import: imp }));
|
|
72
74
|
|
package/src/worker/child.ts
CHANGED
|
@@ -81,7 +81,7 @@ export class TestChildWorker extends IpcChannel<TestRun> {
|
|
|
81
81
|
console.debug('Running', { import: run.import });
|
|
82
82
|
|
|
83
83
|
try {
|
|
84
|
-
await new Runner({
|
|
84
|
+
await new Runner({ consumer: 'exec', target: run }).run();
|
|
85
85
|
} finally {
|
|
86
86
|
this.#done.resolve();
|
|
87
87
|
}
|
package/support/bin/run.ts
CHANGED
|
@@ -1,3 +1,8 @@
|
|
|
1
|
+
import { castTo } from '@travetto/runtime';
|
|
2
|
+
import { AllViewSymbol } from '@travetto/schema/src/internal/types';
|
|
3
|
+
import { SchemaRegistry } from '@travetto/schema';
|
|
4
|
+
|
|
5
|
+
import { TestConsumerRegistry } from '../../src/consumer/registry';
|
|
1
6
|
import type { RunState } from '../../src/execute/types';
|
|
2
7
|
|
|
3
8
|
/**
|
|
@@ -17,4 +22,22 @@ export async function runTests(opts: RunState): Promise<void> {
|
|
|
17
22
|
console.error('Test Worker Failed', { error: err });
|
|
18
23
|
process.exitCode = 1;
|
|
19
24
|
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
export async function selectConsumer(inst: { format?: string }) {
|
|
28
|
+
await TestConsumerRegistry.manualInit();
|
|
29
|
+
|
|
30
|
+
let types = TestConsumerRegistry.getTypes();
|
|
31
|
+
|
|
32
|
+
if (inst.format?.includes('/')) {
|
|
33
|
+
await TestConsumerRegistry.importConsumers(inst.format);
|
|
34
|
+
types = TestConsumerRegistry.getTypes();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const cls = inst.constructor;
|
|
38
|
+
|
|
39
|
+
SchemaRegistry.get(castTo(cls)).views[AllViewSymbol].schema.format.enum = {
|
|
40
|
+
message: `{path} is only allowed to be "${types.join('" or "')}"`,
|
|
41
|
+
values: types
|
|
42
|
+
};
|
|
20
43
|
}
|
package/support/cli.test.ts
CHANGED
|
@@ -7,26 +7,36 @@ import { CliCommandShape, CliCommand, CliValidationError } from '@travetto/cli';
|
|
|
7
7
|
import { WorkPool } from '@travetto/worker';
|
|
8
8
|
import { Max, Min } from '@travetto/schema';
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { selectConsumer } from './bin/run';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Launch test framework and execute tests
|
|
14
14
|
*/
|
|
15
15
|
@CliCommand()
|
|
16
16
|
export class TestCommand implements CliCommandShape {
|
|
17
|
+
|
|
17
18
|
/** Output format for test results */
|
|
18
|
-
format:
|
|
19
|
+
format: string = 'tap';
|
|
20
|
+
|
|
19
21
|
/** Number of tests to run concurrently */
|
|
20
22
|
@Min(1) @Max(WorkPool.MAX_SIZE)
|
|
21
23
|
concurrency: number = WorkPool.DEFAULT_SIZE;
|
|
24
|
+
|
|
22
25
|
/** Test run mode */
|
|
23
|
-
mode:
|
|
26
|
+
mode: 'single' | 'standard' = 'standard';
|
|
27
|
+
|
|
24
28
|
/**
|
|
25
29
|
* Tags to target or exclude
|
|
26
30
|
* @alias env.TRV_TEST_TAGS
|
|
27
31
|
*/
|
|
28
32
|
tags?: string[];
|
|
29
33
|
|
|
34
|
+
/**
|
|
35
|
+
* Format options
|
|
36
|
+
* @alias o
|
|
37
|
+
*/
|
|
38
|
+
formatOptions?: string[];
|
|
39
|
+
|
|
30
40
|
preMain(): void {
|
|
31
41
|
EventEmitter.defaultMaxListeners = 1000;
|
|
32
42
|
Env.TRV_ROLE.set('test');
|
|
@@ -40,12 +50,15 @@ export class TestCommand implements CliCommandShape {
|
|
|
40
50
|
return fs.stat(path.resolve(first ?? '')).then(x => x.isFile(), () => false);
|
|
41
51
|
}
|
|
42
52
|
|
|
43
|
-
async resolvedMode(first: string, rest: string[]): Promise<
|
|
53
|
+
async resolvedMode(first: string, rest: string[]): Promise<string> {
|
|
44
54
|
return (await this.isFirstFile(first)) && rest.length === 0 ? 'single' : this.mode;
|
|
45
55
|
}
|
|
46
56
|
|
|
47
|
-
async
|
|
57
|
+
async preValidate(): Promise<void> {
|
|
58
|
+
await selectConsumer(this);
|
|
59
|
+
}
|
|
48
60
|
|
|
61
|
+
async validate(first: string = '**/*', rest: string[]): Promise<CliValidationError | undefined> {
|
|
49
62
|
const mode = await this.resolvedMode(first, rest);
|
|
50
63
|
|
|
51
64
|
if (mode === 'single' && !await this.isFirstFile(first)) {
|
|
@@ -58,10 +71,12 @@ export class TestCommand implements CliCommandShape {
|
|
|
58
71
|
|
|
59
72
|
const isFirst = await this.isFirstFile(first);
|
|
60
73
|
const isSingle = this.mode === 'single' || (isFirst && globs.length === 0);
|
|
74
|
+
const options = Object.fromEntries((this.formatOptions ?? [])?.map(f => [...f.split(':'), true]));
|
|
61
75
|
|
|
62
76
|
return runTests({
|
|
63
77
|
concurrency: this.concurrency,
|
|
64
|
-
|
|
78
|
+
consumer: this.format,
|
|
79
|
+
consumerOptions: options,
|
|
65
80
|
tags: this.tags,
|
|
66
81
|
target: isSingle ?
|
|
67
82
|
{
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import { Env
|
|
1
|
+
import { Env } from '@travetto/runtime';
|
|
2
2
|
import { CliCommand } from '@travetto/cli';
|
|
3
3
|
|
|
4
|
-
import { runTests } from './bin/run';
|
|
5
|
-
import { TestFormat } from './bin/types';
|
|
4
|
+
import { runTests, selectConsumer } from './bin/run';
|
|
6
5
|
|
|
7
6
|
/** Direct test invocation */
|
|
8
7
|
@CliCommand({ hidden: true })
|
|
9
8
|
export class TestDirectCommand {
|
|
10
9
|
|
|
11
|
-
format:
|
|
10
|
+
format: string = 'tap';
|
|
11
|
+
|
|
12
|
+
async preValidate(): Promise<void> {
|
|
13
|
+
await selectConsumer(this);
|
|
14
|
+
}
|
|
12
15
|
|
|
13
16
|
preMain(): void {
|
|
14
17
|
Env.TRV_ROLE.set('test');
|
|
@@ -19,7 +22,7 @@ export class TestDirectCommand {
|
|
|
19
22
|
|
|
20
23
|
main(importOrFile: string, clsId?: string, methodsNames: string[] = []): Promise<void> {
|
|
21
24
|
return runTests({
|
|
22
|
-
|
|
25
|
+
consumer: this.format,
|
|
23
26
|
target: {
|
|
24
27
|
import: importOrFile,
|
|
25
28
|
classId: clsId,
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Env } from '@travetto/runtime';
|
|
2
2
|
import { CliCommand, CliUtil } from '@travetto/cli';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import { selectConsumer } from './bin/run';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Invoke the test watcher
|
|
@@ -9,9 +9,13 @@ import { TestFormat } from './bin/types';
|
|
|
9
9
|
@CliCommand()
|
|
10
10
|
export class TestWatcherCommand {
|
|
11
11
|
|
|
12
|
-
format:
|
|
12
|
+
format: string = 'tap';
|
|
13
13
|
mode: 'all' | 'change' = 'all';
|
|
14
14
|
|
|
15
|
+
async preValidate(): Promise<void> {
|
|
16
|
+
await selectConsumer(this);
|
|
17
|
+
}
|
|
18
|
+
|
|
15
19
|
preMain(): void {
|
|
16
20
|
Env.TRV_ROLE.set('test');
|
|
17
21
|
Env.TRV_DYNAMIC.set(true);
|
|
@@ -48,21 +48,21 @@ const METHODS: Record<string, Function[]> = {
|
|
|
48
48
|
|
|
49
49
|
const OP_TOKEN_TO_NAME = new Map<number, keyof typeof OPTOKEN_ASSERT>();
|
|
50
50
|
|
|
51
|
-
const
|
|
52
|
-
const
|
|
51
|
+
const AssertSymbol = Symbol.for('@travetto/test:assert');
|
|
52
|
+
const IsTestSymbol = Symbol.for('@travetto/test:valid');
|
|
53
53
|
|
|
54
54
|
/**
|
|
55
55
|
* Assert transformation state
|
|
56
56
|
*/
|
|
57
57
|
interface AssertState {
|
|
58
|
-
[
|
|
58
|
+
[AssertSymbol]?: {
|
|
59
59
|
assert: ts.Identifier;
|
|
60
60
|
hasAssertCall?: boolean;
|
|
61
61
|
assertCheck: ts.Expression;
|
|
62
62
|
checkThrow: ts.Expression;
|
|
63
63
|
checkThrowAsync: ts.Expression;
|
|
64
64
|
};
|
|
65
|
-
[
|
|
65
|
+
[IsTestSymbol]?: boolean;
|
|
66
66
|
}
|
|
67
67
|
|
|
68
68
|
/**
|
|
@@ -136,9 +136,9 @@ export class AssertTransformer {
|
|
|
136
136
|
* Initialize transformer state
|
|
137
137
|
*/
|
|
138
138
|
static initState(state: TransformerState & AssertState): void {
|
|
139
|
-
if (!state[
|
|
139
|
+
if (!state[AssertSymbol]) {
|
|
140
140
|
const asrt = state.importFile('@travetto/test/src/assert/check').ident;
|
|
141
|
-
state[
|
|
141
|
+
state[AssertSymbol] = {
|
|
142
142
|
assert: asrt,
|
|
143
143
|
assertCheck: CoreUtil.createAccess(state.factory, asrt, ASSERT_UTIL, 'check'),
|
|
144
144
|
checkThrow: CoreUtil.createAccess(state.factory, asrt, ASSERT_UTIL, 'checkThrow'),
|
|
@@ -157,7 +157,7 @@ export class AssertTransformer {
|
|
|
157
157
|
const firstText = first!.getText();
|
|
158
158
|
|
|
159
159
|
cmd.args = cmd.args.filter(x => x !== undefined && x !== null);
|
|
160
|
-
const check = state.factory.createCallExpression(state[
|
|
160
|
+
const check = state.factory.createCallExpression(state[AssertSymbol]!.assertCheck, undefined, state.factory.createNodeArray([
|
|
161
161
|
state.fromLiteral({
|
|
162
162
|
module: state.getModuleIdentifier(),
|
|
163
163
|
line: state.fromLiteral(ts.getLineAndCharacterOfPosition(state.source, node.getStart()).line + 1),
|
|
@@ -180,7 +180,7 @@ export class AssertTransformer {
|
|
|
180
180
|
|
|
181
181
|
this.initState(state);
|
|
182
182
|
return state.factory.createCallExpression(
|
|
183
|
-
/reject/i.test(key) ? state[
|
|
183
|
+
/reject/i.test(key) ? state[AssertSymbol]!.checkThrowAsync : state[AssertSymbol]!.checkThrow,
|
|
184
184
|
undefined,
|
|
185
185
|
state.factory.createNodeArray([
|
|
186
186
|
state.fromLiteral({
|
|
@@ -269,13 +269,13 @@ export class AssertTransformer {
|
|
|
269
269
|
|
|
270
270
|
@OnMethod('AssertCheck')
|
|
271
271
|
static onAssertCheck(state: TransformerState & AssertState, node: ts.MethodDeclaration): ts.MethodDeclaration {
|
|
272
|
-
state[
|
|
272
|
+
state[IsTestSymbol] = true;
|
|
273
273
|
return node;
|
|
274
274
|
}
|
|
275
275
|
|
|
276
276
|
@AfterMethod('AssertCheck')
|
|
277
277
|
static afterAssertCheck(state: TransformerState & AssertState, node: ts.MethodDeclaration): ts.MethodDeclaration {
|
|
278
|
-
state[
|
|
278
|
+
state[IsTestSymbol] = false;
|
|
279
279
|
return node;
|
|
280
280
|
}
|
|
281
281
|
|
|
@@ -285,7 +285,7 @@ export class AssertTransformer {
|
|
|
285
285
|
@OnCall()
|
|
286
286
|
static onAssertCall(state: TransformerState & AssertState, node: ts.CallExpression): ts.CallExpression {
|
|
287
287
|
// Only check in test mode
|
|
288
|
-
if (!state[
|
|
288
|
+
if (!state[IsTestSymbol]) {
|
|
289
289
|
return node;
|
|
290
290
|
}
|
|
291
291
|
|
package/support/bin/types.ts
DELETED