@vitest/runner 0.32.2 → 0.32.4
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/index.d.ts +4 -4
- package/dist/index.js +131 -17
- package/dist/{tasks-045d21eb.d.ts → tasks-f541c18c.d.ts} +13 -6
- package/dist/types.d.ts +113 -2
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +155 -3
- package/package.json +3 -4
- package/dist/chunk-tasks.js +0 -152
- package/dist/runner-0b317aff.d.ts +0 -110
package/dist/index.d.ts
CHANGED
@@ -1,7 +1,7 @@
|
|
1
|
-
import {
|
2
|
-
export {
|
3
|
-
import { T as Task, F as File,
|
4
|
-
export { D as DoneCallback,
|
1
|
+
import { VitestRunner } from './types.js';
|
2
|
+
export { CancelReason, VitestRunnerConfig, VitestRunnerConstructor, VitestRunnerImportSource } from './types.js';
|
3
|
+
import { T as Task, F as File, d as SuiteAPI, e as TestAPI, f as SuiteCollector, g as SuiteHooks, O as OnTestFailedHandler, a as Test } from './tasks-f541c18c.js';
|
4
|
+
export { D as DoneCallback, o as Fixtures, p as HookCleanupCallback, H as HookListener, R as RunMode, r as RuntimeContext, t as SequenceHooks, u as SequenceSetupFiles, S as Suite, q as SuiteFactory, i as TaskBase, b as TaskCustom, j as TaskMeta, k as TaskResult, l as TaskResultPack, h as TaskState, s as TestContext, m as TestFunction, n as TestOptions } from './tasks-f541c18c.js';
|
5
5
|
import { Awaitable } from '@vitest/utils';
|
6
6
|
|
7
7
|
declare function updateTask(task: Task, runner: VitestRunner): void;
|
package/dist/index.js
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import limit from 'p-limit';
|
2
2
|
import { getSafeTimers, format, isObject, objDisplay, objectAttr, noop, toArray, shuffle } from '@vitest/utils';
|
3
3
|
import { processError } from '@vitest/utils/error';
|
4
|
-
import {
|
4
|
+
import { createChainable, generateHash, calculateSuiteHash, someTasksAreOnly, interpretTaskModes, partitionSuiteChildren, hasTests, hasFailed } from './utils.js';
|
5
5
|
import { relative } from 'pathe';
|
6
6
|
|
7
7
|
const fnMap = /* @__PURE__ */ new WeakMap();
|
@@ -34,7 +34,7 @@ async function runWithSuite(suite, fn) {
|
|
34
34
|
collectorContext.currentSuite = prev;
|
35
35
|
}
|
36
36
|
function withTimeout(fn, timeout, isHook = false) {
|
37
|
-
if (timeout <= 0 || timeout ===
|
37
|
+
if (timeout <= 0 || timeout === Number.POSITIVE_INFINITY)
|
38
38
|
return fn;
|
39
39
|
const { setTimeout, clearTimeout } = getSafeTimers();
|
40
40
|
return (...args) => {
|
@@ -66,6 +66,110 @@ function makeTimeoutMsg(isHook, timeout) {
|
|
66
66
|
If this is a long-running ${isHook ? "hook" : "test"}, pass a timeout value as the last argument or configure it globally with "${isHook ? "hookTimeout" : "testTimeout"}".`;
|
67
67
|
}
|
68
68
|
|
69
|
+
function mergeContextFixtures(fixtures, context = {}) {
|
70
|
+
const fixtureArray = Object.entries(fixtures).map(([prop, value], index) => {
|
71
|
+
const isFn = typeof value === "function";
|
72
|
+
return {
|
73
|
+
prop,
|
74
|
+
value,
|
75
|
+
index,
|
76
|
+
isFn
|
77
|
+
};
|
78
|
+
});
|
79
|
+
if (Array.isArray(context.fixtures))
|
80
|
+
context.fixtures = context.fixtures.concat(fixtureArray);
|
81
|
+
else
|
82
|
+
context.fixtures = fixtureArray;
|
83
|
+
fixtureArray.forEach((fixture) => {
|
84
|
+
if (fixture.isFn) {
|
85
|
+
const usedProps = getUsedProps(fixture.value);
|
86
|
+
if (usedProps.length)
|
87
|
+
fixture.deps = context.fixtures.filter(({ index, prop }) => index !== fixture.index && usedProps.includes(prop));
|
88
|
+
}
|
89
|
+
});
|
90
|
+
return context;
|
91
|
+
}
|
92
|
+
function withFixtures(fn, fixtures, context) {
|
93
|
+
if (!fixtures.length)
|
94
|
+
return () => fn(context);
|
95
|
+
const usedProps = getUsedProps(fn);
|
96
|
+
if (!usedProps.length)
|
97
|
+
return () => fn(context);
|
98
|
+
const usedFixtures = fixtures.filter(({ prop }) => usedProps.includes(prop));
|
99
|
+
const pendingFixtures = resolveDeps(usedFixtures);
|
100
|
+
let cursor = 0;
|
101
|
+
async function use(fixtureValue) {
|
102
|
+
const { prop } = pendingFixtures[cursor++];
|
103
|
+
context[prop] = fixtureValue;
|
104
|
+
if (cursor < pendingFixtures.length)
|
105
|
+
await next();
|
106
|
+
else
|
107
|
+
await fn(context);
|
108
|
+
}
|
109
|
+
async function next() {
|
110
|
+
const { value } = pendingFixtures[cursor];
|
111
|
+
typeof value === "function" ? await value(context, use) : await use(value);
|
112
|
+
}
|
113
|
+
return () => next();
|
114
|
+
}
|
115
|
+
function resolveDeps(fixtures, depSet = /* @__PURE__ */ new Set(), pendingFixtures = []) {
|
116
|
+
fixtures.forEach((fixture) => {
|
117
|
+
if (pendingFixtures.includes(fixture))
|
118
|
+
return;
|
119
|
+
if (!fixture.isFn || !fixture.deps) {
|
120
|
+
pendingFixtures.push(fixture);
|
121
|
+
return;
|
122
|
+
}
|
123
|
+
if (depSet.has(fixture))
|
124
|
+
throw new Error("circular fixture dependency");
|
125
|
+
depSet.add(fixture);
|
126
|
+
resolveDeps(fixture.deps, depSet, pendingFixtures);
|
127
|
+
pendingFixtures.push(fixture);
|
128
|
+
depSet.clear();
|
129
|
+
});
|
130
|
+
return pendingFixtures;
|
131
|
+
}
|
132
|
+
function getUsedProps(fn) {
|
133
|
+
const match = fn.toString().match(/[^(]*\(([^)]*)/);
|
134
|
+
if (!match)
|
135
|
+
return [];
|
136
|
+
const args = splitByComma(match[1]);
|
137
|
+
if (!args.length)
|
138
|
+
return [];
|
139
|
+
const first = args[0];
|
140
|
+
if (!(first.startsWith("{") && first.endsWith("}")))
|
141
|
+
throw new Error("the first argument must use object destructuring pattern");
|
142
|
+
const _first = first.slice(1, -1).replace(/\s/g, "");
|
143
|
+
const props = splitByComma(_first).map((prop) => {
|
144
|
+
return prop.replace(/\:.*|\=.*/g, "");
|
145
|
+
});
|
146
|
+
const last = props.at(-1);
|
147
|
+
if (last && last.startsWith("..."))
|
148
|
+
throw new Error("Rest parameters are not supported");
|
149
|
+
return props;
|
150
|
+
}
|
151
|
+
function splitByComma(s) {
|
152
|
+
const result = [];
|
153
|
+
const stack = [];
|
154
|
+
let start = 0;
|
155
|
+
for (let i = 0; i < s.length; i++) {
|
156
|
+
if (s[i] === "{" || s[i] === "[") {
|
157
|
+
stack.push(s[i] === "{" ? "}" : "]");
|
158
|
+
} else if (s[i] === stack[stack.length - 1]) {
|
159
|
+
stack.pop();
|
160
|
+
} else if (!stack.length && s[i] === ",") {
|
161
|
+
const token = s.substring(start, i).trim();
|
162
|
+
if (token)
|
163
|
+
result.push(token);
|
164
|
+
start = i + 1;
|
165
|
+
}
|
166
|
+
}
|
167
|
+
const lastToken = s.substring(start).trim();
|
168
|
+
if (lastToken)
|
169
|
+
result.push(lastToken);
|
170
|
+
return result;
|
171
|
+
}
|
172
|
+
|
69
173
|
const suite = createSuite();
|
70
174
|
const test = createTest(
|
71
175
|
function(name, fn, options) {
|
@@ -84,7 +188,7 @@ function getRunner() {
|
|
84
188
|
}
|
85
189
|
function clearCollectorContext(currentRunner) {
|
86
190
|
if (!defaultSuite)
|
87
|
-
defaultSuite = currentRunner.config.sequence.shuffle ? suite.shuffle("") : suite("");
|
191
|
+
defaultSuite = currentRunner.config.sequence.shuffle ? suite.shuffle("") : currentRunner.config.sequence.concurrent ? suite.concurrent("") : suite("");
|
88
192
|
runner = currentRunner;
|
89
193
|
collectorContext.tasks.length = 0;
|
90
194
|
defaultSuite.clear();
|
@@ -121,11 +225,11 @@ function createSuiteCollector(name, factory = () => {
|
|
121
225
|
mode: mode2,
|
122
226
|
suite: void 0,
|
123
227
|
fails: this.fails,
|
124
|
-
retry: options == null ? void 0 : options.retry,
|
228
|
+
retry: (options == null ? void 0 : options.retry) ?? runner.config.retry,
|
125
229
|
repeats: options == null ? void 0 : options.repeats,
|
126
230
|
meta: /* @__PURE__ */ Object.create(null)
|
127
231
|
};
|
128
|
-
if (this.concurrent || concurrent)
|
232
|
+
if (this.concurrent || concurrent || runner.config.sequence.concurrent)
|
129
233
|
test3.concurrent = true;
|
130
234
|
if (shuffle)
|
131
235
|
test3.shuffle = true;
|
@@ -135,7 +239,7 @@ function createSuiteCollector(name, factory = () => {
|
|
135
239
|
enumerable: false
|
136
240
|
});
|
137
241
|
setFn(test3, withTimeout(
|
138
|
-
() => fn(context),
|
242
|
+
this.fixtures ? withFixtures(fn, this.fixtures, context) : () => fn(context),
|
139
243
|
(options == null ? void 0 : options.timeout) ?? runner.config.testTimeout
|
140
244
|
));
|
141
245
|
tasks.push(test3);
|
@@ -238,7 +342,7 @@ function createSuite() {
|
|
238
342
|
suiteFn
|
239
343
|
);
|
240
344
|
}
|
241
|
-
function createTest(fn) {
|
345
|
+
function createTest(fn, context) {
|
242
346
|
const testFn = fn;
|
243
347
|
testFn.each = function(cases, ...args) {
|
244
348
|
const test2 = this.withContext();
|
@@ -257,10 +361,19 @@ function createTest(fn) {
|
|
257
361
|
};
|
258
362
|
testFn.skipIf = (condition) => condition ? test.skip : test;
|
259
363
|
testFn.runIf = (condition) => condition ? test : test.skip;
|
260
|
-
|
364
|
+
testFn.extend = function(fixtures) {
|
365
|
+
const _context = mergeContextFixtures(fixtures, context);
|
366
|
+
return createTest(function fn2(name, fn2, options) {
|
367
|
+
getCurrentSuite().test.fn.call(this, formatName(name), fn2, options);
|
368
|
+
}, _context);
|
369
|
+
};
|
370
|
+
const _test = createChainable(
|
261
371
|
["concurrent", "skip", "only", "todo", "fails"],
|
262
372
|
testFn
|
263
373
|
);
|
374
|
+
if (context)
|
375
|
+
_test.mergeContext(context);
|
376
|
+
return _test;
|
264
377
|
}
|
265
378
|
function formatName(name) {
|
266
379
|
return typeof name === "string" ? name : name instanceof Function ? name.name || "<anonymous>" : String(name);
|
@@ -275,8 +388,8 @@ function formatTitle(template, items, idx) {
|
|
275
388
|
formatted = formatted.replace(
|
276
389
|
/\$([$\w_.]+)/g,
|
277
390
|
(_, key) => {
|
278
|
-
var _a;
|
279
|
-
return objDisplay(objectAttr(items[0], key), (_a = runner == null ? void 0 : runner.config) == null ? void 0 : _a.chaiConfig);
|
391
|
+
var _a, _b;
|
392
|
+
return objDisplay(objectAttr(items[0], key), { truncate: (_b = (_a = runner == null ? void 0 : runner.config) == null ? void 0 : _a.chaiConfig) == null ? void 0 : _b.truncateThreshold });
|
280
393
|
}
|
281
394
|
// https://github.com/chaijs/chai/pull/1490
|
282
395
|
);
|
@@ -463,18 +576,18 @@ async function runTest(test, runner) {
|
|
463
576
|
const start = now();
|
464
577
|
test.result = {
|
465
578
|
state: "run",
|
466
|
-
startTime: start
|
579
|
+
startTime: start,
|
580
|
+
retryCount: 0
|
467
581
|
};
|
468
582
|
updateTask(test, runner);
|
469
583
|
setCurrentTest(test);
|
470
|
-
const repeats =
|
471
|
-
for (let repeatCount = 0; repeatCount
|
472
|
-
const retry = test.retry
|
473
|
-
for (let retryCount = 0; retryCount
|
584
|
+
const repeats = test.repeats ?? 0;
|
585
|
+
for (let repeatCount = 0; repeatCount <= repeats; repeatCount++) {
|
586
|
+
const retry = test.retry ?? 0;
|
587
|
+
for (let retryCount = 0; retryCount <= retry; retryCount++) {
|
474
588
|
let beforeEachCleanups = [];
|
475
589
|
try {
|
476
590
|
await ((_c = runner.onBeforeTryTest) == null ? void 0 : _c.call(runner, test, { retry: retryCount, repeats: repeatCount }));
|
477
|
-
test.result.retryCount = retryCount;
|
478
591
|
test.result.repeatCount = repeatCount;
|
479
592
|
beforeEachCleanups = await callSuiteHook(test.suite, test, "beforeEach", runner, [test.context, test.suite]);
|
480
593
|
if (runner.runTest) {
|
@@ -509,8 +622,9 @@ async function runTest(test, runner) {
|
|
509
622
|
}
|
510
623
|
if (test.result.state === "pass")
|
511
624
|
break;
|
512
|
-
if (retryCount < retry
|
625
|
+
if (retryCount < retry) {
|
513
626
|
test.result.state = "run";
|
627
|
+
test.result.retryCount = (test.result.retryCount ?? 0) + 1;
|
514
628
|
}
|
515
629
|
updateTask(test, runner);
|
516
630
|
}
|
@@ -5,9 +5,9 @@ type ChainableFunction<T extends string, Args extends any[], R = any, E = {}> =
|
|
5
5
|
} & {
|
6
6
|
[x in T]: ChainableFunction<T, Args, R, E>;
|
7
7
|
} & {
|
8
|
-
fn: (this: Record<T,
|
8
|
+
fn: (this: Record<T, any>, ...args: Args) => R;
|
9
9
|
} & E;
|
10
|
-
declare function createChainable<T extends string, Args extends any[], R = any, E = {}>(keys: T[], fn: (this: Record<T,
|
10
|
+
declare function createChainable<T extends string, Args extends any[], R = any, E = {}>(keys: T[], fn: (this: Record<T, any>, ...args: Args) => R): ChainableFunction<T, Args, R, E>;
|
11
11
|
|
12
12
|
type RunMode = 'run' | 'skip' | 'only' | 'todo';
|
13
13
|
type TaskState = RunMode | 'pass' | 'fail';
|
@@ -113,15 +113,14 @@ interface TestOptions {
|
|
113
113
|
* Times to retry the test if fails. Useful for making flaky tests more stable.
|
114
114
|
* When retries is up, the last test error will be thrown.
|
115
115
|
*
|
116
|
-
* @default
|
116
|
+
* @default 0
|
117
117
|
*/
|
118
118
|
retry?: number;
|
119
119
|
/**
|
120
120
|
* How many times the test will run.
|
121
121
|
* Only inner tests will repeat if set on `describe()`, nested `describe()` will inherit parent's repeat by default.
|
122
122
|
*
|
123
|
-
* @default
|
124
|
-
*
|
123
|
+
* @default 0
|
125
124
|
*/
|
126
125
|
repeats?: number;
|
127
126
|
}
|
@@ -129,6 +128,14 @@ type TestAPI<ExtraContext = {}> = ChainableTestAPI<ExtraContext> & {
|
|
129
128
|
each: TestEachFunction;
|
130
129
|
skipIf(condition: any): ChainableTestAPI<ExtraContext>;
|
131
130
|
runIf(condition: any): ChainableTestAPI<ExtraContext>;
|
131
|
+
extend<T extends Record<string, any> = {}>(fixtures: Fixtures<T, ExtraContext>): TestAPI<{
|
132
|
+
[K in keyof T | keyof ExtraContext]: K extends keyof T ? T[K] : K extends keyof ExtraContext ? ExtraContext[K] : never;
|
133
|
+
}>;
|
134
|
+
};
|
135
|
+
type Fixtures<T extends Record<string, any>, ExtraContext = {}> = {
|
136
|
+
[K in keyof T]: T[K] | ((context: {
|
137
|
+
[P in keyof T | keyof ExtraContext as P extends K ? P extends keyof ExtraContext ? P : never : P]: K extends P ? K extends keyof ExtraContext ? ExtraContext[K] : never : P extends keyof T ? T[P] : never;
|
138
|
+
} & TestContext, use: (fixture: T[K]) => Promise<void>) => Promise<void>);
|
132
139
|
};
|
133
140
|
type ChainableSuiteAPI<ExtraContext = {}> = ChainableFunction<'concurrent' | 'only' | 'skip' | 'todo' | 'shuffle', [
|
134
141
|
name: string | Function,
|
@@ -188,4 +195,4 @@ type OnTestFailedHandler = (result: TaskResult) => Awaitable<void>;
|
|
188
195
|
type SequenceHooks = 'stack' | 'list' | 'parallel';
|
189
196
|
type SequenceSetupFiles = 'list' | 'parallel';
|
190
197
|
|
191
|
-
export { ChainableFunction as C, DoneCallback as D, File as F, HookListener as H, OnTestFailedHandler as O, RunMode as R,
|
198
|
+
export { ChainableFunction as C, DoneCallback as D, File as F, HookListener as H, OnTestFailedHandler as O, RunMode as R, Suite as S, Task as T, Test as a, TaskCustom as b, createChainable as c, SuiteAPI as d, TestAPI as e, SuiteCollector as f, SuiteHooks as g, TaskState as h, TaskBase as i, TaskMeta as j, TaskResult as k, TaskResultPack as l, TestFunction as m, TestOptions as n, Fixtures as o, HookCleanupCallback as p, SuiteFactory as q, RuntimeContext as r, TestContext as s, SequenceHooks as t, SequenceSetupFiles as u };
|
package/dist/types.d.ts
CHANGED
@@ -1,3 +1,114 @@
|
|
1
|
-
|
2
|
-
export {
|
1
|
+
import { t as SequenceHooks, u as SequenceSetupFiles, F as File, a as Test, S as Suite, l as TaskResultPack, s as TestContext } from './tasks-f541c18c.js';
|
2
|
+
export { D as DoneCallback, o as Fixtures, p as HookCleanupCallback, H as HookListener, O as OnTestFailedHandler, R as RunMode, r as RuntimeContext, d as SuiteAPI, f as SuiteCollector, q as SuiteFactory, g as SuiteHooks, T as Task, i as TaskBase, b as TaskCustom, j as TaskMeta, k as TaskResult, h as TaskState, e as TestAPI, m as TestFunction, n as TestOptions } from './tasks-f541c18c.js';
|
3
3
|
import '@vitest/utils';
|
4
|
+
|
5
|
+
interface VitestRunnerConfig {
|
6
|
+
root: string;
|
7
|
+
setupFiles: string[] | string;
|
8
|
+
name: string;
|
9
|
+
passWithNoTests: boolean;
|
10
|
+
testNamePattern?: RegExp;
|
11
|
+
allowOnly?: boolean;
|
12
|
+
sequence: {
|
13
|
+
shuffle?: boolean;
|
14
|
+
concurrent?: boolean;
|
15
|
+
seed: number;
|
16
|
+
hooks: SequenceHooks;
|
17
|
+
setupFiles: SequenceSetupFiles;
|
18
|
+
};
|
19
|
+
chaiConfig?: {
|
20
|
+
truncateThreshold?: number;
|
21
|
+
};
|
22
|
+
maxConcurrency: number;
|
23
|
+
testTimeout: number;
|
24
|
+
hookTimeout: number;
|
25
|
+
retry: number;
|
26
|
+
}
|
27
|
+
type VitestRunnerImportSource = 'collect' | 'setup';
|
28
|
+
interface VitestRunnerConstructor {
|
29
|
+
new (config: VitestRunnerConfig): VitestRunner;
|
30
|
+
}
|
31
|
+
type CancelReason = 'keyboard-input' | 'test-failure' | string & {};
|
32
|
+
interface VitestRunner {
|
33
|
+
/**
|
34
|
+
* First thing that's getting called before actually collecting and running tests.
|
35
|
+
*/
|
36
|
+
onBeforeCollect?(paths: string[]): unknown;
|
37
|
+
/**
|
38
|
+
* Called after collecting tests and before "onBeforeRun".
|
39
|
+
*/
|
40
|
+
onCollected?(files: File[]): unknown;
|
41
|
+
/**
|
42
|
+
* Called when test runner should cancel next test runs.
|
43
|
+
* Runner should listen for this method and mark tests and suites as skipped in
|
44
|
+
* "onBeforeRunSuite" and "onBeforeRunTest" when called.
|
45
|
+
*/
|
46
|
+
onCancel?(reason: CancelReason): unknown;
|
47
|
+
/**
|
48
|
+
* Called before running a single test. Doesn't have "result" yet.
|
49
|
+
*/
|
50
|
+
onBeforeRunTest?(test: Test): unknown;
|
51
|
+
/**
|
52
|
+
* Called before actually running the test function. Already has "result" with "state" and "startTime".
|
53
|
+
*/
|
54
|
+
onBeforeTryTest?(test: Test, options: {
|
55
|
+
retry: number;
|
56
|
+
repeats: number;
|
57
|
+
}): unknown;
|
58
|
+
/**
|
59
|
+
* Called after result and state are set.
|
60
|
+
*/
|
61
|
+
onAfterRunTest?(test: Test): unknown;
|
62
|
+
/**
|
63
|
+
* Called right after running the test function. Doesn't have new state yet. Will not be called, if the test function throws.
|
64
|
+
*/
|
65
|
+
onAfterTryTest?(test: Test, options: {
|
66
|
+
retry: number;
|
67
|
+
repeats: number;
|
68
|
+
}): unknown;
|
69
|
+
/**
|
70
|
+
* Called before running a single suite. Doesn't have "result" yet.
|
71
|
+
*/
|
72
|
+
onBeforeRunSuite?(suite: Suite): unknown;
|
73
|
+
/**
|
74
|
+
* Called after running a single suite. Has state and result.
|
75
|
+
*/
|
76
|
+
onAfterRunSuite?(suite: Suite): unknown;
|
77
|
+
/**
|
78
|
+
* If defined, will be called instead of usual Vitest suite partition and handling.
|
79
|
+
* "before" and "after" hooks will not be ignored.
|
80
|
+
*/
|
81
|
+
runSuite?(suite: Suite): Promise<void>;
|
82
|
+
/**
|
83
|
+
* If defined, will be called instead of usual Vitest handling. Useful, if you have your custom test function.
|
84
|
+
* "before" and "after" hooks will not be ignored.
|
85
|
+
*/
|
86
|
+
runTest?(test: Test): Promise<void>;
|
87
|
+
/**
|
88
|
+
* Called, when a task is updated. The same as "onTaskUpdate" in a reporter, but this is running in the same thread as tests.
|
89
|
+
*/
|
90
|
+
onTaskUpdate?(task: TaskResultPack[]): Promise<void>;
|
91
|
+
/**
|
92
|
+
* Called before running all tests in collected paths.
|
93
|
+
*/
|
94
|
+
onBeforeRun?(files: File[]): unknown;
|
95
|
+
/**
|
96
|
+
* Called right after running all tests in collected paths.
|
97
|
+
*/
|
98
|
+
onAfterRun?(files: File[]): unknown;
|
99
|
+
/**
|
100
|
+
* Called when new context for a test is defined. Useful, if you want to add custom properties to the context.
|
101
|
+
* If you only want to define custom context, consider using "beforeAll" in "setupFiles" instead.
|
102
|
+
*/
|
103
|
+
extendTestContext?(context: TestContext): TestContext;
|
104
|
+
/**
|
105
|
+
* Called, when files are imported. Can be called in two situations: when collecting tests and when importing setup files.
|
106
|
+
*/
|
107
|
+
importFile(filepath: string, source: VitestRunnerImportSource): unknown;
|
108
|
+
/**
|
109
|
+
* Publicly available configuration.
|
110
|
+
*/
|
111
|
+
config: VitestRunnerConfig;
|
112
|
+
}
|
113
|
+
|
114
|
+
export { CancelReason, File, SequenceHooks, SequenceSetupFiles, Suite, TaskResultPack, Test, TestContext, VitestRunner, VitestRunnerConfig, VitestRunnerConstructor, VitestRunnerImportSource };
|
package/dist/utils.d.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
import {
|
2
|
-
export { C as ChainableFunction,
|
1
|
+
import { S as Suite, T as Task, a as Test, b as TaskCustom } from './tasks-f541c18c.js';
|
2
|
+
export { C as ChainableFunction, c as createChainable } from './tasks-f541c18c.js';
|
3
3
|
import { Arrayable } from '@vitest/utils';
|
4
4
|
|
5
5
|
/**
|
package/dist/utils.js
CHANGED
@@ -1,3 +1,155 @@
|
|
1
|
-
|
2
|
-
import '@vitest/utils
|
3
|
-
|
1
|
+
import { processError } from '@vitest/utils/error';
|
2
|
+
import { toArray } from '@vitest/utils';
|
3
|
+
|
4
|
+
function partitionSuiteChildren(suite) {
|
5
|
+
let tasksGroup = [];
|
6
|
+
const tasksGroups = [];
|
7
|
+
for (const c of suite.tasks) {
|
8
|
+
if (tasksGroup.length === 0 || c.concurrent === tasksGroup[0].concurrent) {
|
9
|
+
tasksGroup.push(c);
|
10
|
+
} else {
|
11
|
+
tasksGroups.push(tasksGroup);
|
12
|
+
tasksGroup = [c];
|
13
|
+
}
|
14
|
+
}
|
15
|
+
if (tasksGroup.length > 0)
|
16
|
+
tasksGroups.push(tasksGroup);
|
17
|
+
return tasksGroups;
|
18
|
+
}
|
19
|
+
|
20
|
+
function interpretTaskModes(suite, namePattern, onlyMode, parentIsOnly, allowOnly) {
|
21
|
+
const suiteIsOnly = parentIsOnly || suite.mode === "only";
|
22
|
+
suite.tasks.forEach((t) => {
|
23
|
+
const includeTask = suiteIsOnly || t.mode === "only";
|
24
|
+
if (onlyMode) {
|
25
|
+
if (t.type === "suite" && (includeTask || someTasksAreOnly(t))) {
|
26
|
+
if (t.mode === "only") {
|
27
|
+
checkAllowOnly(t, allowOnly);
|
28
|
+
t.mode = "run";
|
29
|
+
}
|
30
|
+
} else if (t.mode === "run" && !includeTask) {
|
31
|
+
t.mode = "skip";
|
32
|
+
} else if (t.mode === "only") {
|
33
|
+
checkAllowOnly(t, allowOnly);
|
34
|
+
t.mode = "run";
|
35
|
+
}
|
36
|
+
}
|
37
|
+
if (t.type === "test") {
|
38
|
+
if (namePattern && !getTaskFullName(t).match(namePattern))
|
39
|
+
t.mode = "skip";
|
40
|
+
} else if (t.type === "suite") {
|
41
|
+
if (t.mode === "skip")
|
42
|
+
skipAllTasks(t);
|
43
|
+
else
|
44
|
+
interpretTaskModes(t, namePattern, onlyMode, includeTask, allowOnly);
|
45
|
+
}
|
46
|
+
});
|
47
|
+
if (suite.mode === "run") {
|
48
|
+
if (suite.tasks.length && suite.tasks.every((i) => i.mode !== "run"))
|
49
|
+
suite.mode = "skip";
|
50
|
+
}
|
51
|
+
}
|
52
|
+
function getTaskFullName(task) {
|
53
|
+
return `${task.suite ? `${getTaskFullName(task.suite)} ` : ""}${task.name}`;
|
54
|
+
}
|
55
|
+
function someTasksAreOnly(suite) {
|
56
|
+
return suite.tasks.some((t) => t.mode === "only" || t.type === "suite" && someTasksAreOnly(t));
|
57
|
+
}
|
58
|
+
function skipAllTasks(suite) {
|
59
|
+
suite.tasks.forEach((t) => {
|
60
|
+
if (t.mode === "run") {
|
61
|
+
t.mode = "skip";
|
62
|
+
if (t.type === "suite")
|
63
|
+
skipAllTasks(t);
|
64
|
+
}
|
65
|
+
});
|
66
|
+
}
|
67
|
+
function checkAllowOnly(task, allowOnly) {
|
68
|
+
if (allowOnly)
|
69
|
+
return;
|
70
|
+
const error = processError(new Error("[Vitest] Unexpected .only modifier. Remove it or pass --allowOnly argument to bypass this error"));
|
71
|
+
task.result = {
|
72
|
+
state: "fail",
|
73
|
+
error,
|
74
|
+
errors: [error]
|
75
|
+
};
|
76
|
+
}
|
77
|
+
function generateHash(str) {
|
78
|
+
let hash = 0;
|
79
|
+
if (str.length === 0)
|
80
|
+
return `${hash}`;
|
81
|
+
for (let i = 0; i < str.length; i++) {
|
82
|
+
const char = str.charCodeAt(i);
|
83
|
+
hash = (hash << 5) - hash + char;
|
84
|
+
hash = hash & hash;
|
85
|
+
}
|
86
|
+
return `${hash}`;
|
87
|
+
}
|
88
|
+
function calculateSuiteHash(parent) {
|
89
|
+
parent.tasks.forEach((t, idx) => {
|
90
|
+
t.id = `${parent.id}_${idx}`;
|
91
|
+
if (t.type === "suite")
|
92
|
+
calculateSuiteHash(t);
|
93
|
+
});
|
94
|
+
}
|
95
|
+
|
96
|
+
function createChainable(keys, fn) {
|
97
|
+
function create(context) {
|
98
|
+
const chain2 = function(...args) {
|
99
|
+
return fn.apply(context, args);
|
100
|
+
};
|
101
|
+
Object.assign(chain2, fn);
|
102
|
+
chain2.withContext = () => chain2.bind(context);
|
103
|
+
chain2.setContext = (key, value) => {
|
104
|
+
context[key] = value;
|
105
|
+
};
|
106
|
+
chain2.mergeContext = (ctx) => {
|
107
|
+
Object.assign(context, ctx);
|
108
|
+
};
|
109
|
+
for (const key of keys) {
|
110
|
+
Object.defineProperty(chain2, key, {
|
111
|
+
get() {
|
112
|
+
return create({ ...context, [key]: true });
|
113
|
+
}
|
114
|
+
});
|
115
|
+
}
|
116
|
+
return chain2;
|
117
|
+
}
|
118
|
+
const chain = create({});
|
119
|
+
chain.fn = fn;
|
120
|
+
return chain;
|
121
|
+
}
|
122
|
+
|
123
|
+
function isAtomTest(s) {
|
124
|
+
return s.type === "test" || s.type === "custom";
|
125
|
+
}
|
126
|
+
function getTests(suite) {
|
127
|
+
return toArray(suite).flatMap((s) => isAtomTest(s) ? [s] : s.tasks.flatMap((c) => isAtomTest(c) ? [c] : getTests(c)));
|
128
|
+
}
|
129
|
+
function getTasks(tasks = []) {
|
130
|
+
return toArray(tasks).flatMap((s) => isAtomTest(s) ? [s] : [s, ...getTasks(s.tasks)]);
|
131
|
+
}
|
132
|
+
function getSuites(suite) {
|
133
|
+
return toArray(suite).flatMap((s) => s.type === "suite" ? [s, ...getSuites(s.tasks)] : []);
|
134
|
+
}
|
135
|
+
function hasTests(suite) {
|
136
|
+
return toArray(suite).some((s) => s.tasks.some((c) => isAtomTest(c) || hasTests(c)));
|
137
|
+
}
|
138
|
+
function hasFailed(suite) {
|
139
|
+
return toArray(suite).some((s) => {
|
140
|
+
var _a;
|
141
|
+
return ((_a = s.result) == null ? void 0 : _a.state) === "fail" || s.type === "suite" && hasFailed(s.tasks);
|
142
|
+
});
|
143
|
+
}
|
144
|
+
function getNames(task) {
|
145
|
+
const names = [task.name];
|
146
|
+
let current = task;
|
147
|
+
while ((current == null ? void 0 : current.suite) || (current == null ? void 0 : current.file)) {
|
148
|
+
current = current.suite || current.file;
|
149
|
+
if (current == null ? void 0 : current.name)
|
150
|
+
names.unshift(current.name);
|
151
|
+
}
|
152
|
+
return names;
|
153
|
+
}
|
154
|
+
|
155
|
+
export { calculateSuiteHash, createChainable, generateHash, getNames, getSuites, getTasks, getTests, hasFailed, hasTests, interpretTaskModes, partitionSuiteChildren, someTasksAreOnly };
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@vitest/runner",
|
3
3
|
"type": "module",
|
4
|
-
"version": "0.32.
|
4
|
+
"version": "0.32.4",
|
5
5
|
"description": "Vitest test runner",
|
6
6
|
"license": "MIT",
|
7
7
|
"funding": "https://opencollective.com/vitest",
|
@@ -38,10 +38,9 @@
|
|
38
38
|
"*.d.ts"
|
39
39
|
],
|
40
40
|
"dependencies": {
|
41
|
-
"concordance": "^5.0.4",
|
42
41
|
"p-limit": "^4.0.0",
|
43
|
-
"pathe": "^1.1.
|
44
|
-
"@vitest/utils": "0.32.
|
42
|
+
"pathe": "^1.1.1",
|
43
|
+
"@vitest/utils": "0.32.4"
|
45
44
|
},
|
46
45
|
"scripts": {
|
47
46
|
"build": "rimraf dist && rollup -c",
|
package/dist/chunk-tasks.js
DELETED
@@ -1,152 +0,0 @@
|
|
1
|
-
import { processError } from '@vitest/utils/error';
|
2
|
-
import { toArray } from '@vitest/utils';
|
3
|
-
|
4
|
-
function partitionSuiteChildren(suite) {
|
5
|
-
let tasksGroup = [];
|
6
|
-
const tasksGroups = [];
|
7
|
-
for (const c of suite.tasks) {
|
8
|
-
if (tasksGroup.length === 0 || c.concurrent === tasksGroup[0].concurrent) {
|
9
|
-
tasksGroup.push(c);
|
10
|
-
} else {
|
11
|
-
tasksGroups.push(tasksGroup);
|
12
|
-
tasksGroup = [c];
|
13
|
-
}
|
14
|
-
}
|
15
|
-
if (tasksGroup.length > 0)
|
16
|
-
tasksGroups.push(tasksGroup);
|
17
|
-
return tasksGroups;
|
18
|
-
}
|
19
|
-
|
20
|
-
function interpretTaskModes(suite, namePattern, onlyMode, parentIsOnly, allowOnly) {
|
21
|
-
const suiteIsOnly = parentIsOnly || suite.mode === "only";
|
22
|
-
suite.tasks.forEach((t) => {
|
23
|
-
const includeTask = suiteIsOnly || t.mode === "only";
|
24
|
-
if (onlyMode) {
|
25
|
-
if (t.type === "suite" && (includeTask || someTasksAreOnly(t))) {
|
26
|
-
if (t.mode === "only") {
|
27
|
-
checkAllowOnly(t, allowOnly);
|
28
|
-
t.mode = "run";
|
29
|
-
}
|
30
|
-
} else if (t.mode === "run" && !includeTask) {
|
31
|
-
t.mode = "skip";
|
32
|
-
} else if (t.mode === "only") {
|
33
|
-
checkAllowOnly(t, allowOnly);
|
34
|
-
t.mode = "run";
|
35
|
-
}
|
36
|
-
}
|
37
|
-
if (t.type === "test") {
|
38
|
-
if (namePattern && !getTaskFullName(t).match(namePattern))
|
39
|
-
t.mode = "skip";
|
40
|
-
} else if (t.type === "suite") {
|
41
|
-
if (t.mode === "skip")
|
42
|
-
skipAllTasks(t);
|
43
|
-
else
|
44
|
-
interpretTaskModes(t, namePattern, onlyMode, includeTask, allowOnly);
|
45
|
-
}
|
46
|
-
});
|
47
|
-
if (suite.mode === "run") {
|
48
|
-
if (suite.tasks.length && suite.tasks.every((i) => i.mode !== "run"))
|
49
|
-
suite.mode = "skip";
|
50
|
-
}
|
51
|
-
}
|
52
|
-
function getTaskFullName(task) {
|
53
|
-
return `${task.suite ? `${getTaskFullName(task.suite)} ` : ""}${task.name}`;
|
54
|
-
}
|
55
|
-
function someTasksAreOnly(suite) {
|
56
|
-
return suite.tasks.some((t) => t.mode === "only" || t.type === "suite" && someTasksAreOnly(t));
|
57
|
-
}
|
58
|
-
function skipAllTasks(suite) {
|
59
|
-
suite.tasks.forEach((t) => {
|
60
|
-
if (t.mode === "run") {
|
61
|
-
t.mode = "skip";
|
62
|
-
if (t.type === "suite")
|
63
|
-
skipAllTasks(t);
|
64
|
-
}
|
65
|
-
});
|
66
|
-
}
|
67
|
-
function checkAllowOnly(task, allowOnly) {
|
68
|
-
if (allowOnly)
|
69
|
-
return;
|
70
|
-
const error = processError(new Error("[Vitest] Unexpected .only modifier. Remove it or pass --allowOnly argument to bypass this error"));
|
71
|
-
task.result = {
|
72
|
-
state: "fail",
|
73
|
-
error,
|
74
|
-
errors: [error]
|
75
|
-
};
|
76
|
-
}
|
77
|
-
function generateHash(str) {
|
78
|
-
let hash = 0;
|
79
|
-
if (str.length === 0)
|
80
|
-
return `${hash}`;
|
81
|
-
for (let i = 0; i < str.length; i++) {
|
82
|
-
const char = str.charCodeAt(i);
|
83
|
-
hash = (hash << 5) - hash + char;
|
84
|
-
hash = hash & hash;
|
85
|
-
}
|
86
|
-
return `${hash}`;
|
87
|
-
}
|
88
|
-
function calculateSuiteHash(parent) {
|
89
|
-
parent.tasks.forEach((t, idx) => {
|
90
|
-
t.id = `${parent.id}_${idx}`;
|
91
|
-
if (t.type === "suite")
|
92
|
-
calculateSuiteHash(t);
|
93
|
-
});
|
94
|
-
}
|
95
|
-
|
96
|
-
function createChainable(keys, fn) {
|
97
|
-
function create(context) {
|
98
|
-
const chain2 = function(...args) {
|
99
|
-
return fn.apply(context, args);
|
100
|
-
};
|
101
|
-
Object.assign(chain2, fn);
|
102
|
-
chain2.withContext = () => chain2.bind(context);
|
103
|
-
chain2.setContext = (key, value) => {
|
104
|
-
context[key] = value;
|
105
|
-
};
|
106
|
-
for (const key of keys) {
|
107
|
-
Object.defineProperty(chain2, key, {
|
108
|
-
get() {
|
109
|
-
return create({ ...context, [key]: true });
|
110
|
-
}
|
111
|
-
});
|
112
|
-
}
|
113
|
-
return chain2;
|
114
|
-
}
|
115
|
-
const chain = create({});
|
116
|
-
chain.fn = fn;
|
117
|
-
return chain;
|
118
|
-
}
|
119
|
-
|
120
|
-
function isAtomTest(s) {
|
121
|
-
return s.type === "test" || s.type === "custom";
|
122
|
-
}
|
123
|
-
function getTests(suite) {
|
124
|
-
return toArray(suite).flatMap((s) => isAtomTest(s) ? [s] : s.tasks.flatMap((c) => isAtomTest(c) ? [c] : getTests(c)));
|
125
|
-
}
|
126
|
-
function getTasks(tasks = []) {
|
127
|
-
return toArray(tasks).flatMap((s) => isAtomTest(s) ? [s] : [s, ...getTasks(s.tasks)]);
|
128
|
-
}
|
129
|
-
function getSuites(suite) {
|
130
|
-
return toArray(suite).flatMap((s) => s.type === "suite" ? [s, ...getSuites(s.tasks)] : []);
|
131
|
-
}
|
132
|
-
function hasTests(suite) {
|
133
|
-
return toArray(suite).some((s) => s.tasks.some((c) => isAtomTest(c) || hasTests(c)));
|
134
|
-
}
|
135
|
-
function hasFailed(suite) {
|
136
|
-
return toArray(suite).some((s) => {
|
137
|
-
var _a;
|
138
|
-
return ((_a = s.result) == null ? void 0 : _a.state) === "fail" || s.type === "suite" && hasFailed(s.tasks);
|
139
|
-
});
|
140
|
-
}
|
141
|
-
function getNames(task) {
|
142
|
-
const names = [task.name];
|
143
|
-
let current = task;
|
144
|
-
while ((current == null ? void 0 : current.suite) || (current == null ? void 0 : current.file)) {
|
145
|
-
current = current.suite || current.file;
|
146
|
-
if (current == null ? void 0 : current.name)
|
147
|
-
names.unshift(current.name);
|
148
|
-
}
|
149
|
-
return names;
|
150
|
-
}
|
151
|
-
|
152
|
-
export { calculateSuiteHash as a, hasFailed as b, createChainable as c, getTests as d, getTasks as e, getSuites as f, generateHash as g, hasTests as h, interpretTaskModes as i, getNames as j, partitionSuiteChildren as p, someTasksAreOnly as s };
|
@@ -1,110 +0,0 @@
|
|
1
|
-
import { r as SequenceHooks, s as SequenceSetupFiles, F as File, d as Test, k as Suite, j as TaskResultPack, q as TestContext } from './tasks-045d21eb.js';
|
2
|
-
|
3
|
-
interface VitestRunnerConfig {
|
4
|
-
root: string;
|
5
|
-
setupFiles: string[] | string;
|
6
|
-
name: string;
|
7
|
-
passWithNoTests: boolean;
|
8
|
-
testNamePattern?: RegExp;
|
9
|
-
allowOnly?: boolean;
|
10
|
-
sequence: {
|
11
|
-
shuffle?: boolean;
|
12
|
-
seed: number;
|
13
|
-
hooks: SequenceHooks;
|
14
|
-
setupFiles: SequenceSetupFiles;
|
15
|
-
};
|
16
|
-
chaiConfig?: {
|
17
|
-
truncateThreshold?: number;
|
18
|
-
};
|
19
|
-
maxConcurrency: number;
|
20
|
-
testTimeout: number;
|
21
|
-
hookTimeout: number;
|
22
|
-
}
|
23
|
-
type VitestRunnerImportSource = 'collect' | 'setup';
|
24
|
-
interface VitestRunnerConstructor {
|
25
|
-
new (config: VitestRunnerConfig): VitestRunner;
|
26
|
-
}
|
27
|
-
type CancelReason = 'keyboard-input' | 'test-failure' | string & {};
|
28
|
-
interface VitestRunner {
|
29
|
-
/**
|
30
|
-
* First thing that's getting called before actually collecting and running tests.
|
31
|
-
*/
|
32
|
-
onBeforeCollect?(paths: string[]): unknown;
|
33
|
-
/**
|
34
|
-
* Called after collecting tests and before "onBeforeRun".
|
35
|
-
*/
|
36
|
-
onCollected?(files: File[]): unknown;
|
37
|
-
/**
|
38
|
-
* Called when test runner should cancel next test runs.
|
39
|
-
* Runner should listen for this method and mark tests and suites as skipped in
|
40
|
-
* "onBeforeRunSuite" and "onBeforeRunTest" when called.
|
41
|
-
*/
|
42
|
-
onCancel?(reason: CancelReason): unknown;
|
43
|
-
/**
|
44
|
-
* Called before running a single test. Doesn't have "result" yet.
|
45
|
-
*/
|
46
|
-
onBeforeRunTest?(test: Test): unknown;
|
47
|
-
/**
|
48
|
-
* Called before actually running the test function. Already has "result" with "state" and "startTime".
|
49
|
-
*/
|
50
|
-
onBeforeTryTest?(test: Test, options: {
|
51
|
-
retry: number;
|
52
|
-
repeats: number;
|
53
|
-
}): unknown;
|
54
|
-
/**
|
55
|
-
* Called after result and state are set.
|
56
|
-
*/
|
57
|
-
onAfterRunTest?(test: Test): unknown;
|
58
|
-
/**
|
59
|
-
* Called right after running the test function. Doesn't have new state yet. Will not be called, if the test function throws.
|
60
|
-
*/
|
61
|
-
onAfterTryTest?(test: Test, options: {
|
62
|
-
retry: number;
|
63
|
-
repeats: number;
|
64
|
-
}): unknown;
|
65
|
-
/**
|
66
|
-
* Called before running a single suite. Doesn't have "result" yet.
|
67
|
-
*/
|
68
|
-
onBeforeRunSuite?(suite: Suite): unknown;
|
69
|
-
/**
|
70
|
-
* Called after running a single suite. Has state and result.
|
71
|
-
*/
|
72
|
-
onAfterRunSuite?(suite: Suite): unknown;
|
73
|
-
/**
|
74
|
-
* If defined, will be called instead of usual Vitest suite partition and handling.
|
75
|
-
* "before" and "after" hooks will not be ignored.
|
76
|
-
*/
|
77
|
-
runSuite?(suite: Suite): Promise<void>;
|
78
|
-
/**
|
79
|
-
* If defined, will be called instead of usual Vitest handling. Useful, if you have your custom test function.
|
80
|
-
* "before" and "after" hooks will not be ignored.
|
81
|
-
*/
|
82
|
-
runTest?(test: Test): Promise<void>;
|
83
|
-
/**
|
84
|
-
* Called, when a task is updated. The same as "onTaskUpdate" in a reporter, but this is running in the same thread as tests.
|
85
|
-
*/
|
86
|
-
onTaskUpdate?(task: TaskResultPack[]): Promise<void>;
|
87
|
-
/**
|
88
|
-
* Called before running all tests in collected paths.
|
89
|
-
*/
|
90
|
-
onBeforeRun?(files: File[]): unknown;
|
91
|
-
/**
|
92
|
-
* Called right after running all tests in collected paths.
|
93
|
-
*/
|
94
|
-
onAfterRun?(files: File[]): unknown;
|
95
|
-
/**
|
96
|
-
* Called when new context for a test is defined. Useful, if you want to add custom properties to the context.
|
97
|
-
* If you only want to define custom context, consider using "beforeAll" in "setupFiles" instead.
|
98
|
-
*/
|
99
|
-
extendTestContext?(context: TestContext): TestContext;
|
100
|
-
/**
|
101
|
-
* Called, when files are imported. Can be called in two situations: when collecting tests and when importing setup files.
|
102
|
-
*/
|
103
|
-
importFile(filepath: string, source: VitestRunnerImportSource): unknown;
|
104
|
-
/**
|
105
|
-
* Publicly available configuration.
|
106
|
-
*/
|
107
|
-
config: VitestRunnerConfig;
|
108
|
-
}
|
109
|
-
|
110
|
-
export { CancelReason as C, VitestRunner as V, VitestRunnerConfig as a, VitestRunnerImportSource as b, VitestRunnerConstructor as c };
|