@travetto/test 8.0.0-alpha.6 → 8.0.0-alpha.8
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
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@travetto/test",
|
|
3
|
-
"version": "8.0.0-alpha.
|
|
3
|
+
"version": "8.0.0-alpha.8",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "Declarative test framework",
|
|
6
6
|
"keywords": [
|
|
@@ -28,14 +28,14 @@
|
|
|
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.8",
|
|
32
|
+
"@travetto/runtime": "^8.0.0-alpha.8",
|
|
33
|
+
"@travetto/terminal": "^8.0.0-alpha.8",
|
|
34
|
+
"@travetto/worker": "^8.0.0-alpha.8",
|
|
35
35
|
"yaml": "^2.8.2"
|
|
36
36
|
},
|
|
37
37
|
"peerDependencies": {
|
|
38
|
-
"@travetto/cli": "^8.0.0-alpha.
|
|
38
|
+
"@travetto/cli": "^8.0.0-alpha.13",
|
|
39
39
|
"@travetto/transformer": "^8.0.0-alpha.4"
|
|
40
40
|
},
|
|
41
41
|
"peerDependenciesMeta": {
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import path from 'node:path';
|
|
2
|
-
import { AssertionError } from 'node:assert';
|
|
3
2
|
import { stringify } from 'yaml';
|
|
4
3
|
|
|
5
4
|
import { Terminal, StyleUtil } from '@travetto/terminal';
|
|
@@ -9,6 +8,7 @@ import type { TestEvent } from '../../model/event.ts';
|
|
|
9
8
|
import type { SuitesSummary, TestConsumerShape } from '../types.ts';
|
|
10
9
|
import { TestConsumer } from '../decorator.ts';
|
|
11
10
|
import { type TestResultsEnhancer, CONSOLE_ENHANCER } from '../enhancer.ts';
|
|
11
|
+
import { TestConsumerUtil } from './util.ts';
|
|
12
12
|
|
|
13
13
|
const SPACE = ' ';
|
|
14
14
|
|
|
@@ -57,22 +57,6 @@ export class TapEmitter implements TestConsumerShape {
|
|
|
57
57
|
this.log(`---\n${this.#enhancer.objectInspect(body)}\n...`);
|
|
58
58
|
}
|
|
59
59
|
|
|
60
|
-
/**
|
|
61
|
-
* Error to string
|
|
62
|
-
* @param error
|
|
63
|
-
*/
|
|
64
|
-
errorToString(error?: Error): string | undefined {
|
|
65
|
-
if (error instanceof AssertionError) {
|
|
66
|
-
return;
|
|
67
|
-
} else if (error instanceof Error) {
|
|
68
|
-
return error.stack ?
|
|
69
|
-
error.stack.split(/\n/).slice(0, this.#options?.verbose ? -1 : 5).join('\n') :
|
|
70
|
-
error.message;
|
|
71
|
-
} else {
|
|
72
|
-
return `${error}`;
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
60
|
/**
|
|
77
61
|
* Listen for each event
|
|
78
62
|
*/
|
|
@@ -140,7 +124,7 @@ export class TapEmitter implements TestConsumerShape {
|
|
|
140
124
|
case 'errored':
|
|
141
125
|
case 'failed': {
|
|
142
126
|
if (test.error) {
|
|
143
|
-
const message =
|
|
127
|
+
const message = TestConsumerUtil.errorToString(test.error, !!this.#options?.verbose);
|
|
144
128
|
if (message) {
|
|
145
129
|
this.logMeta({ error: message });
|
|
146
130
|
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import util from 'node:util';
|
|
2
|
+
import { AssertionError } from 'node:assert';
|
|
3
|
+
|
|
4
|
+
import { TypedObject } from '@travetto/runtime';
|
|
5
|
+
|
|
6
|
+
export class TestConsumerUtil {
|
|
7
|
+
/**
|
|
8
|
+
* Convert error to string
|
|
9
|
+
*/
|
|
10
|
+
static errorToString(error?: Error, verbose?: boolean): string | undefined {
|
|
11
|
+
if (error instanceof AssertionError) {
|
|
12
|
+
return;
|
|
13
|
+
} else if (error instanceof Error) {
|
|
14
|
+
const stack = error.stack ?
|
|
15
|
+
error.stack.split(/\n/).slice(0, verbose ? -1 : 5).join('\n') :
|
|
16
|
+
error.message;
|
|
17
|
+
const subObject: Record<string, unknown> = {};
|
|
18
|
+
for (const key of TypedObject.keys(error)) {
|
|
19
|
+
if (key !== 'stack' && key !== 'message' && key !== 'name') {
|
|
20
|
+
subObject[key] = error[key];
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return `${stack}${Object.keys(subObject).length ? `\n${util.inspect(subObject)}` : ''}`;
|
|
24
|
+
} else {
|
|
25
|
+
return `${error}`;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
}
|
|
@@ -7,6 +7,7 @@ import { RuntimeIndex } from '@travetto/runtime';
|
|
|
7
7
|
import type { TestEvent } from '../../model/event.ts';
|
|
8
8
|
import type { SuitesSummary, TestConsumerShape } from '../types.ts';
|
|
9
9
|
import { TestConsumer } from '../decorator.ts';
|
|
10
|
+
import { TestConsumerUtil } from './util.ts';
|
|
10
11
|
|
|
11
12
|
/**
|
|
12
13
|
* Xunit consumer, compatible with JUnit formatters
|
|
@@ -59,9 +60,9 @@ export class XunitEmitter implements TestConsumerShape {
|
|
|
59
60
|
let body = '';
|
|
60
61
|
|
|
61
62
|
if (test.error) {
|
|
62
|
-
const
|
|
63
|
+
const errorMessage = TestConsumerUtil.errorToString(test.error);
|
|
63
64
|
const node = test.status === 'failed' ? 'failure' : 'error';
|
|
64
|
-
body = `<${node} type="${
|
|
65
|
+
body = `<${node} type="${test.error.constructor.name}" message="${encodeURIComponent(test.error.message)}"><![CDATA[${errorMessage}]]></${node}>`;
|
|
65
66
|
}
|
|
66
67
|
|
|
67
68
|
const groupedByLevel: Record<string, string[]> = {};
|
package/src/execute/executor.ts
CHANGED
|
@@ -31,15 +31,13 @@ export class TestExecutor {
|
|
|
31
31
|
*
|
|
32
32
|
* This method should never throw under any circumstances.
|
|
33
33
|
*/
|
|
34
|
-
async #executeTestMethod(test: TestConfig): Promise<Error | undefined> {
|
|
35
|
-
const suite = SuiteRegistryIndex.getConfig(test.class);
|
|
36
|
-
|
|
34
|
+
async #executeTestMethod(instance: unknown, test: TestConfig): Promise<Error | undefined> {
|
|
37
35
|
// Ensure all the criteria below are satisfied before moving forward
|
|
38
36
|
return Barrier.awaitOperation(test.timeout || TEST_TIMEOUT, async () => {
|
|
39
37
|
const env = process.env;
|
|
40
38
|
process.env = { ...env }; // Created an isolated environment
|
|
41
39
|
try {
|
|
42
|
-
await castTo<Record<string, Function>>(
|
|
40
|
+
await castTo<Record<string, Function>>(instance)[test.methodName]();
|
|
43
41
|
} finally {
|
|
44
42
|
process.env = env; // Restore
|
|
45
43
|
}
|
|
@@ -58,7 +56,7 @@ export class TestExecutor {
|
|
|
58
56
|
/**
|
|
59
57
|
* Execute the test, capture output, assertions and promises
|
|
60
58
|
*/
|
|
61
|
-
async executeTest(test: TestConfig, suite: SuiteConfig, override?: Partial<TestResult>): Promise<TestResult> {
|
|
59
|
+
async executeTest(instance: unknown, test: TestConfig, suite: SuiteConfig, override?: Partial<TestResult>): Promise<TestResult> {
|
|
62
60
|
|
|
63
61
|
const result = TestModelUtil.createTestResult(suite, test, override);
|
|
64
62
|
|
|
@@ -81,7 +79,7 @@ export class TestExecutor {
|
|
|
81
79
|
} else {
|
|
82
80
|
// Run method and get result
|
|
83
81
|
const startTime = Date.now();
|
|
84
|
-
const error = await this.#executeTestMethod(test);
|
|
82
|
+
const error = await this.#executeTestMethod(instance, test);
|
|
85
83
|
const [status, finalError] = AssertCheck.validateTestResultError(test, error);
|
|
86
84
|
result.status = status;
|
|
87
85
|
result.selfDuration = Date.now() - startTime;
|
|
@@ -104,9 +102,9 @@ export class TestExecutor {
|
|
|
104
102
|
*/
|
|
105
103
|
async executeSuite(suite: SuiteConfig, tests: TestConfig[]): Promise<void> {
|
|
106
104
|
|
|
107
|
-
|
|
105
|
+
const instance = classConstruct(suite.class);
|
|
108
106
|
|
|
109
|
-
const shouldSkip = await this.#shouldSkip(suite,
|
|
107
|
+
const shouldSkip = await this.#shouldSkip(suite, instance);
|
|
110
108
|
|
|
111
109
|
const result: SuiteResult = TestModelUtil.createSuiteResult(suite);
|
|
112
110
|
|
|
@@ -126,7 +124,7 @@ export class TestExecutor {
|
|
|
126
124
|
return;
|
|
127
125
|
}
|
|
128
126
|
|
|
129
|
-
const manager = new TestPhaseManager(suite);
|
|
127
|
+
const manager = new TestPhaseManager(suite, instance);
|
|
130
128
|
const originalEnv = { ...process.env };
|
|
131
129
|
const startTime = Date.now();
|
|
132
130
|
const testResultOverrides: Record<string, Partial<TestResult>> = {};
|
|
@@ -158,7 +156,7 @@ export class TestExecutor {
|
|
|
158
156
|
const testStart = Date.now();
|
|
159
157
|
const testResultOverride = (testResultOverrides[test.methodName] ??= {});
|
|
160
158
|
|
|
161
|
-
if (await this.#shouldSkip(test,
|
|
159
|
+
if (await this.#shouldSkip(test, instance)) {
|
|
162
160
|
testResultOverride.status = 'skipped';
|
|
163
161
|
}
|
|
164
162
|
|
|
@@ -172,7 +170,7 @@ export class TestExecutor {
|
|
|
172
170
|
}
|
|
173
171
|
|
|
174
172
|
// Run test
|
|
175
|
-
const testResult = await this.executeTest(test, suite, testResultOverride);
|
|
173
|
+
const testResult = await this.executeTest(instance, test, suite, testResultOverride);
|
|
176
174
|
|
|
177
175
|
// Handle after each
|
|
178
176
|
try {
|
package/src/execute/phase.ts
CHANGED
|
@@ -13,9 +13,11 @@ const TEST_PHASE_TIMEOUT = TimeUtil.duration(Env.TRV_TEST_PHASE_TIMEOUT.value ??
|
|
|
13
13
|
export class TestPhaseManager {
|
|
14
14
|
#progress: ('all' | 'each')[] = [];
|
|
15
15
|
#suite: SuiteConfig;
|
|
16
|
+
#instance: unknown;
|
|
16
17
|
|
|
17
|
-
constructor(suite: SuiteConfig) {
|
|
18
|
+
constructor(suite: SuiteConfig, instance: unknown) {
|
|
18
19
|
this.#suite = suite;
|
|
20
|
+
this.#instance = instance;
|
|
19
21
|
}
|
|
20
22
|
|
|
21
23
|
/**
|
|
@@ -29,7 +31,7 @@ export class TestPhaseManager {
|
|
|
29
31
|
}
|
|
30
32
|
|
|
31
33
|
// Ensure all the criteria below are satisfied before moving forward
|
|
32
|
-
error = await Barrier.awaitOperation(TEST_PHASE_TIMEOUT, async () => handler[phase]?.(this.#
|
|
34
|
+
error = await Barrier.awaitOperation(TEST_PHASE_TIMEOUT, async () => handler[phase]?.(this.#instance));
|
|
33
35
|
|
|
34
36
|
if (error) {
|
|
35
37
|
throw error;
|
package/src/execute/run.ts
CHANGED
|
@@ -3,7 +3,7 @@ import fs from 'node:fs/promises';
|
|
|
3
3
|
import readline from 'node:readline/promises';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
|
|
6
|
-
import { Env, ExecUtil, Util, RuntimeIndex, Runtime, TimeUtil, JSONUtil } from '@travetto/runtime';
|
|
6
|
+
import { Env, ExecUtil, Util, RuntimeIndex, Runtime, TimeUtil, JSONUtil, describeFunction } from '@travetto/runtime';
|
|
7
7
|
import { WorkPool } from '@travetto/worker';
|
|
8
8
|
import { Registry } from '@travetto/registry';
|
|
9
9
|
|
|
@@ -126,6 +126,7 @@ export class RunUtil {
|
|
|
126
126
|
const imported = await Registry.manualInit([importPath]);
|
|
127
127
|
const classes = Object.fromEntries(
|
|
128
128
|
imported
|
|
129
|
+
.filter(cls => !describeFunction(cls).abstract)
|
|
129
130
|
.filter(cls => SuiteRegistryIndex.hasConfig(cls))
|
|
130
131
|
.map(cls => [cls.Ⲑid, SuiteRegistryIndex.getConfig(cls)])
|
|
131
132
|
);
|