@vitest/runner 0.32.1 → 0.32.3

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 CHANGED
@@ -1,7 +1,7 @@
1
- import { V as VitestRunner } from './runner-0b317aff.js';
2
- export { C as CancelReason, a as VitestRunnerConfig, c as VitestRunnerConstructor, b as VitestRunnerImportSource } from './runner-0b317aff.js';
3
- import { T as Task, F as File, S as SuiteAPI, a as TestAPI, b as SuiteCollector, c as SuiteHooks, O as OnTestFailedHandler, d as Test } from './tasks-045d21eb.js';
4
- export { D as DoneCallback, n as HookCleanupCallback, H as HookListener, R as RunMode, p as RuntimeContext, r as SequenceHooks, s as SequenceSetupFiles, k as Suite, o as SuiteFactory, f as TaskBase, h as TaskCustom, g as TaskMeta, i as TaskResult, j as TaskResultPack, e as TaskState, q as TestContext, l as TestFunction, m as TestOptions } from './tasks-045d21eb.js';
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 { c as createChainable, g as generateHash, a as calculateSuiteHash, s as someTasksAreOnly, i as interpretTaskModes, p as partitionSuiteChildren, h as hasTests, b as hasFailed } from './chunk-tasks.js';
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 === Infinity)
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
- return createChainable(
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 = typeof test.repeats === "number" ? test.repeats : 1;
471
- for (let repeatCount = 0; repeatCount < repeats; repeatCount++) {
472
- const retry = test.retry || 1;
473
- for (let retryCount = 0; retryCount < retry; 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 - 1) {
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, boolean | undefined>, ...args: Args) => R;
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, boolean | undefined>, ...args: Args) => R): ChainableFunction<T, Args, R, E>;
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 1
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 1
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, SuiteAPI as S, Task as T, TestAPI as a, SuiteCollector as b, SuiteHooks as c, Test as d, TaskState as e, TaskBase as f, TaskMeta as g, TaskCustom as h, TaskResult as i, TaskResultPack as j, Suite as k, TestFunction as l, TestOptions as m, HookCleanupCallback as n, SuiteFactory as o, RuntimeContext as p, TestContext as q, SequenceHooks as r, SequenceSetupFiles as s, createChainable as t };
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
- export { D as DoneCallback, F as File, n as HookCleanupCallback, H as HookListener, O as OnTestFailedHandler, R as RunMode, p as RuntimeContext, r as SequenceHooks, s as SequenceSetupFiles, k as Suite, S as SuiteAPI, b as SuiteCollector, o as SuiteFactory, c as SuiteHooks, T as Task, f as TaskBase, h as TaskCustom, g as TaskMeta, i as TaskResult, j as TaskResultPack, e as TaskState, d as Test, a as TestAPI, q as TestContext, l as TestFunction, m as TestOptions } from './tasks-045d21eb.js';
2
- export { C as CancelReason, V as VitestRunner, a as VitestRunnerConfig, c as VitestRunnerConstructor, b as VitestRunnerImportSource } from './runner-0b317aff.js';
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 { k as Suite, T as Task, d as Test, h as TaskCustom } from './tasks-045d21eb.js';
2
- export { C as ChainableFunction, t as createChainable } from './tasks-045d21eb.js';
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
- export { a as calculateSuiteHash, c as createChainable, g as generateHash, j as getNames, f as getSuites, e as getTasks, d as getTests, b as hasFailed, h as hasTests, i as interpretTaskModes, p as partitionSuiteChildren, s as someTasksAreOnly } from './chunk-tasks.js';
2
- import '@vitest/utils/error';
3
- import '@vitest/utils';
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.1",
4
+ "version": "0.32.3",
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.0",
44
- "@vitest/utils": "0.32.1"
42
+ "pathe": "^1.1.1",
43
+ "@vitest/utils": "0.32.3"
45
44
  },
46
45
  "scripts": {
47
46
  "build": "rimraf dist && rollup -c",
@@ -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 };