@travetto/test 8.0.0-alpha.0 → 8.0.0-alpha.2
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 +7 -7
- package/src/assert/util.ts +5 -7
- package/src/consumer/types/tap-summary.ts +1 -1
- package/src/decorator/suite.ts +1 -3
- package/src/execute/executor.ts +17 -3
- package/src/registry/registry-adapter.ts +20 -5
- package/support/bin/run.ts +1 -18
- package/support/cli.test.ts +4 -7
- package/support/cli.test_diff.ts +3 -6
- package/support/cli.test_direct.ts +3 -6
- package/support/cli.test_watch.ts +4 -6
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/test",
|
|
3
|
-
"version": "8.0.0-alpha.
|
|
3
|
+
"version": "8.0.0-alpha.2",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Declarative test framework",
|
|
6
6
|
"keywords": [
|
|
@@ -28,15 +28,15 @@
|
|
|
28
28
|
"directory": "module/test"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@travetto/registry": "^8.0.0-alpha.
|
|
32
|
-
"@travetto/runtime": "^8.0.0-alpha.
|
|
33
|
-
"@travetto/terminal": "^8.0.0-alpha.
|
|
34
|
-
"@travetto/worker": "^8.0.0-alpha.
|
|
31
|
+
"@travetto/registry": "^8.0.0-alpha.2",
|
|
32
|
+
"@travetto/runtime": "^8.0.0-alpha.2",
|
|
33
|
+
"@travetto/terminal": "^8.0.0-alpha.2",
|
|
34
|
+
"@travetto/worker": "^8.0.0-alpha.2",
|
|
35
35
|
"yaml": "^2.8.2"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
|
-
"@travetto/cli": "^8.0.0-alpha.
|
|
39
|
-
"@travetto/transformer": "^8.0.0-alpha.
|
|
38
|
+
"@travetto/cli": "^8.0.0-alpha.3",
|
|
39
|
+
"@travetto/transformer": "^8.0.0-alpha.2"
|
|
40
40
|
},
|
|
41
41
|
"peerDependenciesMeta": {
|
|
42
42
|
"@travetto/transformer": {
|
package/src/assert/util.ts
CHANGED
|
@@ -40,15 +40,13 @@ export class AssertUtil {
|
|
|
40
40
|
* Determine file location for a given error and the stack trace
|
|
41
41
|
*/
|
|
42
42
|
static getPositionOfError(error: Error): { import: string, line: number } | undefined {
|
|
43
|
-
const
|
|
44
|
-
const frames = Util.stackTraceToParts(stack)
|
|
43
|
+
const frames = Util.stackTraceToParts(error.stack ?? new Error().stack!)
|
|
45
44
|
.map(frame => {
|
|
46
|
-
const
|
|
47
|
-
return { ...frame, import:
|
|
48
|
-
})
|
|
49
|
-
.filter(frame => !!frame.import);
|
|
45
|
+
const entry = RuntimeIndex.getEntry(frame.filename);
|
|
46
|
+
return { ...frame, import: entry?.import!, line: entry?.type === 'ts' ? frame.line : 1 };
|
|
47
|
+
});
|
|
50
48
|
|
|
51
|
-
return frames
|
|
49
|
+
return frames.find(frame => frame.import);
|
|
52
50
|
}
|
|
53
51
|
|
|
54
52
|
/**
|
|
@@ -99,7 +99,7 @@ export class TapSummaryEmitter implements TestConsumerShape {
|
|
|
99
99
|
total[value.status] += 1;
|
|
100
100
|
total.count += 1;
|
|
101
101
|
const statusLine = `${total.failed} failed, ${total.errored} errored, ${total.skipped} skipped`;
|
|
102
|
-
return { value: `Tests %idx/%total [${statusLine}] -- ${value.classId}`, total: state.testCount, idx: total.
|
|
102
|
+
return { value: `Tests %idx/%total [${statusLine}] -- ${value.classId}`, total: state.testCount, idx: total.passed };
|
|
103
103
|
|
|
104
104
|
},
|
|
105
105
|
TerminalUtil.progressBarUpdater(this.#terminal, { style: () => ({ complete: (total.failed || total.errored) ? fail : success }) })
|
package/src/decorator/suite.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { castTo, type Class, type ClassInstance,
|
|
1
|
+
import { castTo, type Class, type ClassInstance, getClass } from '@travetto/runtime';
|
|
2
2
|
|
|
3
3
|
import type { SuiteConfig } from '../model/suite.ts';
|
|
4
4
|
import { SuiteRegistryIndex } from '../registry/registry-index.ts';
|
|
@@ -15,11 +15,9 @@ export function Suite(...rest: Partial<SuiteConfig>[]): ClassDecorator;
|
|
|
15
15
|
export function Suite(description: string, ...rest: Partial<SuiteConfig>[]): ClassDecorator;
|
|
16
16
|
export function Suite(description?: string | Partial<SuiteConfig>, ...rest: Partial<SuiteConfig>[]): ClassDecorator {
|
|
17
17
|
const decorator = (cls: Class): typeof cls => {
|
|
18
|
-
const isAbstract = describeFunction(cls).abstract;
|
|
19
18
|
SuiteRegistryIndex.getForRegister(cls).register(
|
|
20
19
|
...(typeof description !== 'string' && description ? [description] : []),
|
|
21
20
|
...rest,
|
|
22
|
-
...isAbstract ? [{ skip: true }] : [],
|
|
23
21
|
...(typeof description === 'string' ? [{ description }] : []),
|
|
24
22
|
);
|
|
25
23
|
return cls;
|
package/src/execute/executor.ts
CHANGED
|
@@ -92,7 +92,7 @@ export class TestExecutor {
|
|
|
92
92
|
/**
|
|
93
93
|
* An empty suite result based on a suite config
|
|
94
94
|
*/
|
|
95
|
-
createSuiteResult(suite: SuiteConfig): SuiteResult {
|
|
95
|
+
createSuiteResult(suite: SuiteConfig, override?: Partial<SuiteResult>): SuiteResult {
|
|
96
96
|
return {
|
|
97
97
|
passed: 0,
|
|
98
98
|
failed: 0,
|
|
@@ -107,7 +107,8 @@ export class TestExecutor {
|
|
|
107
107
|
classId: suite.classId,
|
|
108
108
|
sourceHash: suite.sourceHash,
|
|
109
109
|
duration: 0,
|
|
110
|
-
tests: {}
|
|
110
|
+
tests: {},
|
|
111
|
+
...override
|
|
111
112
|
};
|
|
112
113
|
}
|
|
113
114
|
|
|
@@ -176,7 +177,20 @@ export class TestExecutor {
|
|
|
176
177
|
|
|
177
178
|
suite.instance = classConstruct(suite.class);
|
|
178
179
|
|
|
179
|
-
|
|
180
|
+
const shouldSkip = await this.#shouldSkip(suite, suite.instance);
|
|
181
|
+
|
|
182
|
+
if (shouldSkip) {
|
|
183
|
+
this.#consumer.onEvent({
|
|
184
|
+
phase: 'after', type: 'suite',
|
|
185
|
+
suite: this.createSuiteResult(suite, {
|
|
186
|
+
status: 'skipped',
|
|
187
|
+
skipped: tests.length,
|
|
188
|
+
total: tests.length
|
|
189
|
+
})
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
if (shouldSkip || !tests.length) {
|
|
180
194
|
return;
|
|
181
195
|
}
|
|
182
196
|
|
|
@@ -8,7 +8,7 @@ import type { TestConfig } from '../model/test.ts';
|
|
|
8
8
|
function combineClasses(baseConfig: SuiteConfig, ...subConfig: Partial<SuiteConfig>[]): SuiteConfig {
|
|
9
9
|
for (const config of subConfig) {
|
|
10
10
|
if (config.tags) {
|
|
11
|
-
baseConfig.tags = [...baseConfig.tags ?? [], ...config.tags];
|
|
11
|
+
baseConfig.tags = [...new Set([...baseConfig.tags ?? [], ...config.tags])];
|
|
12
12
|
}
|
|
13
13
|
baseConfig.skip = config.skip ?? baseConfig.skip;
|
|
14
14
|
|
|
@@ -30,6 +30,21 @@ function combineClasses(baseConfig: SuiteConfig, ...subConfig: Partial<SuiteConf
|
|
|
30
30
|
return baseConfig;
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
function combineWithParent(baseConfig: SuiteConfig, parentConfig: SuiteConfig): SuiteConfig {
|
|
34
|
+
baseConfig.tags = [...parentConfig.tags ?? [], ...baseConfig.tags ?? []];
|
|
35
|
+
baseConfig.skip = baseConfig.skip ?? parentConfig.skip;
|
|
36
|
+
baseConfig.phaseHandlers = [...(parentConfig.phaseHandlers ?? []), ...(baseConfig.phaseHandlers ?? [])];
|
|
37
|
+
for (const [key, test] of Object.entries(parentConfig.tests ?? {})) {
|
|
38
|
+
baseConfig.tests[key] = {
|
|
39
|
+
...test,
|
|
40
|
+
class: baseConfig.class,
|
|
41
|
+
classId: baseConfig.classId,
|
|
42
|
+
import: baseConfig.import,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return baseConfig;
|
|
46
|
+
}
|
|
47
|
+
|
|
33
48
|
function combineMethods(suite: SuiteConfig, baseConfig: TestConfig, ...subConfig: Partial<TestConfig>[]): TestConfig {
|
|
34
49
|
baseConfig.classId = suite.classId;
|
|
35
50
|
baseConfig.import = suite.import;
|
|
@@ -54,12 +69,12 @@ export class SuiteRegistryAdapter implements RegistryAdapter<SuiteConfig> {
|
|
|
54
69
|
|
|
55
70
|
register(...data: Partial<SuiteConfig>[]): SuiteConfig {
|
|
56
71
|
if (!this.#config) {
|
|
57
|
-
const { lines, hash } = describeFunction(this.#cls) ?? {};
|
|
72
|
+
const { lines, hash, abstract: isAbstract } = describeFunction(this.#cls) ?? {};
|
|
58
73
|
this.#config = asFull<SuiteConfig>({
|
|
59
74
|
class: this.#cls,
|
|
60
75
|
classId: this.#cls.Ⲑid,
|
|
61
76
|
tags: [],
|
|
62
|
-
skip:
|
|
77
|
+
skip: isAbstract,
|
|
63
78
|
import: Runtime.getImport(this.#cls),
|
|
64
79
|
lineStart: lines?.[0],
|
|
65
80
|
lineEnd: lines?.[1],
|
|
@@ -99,11 +114,11 @@ export class SuiteRegistryAdapter implements RegistryAdapter<SuiteConfig> {
|
|
|
99
114
|
|
|
100
115
|
finalize(parent?: SuiteConfig): void {
|
|
101
116
|
if (parent) {
|
|
102
|
-
|
|
117
|
+
combineWithParent(this.#config, parent);
|
|
103
118
|
}
|
|
104
119
|
|
|
105
120
|
for (const test of Object.values(this.#config.tests)) {
|
|
106
|
-
test.tags = [...test.tags ?? [], ...this.#config.tags ?? []];
|
|
121
|
+
test.tags = [...new Set([...test.tags ?? [], ...this.#config.tags ?? []])];
|
|
107
122
|
test.description ||= SchemaRegistryIndex.get(this.#cls).getMethod(test.methodName).description;
|
|
108
123
|
}
|
|
109
124
|
}
|
package/support/bin/run.ts
CHANGED
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
import { getClass, Runtime } from '@travetto/runtime';
|
|
2
|
-
import { SchemaRegistryIndex } from '@travetto/schema';
|
|
3
|
-
|
|
4
|
-
import { TestConsumerRegistryIndex } from '../../src/consumer/registry-index.ts';
|
|
5
1
|
import type { TestConsumerConfig } from '../../src/execute/types.ts';
|
|
6
2
|
import type { TestRunInput } from '../../src/model/test.ts';
|
|
7
3
|
|
|
@@ -21,17 +17,4 @@ export async function runTests(state: TestConsumerConfig, input: TestRunInput):
|
|
|
21
17
|
}
|
|
22
18
|
}
|
|
23
19
|
|
|
24
|
-
export
|
|
25
|
-
if (instance.format?.includes('/')) {
|
|
26
|
-
await Runtime.importFrom(instance.format);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
const types = await TestConsumerRegistryIndex.getTypes();
|
|
30
|
-
|
|
31
|
-
SchemaRegistryIndex.getForRegister(getClass(instance), true).registerField('format', {
|
|
32
|
-
enum: {
|
|
33
|
-
message: `{path} is only allowed to be "${types.join('" or "')}"`,
|
|
34
|
-
values: types
|
|
35
|
-
}
|
|
36
|
-
});
|
|
37
|
-
}
|
|
20
|
+
export type TestConsumerType = 'tap' | 'tap-summary' | 'json' | 'exec' | 'event' | 'xunit' | 'custom';
|
package/support/cli.test.ts
CHANGED
|
@@ -5,6 +5,8 @@ import { type CliCommandShape, CliCommand, CliUtil } from '@travetto/cli';
|
|
|
5
5
|
import { WorkPool } from '@travetto/worker';
|
|
6
6
|
import { Max, Min } from '@travetto/schema';
|
|
7
7
|
|
|
8
|
+
import type { TestConsumerType } from './bin/run.ts';
|
|
9
|
+
|
|
8
10
|
/**
|
|
9
11
|
* Launch test framework and execute tests
|
|
10
12
|
*/
|
|
@@ -12,7 +14,7 @@ import { Max, Min } from '@travetto/schema';
|
|
|
12
14
|
export class TestCommand implements CliCommandShape {
|
|
13
15
|
|
|
14
16
|
/** Output format for test results */
|
|
15
|
-
format:
|
|
17
|
+
format: TestConsumerType = 'tap';
|
|
16
18
|
|
|
17
19
|
/** Number of tests to run concurrently */
|
|
18
20
|
@Min(1) @Max(WorkPool.MAX_SIZE)
|
|
@@ -30,7 +32,7 @@ export class TestCommand implements CliCommandShape {
|
|
|
30
32
|
*/
|
|
31
33
|
formatOptions?: string[];
|
|
32
34
|
|
|
33
|
-
|
|
35
|
+
finalize(): void {
|
|
34
36
|
EventEmitter.defaultMaxListeners = 1000;
|
|
35
37
|
Env.TRV_ROLE.set('test');
|
|
36
38
|
Env.DEBUG.set(false);
|
|
@@ -38,11 +40,6 @@ export class TestCommand implements CliCommandShape {
|
|
|
38
40
|
Env.TRV_LOG_TIME.clear();
|
|
39
41
|
}
|
|
40
42
|
|
|
41
|
-
async preValidate(): Promise<void> {
|
|
42
|
-
const { selectConsumer } = await import('./bin/run.ts');
|
|
43
|
-
await selectConsumer(this);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
43
|
async main(first: string = '**/*', globs: string[] = []): Promise<void> {
|
|
47
44
|
const { runTests } = await import('./bin/run.ts');
|
|
48
45
|
|
package/support/cli.test_diff.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { Env, JSONUtil, RuntimeIndex } from '@travetto/runtime';
|
|
|
4
4
|
import { CliCommand, CliUtil } from '@travetto/cli';
|
|
5
5
|
import { IsPrivate } from '@travetto/schema';
|
|
6
6
|
|
|
7
|
-
import { runTests,
|
|
7
|
+
import { runTests, type TestConsumerType } from './bin/run.ts';
|
|
8
8
|
import type { TestDiffSource } from '../src/model/test.ts';
|
|
9
9
|
|
|
10
10
|
/** Direct test invocation */
|
|
@@ -12,7 +12,8 @@ import type { TestDiffSource } from '../src/model/test.ts';
|
|
|
12
12
|
@IsPrivate()
|
|
13
13
|
export class TestDiffCommand {
|
|
14
14
|
|
|
15
|
-
format
|
|
15
|
+
/** Output format for test results */
|
|
16
|
+
format: TestConsumerType = 'tap';
|
|
16
17
|
|
|
17
18
|
/**
|
|
18
19
|
* Format options
|
|
@@ -20,10 +21,6 @@ export class TestDiffCommand {
|
|
|
20
21
|
*/
|
|
21
22
|
formatOptions?: string[];
|
|
22
23
|
|
|
23
|
-
async preValidate(): Promise<void> {
|
|
24
|
-
await selectConsumer(this);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
24
|
preMain(): void {
|
|
28
25
|
Env.TRV_ROLE.set('test');
|
|
29
26
|
Env.TRV_LOG_PLAIN.set(true);
|
|
@@ -2,14 +2,15 @@ import { Env, RuntimeIndex } from '@travetto/runtime';
|
|
|
2
2
|
import { CliCommand, CliUtil } from '@travetto/cli';
|
|
3
3
|
import { IsPrivate } from '@travetto/schema';
|
|
4
4
|
|
|
5
|
-
import { runTests,
|
|
5
|
+
import { runTests, type TestConsumerType } from './bin/run.ts';
|
|
6
6
|
|
|
7
7
|
/** Direct test invocation */
|
|
8
8
|
@CliCommand()
|
|
9
9
|
@IsPrivate()
|
|
10
10
|
export class TestDirectCommand {
|
|
11
11
|
|
|
12
|
-
format
|
|
12
|
+
/** Output format for test results */
|
|
13
|
+
format: TestConsumerType = 'tap';
|
|
13
14
|
|
|
14
15
|
/**
|
|
15
16
|
* Format options
|
|
@@ -17,10 +18,6 @@ export class TestDirectCommand {
|
|
|
17
18
|
*/
|
|
18
19
|
formatOptions?: string[];
|
|
19
20
|
|
|
20
|
-
async preValidate(): Promise<void> {
|
|
21
|
-
await selectConsumer(this);
|
|
22
|
-
}
|
|
23
|
-
|
|
24
21
|
preMain(): void {
|
|
25
22
|
Env.TRV_ROLE.set('test');
|
|
26
23
|
Env.TRV_LOG_PLAIN.set(true);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Env } from '@travetto/runtime';
|
|
2
2
|
import { CliCommand } from '@travetto/cli';
|
|
3
3
|
|
|
4
|
-
import {
|
|
4
|
+
import type { TestConsumerType } from './bin/run.ts';
|
|
5
5
|
|
|
6
6
|
/**
|
|
7
7
|
* Invoke the test watcher
|
|
@@ -9,12 +9,10 @@ import { selectConsumer } from './bin/run.ts';
|
|
|
9
9
|
@CliCommand()
|
|
10
10
|
export class TestWatcherCommand {
|
|
11
11
|
|
|
12
|
-
format
|
|
13
|
-
|
|
12
|
+
/** Output format for test results */
|
|
13
|
+
format: TestConsumerType = 'tap';
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
await selectConsumer(this);
|
|
17
|
-
}
|
|
15
|
+
mode: 'all' | 'change' = 'all';
|
|
18
16
|
|
|
19
17
|
preMain(): void {
|
|
20
18
|
Env.TRV_ROLE.set('test');
|