@unrift/core 0.4.0 → 0.5.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/dist/esm/cli.js +14 -1
- package/dist/esm/expect.d.ts +2 -0
- package/dist/esm/expect.d.ts.map +1 -1
- package/dist/esm/index.d.ts +1 -1
- package/dist/esm/index.d.ts.map +1 -1
- package/dist/esm/interface.d.ts +7 -3
- package/dist/esm/interface.d.ts.map +1 -1
- package/dist/esm/interface.js +9 -5
- package/dist/esm/matchers.js +34 -0
- package/dist/esm/run.d.ts +4 -7
- package/dist/esm/run.d.ts.map +1 -1
- package/dist/esm/run.js +6 -2
- package/dist/esm/runner.d.ts +1 -0
- package/dist/esm/runner.d.ts.map +1 -1
- package/dist/esm/runner.js +8 -2
- package/dist/esm/suite.d.ts +24 -6
- package/dist/esm/suite.d.ts.map +1 -1
- package/dist/esm/suite.js +114 -20
- package/dist/esm/test.d.ts +5 -1
- package/dist/esm/test.d.ts.map +1 -1
- package/dist/esm/test.js +8 -1
- package/dist/esm/utils/defineConfig.d.ts +1 -0
- package/dist/esm/utils/defineConfig.d.ts.map +1 -1
- package/dist/esm/utils/helpers.d.ts +2 -0
- package/dist/esm/utils/helpers.d.ts.map +1 -1
- package/dist/esm/utils/helpers.js +7 -0
- package/package.json +1 -1
package/dist/esm/cli.js
CHANGED
|
@@ -36,6 +36,7 @@ Usage:
|
|
|
36
36
|
|
|
37
37
|
Options:
|
|
38
38
|
-c, --config <path> Path to config file
|
|
39
|
+
-g, --grep <pattern> Only run tests whose full name matches (regex)
|
|
39
40
|
-b, --bail Stop on first test failure
|
|
40
41
|
-t, --timeout <ms> Default test timeout in milliseconds
|
|
41
42
|
-w, --watch Re-run tests on file changes
|
|
@@ -49,6 +50,7 @@ Options:
|
|
|
49
50
|
Examples:
|
|
50
51
|
unrift
|
|
51
52
|
unrift math
|
|
53
|
+
unrift --grep "adds numbers"
|
|
52
54
|
unrift -c test/config.ts --bail
|
|
53
55
|
unrift --timeout 10000
|
|
54
56
|
unrift --watch
|
|
@@ -57,6 +59,7 @@ Examples:
|
|
|
57
59
|
function parseArgs(argv) {
|
|
58
60
|
let configPath;
|
|
59
61
|
let pattern;
|
|
62
|
+
let grep;
|
|
60
63
|
let timeoutMs;
|
|
61
64
|
let bail;
|
|
62
65
|
let debug = false;
|
|
@@ -85,6 +88,14 @@ function parseArgs(argv) {
|
|
|
85
88
|
i++;
|
|
86
89
|
continue;
|
|
87
90
|
}
|
|
91
|
+
if (a === "--grep" || a === "-g") {
|
|
92
|
+
const next = argv[i + 1];
|
|
93
|
+
if (!next)
|
|
94
|
+
throw new Error(`${a} requires a pattern`);
|
|
95
|
+
grep = safeRegExp(next);
|
|
96
|
+
i++;
|
|
97
|
+
continue;
|
|
98
|
+
}
|
|
88
99
|
if (a === "--bail" || a === "-b") {
|
|
89
100
|
bail = true;
|
|
90
101
|
continue;
|
|
@@ -127,6 +138,7 @@ function parseArgs(argv) {
|
|
|
127
138
|
return {
|
|
128
139
|
configPath,
|
|
129
140
|
pattern,
|
|
141
|
+
grep,
|
|
130
142
|
timeoutMs,
|
|
131
143
|
bail,
|
|
132
144
|
debug,
|
|
@@ -138,7 +150,7 @@ function parseArgs(argv) {
|
|
|
138
150
|
showVersion,
|
|
139
151
|
};
|
|
140
152
|
}
|
|
141
|
-
const { configPath, pattern, timeoutMs, bail, debug, list, json, cacheClean, watch, help, showVersion, } = parseArgs(process.argv.slice(2));
|
|
153
|
+
const { configPath, pattern, grep, timeoutMs, bail, debug, list, json, cacheClean, watch, help, showVersion, } = parseArgs(process.argv.slice(2));
|
|
142
154
|
if (showVersion) {
|
|
143
155
|
console.log(version);
|
|
144
156
|
process.exit(0);
|
|
@@ -149,6 +161,7 @@ if (help) {
|
|
|
149
161
|
}
|
|
150
162
|
const runOpts = {
|
|
151
163
|
pattern,
|
|
164
|
+
grep,
|
|
152
165
|
configPath,
|
|
153
166
|
timeoutMs,
|
|
154
167
|
bail,
|
package/dist/esm/expect.d.ts
CHANGED
|
@@ -17,6 +17,7 @@ export interface Matchers<T> {
|
|
|
17
17
|
prototype: unknown;
|
|
18
18
|
}): void | Promise<void>;
|
|
19
19
|
toContain(expected: unknown): void | Promise<void>;
|
|
20
|
+
toContainEqual(expected: unknown): void | Promise<void>;
|
|
20
21
|
toEqual(expected: unknown): void | Promise<void>;
|
|
21
22
|
toHaveLength(expected: number): void | Promise<void>;
|
|
22
23
|
toMatch(expected: RegExp | string): void | Promise<void>;
|
|
@@ -24,6 +25,7 @@ export interface Matchers<T> {
|
|
|
24
25
|
toThrow(expected?: unknown): void | Promise<void>;
|
|
25
26
|
toBeGreaterThanOrEqual(expected: number): void | Promise<void>;
|
|
26
27
|
toBeLessThanOrEqual(expected: number): void | Promise<void>;
|
|
28
|
+
toBeCloseTo(expected: number, precision?: number): void | Promise<void>;
|
|
27
29
|
toBeNaN(): void | Promise<void>;
|
|
28
30
|
toBeFinite(): void | Promise<void>;
|
|
29
31
|
toMatchObject(expected: Record<string, unknown>): void | Promise<void>;
|
package/dist/esm/expect.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"expect.d.ts","sourceRoot":"","sources":["../../src/expect.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"expect.d.ts","sourceRoot":"","sources":["../../src/expect.ts"],"names":[],"mappings":"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"}
|
package/dist/esm/index.d.ts
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
export { beforeEach, afterEach, beforeAll, afterAll } from "./hooks";
|
|
2
2
|
export { defineConfig, type UnriftConfigOptions } from "./utils/defineConfig";
|
|
3
|
-
export { describe, it, test } from "./interface";
|
|
3
|
+
export { describe, it, test, type TestOptions } from "./interface";
|
|
4
4
|
export { expect, extendMatchers } from "./expect";
|
|
5
5
|
export type { Matchers, ExpectInterface } from "./expect";
|
|
6
6
|
export type { MatcherContext, MatcherFn, MatcherMap, Promisable, } from "./types";
|
package/dist/esm/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC9E,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACrE,OAAO,EAAE,YAAY,EAAE,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AAC9E,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AAElD,YAAY,EAAE,QAAQ,EAAE,eAAe,EAAE,MAAM,UAAU,CAAC;AAC1D,YAAY,EACV,cAAc,EACd,SAAS,EACT,UAAU,EACV,UAAU,GACX,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AAClC,YAAY,EAAE,eAAe,EAAE,MAAM,OAAO,CAAC;AAG7C,OAAO,EACL,IAAI,EACJ,GAAG,EACH,KAAK,EACL,KAAK,EACL,UAAU,EACV,SAAS,EACT,IAAI,EACJ,UAAU,EACV,SAAS,EACT,aAAa,EACb,aAAa,EACb,aAAa,EACb,mBAAmB,EACnB,wBAAwB,EACxB,YAAY,EACZ,iBAAiB,EACjB,oBAAoB,EACpB,yBAAyB,EACzB,aAAa,EACb,aAAa,EACb,iBAAiB,EACjB,MAAM,EACN,MAAM,EACN,eAAe,EACf,UAAU,EACV,MAAM,EACN,aAAa,EACb,aAAa,EACb,eAAe,GAChB,MAAM,cAAc,CAAC;AACtB,YAAY,EACV,GAAG,EACH,SAAS,EACT,UAAU,EACV,SAAS,EACT,YAAY,EACZ,gBAAgB,EAChB,iBAAiB,EACjB,oBAAoB,EACpB,WAAW,EACX,aAAa,EACb,YAAY,EACZ,WAAW,GACZ,MAAM,cAAc,CAAC"}
|
package/dist/esm/interface.d.ts
CHANGED
|
@@ -8,10 +8,14 @@ type DescribeFn = {
|
|
|
8
8
|
skip: (description: string, fn: () => void) => void;
|
|
9
9
|
todo: (description: string) => void;
|
|
10
10
|
};
|
|
11
|
+
export interface TestOptions {
|
|
12
|
+
timeout?: number;
|
|
13
|
+
retries?: number;
|
|
14
|
+
}
|
|
11
15
|
type ItFn = {
|
|
12
|
-
(description: string, fn: PromisableFn<void>,
|
|
13
|
-
only: (description: string, fn: PromisableFn<void>,
|
|
14
|
-
skip: (description: string, fn: PromisableFn<void>,
|
|
16
|
+
(description: string, fn: PromisableFn<void>, options?: number | TestOptions): void;
|
|
17
|
+
only: (description: string, fn: PromisableFn<void>, options?: number | TestOptions) => void;
|
|
18
|
+
skip: (description: string, fn: PromisableFn<void>, options?: number | TestOptions) => void;
|
|
15
19
|
todo: (description: string) => void;
|
|
16
20
|
};
|
|
17
21
|
declare const describe: DescribeFn;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/interface.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,YAAY,EAAY,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"interface.d.ts","sourceRoot":"","sources":["../../src/interface.ts"],"names":[],"mappings":"AAIA,OAAO,EAAE,KAAK,YAAY,EAAY,MAAM,SAAS,CAAC;AAGtD;;GAEG;AAEH,KAAK,UAAU,GAAG;IAChB,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,IAAI,GAAG,IAAI,CAAC;IAC5C,IAAI,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IACpD,IAAI,EAAE,CAAC,WAAW,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;IACpD,IAAI,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC,CAAC;AAEF,MAAM,WAAW,WAAW;IAC1B,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,KAAK,IAAI,GAAG;IACV,CACE,WAAW,EAAE,MAAM,EACnB,EAAE,EAAE,YAAY,CAAC,IAAI,CAAC,EACtB,OAAO,CAAC,EAAE,MAAM,GAAG,WAAW,GAC7B,IAAI,CAAC;IACR,IAAI,EAAE,CACJ,WAAW,EAAE,MAAM,EACnB,EAAE,EAAE,YAAY,CAAC,IAAI,CAAC,EACtB,OAAO,CAAC,EAAE,MAAM,GAAG,WAAW,KAC3B,IAAI,CAAC;IACV,IAAI,EAAE,CACJ,WAAW,EAAE,MAAM,EACnB,EAAE,EAAE,YAAY,CAAC,IAAI,CAAC,EACtB,OAAO,CAAC,EAAE,MAAM,GAAG,WAAW,KAC3B,IAAI,CAAC;IACV,IAAI,EAAE,CAAC,WAAW,EAAE,MAAM,KAAK,IAAI,CAAC;CACrC,CAAC;AA6BF,QAAA,MAAM,QAAQ,EAAE,UAC8B,CAAC;AAyB/C,QAAA,MAAM,EAAE,EAAE,IACuC,CAAC;AAOlD,QAAA,MAAM,IAAI,EAAE,IAAS,CAAC;AAEtB,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC"}
|
package/dist/esm/interface.js
CHANGED
|
@@ -2,6 +2,7 @@ import { assertRegisterState, unriftGlobalContext } from "./context.js";
|
|
|
2
2
|
import { getCurrentSuite, Suite } from "./suite.js";
|
|
3
3
|
import { Test } from "./test.js";
|
|
4
4
|
import { TaskMode } from "./types.js";
|
|
5
|
+
import { assertValidRetries } from "./utils/helpers.js";
|
|
5
6
|
function _describe(description, fn, mode) {
|
|
6
7
|
assertRegisterState("describe");
|
|
7
8
|
const parent = getCurrentSuite();
|
|
@@ -24,14 +25,17 @@ const describe = (description, fn) => _describe(description, fn, TaskMode.Defaul
|
|
|
24
25
|
describe.only = (description, fn) => _describe(description, fn, TaskMode.Only);
|
|
25
26
|
describe.skip = (description, fn) => _describe(description, fn, TaskMode.Skip);
|
|
26
27
|
describe.todo = (description) => _describe(description, () => { }, TaskMode.Todo);
|
|
27
|
-
function _it(description, fn, mode,
|
|
28
|
+
function _it(description, fn, mode, options) {
|
|
28
29
|
assertRegisterState("it");
|
|
29
|
-
|
|
30
|
+
// A bare number is the timeout, kept for backwards compatibility.
|
|
31
|
+
const { timeout, retries } = typeof options === "number" ? { timeout: options } : (options ?? {});
|
|
32
|
+
assertValidRetries(retries, `it("${description}")`);
|
|
33
|
+
const test = new Test(description, fn, mode, timeout, retries);
|
|
30
34
|
getCurrentSuite().addTest(test);
|
|
31
35
|
}
|
|
32
|
-
const it = (description, fn,
|
|
33
|
-
it.only = (description, fn,
|
|
34
|
-
it.skip = (description, fn,
|
|
36
|
+
const it = (description, fn, options) => _it(description, fn, TaskMode.Default, options);
|
|
37
|
+
it.only = (description, fn, options) => _it(description, fn, TaskMode.Only, options);
|
|
38
|
+
it.skip = (description, fn, options) => _it(description, fn, TaskMode.Skip, options);
|
|
35
39
|
it.todo = (description) => _it(description, () => { }, TaskMode.Todo);
|
|
36
40
|
const test = it;
|
|
37
41
|
export { describe, it, test };
|
package/dist/esm/matchers.js
CHANGED
|
@@ -165,6 +165,22 @@ function registerCoreMatchers() {
|
|
|
165
165
|
throw new Error(this.diff(received, expected));
|
|
166
166
|
}
|
|
167
167
|
},
|
|
168
|
+
toContainEqual(received, expected) {
|
|
169
|
+
if (!Array.isArray(received)) {
|
|
170
|
+
throw new Error(this.diff(received, "expected an array for toContainEqual()"));
|
|
171
|
+
}
|
|
172
|
+
// for...of visits sparse holes as undefined; Array.some would skip them.
|
|
173
|
+
let pass = false;
|
|
174
|
+
for (const item of received) {
|
|
175
|
+
if (looseEqual(item, expected)) {
|
|
176
|
+
pass = true;
|
|
177
|
+
break;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
if (this.isNot ? pass : !pass) {
|
|
181
|
+
throw new Error(this.diff(received, expected));
|
|
182
|
+
}
|
|
183
|
+
},
|
|
168
184
|
toEqual(received, expected) {
|
|
169
185
|
const pass = looseEqual(received, expected);
|
|
170
186
|
if (this.isNot ? pass : !pass) {
|
|
@@ -229,6 +245,24 @@ function registerCoreMatchers() {
|
|
|
229
245
|
throw new Error(this.diff(received, `<= ${expected}`));
|
|
230
246
|
}
|
|
231
247
|
},
|
|
248
|
+
toBeCloseTo(received, expected, precision = 2) {
|
|
249
|
+
if (typeof received !== "number") {
|
|
250
|
+
throw new Error(this.diff(received, "expected a number"));
|
|
251
|
+
}
|
|
252
|
+
if (typeof expected !== "number") {
|
|
253
|
+
throw new Error(this.diff(expected, "a number for expected"));
|
|
254
|
+
}
|
|
255
|
+
if (!Number.isFinite(precision)) {
|
|
256
|
+
throw new Error(this.diff(precision, "a finite number for precision"));
|
|
257
|
+
}
|
|
258
|
+
// Same-signed infinities are equal; the subtraction below would be NaN.
|
|
259
|
+
// Finite values always go through the tolerance check.
|
|
260
|
+
const pass = (!Number.isFinite(received) && received === expected) ||
|
|
261
|
+
Math.abs(received - expected) < 10 ** -precision / 2;
|
|
262
|
+
if (this.isNot ? pass : !pass) {
|
|
263
|
+
throw new Error(this.diff(received, `${expected} (precision ${precision})`));
|
|
264
|
+
}
|
|
265
|
+
},
|
|
232
266
|
toBeNaN(received) {
|
|
233
267
|
const pass = Number.isNaN(received);
|
|
234
268
|
if (this.isNot ? pass : !pass) {
|
package/dist/esm/run.d.ts
CHANGED
|
@@ -1,20 +1,17 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { type TestResult } from "./suite";
|
|
2
2
|
type RunEngineOptions = {
|
|
3
3
|
files: string[];
|
|
4
4
|
timeoutMs?: number;
|
|
5
5
|
bail?: boolean;
|
|
6
|
+
grep?: RegExp;
|
|
7
|
+
retries?: number;
|
|
6
8
|
matchers?: string[];
|
|
7
9
|
};
|
|
8
10
|
export type RunEngineResult = {
|
|
9
11
|
isOnly: boolean;
|
|
10
12
|
timeoutMs?: number;
|
|
11
13
|
bail: boolean;
|
|
12
|
-
results:
|
|
13
|
-
description: string;
|
|
14
|
-
status: TaskStatus;
|
|
15
|
-
error?: Error;
|
|
16
|
-
durationMs: number;
|
|
17
|
-
}>;
|
|
14
|
+
results: TestResult[];
|
|
18
15
|
};
|
|
19
16
|
export declare function runEngine(options: RunEngineOptions): Promise<RunEngineResult>;
|
|
20
17
|
export {};
|
package/dist/esm/run.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/run.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"run.d.ts","sourceRoot":"","sources":["../../src/run.ts"],"names":[],"mappings":"AAAA,OAAO,EAKL,KAAK,UAAU,EAChB,MAAM,SAAS,CAAC;AASjB,KAAK,gBAAgB,GAAG;IACtB,KAAK,EAAE,MAAM,EAAE,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB,CAAC;AAEF,MAAM,MAAM,eAAe,GAAG;IAC5B,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,UAAU,EAAE,CAAC;CACvB,CAAC;AAQF,wBAAsB,SAAS,CAC7B,OAAO,EAAE,gBAAgB,GACxB,OAAO,CAAC,eAAe,CAAC,CAoE1B"}
|
package/dist/esm/run.js
CHANGED
|
@@ -1,10 +1,11 @@
|
|
|
1
|
-
import { clearContext, computeOnlyFlags, rootSuite, Suite } from "./suite.js";
|
|
1
|
+
import { clearContext, computeOnlyFlags, rootSuite, Suite, } from "./suite.js";
|
|
2
2
|
import { ensureInternalMatchers } from "./matchers.js";
|
|
3
3
|
import { RunState, unriftGlobalContext } from "./context.js";
|
|
4
4
|
import { normalizePath } from "./utils/normalizePath.js";
|
|
5
5
|
import { TaskMode } from "./types.js";
|
|
6
6
|
import { toError } from "./utils/toError.js";
|
|
7
7
|
import { toImportUrl } from "./utils/transform.js";
|
|
8
|
+
import { assertValidRetries } from "./utils/helpers.js";
|
|
8
9
|
async function loadMatcherModules(specifiers) {
|
|
9
10
|
for (const spec of specifiers ?? []) {
|
|
10
11
|
await import(spec);
|
|
@@ -12,6 +13,9 @@ async function loadMatcherModules(specifiers) {
|
|
|
12
13
|
}
|
|
13
14
|
export async function runEngine(options) {
|
|
14
15
|
const { files } = options;
|
|
16
|
+
// Validate before touching global state. A bad value (e.g. "3" from a JSON
|
|
17
|
+
// config) would otherwise turn into "31" attempts or zero.
|
|
18
|
+
assertValidRetries(options.retries, "runEngine");
|
|
15
19
|
clearContext();
|
|
16
20
|
ensureInternalMatchers();
|
|
17
21
|
await loadMatcherModules(options.matchers);
|
|
@@ -40,7 +44,7 @@ export async function runEngine(options) {
|
|
|
40
44
|
}
|
|
41
45
|
const isOnly = computeOnlyFlags(rootSuite);
|
|
42
46
|
unriftGlobalContext.state = RunState.Run;
|
|
43
|
-
await rootSuite.run({ timeoutMs, bail }, { bailed: false }, isOnly, false);
|
|
47
|
+
await rootSuite.run({ timeoutMs, bail, grep: options.grep, retries: options.retries }, { bailed: false }, isOnly, false);
|
|
44
48
|
const results = rootSuite.getResults();
|
|
45
49
|
return {
|
|
46
50
|
isOnly,
|
package/dist/esm/runner.d.ts
CHANGED
package/dist/esm/runner.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/runner.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"runner.d.ts","sourceRoot":"","sources":["../../src/runner.ts"],"names":[],"mappings":"AAyBA,UAAU,aAAa;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AA+MD,wBAAsB,WAAW,CAAC,OAAO,GAAE,aAAkB,iBAwU5D;AA+DD,wBAAsB,aAAa,CAAC,OAAO,GAAE,aAAkB,iBAyD9D"}
|
package/dist/esm/runner.js
CHANGED
|
@@ -237,6 +237,8 @@ export async function runTestsCLI(options = {}) {
|
|
|
237
237
|
files,
|
|
238
238
|
timeoutMs,
|
|
239
239
|
bail,
|
|
240
|
+
grep: options.grep,
|
|
241
|
+
retries: config?.retries,
|
|
240
242
|
matchers: config?.matchers,
|
|
241
243
|
});
|
|
242
244
|
debugLog(options.debug, options.json, "Only mode:", engine.isOnly);
|
|
@@ -264,6 +266,7 @@ export async function runTestsCLI(options = {}) {
|
|
|
264
266
|
description: result.description,
|
|
265
267
|
status: result.status,
|
|
266
268
|
durationMs: result.durationMs ?? 0,
|
|
269
|
+
attempts: result.attempts && result.attempts > 1 ? result.attempts : undefined,
|
|
267
270
|
error: result.error
|
|
268
271
|
? { message: result.error.message, stack: result.error.stack }
|
|
269
272
|
: undefined,
|
|
@@ -328,14 +331,17 @@ export async function runTestsCLI(options = {}) {
|
|
|
328
331
|
lastSuitePath = suitePath;
|
|
329
332
|
}
|
|
330
333
|
const indent = " " + " ".repeat(depth);
|
|
334
|
+
const retried = result.attempts && result.attempts > 1
|
|
335
|
+
? colors.yellow(` (${result.status === TaskStatus.Fail ? "failed" : "passed"} after ${result.attempts} attempts)`)
|
|
336
|
+
: "";
|
|
331
337
|
if (result.status === TaskStatus.Pass) {
|
|
332
338
|
const dur = colors.dim(formatDuration(result.durationMs ?? 0));
|
|
333
|
-
console.log(`${indent}${colors.green("✔")} ${colors.dim(leaf)} ${dur}`);
|
|
339
|
+
console.log(`${indent}${colors.green("✔")} ${colors.dim(leaf)}${retried} ${dur}`);
|
|
334
340
|
continue;
|
|
335
341
|
}
|
|
336
342
|
if (result.status === TaskStatus.Fail) {
|
|
337
343
|
const dur = colors.dim(formatDuration(result.durationMs ?? 0));
|
|
338
|
-
console.log(`${indent}${colors.red("✘")} ${colors.boldRed(leaf)} ${dur}`);
|
|
344
|
+
console.log(`${indent}${colors.red("✘")} ${colors.boldRed(leaf)}${retried} ${dur}`);
|
|
339
345
|
continue;
|
|
340
346
|
}
|
|
341
347
|
if (result.status === TaskStatus.Skipped) {
|
package/dist/esm/suite.d.ts
CHANGED
|
@@ -3,10 +3,20 @@ import { type PromisableFn, TaskMode, TaskStatus } from "./types";
|
|
|
3
3
|
interface RunOptions {
|
|
4
4
|
timeoutMs?: number;
|
|
5
5
|
bail?: boolean;
|
|
6
|
+
grep?: RegExp;
|
|
7
|
+
retries?: number;
|
|
6
8
|
}
|
|
7
9
|
interface SuiteRunState {
|
|
8
10
|
bailed: boolean;
|
|
9
11
|
}
|
|
12
|
+
export interface TestResult {
|
|
13
|
+
description: string;
|
|
14
|
+
status: TaskStatus;
|
|
15
|
+
error?: Error;
|
|
16
|
+
durationMs: number;
|
|
17
|
+
/** How many times the test ran. Above 1 means it was retried. */
|
|
18
|
+
attempts?: number;
|
|
19
|
+
}
|
|
10
20
|
export declare class Suite {
|
|
11
21
|
description: string;
|
|
12
22
|
mode: TaskMode;
|
|
@@ -27,20 +37,28 @@ export declare class Suite {
|
|
|
27
37
|
afterEachHooks: PromisableFn<void>[];
|
|
28
38
|
constructor(description: string, parent?: Suite, mode?: TaskMode);
|
|
29
39
|
markSubtreeSkipped(): void;
|
|
40
|
+
/**
|
|
41
|
+
* Used when --grep prunes a suite. Matching todos stay todo so their status
|
|
42
|
+
* doesn't depend on whether a runnable sibling matched; everything else is
|
|
43
|
+
* skipped.
|
|
44
|
+
*/
|
|
45
|
+
private markSubtreeFilteredOut;
|
|
30
46
|
markSubtreeTodo(): void;
|
|
31
47
|
addSuite(suite: Suite): void;
|
|
32
48
|
addTest(test: Test): void;
|
|
33
49
|
private collectBeforeEachHooks;
|
|
34
50
|
private collectAfterEachHooks;
|
|
35
51
|
run(options?: RunOptions, state?: SuiteRunState, isOnly?: boolean, ancestorOnly?: boolean): Promise<void>;
|
|
52
|
+
private testMatchesGrep;
|
|
53
|
+
/**
|
|
54
|
+
* True if a test below this suite matches grep AND would actually run, using
|
|
55
|
+
* the same skip/todo/only rules as run(). A matching test that won't run
|
|
56
|
+
* shouldn't cause this suite's hooks to fire.
|
|
57
|
+
*/
|
|
58
|
+
private hasRunnableMatch;
|
|
36
59
|
getFullDescription(): string;
|
|
37
60
|
reset(): void;
|
|
38
|
-
getResults():
|
|
39
|
-
description: string;
|
|
40
|
-
status: TaskStatus;
|
|
41
|
-
error?: Error;
|
|
42
|
-
durationMs: number;
|
|
43
|
-
}>;
|
|
61
|
+
getResults(): TestResult[];
|
|
44
62
|
}
|
|
45
63
|
export declare function computeOnlyFlags(suite: Suite): boolean;
|
|
46
64
|
export declare const rootSuite: Suite;
|
package/dist/esm/suite.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"suite.d.ts","sourceRoot":"","sources":["../../src/suite.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE9B,OAAO,EAAE,KAAK,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;
|
|
1
|
+
{"version":3,"file":"suite.d.ts","sourceRoot":"","sources":["../../src/suite.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAE9B,OAAO,EAAE,KAAK,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AAIlE,UAAU,UAAU;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,UAAU,aAAa;IACrB,MAAM,EAAE,OAAO,CAAC;CACjB;AAsBD,MAAM,WAAW,UAAU;IACzB,WAAW,EAAE,MAAM,CAAC;IACpB,MAAM,EAAE,UAAU,CAAC;IACnB,KAAK,CAAC,EAAE,KAAK,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,iEAAiE;IACjE,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,KAAK;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,QAAQ,CAAC;IACf,MAAM,CAAC,EAAE,KAAK,CAAC;IAEf,cAAc,EAAE,OAAO,CAAS;IAEhC,IAAI,EAAE,OAAO,CAAS;IACtB,MAAM,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,KAAK,CAAA;KAAE,CAAC,CAAM;IACpD,MAAM,EAAE,KAAK,EAAE,CAAM;IACrB,KAAK,EAAE,IAAI,EAAE,CAAM;IAEnB,aAAa,CAAC,EAAE,KAAK,CAAC;IACtB,cAAc,CAAC,EAAE,KAAK,CAAC;IAEvB,cAAc,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,CAAM;IAC1C,aAAa,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,CAAM;IACzC,eAAe,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,CAAM;IAC3C,cAAc,EAAE,YAAY,CAAC,IAAI,CAAC,EAAE,CAAM;gBAGxC,WAAW,EAAE,MAAM,EACnB,MAAM,CAAC,EAAE,KAAK,EACd,IAAI,GAAE,QAA2B;IAO5B,kBAAkB;IASzB;;;;OAIG;IACH,OAAO,CAAC,sBAAsB;IA8BvB,eAAe;IAStB,QAAQ,CAAC,KAAK,EAAE,KAAK;IAIrB,OAAO,CAAC,IAAI,EAAE,IAAI;IAIlB,OAAO,CAAC,sBAAsB;IAiB9B,OAAO,CAAC,qBAAqB;IAYvB,GAAG,CACP,OAAO,CAAC,EAAE,UAAU,EACpB,KAAK,GAAE,aAAiC,EACxC,MAAM,GAAE,OAAe,EACvB,YAAY,GAAE,OAAe,GAC5B,OAAO,CAAC,IAAI,CAAC;IAmNhB,OAAO,CAAC,eAAe;IAOvB;;;;OAIG;IACH,OAAO,CAAC,gBAAgB;IA4BxB,kBAAkB,IAAI,MAAM;IAK5B,KAAK;IAaL,UAAU,IAAI,UAAU,EAAE;CA8C3B;AAED,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAiBtD;AAKD,eAAO,MAAM,SAAS,OAAoB,CAAC;AAG3C,wBAAgB,eAAe,UAE9B;AAED,wBAAgB,YAAY,SAK3B"}
|
package/dist/esm/suite.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { unriftGlobalContext } from "./context.js";
|
|
2
2
|
import { resetMatchers } from "./matchers.js";
|
|
3
3
|
import { TaskMode, TaskStatus } from "./types.js";
|
|
4
|
+
import { regexTest } from "./utils/helpers.js";
|
|
4
5
|
import { toError } from "./utils/toError.js";
|
|
5
6
|
function appendHookFailure(existing, hookName, hookError) {
|
|
6
7
|
if (!existing)
|
|
@@ -42,6 +43,34 @@ export class Suite {
|
|
|
42
43
|
for (const suite of this.suites)
|
|
43
44
|
suite.markSubtreeSkipped();
|
|
44
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Used when --grep prunes a suite. Matching todos stay todo so their status
|
|
48
|
+
* doesn't depend on whether a runnable sibling matched; everything else is
|
|
49
|
+
* skipped.
|
|
50
|
+
*/
|
|
51
|
+
markSubtreeFilteredOut(grep, isOnly, inOnlyContext) {
|
|
52
|
+
for (const test of this.tests) {
|
|
53
|
+
if (test.status !== TaskStatus.Pending)
|
|
54
|
+
continue;
|
|
55
|
+
test.status =
|
|
56
|
+
test.mode === TaskMode.Todo && this.testMatchesGrep(test, grep)
|
|
57
|
+
? TaskStatus.Todo
|
|
58
|
+
: TaskStatus.Skipped;
|
|
59
|
+
test.durationMs = 0;
|
|
60
|
+
}
|
|
61
|
+
// Same skip and .only rules as run(), so a suite excluded by .only stays
|
|
62
|
+
// skipped no matter which pattern pruned its parent.
|
|
63
|
+
for (const suite of this.suites) {
|
|
64
|
+
const childOnly = inOnlyContext || suite.mode === TaskMode.Only;
|
|
65
|
+
if (suite.mode === TaskMode.Skip ||
|
|
66
|
+
(isOnly && !suite.subtreeHasOnly && !childOnly)) {
|
|
67
|
+
suite.markSubtreeSkipped();
|
|
68
|
+
}
|
|
69
|
+
else {
|
|
70
|
+
suite.markSubtreeFilteredOut(grep, isOnly, childOnly);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
45
74
|
markSubtreeTodo() {
|
|
46
75
|
for (const test of this.tests) {
|
|
47
76
|
if (test.status === TaskStatus.Pending)
|
|
@@ -100,6 +129,12 @@ export class Suite {
|
|
|
100
129
|
this.markSubtreeSkipped();
|
|
101
130
|
return;
|
|
102
131
|
}
|
|
132
|
+
// Same for --grep: nothing below can run, so don't run hooks either
|
|
133
|
+
if (options?.grep &&
|
|
134
|
+
!this.hasRunnableMatch(options.grep, isOnly, inOnlyContext)) {
|
|
135
|
+
this.markSubtreeFilteredOut(options.grep, isOnly, inOnlyContext);
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
103
138
|
let entered = false;
|
|
104
139
|
try {
|
|
105
140
|
// beforeAll
|
|
@@ -122,6 +157,12 @@ export class Suite {
|
|
|
122
157
|
const test = this.tests[i];
|
|
123
158
|
if (state.bailed)
|
|
124
159
|
break;
|
|
160
|
+
// Checked before skip/todo so a non-matching todo reports as skipped
|
|
161
|
+
if (options?.grep && !this.testMatchesGrep(test, options.grep)) {
|
|
162
|
+
test.status = TaskStatus.Skipped;
|
|
163
|
+
test.durationMs = 0;
|
|
164
|
+
continue;
|
|
165
|
+
}
|
|
125
166
|
if (test.mode === TaskMode.Skip) {
|
|
126
167
|
test.status = TaskStatus.Skipped;
|
|
127
168
|
test.durationMs = 0;
|
|
@@ -139,32 +180,59 @@ export class Suite {
|
|
|
139
180
|
test.durationMs = 0;
|
|
140
181
|
continue;
|
|
141
182
|
}
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
183
|
+
// Each attempt gets its own beforeEach/afterEach so state resets between retries.
|
|
184
|
+
const maxAttempts = (test.retries ?? options?.retries ?? 0) + 1;
|
|
185
|
+
let totalMs = 0;
|
|
186
|
+
for (let attempt = 1; attempt <= maxAttempts; attempt++) {
|
|
187
|
+
test.attempts = attempt;
|
|
188
|
+
test.error = undefined;
|
|
189
|
+
// Reset so an attempt whose beforeEach throws doesn't report the
|
|
190
|
+
// previous attempt's time.
|
|
191
|
+
test.durationMs = 0;
|
|
192
|
+
try {
|
|
193
|
+
for (const hook of beforeEachHooks) {
|
|
194
|
+
try {
|
|
195
|
+
await hook();
|
|
196
|
+
}
|
|
197
|
+
catch (error) {
|
|
198
|
+
throw appendHookFailure(undefined, "beforeEach", toError(error));
|
|
199
|
+
}
|
|
149
200
|
}
|
|
201
|
+
await test.run(options?.timeoutMs);
|
|
150
202
|
}
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
203
|
+
catch (error) {
|
|
204
|
+
test.status = TaskStatus.Fail;
|
|
205
|
+
test.error = toError(error);
|
|
206
|
+
}
|
|
207
|
+
finally {
|
|
208
|
+
for (const hook of afterEachHooks) {
|
|
209
|
+
try {
|
|
210
|
+
await hook();
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
test.status = TaskStatus.Fail;
|
|
214
|
+
test.error = appendHookFailure(test.error, "afterEach", toError(error));
|
|
215
|
+
}
|
|
161
216
|
}
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
217
|
+
}
|
|
218
|
+
totalMs += test.durationMs;
|
|
219
|
+
if (test.status !== TaskStatus.Fail)
|
|
220
|
+
break;
|
|
221
|
+
// A timed-out body can't be cancelled and may still be running, so
|
|
222
|
+
// another attempt could race with it. Stop here instead.
|
|
223
|
+
if (test.timedOut) {
|
|
224
|
+
if (attempt < maxAttempts && test.error) {
|
|
225
|
+
const note = "\n\n[retries] not retried: the timed-out attempt may still be running";
|
|
226
|
+
// Read the stack before touching the message: V8 builds it lazily,
|
|
227
|
+
// and an afterEach failure may have already combined it.
|
|
228
|
+
const stack = test.error.stack ?? test.error.message;
|
|
229
|
+
test.error.message += note;
|
|
230
|
+
test.error.stack = stack + note;
|
|
165
231
|
}
|
|
232
|
+
break;
|
|
166
233
|
}
|
|
167
234
|
}
|
|
235
|
+
test.durationMs = totalMs;
|
|
168
236
|
// Mark everything that hasn't run as skipped on bail
|
|
169
237
|
if (options?.bail && test.status === TaskStatus.Fail) {
|
|
170
238
|
state.bailed = true;
|
|
@@ -212,6 +280,31 @@ export class Suite {
|
|
|
212
280
|
}
|
|
213
281
|
}
|
|
214
282
|
}
|
|
283
|
+
testMatchesGrep(test, grep) {
|
|
284
|
+
return regexTest(grep, `${this.getFullDescription()} › ${test.description}`);
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* True if a test below this suite matches grep AND would actually run, using
|
|
288
|
+
* the same skip/todo/only rules as run(). A matching test that won't run
|
|
289
|
+
* shouldn't cause this suite's hooks to fire.
|
|
290
|
+
*/
|
|
291
|
+
hasRunnableMatch(grep, isOnly, inOnlyContext) {
|
|
292
|
+
const runnable = this.tests.some((test) => test.mode !== TaskMode.Skip &&
|
|
293
|
+
test.mode !== TaskMode.Todo &&
|
|
294
|
+
(!isOnly || inOnlyContext || test.mode === TaskMode.Only) &&
|
|
295
|
+
this.testMatchesGrep(test, grep));
|
|
296
|
+
if (runnable)
|
|
297
|
+
return true;
|
|
298
|
+
return this.suites.some((suite) => {
|
|
299
|
+
if (suite.mode === TaskMode.Skip || suite.mode === TaskMode.Todo) {
|
|
300
|
+
return false;
|
|
301
|
+
}
|
|
302
|
+
const childOnly = inOnlyContext || suite.mode === TaskMode.Only;
|
|
303
|
+
if (isOnly && !suite.subtreeHasOnly && !childOnly)
|
|
304
|
+
return false;
|
|
305
|
+
return suite.hasRunnableMatch(grep, isOnly, childOnly);
|
|
306
|
+
});
|
|
307
|
+
}
|
|
215
308
|
getFullDescription() {
|
|
216
309
|
if (!this.parent || this.parent.root)
|
|
217
310
|
return this.description;
|
|
@@ -261,6 +354,7 @@ export class Suite {
|
|
|
261
354
|
status: test.status,
|
|
262
355
|
error: test.error,
|
|
263
356
|
durationMs: test.durationMs ?? 0,
|
|
357
|
+
attempts: test.attempts,
|
|
264
358
|
});
|
|
265
359
|
}
|
|
266
360
|
for (const child of this.suites) {
|
package/dist/esm/test.d.ts
CHANGED
|
@@ -7,7 +7,11 @@ export declare class Test {
|
|
|
7
7
|
mode: TaskMode;
|
|
8
8
|
status: TaskStatus;
|
|
9
9
|
timeoutMs?: number;
|
|
10
|
-
|
|
10
|
+
retries?: number;
|
|
11
|
+
attempts: number;
|
|
12
|
+
/** True if the last run timed out. Its body may still be running. */
|
|
13
|
+
timedOut: boolean;
|
|
14
|
+
constructor(description: string, fn: PromisableFn<void>, mode?: TaskMode, timeoutMs?: number, retries?: number);
|
|
11
15
|
run(globalTimeoutMs?: number): Promise<void>;
|
|
12
16
|
}
|
|
13
17
|
//# sourceMappingURL=test.d.ts.map
|
package/dist/esm/test.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../../src/test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,YAAY,EAAE,MAAM,SAAS,CAAC;AASlE,qBAAa,IAAI;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAK;IACvB,KAAK,CAAC,EAAE,KAAK,CAAC;IAEd,EAAE,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,EAAE,QAAQ,CAAC;IAEf,MAAM,EAAE,UAAU,CAAsB;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"test.d.ts","sourceRoot":"","sources":["../../src/test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,KAAK,YAAY,EAAE,MAAM,SAAS,CAAC;AASlE,qBAAa,IAAI;IACf,WAAW,EAAE,MAAM,CAAC;IACpB,UAAU,EAAE,MAAM,CAAK;IACvB,KAAK,CAAC,EAAE,KAAK,CAAC;IAEd,EAAE,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC;IACvB,IAAI,EAAE,QAAQ,CAAC;IAEf,MAAM,EAAE,UAAU,CAAsB;IACxC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,EAAE,MAAM,CAAK;IACrB,qEAAqE;IACrE,QAAQ,EAAE,OAAO,CAAS;gBAGxB,WAAW,EAAE,MAAM,EACnB,EAAE,EAAE,YAAY,CAAC,IAAI,CAAC,EACtB,IAAI,GAAE,QAA2B,EACjC,SAAS,CAAC,EAAE,MAAM,EAClB,OAAO,CAAC,EAAE,MAAM;IASZ,GAAG,CAAC,eAAe,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CA2DnD"}
|
package/dist/esm/test.js
CHANGED
|
@@ -13,11 +13,16 @@ export class Test {
|
|
|
13
13
|
mode;
|
|
14
14
|
status = TaskStatus.Pending;
|
|
15
15
|
timeoutMs;
|
|
16
|
-
|
|
16
|
+
retries;
|
|
17
|
+
attempts = 0;
|
|
18
|
+
/** True if the last run timed out. Its body may still be running. */
|
|
19
|
+
timedOut = false;
|
|
20
|
+
constructor(description, fn, mode = TaskMode.Default, timeoutMs, retries) {
|
|
17
21
|
this.description = description;
|
|
18
22
|
this.fn = fn;
|
|
19
23
|
this.mode = mode;
|
|
20
24
|
this.timeoutMs = timeoutMs;
|
|
25
|
+
this.retries = retries;
|
|
21
26
|
}
|
|
22
27
|
async run(globalTimeoutMs) {
|
|
23
28
|
const timeoutMs = this.timeoutMs ?? globalTimeoutMs;
|
|
@@ -33,12 +38,14 @@ export class Test {
|
|
|
33
38
|
}
|
|
34
39
|
const start = realPerformanceNow();
|
|
35
40
|
this.status = TaskStatus.Running;
|
|
41
|
+
this.timedOut = false;
|
|
36
42
|
const exec = Promise.resolve().then(() => this.fn());
|
|
37
43
|
try {
|
|
38
44
|
if (timeoutMs !== undefined) {
|
|
39
45
|
let timeoutId = null;
|
|
40
46
|
const timeoutFn = new Promise((_, reject) => {
|
|
41
47
|
timeoutId = setTimeout(() => {
|
|
48
|
+
this.timedOut = true;
|
|
42
49
|
reject(new Error(`Test "${this.description}" timed out after ${timeoutMs} ms`));
|
|
43
50
|
}, timeoutMs);
|
|
44
51
|
});
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"defineConfig.d.ts","sourceRoot":"","sources":["../../../src/utils/defineConfig.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,mBAAmB,GAC3B,mBAAmB,CAErB"}
|
|
1
|
+
{"version":3,"file":"defineConfig.d.ts","sourceRoot":"","sources":["../../../src/utils/defineConfig.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,mBAAmB;IAClC,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;IACpB,QAAQ,CAAC,EAAE,MAAM,EAAE,CAAC;CACrB;AAED,wBAAgB,YAAY,CAC1B,OAAO,EAAE,mBAAmB,GAC3B,mBAAmB,CAErB"}
|
|
@@ -30,5 +30,7 @@ export declare function regexTest(re: RegExp, value: string): boolean;
|
|
|
30
30
|
* - +0 and -0 are equal
|
|
31
31
|
*/
|
|
32
32
|
export declare function sameValue(a: unknown, b: unknown): boolean;
|
|
33
|
+
/** Throws unless `retries` is undefined or a non-negative integer. */
|
|
34
|
+
export declare function assertValidRetries(retries: unknown, where: string): void;
|
|
33
35
|
export {};
|
|
34
36
|
//# sourceMappingURL=helpers.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/utils/helpers.ts"],"names":[],"mappings":"AAAA,KAAK,SAAS,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAEhF,MAAM,MAAM,UAAU,GAClB,UAAU,GACV,SAAS,GACT,WAAW,GACX,UAAU,GACV,WAAW,GACX,UAAU,GACV,YAAY,GACZ,YAAY,GACZ,aAAa,GACb,cAAc,CAAC;AAEnB,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAY9D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAE5D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAEhE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAyDhD;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAOjD;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAG5D;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CASzD"}
|
|
1
|
+
{"version":3,"file":"helpers.d.ts","sourceRoot":"","sources":["../../../src/utils/helpers.ts"],"names":[],"mappings":"AAAA,KAAK,SAAS,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,GAAG,MAAM,CAAC;AAEhF,MAAM,MAAM,UAAU,GAClB,UAAU,GACV,SAAS,GACT,WAAW,GACX,UAAU,GACV,WAAW,GACX,UAAU,GACV,YAAY,GACZ,YAAY,GACZ,aAAa,GACb,cAAc,CAAC;AAEnB,wBAAgB,WAAW,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,SAAS,CAY9D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,MAAM,CAE5D;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,UAAU,CAEhE;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAEtD;AAED;;;GAGG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAyDhD;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAOjD;AAED;;;;;;;;GAQG;AACH,wBAAgB,SAAS,CAAC,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAG5D;AAED;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO,GAAG,OAAO,CASzD;AAED,sEAAsE;AACtE,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,OAAO,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CASxE"}
|
|
@@ -124,3 +124,10 @@ export function sameValue(a, b) {
|
|
|
124
124
|
Number.isNaN(a) &&
|
|
125
125
|
Number.isNaN(b));
|
|
126
126
|
}
|
|
127
|
+
/** Throws unless `retries` is undefined or a non-negative integer. */
|
|
128
|
+
export function assertValidRetries(retries, where) {
|
|
129
|
+
if (retries !== undefined &&
|
|
130
|
+
!(typeof retries === "number" && Number.isInteger(retries) && retries >= 0)) {
|
|
131
|
+
throw new TypeError(`${where}: retries must be a non-negative integer, got ${typeof retries === "string" ? JSON.stringify(retries) : String(retries)}`);
|
|
132
|
+
}
|
|
133
|
+
}
|