@travetto/test 5.0.0-rc.0 → 5.0.0-rc.10
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 +12 -13
- package/package.json +8 -8
- package/src/assert/capture.ts +5 -4
- package/src/assert/check.ts +24 -33
- package/src/assert/util.ts +32 -17
- package/src/consumer/registry.ts +2 -3
- package/src/consumer/{error.ts → serialize.ts} +13 -22
- package/src/consumer/types/cumulative.ts +15 -22
- package/src/consumer/types/delegating.ts +58 -0
- package/src/consumer/types/event.ts +2 -4
- package/src/consumer/types/execution.ts +2 -4
- package/src/consumer/types/runnable.ts +12 -41
- package/src/consumer/types/tap-streamed.ts +9 -6
- package/src/consumer/types/tap.ts +5 -5
- package/src/consumer/types/xunit.ts +4 -2
- package/src/decorator/suite.ts +5 -7
- package/src/decorator/test.ts +2 -1
- package/src/execute/console.ts +1 -1
- package/src/execute/executor.ts +84 -104
- package/src/execute/phase.ts +20 -30
- package/src/execute/promise.ts +4 -4
- package/src/execute/runner.ts +34 -24
- package/src/execute/types.ts +12 -10
- package/src/execute/util.ts +61 -34
- package/src/execute/watcher.ts +34 -36
- package/src/fixture.ts +7 -2
- package/src/model/common.ts +11 -7
- package/src/model/event.ts +9 -5
- package/src/model/suite.ts +14 -4
- package/src/model/test.ts +30 -4
- package/src/registry/suite.ts +42 -39
- package/src/trv.d.ts +3 -3
- package/src/worker/child.ts +11 -18
- package/src/worker/standard.ts +18 -21
- package/src/worker/types.ts +13 -10
- package/support/cli.test.ts +20 -6
- package/support/cli.test_child.ts +1 -1
- package/support/cli.test_digest.ts +43 -0
- package/support/cli.test_direct.ts +10 -3
- package/support/cli.test_watch.ts +1 -1
- package/support/transformer.assert.ts +12 -12
- package/support/cli.test_count.ts +0 -39
- package/support/transformer.annotate.ts +0 -103
package/src/registry/suite.ts
CHANGED
|
@@ -1,9 +1,8 @@
|
|
|
1
|
-
import { Class,
|
|
2
|
-
import { RuntimeIndex, RuntimeContext } from '@travetto/manifest';
|
|
1
|
+
import { Class, Runtime, classConstruct, describeFunction, asFull } from '@travetto/runtime';
|
|
3
2
|
import { MetadataRegistry } from '@travetto/registry';
|
|
4
3
|
|
|
5
4
|
import { SuiteConfig } from '../model/suite';
|
|
6
|
-
import { TestConfig } from '../model/test';
|
|
5
|
+
import { TestConfig, TestRun } from '../model/test';
|
|
7
6
|
|
|
8
7
|
/**
|
|
9
8
|
* Test Suite registry
|
|
@@ -14,18 +13,18 @@ class $SuiteRegistry extends MetadataRegistry<SuiteConfig, TestConfig> {
|
|
|
14
13
|
* Find all valid tests (ignoring abstract)
|
|
15
14
|
*/
|
|
16
15
|
getValidClasses(): Class[] {
|
|
17
|
-
return this.getClasses().filter(c => !
|
|
16
|
+
return this.getClasses().filter(c => !describeFunction(c).abstract);
|
|
18
17
|
}
|
|
19
18
|
|
|
20
19
|
createPending(cls: Class): Partial<SuiteConfig> {
|
|
21
|
-
const
|
|
20
|
+
const lines = describeFunction(cls)?.lines;
|
|
22
21
|
return {
|
|
23
22
|
class: cls,
|
|
24
|
-
module: RuntimeContext.main.name,
|
|
25
23
|
classId: cls.Ⲑid,
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
24
|
+
tags: [],
|
|
25
|
+
import: Runtime.getImport(cls),
|
|
26
|
+
lineStart: lines?.[0],
|
|
27
|
+
lineEnd: lines?.[1],
|
|
29
28
|
tests: [],
|
|
30
29
|
beforeAll: [],
|
|
31
30
|
beforeEach: [],
|
|
@@ -35,14 +34,14 @@ class $SuiteRegistry extends MetadataRegistry<SuiteConfig, TestConfig> {
|
|
|
35
34
|
}
|
|
36
35
|
|
|
37
36
|
override createPendingField(cls: Class, fn: Function): Partial<TestConfig> {
|
|
38
|
-
const
|
|
39
|
-
const meth = meta.methods![fn.name];
|
|
37
|
+
const lines = describeFunction(cls)?.methods?.[fn.name].lines;
|
|
40
38
|
return {
|
|
41
39
|
class: cls,
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
lineStart:
|
|
45
|
-
lineEnd:
|
|
40
|
+
tags: [],
|
|
41
|
+
import: Runtime.getImport(cls),
|
|
42
|
+
lineStart: lines?.[0],
|
|
43
|
+
lineEnd: lines?.[1],
|
|
44
|
+
lineBodyStart: lines?.[2],
|
|
46
45
|
methodName: fn.name
|
|
47
46
|
};
|
|
48
47
|
}
|
|
@@ -60,8 +59,7 @@ class $SuiteRegistry extends MetadataRegistry<SuiteConfig, TestConfig> {
|
|
|
60
59
|
* a full projection of all listeners and tests.
|
|
61
60
|
*/
|
|
62
61
|
onInstallFinalize<T>(cls: Class<T>): SuiteConfig {
|
|
63
|
-
|
|
64
|
-
const config = this.getOrCreatePending(cls) as SuiteConfig;
|
|
62
|
+
const config = asFull(this.getOrCreatePending(cls));
|
|
65
63
|
const tests = [...this.pendingFields.get(cls.Ⲑid)!.values()];
|
|
66
64
|
|
|
67
65
|
const parent = this.getParentClass(cls);
|
|
@@ -74,20 +72,19 @@ class $SuiteRegistry extends MetadataRegistry<SuiteConfig, TestConfig> {
|
|
|
74
72
|
config.beforeEach.push(...pConf.beforeEach);
|
|
75
73
|
tests.push(...[...pConf.tests.values()].map(t => ({
|
|
76
74
|
...t,
|
|
75
|
+
sourceImport: pConf.import,
|
|
77
76
|
class: cls
|
|
78
77
|
})));
|
|
79
78
|
}
|
|
80
79
|
|
|
81
|
-
|
|
82
|
-
config.
|
|
83
|
-
|
|
84
|
-
config.tests = tests as TestConfig[];
|
|
80
|
+
config.instance = classConstruct(config.class);
|
|
81
|
+
config.tests = tests!.map(x => asFull(x));
|
|
82
|
+
config.description ||= config.classId;
|
|
85
83
|
|
|
86
|
-
if (!config.description) {
|
|
87
|
-
config.description = config.classId;
|
|
88
|
-
}
|
|
89
84
|
for (const t of config.tests) {
|
|
90
85
|
t.classId = config.classId;
|
|
86
|
+
t.import = config.import;
|
|
87
|
+
t.tags = [...t.tags!, ...config.tags!];
|
|
91
88
|
}
|
|
92
89
|
return config;
|
|
93
90
|
}
|
|
@@ -95,33 +92,39 @@ class $SuiteRegistry extends MetadataRegistry<SuiteConfig, TestConfig> {
|
|
|
95
92
|
/**
|
|
96
93
|
* Get run parameters from provided input
|
|
97
94
|
*/
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
95
|
+
getSuiteTests(run: TestRun): { suite: SuiteConfig, tests: TestConfig[] }[] {
|
|
96
|
+
const clsId = run.classId;
|
|
97
|
+
const imp = run.import;
|
|
98
|
+
const methodNames = run.methodNames ?? [];
|
|
99
|
+
|
|
100
|
+
if (clsId && /^\d+$/.test(clsId)) { // If we only have a line number
|
|
101
|
+
const line = parseInt(clsId, 10);
|
|
102
|
+
const suites = this.getValidClasses()
|
|
103
|
+
.filter(cls => Runtime.getImport(cls) === imp)
|
|
104
|
+
.map(x => this.get(x)).filter(x => !x.skip);
|
|
102
105
|
const suite = suites.find(x => line >= x.lineStart && line <= x.lineEnd);
|
|
103
106
|
|
|
104
107
|
if (suite) {
|
|
105
108
|
const test = suite.tests.find(x => line >= x.lineStart && line <= x.lineEnd);
|
|
106
|
-
return test ? { suite, test } : { suite };
|
|
109
|
+
return test ? [{ suite, tests: [test] }] : [{ suite, tests: suite.tests }];
|
|
107
110
|
} else {
|
|
108
|
-
return {
|
|
111
|
+
return suites.map(x => ({ suite: x, tests: x.tests }));
|
|
109
112
|
}
|
|
110
113
|
} else { // Else lookup directly
|
|
111
|
-
if (
|
|
112
|
-
const cls = this.getValidClasses().find(x => x
|
|
114
|
+
if (methodNames.length) {
|
|
115
|
+
const cls = this.getValidClasses().find(x => x.Ⲑid === clsId)!;
|
|
113
116
|
const suite = this.get(cls);
|
|
114
|
-
const
|
|
115
|
-
return { suite,
|
|
116
|
-
} else if (
|
|
117
|
-
const cls = this.getValidClasses().find(x => x
|
|
117
|
+
const tests = suite.tests.filter(x => methodNames.includes(x.methodName))!;
|
|
118
|
+
return [{ suite, tests }];
|
|
119
|
+
} else if (clsId) {
|
|
120
|
+
const cls = this.getValidClasses().find(x => x.Ⲑid === clsId)!;
|
|
118
121
|
const suite = this.get(cls);
|
|
119
|
-
return { suite };
|
|
122
|
+
return [{ suite, tests: suite.tests }];
|
|
120
123
|
} else {
|
|
121
124
|
const suites = this.getValidClasses()
|
|
122
125
|
.map(x => this.get(x))
|
|
123
|
-
.filter(x => !
|
|
124
|
-
return {
|
|
126
|
+
.filter(x => !describeFunction(x.class).abstract); // Do not run abstract suites
|
|
127
|
+
return suites.map(x => ({ suite: x, tests: x.tests }));
|
|
125
128
|
}
|
|
126
129
|
}
|
|
127
130
|
}
|
package/src/trv.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TimeSpan } from '@travetto/
|
|
1
|
+
import { TimeSpan } from '@travetto/runtime';
|
|
2
2
|
|
|
3
3
|
declare global {
|
|
4
4
|
interface TravettoEnv {
|
|
@@ -13,8 +13,8 @@ declare global {
|
|
|
13
13
|
*/
|
|
14
14
|
TRV_TEST_TIMEOUT: TimeSpan | number;
|
|
15
15
|
/**
|
|
16
|
-
*
|
|
16
|
+
* The tags to include or exclude during testing
|
|
17
17
|
*/
|
|
18
|
-
|
|
18
|
+
TRV_TEST_TAGS: string[];
|
|
19
19
|
}
|
|
20
20
|
}
|
package/src/worker/child.ts
CHANGED
|
@@ -1,19 +1,19 @@
|
|
|
1
1
|
import { createWriteStream } from 'node:fs';
|
|
2
2
|
|
|
3
|
-
import {
|
|
4
|
-
import { ConsoleManager, Env, Util } from '@travetto/base';
|
|
3
|
+
import { ConsoleManager, Env, Util, Runtime } from '@travetto/runtime';
|
|
5
4
|
import { ChildCommChannel } from '@travetto/worker';
|
|
6
5
|
|
|
7
|
-
import {
|
|
6
|
+
import { SerializeUtil } from '../consumer/serialize';
|
|
8
7
|
import { RunnerUtil } from '../execute/util';
|
|
9
8
|
import { Runner } from '../execute/runner';
|
|
10
|
-
import { Events
|
|
9
|
+
import { Events } from './types';
|
|
10
|
+
import { TestRun } from '../model/test';
|
|
11
11
|
|
|
12
12
|
/**
|
|
13
13
|
* Child Worker for the Test Runner. Receives events as commands
|
|
14
14
|
* to run specific tests
|
|
15
15
|
*/
|
|
16
|
-
export class TestChildWorker extends ChildCommChannel<
|
|
16
|
+
export class TestChildWorker extends ChildCommChannel<TestRun> {
|
|
17
17
|
|
|
18
18
|
#done = Util.resolvablePromise();
|
|
19
19
|
|
|
@@ -26,7 +26,7 @@ export class TestChildWorker extends ChildCommChannel<RunEvent> {
|
|
|
26
26
|
throw err;
|
|
27
27
|
}
|
|
28
28
|
// Mark as errored out
|
|
29
|
-
this.send(type, { error:
|
|
29
|
+
this.send(type, { error: SerializeUtil.serializeError(err) });
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -35,7 +35,7 @@ export class TestChildWorker extends ChildCommChannel<RunEvent> {
|
|
|
35
35
|
*/
|
|
36
36
|
async activate(): Promise<void> {
|
|
37
37
|
if (/\b@travetto[/]test\b/.test(Env.DEBUG.val ?? '')) {
|
|
38
|
-
const file =
|
|
38
|
+
const file = Runtime.toolPath(`test-worker.${process.pid}.log`);
|
|
39
39
|
const stdout = createWriteStream(file, { flags: 'a' });
|
|
40
40
|
const c = new console.Console({ stdout, inspectOptions: { depth: 4, colors: false } });
|
|
41
41
|
ConsoleManager.set({ log: (ev) => c[ev.level](process.pid, ...ev.args) });
|
|
@@ -57,7 +57,7 @@ export class TestChildWorker extends ChildCommChannel<RunEvent> {
|
|
|
57
57
|
/**
|
|
58
58
|
* When we receive a command from the parent
|
|
59
59
|
*/
|
|
60
|
-
async onCommand(event:
|
|
60
|
+
async onCommand(event: TestRun & { type: string }): Promise<boolean> {
|
|
61
61
|
console.debug('on message', { ...event });
|
|
62
62
|
|
|
63
63
|
if (event.type === Events.INIT) { // On request to init, start initialization
|
|
@@ -77,18 +77,11 @@ export class TestChildWorker extends ChildCommChannel<RunEvent> {
|
|
|
77
77
|
/**
|
|
78
78
|
* Run a specific test/suite
|
|
79
79
|
*/
|
|
80
|
-
async onRunCommand(
|
|
81
|
-
console.debug('
|
|
82
|
-
|
|
83
|
-
console.debug('Running', { file: event.file });
|
|
80
|
+
async onRunCommand(run: TestRun): Promise<void> {
|
|
81
|
+
console.debug('Running', { import: run.import });
|
|
84
82
|
|
|
85
83
|
try {
|
|
86
|
-
await new Runner({
|
|
87
|
-
format: 'exec',
|
|
88
|
-
mode: 'single',
|
|
89
|
-
args: [event.file!, event.class!, event.method!],
|
|
90
|
-
concurrency: 1
|
|
91
|
-
}).run();
|
|
84
|
+
await new Runner({ format: 'exec', target: run }).run();
|
|
92
85
|
} finally {
|
|
93
86
|
this.#done.resolve();
|
|
94
87
|
}
|
package/src/worker/standard.ts
CHANGED
|
@@ -1,39 +1,36 @@
|
|
|
1
1
|
import { fork } from 'node:child_process';
|
|
2
2
|
|
|
3
|
-
import { RuntimeIndex } from '@travetto/
|
|
4
|
-
import { Env } from '@travetto/base';
|
|
3
|
+
import { Env, RuntimeIndex } from '@travetto/runtime';
|
|
5
4
|
import { ParentCommChannel } from '@travetto/worker';
|
|
6
5
|
|
|
7
|
-
import { Events,
|
|
6
|
+
import { Events, TestLogEvent } from './types';
|
|
8
7
|
import { TestConsumer } from '../consumer/types';
|
|
9
|
-
import {
|
|
8
|
+
import { SerializeUtil } from '../consumer/serialize';
|
|
10
9
|
import { TestEvent } from '../model/event';
|
|
10
|
+
import { TestRun } from '../model/test';
|
|
11
|
+
|
|
12
|
+
const log = (message: string): void => {
|
|
13
|
+
process.send?.({ type: 'log', message } satisfies TestLogEvent);
|
|
14
|
+
};
|
|
11
15
|
|
|
12
16
|
/**
|
|
13
17
|
* Produce a handler for the child worker
|
|
14
18
|
*/
|
|
15
|
-
export async function buildStandardTestManager(consumer: TestConsumer,
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
let event: RunEvent;
|
|
19
|
-
if (file.includes('#')) {
|
|
20
|
-
const [f, cls, method] = file.split('#');
|
|
21
|
-
event = { file: f, class: cls, method };
|
|
22
|
-
} else {
|
|
23
|
-
event = { file };
|
|
24
|
-
}
|
|
19
|
+
export async function buildStandardTestManager(consumer: TestConsumer, run: TestRun): Promise<void> {
|
|
20
|
+
log(`Worker Input ${JSON.stringify(run)}`);
|
|
21
|
+
log(`Worker Executing ${run.import}`);
|
|
25
22
|
|
|
26
|
-
const { module } = RuntimeIndex.
|
|
27
|
-
const
|
|
23
|
+
const { module } = RuntimeIndex.getFromImport(run.import)!;
|
|
24
|
+
const suiteMod = RuntimeIndex.getModule(module)!;
|
|
28
25
|
|
|
29
26
|
const channel = new ParentCommChannel<TestEvent & { error?: Error }>(
|
|
30
27
|
fork(
|
|
31
28
|
RuntimeIndex.resolveFileImport('@travetto/cli/support/entry.trv'), ['test:child'],
|
|
32
29
|
{
|
|
33
|
-
cwd,
|
|
30
|
+
cwd: suiteMod.sourcePath,
|
|
34
31
|
env: {
|
|
35
32
|
...process.env,
|
|
36
|
-
...Env.TRV_MANIFEST.export(
|
|
33
|
+
...Env.TRV_MANIFEST.export(suiteMod.outputPath),
|
|
37
34
|
...Env.TRV_QUIET.export(true)
|
|
38
35
|
},
|
|
39
36
|
stdio: ['ignore', 'ignore', 2, 'ipc']
|
|
@@ -56,7 +53,7 @@ export async function buildStandardTestManager(consumer: TestConsumer, file: str
|
|
|
56
53
|
// Listen for child to complete
|
|
57
54
|
const complete = channel.once(Events.RUN_COMPLETE);
|
|
58
55
|
// Start test
|
|
59
|
-
channel.send(Events.RUN,
|
|
56
|
+
channel.send(Events.RUN, run);
|
|
60
57
|
|
|
61
58
|
// Wait for complete
|
|
62
59
|
const { error } = await complete;
|
|
@@ -64,10 +61,10 @@ export async function buildStandardTestManager(consumer: TestConsumer, file: str
|
|
|
64
61
|
// Kill on complete
|
|
65
62
|
await channel.destroy();
|
|
66
63
|
|
|
67
|
-
|
|
64
|
+
log(`Worker Finished ${run.import}`);
|
|
68
65
|
|
|
69
66
|
// If we received an error, throw it
|
|
70
67
|
if (error) {
|
|
71
|
-
throw
|
|
68
|
+
throw SerializeUtil.deserializeError(error);
|
|
72
69
|
}
|
|
73
70
|
}
|
package/src/worker/types.ts
CHANGED
|
@@ -1,12 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
*/
|
|
4
|
-
export type RunEvent = {
|
|
5
|
-
file?: string;
|
|
6
|
-
error?: unknown;
|
|
7
|
-
class?: string;
|
|
8
|
-
method?: string;
|
|
9
|
-
};
|
|
1
|
+
import { TestEvent } from '../model/event';
|
|
2
|
+
import { TestRun } from '../model/test';
|
|
10
3
|
|
|
11
4
|
/**
|
|
12
5
|
* Test Run Event Keys
|
|
@@ -17,4 +10,14 @@ export const Events = {
|
|
|
17
10
|
INIT: 'init',
|
|
18
11
|
INIT_COMPLETE: 'initComplete',
|
|
19
12
|
READY: 'ready'
|
|
20
|
-
};
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export type TestRemovedEvent = { type: 'removeTest', method?: string } & TestRun;
|
|
16
|
+
export type TestReadyEvent = { type: 'ready' };
|
|
17
|
+
export type TestLogEvent = { type: 'log', message: string };
|
|
18
|
+
|
|
19
|
+
export type TestWatchEvent =
|
|
20
|
+
TestEvent |
|
|
21
|
+
TestRemovedEvent |
|
|
22
|
+
TestReadyEvent |
|
|
23
|
+
TestLogEvent;
|
package/support/cli.test.ts
CHANGED
|
@@ -2,7 +2,7 @@ import { EventEmitter } from 'node:events';
|
|
|
2
2
|
import fs from 'node:fs/promises';
|
|
3
3
|
import path from 'node:path';
|
|
4
4
|
|
|
5
|
-
import { Env } from '@travetto/
|
|
5
|
+
import { Env } from '@travetto/runtime';
|
|
6
6
|
import { CliCommandShape, CliCommand, CliValidationError } from '@travetto/cli';
|
|
7
7
|
import { WorkPool } from '@travetto/worker';
|
|
8
8
|
import { Max, Min } from '@travetto/schema';
|
|
@@ -21,6 +21,11 @@ export class TestCommand implements CliCommandShape {
|
|
|
21
21
|
concurrency: number = WorkPool.DEFAULT_SIZE;
|
|
22
22
|
/** Test run mode */
|
|
23
23
|
mode: TestMode = 'standard';
|
|
24
|
+
/**
|
|
25
|
+
* Tags to target or exclude
|
|
26
|
+
* @alias env.TRV_TEST_TAGS
|
|
27
|
+
*/
|
|
28
|
+
tags?: string[];
|
|
24
29
|
|
|
25
30
|
preMain(): void {
|
|
26
31
|
EventEmitter.defaultMaxListeners = 1000;
|
|
@@ -39,7 +44,7 @@ export class TestCommand implements CliCommandShape {
|
|
|
39
44
|
return (await this.isFirstFile(first)) && rest.length === 0 ? 'single' : this.mode;
|
|
40
45
|
}
|
|
41
46
|
|
|
42
|
-
async validate(first: string = '
|
|
47
|
+
async validate(first: string = '**/*', rest: string[]): Promise<CliValidationError | undefined> {
|
|
43
48
|
|
|
44
49
|
const mode = await this.resolvedMode(first, rest);
|
|
45
50
|
|
|
@@ -48,14 +53,23 @@ export class TestCommand implements CliCommandShape {
|
|
|
48
53
|
}
|
|
49
54
|
}
|
|
50
55
|
|
|
51
|
-
async main(first: string = '
|
|
56
|
+
async main(first: string = '**/*', globs: string[] = []): Promise<void> {
|
|
52
57
|
const { runTests } = await import('./bin/run');
|
|
53
58
|
|
|
59
|
+
const isFirst = await this.isFirstFile(first);
|
|
60
|
+
const isSingle = this.mode === 'single' || (isFirst && globs.length === 0);
|
|
61
|
+
|
|
54
62
|
return runTests({
|
|
55
|
-
args: [first, ...regexes],
|
|
56
|
-
mode: await this.resolvedMode(first, regexes),
|
|
57
63
|
concurrency: this.concurrency,
|
|
58
|
-
format: this.format
|
|
64
|
+
format: this.format,
|
|
65
|
+
tags: this.tags,
|
|
66
|
+
target: isSingle ?
|
|
67
|
+
{
|
|
68
|
+
import: first,
|
|
69
|
+
classId: globs[0],
|
|
70
|
+
methodNames: globs.slice(1),
|
|
71
|
+
} :
|
|
72
|
+
{ globs: [first, ...globs], }
|
|
59
73
|
});
|
|
60
74
|
}
|
|
61
75
|
}
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { CliCommand } from '@travetto/cli';
|
|
2
|
+
import { Env, Runtime, describeFunction } from '@travetto/runtime';
|
|
3
|
+
|
|
4
|
+
import { SuiteRegistry } from '../src/registry/suite';
|
|
5
|
+
import { RunnerUtil } from '../src/execute/util';
|
|
6
|
+
|
|
7
|
+
@CliCommand({ hidden: true })
|
|
8
|
+
export class TestDigestCommand {
|
|
9
|
+
|
|
10
|
+
output: 'json' | 'text' = 'text';
|
|
11
|
+
|
|
12
|
+
preMain(): void {
|
|
13
|
+
Env.TRV_ROLE.set('test');
|
|
14
|
+
Env.DEBUG.set(false);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
async main(globs: string[] = ['**/*.ts']) {
|
|
18
|
+
// Load all tests
|
|
19
|
+
for await (const imp of await RunnerUtil.getTestImports(globs)) {
|
|
20
|
+
try {
|
|
21
|
+
await Runtime.importFrom(imp);
|
|
22
|
+
} catch (err) {
|
|
23
|
+
console.error('Failed to import', imp, err);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
await SuiteRegistry.init();
|
|
28
|
+
|
|
29
|
+
const suites = SuiteRegistry.getClasses();
|
|
30
|
+
const all = suites
|
|
31
|
+
.map(c => SuiteRegistry.get(c))
|
|
32
|
+
.filter(c => !describeFunction(c.class).abstract)
|
|
33
|
+
.flatMap(c => c.tests);
|
|
34
|
+
|
|
35
|
+
if (this.output === 'json') {
|
|
36
|
+
console.log(JSON.stringify(all));
|
|
37
|
+
} else {
|
|
38
|
+
for (const item of all) {
|
|
39
|
+
console.log(`${item.classId}#${item.methodName}`, item.tags?.join('|') ?? '');
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Env } from '@travetto/
|
|
1
|
+
import { Env, RuntimeIndex } from '@travetto/runtime';
|
|
2
2
|
import { CliCommand } from '@travetto/cli';
|
|
3
3
|
|
|
4
4
|
import { runTests } from './bin/run';
|
|
@@ -17,7 +17,14 @@ export class TestDirectCommand {
|
|
|
17
17
|
Env.TRV_LOG_TIME.clear();
|
|
18
18
|
}
|
|
19
19
|
|
|
20
|
-
main(
|
|
21
|
-
return runTests({
|
|
20
|
+
main(importOrFile: string, clsId?: string, methodsNames: string[] = []): Promise<void> {
|
|
21
|
+
return runTests({
|
|
22
|
+
format: this.format,
|
|
23
|
+
target: {
|
|
24
|
+
import: importOrFile,
|
|
25
|
+
classId: clsId,
|
|
26
|
+
methodNames: methodsNames,
|
|
27
|
+
}
|
|
28
|
+
});
|
|
22
29
|
}
|
|
23
30
|
}
|
|
@@ -93,7 +93,7 @@ export class AssertTransformer {
|
|
|
93
93
|
/**
|
|
94
94
|
* Resolves optoken to syntax kind. Relies on `ts`
|
|
95
95
|
*/
|
|
96
|
-
static lookupOpToken(key: number): string {
|
|
96
|
+
static lookupOpToken(key: number): string | undefined {
|
|
97
97
|
if (OP_TOKEN_TO_NAME.size === 0) {
|
|
98
98
|
Object.keys(ts.SyntaxKind)
|
|
99
99
|
.filter(x => !/^\d+$/.test(x))
|
|
@@ -106,7 +106,7 @@ export class AssertTransformer {
|
|
|
106
106
|
if (name in OPTOKEN_ASSERT) {
|
|
107
107
|
return OPTOKEN_ASSERT[name];
|
|
108
108
|
} else {
|
|
109
|
-
|
|
109
|
+
return;
|
|
110
110
|
}
|
|
111
111
|
}
|
|
112
112
|
|
|
@@ -137,12 +137,12 @@ export class AssertTransformer {
|
|
|
137
137
|
*/
|
|
138
138
|
static initState(state: TransformerState & AssertState): void {
|
|
139
139
|
if (!state[AssertⲐ]) {
|
|
140
|
-
const
|
|
140
|
+
const asrt = state.importFile('@travetto/test/src/assert/check').ident;
|
|
141
141
|
state[AssertⲐ] = {
|
|
142
|
-
assert:
|
|
143
|
-
assertCheck: CoreUtil.createAccess(state.factory,
|
|
144
|
-
checkThrow: CoreUtil.createAccess(state.factory,
|
|
145
|
-
checkThrowAsync: CoreUtil.createAccess(state.factory,
|
|
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,13 +153,13 @@ 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.
|
|
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);
|
|
160
160
|
const check = state.factory.createCallExpression(state[AssertⲐ]!.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),
|
|
164
164
|
text: state.fromLiteral(firstText),
|
|
165
165
|
operator: state.fromLiteral(cmd.fn)
|
|
@@ -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.
|
|
179
|
-
const firstText = first
|
|
178
|
+
const first = CoreUtil.firstArgument(node)!;
|
|
179
|
+
const firstText = first.getText();
|
|
180
180
|
|
|
181
181
|
this.initState(state);
|
|
182
182
|
return state.factory.createCallExpression(
|
|
@@ -184,7 +184,7 @@ export class AssertTransformer {
|
|
|
184
184
|
undefined,
|
|
185
185
|
state.factory.createNodeArray([
|
|
186
186
|
state.fromLiteral({
|
|
187
|
-
|
|
187
|
+
module: state.getModuleIdentifier(),
|
|
188
188
|
line: state.fromLiteral(ts.getLineAndCharacterOfPosition(state.source, node.getStart()).line + 1),
|
|
189
189
|
text: state.fromLiteral(`${key} ${firstText}`),
|
|
190
190
|
operator: state.fromLiteral(`${key}`)
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { CliCommand } from '@travetto/cli';
|
|
2
|
-
import { RuntimeIndex } from '@travetto/manifest';
|
|
3
|
-
import { Env } from '@travetto/base';
|
|
4
|
-
|
|
5
|
-
import { SuiteRegistry } from '../src/registry/suite';
|
|
6
|
-
import { RunnerUtil } from '../src/execute/util';
|
|
7
|
-
|
|
8
|
-
@CliCommand({ hidden: true })
|
|
9
|
-
export class TestCountCommand {
|
|
10
|
-
|
|
11
|
-
preMain(): void {
|
|
12
|
-
Env.TRV_ROLE.set('test');
|
|
13
|
-
Env.DEBUG.set(false);
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
async main(patterns: string[]) {
|
|
17
|
-
const regexes = patterns.map(x => new RegExp(x));
|
|
18
|
-
const files = await RunnerUtil.getTestFiles(regexes);
|
|
19
|
-
|
|
20
|
-
// Load all tests
|
|
21
|
-
for (const file of files) {
|
|
22
|
-
try {
|
|
23
|
-
await import(file.import);
|
|
24
|
-
} catch (err) {
|
|
25
|
-
console.error('Failed to import', file.sourceFile, err);
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
await SuiteRegistry.init();
|
|
30
|
-
|
|
31
|
-
const suites = SuiteRegistry.getClasses();
|
|
32
|
-
const total = suites
|
|
33
|
-
.map(c => SuiteRegistry.get(c))
|
|
34
|
-
.filter(c => !RuntimeIndex.getFunctionMetadata(c.class)?.abstract)
|
|
35
|
-
.reduce((acc, c) => acc + (c.tests?.length ?? 0), 0);
|
|
36
|
-
|
|
37
|
-
console.log(total);
|
|
38
|
-
}
|
|
39
|
-
}
|