@vitest/runner 2.2.0-beta.2 → 3.0.0-beta.1

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.
@@ -29,39 +29,67 @@ function createChainable(keys, fn) {
29
29
  return chain;
30
30
  }
31
31
 
32
- function interpretTaskModes(suite, namePattern, onlyMode, parentIsOnly, allowOnly) {
33
- const suiteIsOnly = parentIsOnly || suite.mode === "only";
34
- suite.tasks.forEach((t) => {
35
- const includeTask = suiteIsOnly || t.mode === "only";
36
- if (onlyMode) {
37
- if (t.type === "suite" && (includeTask || someTasksAreOnly(t))) {
38
- if (t.mode === "only") {
32
+ function interpretTaskModes(file, namePattern, testLocations, onlyMode, parentIsOnly, allowOnly) {
33
+ const matchedLocations = [];
34
+ const traverseSuite = (suite, parentIsOnly2) => {
35
+ const suiteIsOnly = parentIsOnly2 || suite.mode === "only";
36
+ suite.tasks.forEach((t) => {
37
+ const includeTask = suiteIsOnly || t.mode === "only";
38
+ if (onlyMode) {
39
+ if (t.type === "suite" && (includeTask || someTasksAreOnly(t))) {
40
+ if (t.mode === "only") {
41
+ checkAllowOnly(t, allowOnly);
42
+ t.mode = "run";
43
+ }
44
+ } else if (t.mode === "run" && !includeTask) {
45
+ t.mode = "skip";
46
+ } else if (t.mode === "only") {
39
47
  checkAllowOnly(t, allowOnly);
40
48
  t.mode = "run";
41
49
  }
42
- } else if (t.mode === "run" && !includeTask) {
43
- t.mode = "skip";
44
- } else if (t.mode === "only") {
45
- checkAllowOnly(t, allowOnly);
46
- t.mode = "run";
47
50
  }
48
- }
49
- if (t.type === "test") {
50
- if (namePattern && !getTaskFullName(t).match(namePattern)) {
51
- t.mode = "skip";
51
+ if (t.type === "test") {
52
+ if (namePattern && !getTaskFullName(t).match(namePattern)) {
53
+ t.mode = "skip";
54
+ }
55
+ if (testLocations !== void 0 && testLocations.length !== 0) {
56
+ if (t.location && (testLocations == null ? void 0 : testLocations.includes(t.location.line))) {
57
+ t.mode = "run";
58
+ matchedLocations.push(t.location.line);
59
+ } else {
60
+ t.mode = "skip";
61
+ }
62
+ }
63
+ } else if (t.type === "suite") {
64
+ if (t.mode === "skip") {
65
+ skipAllTasks(t);
66
+ } else {
67
+ traverseSuite(t, includeTask);
68
+ }
52
69
  }
53
- } else if (t.type === "suite") {
54
- if (t.mode === "skip") {
55
- skipAllTasks(t);
56
- } else {
57
- interpretTaskModes(t, namePattern, onlyMode, includeTask, allowOnly);
70
+ });
71
+ if (suite.mode === "run") {
72
+ if (suite.tasks.length && suite.tasks.every((i) => i.mode !== "run")) {
73
+ suite.mode = "skip";
58
74
  }
59
75
  }
60
- });
61
- if (suite.mode === "run") {
62
- if (suite.tasks.length && suite.tasks.every((i) => i.mode !== "run")) {
63
- suite.mode = "skip";
76
+ };
77
+ traverseSuite(file, parentIsOnly);
78
+ const nonMatching = testLocations == null ? void 0 : testLocations.filter((loc) => !matchedLocations.includes(loc));
79
+ if (nonMatching && nonMatching.length !== 0) {
80
+ const message = nonMatching.length === 1 ? `line ${nonMatching[0]}` : `lines ${nonMatching.join(", ")}`;
81
+ if (file.result === void 0) {
82
+ file.result = {
83
+ state: "fail",
84
+ errors: []
85
+ };
86
+ }
87
+ if (file.result.errors === void 0) {
88
+ file.result.errors = [];
64
89
  }
90
+ file.result.errors.push(
91
+ processError(new Error(`No test found in ${file.name} in ${message}`))
92
+ );
65
93
  }
66
94
  }
67
95
  function getTaskFullName(task) {
@@ -182,7 +210,7 @@ function isAtomTest(s) {
182
210
  return isTestCase(s);
183
211
  }
184
212
  function isTestCase(s) {
185
- return s.type === "test" || s.type === "custom";
213
+ return s.type === "test";
186
214
  }
187
215
  function getTests(suite) {
188
216
  const tests = [];
@@ -249,4 +277,4 @@ function getTestName(task, separator = " > ") {
249
277
  return getNames(task).slice(1).join(separator);
250
278
  }
251
279
 
252
- export { calculateSuiteHash as a, createFileTask as b, createChainable as c, getFullName as d, getNames as e, getSuites as f, generateHash as g, getTasks as h, interpretTaskModes as i, getTestName as j, getTests as k, limitConcurrency as l, hasFailed as m, hasTests as n, isAtomTest as o, partitionSuiteChildren as p, someTasksAreOnly as s };
280
+ export { calculateSuiteHash as a, createFileTask as b, createChainable as c, getFullName as d, getNames as e, getSuites as f, generateHash as g, getTasks as h, interpretTaskModes as i, getTestName as j, getTests as k, limitConcurrency as l, hasFailed as m, hasTests as n, isAtomTest as o, partitionSuiteChildren as p, isTestCase as q, someTasksAreOnly as s };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
- import { B as BeforeAllListener, A as AfterAllListener, d as BeforeEachListener, e as AfterEachListener, f as TaskHook, O as OnTestFailedHandler, g as OnTestFinishedHandler, a as Test, C as Custom, S as Suite, h as SuiteHooks, T as Task, F as File, i as SuiteAPI, j as TestAPI, k as SuiteCollector } from './tasks-CgWT5bp6.js';
2
- export { D as DoneCallback, E as ExtendedContext, l as Fixture, m as FixtureFn, n as FixtureOptions, o as Fixtures, H as HookCleanupCallback, p as HookListener, I as InferFixturesTypes, R as RunMode, q as RuntimeContext, r as SequenceHooks, s as SequenceSetupFiles, t as SuiteFactory, u as TaskBase, v as TaskContext, w as TaskCustomOptions, x as TaskMeta, y as TaskPopulated, z as TaskResult, G as TaskResultPack, J as TaskState, K as TestContext, L as TestFunction, M as TestOptions, U as Use } from './tasks-CgWT5bp6.js';
1
+ import { B as BeforeAllListener, A as AfterAllListener, b as BeforeEachListener, d as AfterEachListener, e as TaskHook, O as OnTestFailedHandler, f as OnTestFinishedHandler, a as Test, g as Custom, S as Suite, h as SuiteHooks, T as Task, F as File, i as SuiteAPI, j as TestAPI, k as SuiteCollector } from './tasks-D_Ah6OyC.js';
2
+ export { D as DoneCallback, E as ExtendedContext, l as Fixture, m as FixtureFn, n as FixtureOptions, o as Fixtures, H as HookCleanupCallback, p as HookListener, I as InferFixturesTypes, R as RunMode, q as RuntimeContext, r as SequenceHooks, s as SequenceSetupFiles, t as SuiteFactory, u as TaskBase, v as TaskContext, w as TaskCustomOptions, x as TaskMeta, y as TaskPopulated, z as TaskResult, G as TaskResultPack, J as TaskState, K as TestContext, L as TestFunction, M as TestOptions, U as Use } from './tasks-D_Ah6OyC.js';
3
3
  import { Awaitable } from '@vitest/utils';
4
- import { VitestRunner } from './types.js';
4
+ import { VitestRunner, FileSpec } from './types.js';
5
5
  export { CancelReason, VitestRunnerConfig, VitestRunnerConstructor, VitestRunnerImportSource } from './types.js';
6
6
  export { processError } from '@vitest/utils/error';
7
7
  import '@vitest/utils/diff';
@@ -126,8 +126,8 @@ declare function setHooks(key: Suite, hooks: SuiteHooks): void;
126
126
  declare function getHooks(key: Suite): SuiteHooks;
127
127
 
128
128
  declare function updateTask(task: Task, runner: VitestRunner): void;
129
- declare function startTests(paths: string[], runner: VitestRunner): Promise<File[]>;
130
- declare function publicCollect(paths: string[], runner: VitestRunner): Promise<File[]>;
129
+ declare function startTests(specs: string[] | FileSpec[], runner: VitestRunner): Promise<File[]>;
130
+ declare function publicCollect(specs: string[] | FileSpec[], runner: VitestRunner): Promise<File[]>;
131
131
 
132
132
  /**
133
133
  * Creates a suite of tests, allowing for grouping and hierarchical organization of tests.
@@ -254,6 +254,6 @@ declare const it: TestAPI;
254
254
  declare function getCurrentSuite<ExtraContext = object>(): SuiteCollector<ExtraContext>;
255
255
  declare function createTaskCollector(fn: (...args: any[]) => any, context?: Record<string, unknown>): TestAPI;
256
256
 
257
- declare function getCurrentTest<T extends Test | Custom | undefined>(): T;
257
+ declare function getCurrentTest<T extends Test | undefined>(): T;
258
258
 
259
- export { AfterAllListener, AfterEachListener, BeforeAllListener, BeforeEachListener, Custom, TestAPI as CustomAPI, File, OnTestFailedHandler, OnTestFinishedHandler, Suite, SuiteAPI, SuiteCollector, SuiteHooks, Task, TaskHook, Test, TestAPI, VitestRunner, afterAll, afterEach, beforeAll, beforeEach, publicCollect as collectTests, createTaskCollector, describe, getCurrentSuite, getCurrentTest, getFn, getHooks, it, onTestFailed, onTestFinished, setFn, setHooks, startTests, suite, test, updateTask };
259
+ export { AfterAllListener, AfterEachListener, BeforeAllListener, BeforeEachListener, Custom, TestAPI as CustomAPI, File, FileSpec, OnTestFailedHandler, OnTestFinishedHandler, Suite, SuiteAPI, SuiteCollector, SuiteHooks, Task, TaskHook, Test, TestAPI, VitestRunner, afterAll, afterEach, beforeAll, beforeEach, publicCollect as collectTests, createTaskCollector, describe, getCurrentSuite, getCurrentTest, getFn, getHooks, it, onTestFailed, onTestFinished, setFn, setHooks, startTests, suite, test, updateTask };
package/dist/index.js CHANGED
@@ -59,13 +59,17 @@ function createTestContext(test, runner) {
59
59
  test.pending = true;
60
60
  throw new PendingError("test is skipped; abort execution", test, note);
61
61
  };
62
- context.onTestFailed = (fn) => {
62
+ context.onTestFailed = (handler, timeout) => {
63
63
  test.onFailed || (test.onFailed = []);
64
- test.onFailed.push(fn);
64
+ test.onFailed.push(
65
+ withTimeout(handler, timeout ?? runner.config.hookTimeout, true)
66
+ );
65
67
  };
66
- context.onTestFinished = (fn) => {
68
+ context.onTestFinished = (handler, timeout) => {
67
69
  test.onFinished || (test.onFinished = []);
68
- test.onFinished.push(fn);
70
+ test.onFinished.push(
71
+ withTimeout(handler, timeout ?? runner.config.hookTimeout, true)
72
+ );
69
73
  };
70
74
  return ((_a = runner.extendTaskContext) == null ? void 0 : _a.call(runner, context)) || context;
71
75
  }
@@ -331,8 +335,7 @@ function getRunner() {
331
335
  }
332
336
  function createDefaultSuite(runner2) {
333
337
  const config = runner2.config.sequence;
334
- const api = config.shuffle ? suite.shuffle : suite;
335
- return api("", { concurrent: config.concurrent }, () => {
338
+ return suite("", { concurrent: config.concurrent }, () => {
336
339
  });
337
340
  }
338
341
  function clearCollectorContext(filepath, currentRunner) {
@@ -368,6 +371,9 @@ function parseArguments(optionsOrFn, optionsOrTest) {
368
371
  "Cannot use two objects as arguments. Please provide options and a function callback in that order."
369
372
  );
370
373
  }
374
+ console.warn(
375
+ "Using an object as a third argument is deprecated. Vitest 4 will throw an error if the third argument is not a timeout number. Please use the second argument for options. See more at https://vitest.dev/guide/migration"
376
+ );
371
377
  options = optionsOrTest;
372
378
  } else if (typeof optionsOrTest === "number") {
373
379
  options = { timeout: optionsOrTest };
@@ -390,7 +396,7 @@ function parseArguments(optionsOrFn, optionsOrTest) {
390
396
  };
391
397
  }
392
398
  function createSuiteCollector(name, factory = () => {
393
- }, mode, shuffle, each, suiteOptions) {
399
+ }, mode, each, suiteOptions) {
394
400
  const tasks = [];
395
401
  const factoryQueue = [];
396
402
  let suite2;
@@ -414,9 +420,7 @@ function createSuiteCollector(name, factory = () => {
414
420
  if (options.concurrent || !options.sequential && runner.config.sequence.concurrent) {
415
421
  task2.concurrent = true;
416
422
  }
417
- if (shuffle) {
418
- task2.shuffle = true;
419
- }
423
+ task2.shuffle = suiteOptions == null ? void 0 : suiteOptions.shuffle;
420
424
  const context = createTestContext(task2, runner);
421
425
  Object.defineProperty(task2, "context", {
422
426
  value: context,
@@ -485,7 +489,7 @@ function createSuiteCollector(name, factory = () => {
485
489
  mode,
486
490
  each,
487
491
  file: void 0,
488
- shuffle,
492
+ shuffle: suiteOptions == null ? void 0 : suiteOptions.shuffle,
489
493
  tasks: [],
490
494
  meta: /* @__PURE__ */ Object.create(null),
491
495
  concurrent: suiteOptions == null ? void 0 : suiteOptions.concurrent
@@ -543,7 +547,8 @@ function withAwaitAsyncAssetions(fn, task) {
543
547
  };
544
548
  }
545
549
  function createSuite() {
546
- function suiteFn(name, factoryOrOptions, optionsOrFactory = {}) {
550
+ function suiteFn(name, factoryOrOptions, optionsOrFactory) {
551
+ var _a;
547
552
  const mode = this.only ? "only" : this.skip ? "skip" : this.todo ? "todo" : "run";
548
553
  const currentSuite = collectorContext.currentSuite || defaultSuite;
549
554
  let { options, handler: factory } = parseArguments(
@@ -552,9 +557,11 @@ function createSuite() {
552
557
  );
553
558
  const isConcurrentSpecified = options.concurrent || this.concurrent || options.sequential === false;
554
559
  const isSequentialSpecified = options.sequential || this.sequential || options.concurrent === false;
555
- if (currentSuite == null ? void 0 : currentSuite.options) {
556
- options = { ...currentSuite.options, ...options };
557
- }
560
+ options = {
561
+ ...currentSuite == null ? void 0 : currentSuite.options,
562
+ ...options,
563
+ shuffle: this.shuffle ?? options.shuffle ?? ((_a = currentSuite == null ? void 0 : currentSuite.options) == null ? void 0 : _a.shuffle) ?? (runner == null ? void 0 : runner.config.sequence.shuffle)
564
+ };
558
565
  const isConcurrent = isConcurrentSpecified || options.concurrent && !isSequentialSpecified;
559
566
  const isSequential = isSequentialSpecified || options.sequential && !isConcurrentSpecified;
560
567
  options.concurrent = isConcurrent && !isSequential;
@@ -563,7 +570,6 @@ function createSuite() {
563
570
  formatName(name),
564
571
  factory,
565
572
  mode,
566
- this.shuffle,
567
573
  this.each,
568
574
  options
569
575
  );
@@ -578,7 +584,7 @@ function createSuite() {
578
584
  const _name = formatName(name);
579
585
  const arrayOnlyCases = cases.every(Array.isArray);
580
586
  const { options, handler } = parseArguments(optionsOrFn, fnOrOptions);
581
- const fnFirst = typeof optionsOrFn === "function";
587
+ const fnFirst = typeof optionsOrFn === "function" && typeof fnOrOptions === "object";
582
588
  cases.forEach((i, idx) => {
583
589
  const items = Array.isArray(i) ? i : [i];
584
590
  if (fnFirst) {
@@ -621,7 +627,7 @@ function createTaskCollector(fn, context) {
621
627
  const _name = formatName(name);
622
628
  const arrayOnlyCases = cases.every(Array.isArray);
623
629
  const { options, handler } = parseArguments(optionsOrFn, fnOrOptions);
624
- const fnFirst = typeof optionsOrFn === "function";
630
+ const fnFirst = typeof optionsOrFn === "function" && typeof fnOrOptions === "object";
625
631
  cases.forEach((i, idx) => {
626
632
  const items = Array.isArray(i) ? i : [i];
627
633
  if (fnFirst) {
@@ -838,12 +844,15 @@ async function runSetupFiles(config, files, runner) {
838
844
  }
839
845
 
840
846
  const now$1 = globalThis.performance ? globalThis.performance.now.bind(globalThis.performance) : Date.now;
841
- async function collectTests(paths, runner) {
847
+ async function collectTests(specs, runner) {
842
848
  var _a;
843
849
  const files = [];
844
850
  const config = runner.config;
845
- for (const filepath of paths) {
851
+ for (const spec of specs) {
852
+ const filepath = typeof spec === "string" ? spec : spec.filepath;
853
+ const testLocations = typeof spec === "string" ? void 0 : spec.testLocations;
846
854
  const file = createFileTask(filepath, config.root, config.name, runner.pool);
855
+ file.shuffle = config.sequence.shuffle;
847
856
  (_a = runner.onCollectStart) == null ? void 0 : _a.call(runner, file);
848
857
  clearCollectorContext(filepath, runner);
849
858
  try {
@@ -862,7 +871,7 @@ async function collectTests(paths, runner) {
862
871
  const fileHooks = createSuiteHooks();
863
872
  mergeHooks(fileHooks, getHooks(defaultTasks));
864
873
  for (const c of [...defaultTasks.tasks, ...collectorContext.tasks]) {
865
- if (c.type === "test" || c.type === "custom" || c.type === "suite") {
874
+ if (c.type === "test" || c.type === "suite") {
866
875
  file.tasks.push(c);
867
876
  } else if (c.type === "collector") {
868
877
  const suite = await c.collect(file);
@@ -894,6 +903,7 @@ async function collectTests(paths, runner) {
894
903
  interpretTaskModes(
895
904
  file,
896
905
  config.testNamePattern,
906
+ testLocations,
897
907
  hasOnlyTasks,
898
908
  false,
899
909
  config.allowOnly
@@ -933,25 +943,38 @@ function getSuiteHooks(suite, name, sequence) {
933
943
  }
934
944
  return hooks;
935
945
  }
936
- async function callTestHooks(runner, task, hooks, sequence) {
946
+ async function callTestHooks(runner, test, hooks, sequence) {
937
947
  if (sequence === "stack") {
938
948
  hooks = hooks.slice().reverse();
939
949
  }
950
+ if (!hooks.length) {
951
+ return;
952
+ }
953
+ const onTestFailed = test.context.onTestFailed;
954
+ const onTestFinished = test.context.onTestFinished;
955
+ test.context.onTestFailed = () => {
956
+ throw new Error(`Cannot call "onTestFailed" inside a test hook.`);
957
+ };
958
+ test.context.onTestFinished = () => {
959
+ throw new Error(`Cannot call "onTestFinished" inside a test hook.`);
960
+ };
940
961
  if (sequence === "parallel") {
941
962
  try {
942
- await Promise.all(hooks.map((fn) => fn(task.result)));
963
+ await Promise.all(hooks.map((fn) => fn(test.context)));
943
964
  } catch (e) {
944
- failTask(task.result, e, runner.config.diffOptions);
965
+ failTask(test.result, e, runner.config.diffOptions);
945
966
  }
946
967
  } else {
947
968
  for (const fn of hooks) {
948
969
  try {
949
- await fn(task.result);
970
+ await fn(test.context);
950
971
  } catch (e) {
951
- failTask(task.result, e, runner.config.diffOptions);
972
+ failTask(test.result, e, runner.config.diffOptions);
952
973
  }
953
974
  }
954
975
  }
976
+ test.context.onTestFailed = onTestFailed;
977
+ test.context.onTestFinished = onTestFinished;
955
978
  }
956
979
  async function callSuiteHook(suite, currentTask, name, runner, args) {
957
980
  const sequence = runner.config.sequence.hooks;
@@ -1201,7 +1224,7 @@ async function runSuite(suite, runner) {
1201
1224
  await Promise.all(tasksGroup.map((c) => runSuiteChild(c, runner)));
1202
1225
  } else {
1203
1226
  const { sequence } = runner.config;
1204
- if (sequence.shuffle || suite.shuffle) {
1227
+ if (suite.shuffle) {
1205
1228
  const suites = tasksGroup.filter(
1206
1229
  (group) => group.type === "suite"
1207
1230
  );
@@ -1248,7 +1271,7 @@ async function runSuite(suite, runner) {
1248
1271
  }
1249
1272
  let limitMaxConcurrency;
1250
1273
  async function runSuiteChild(c, runner) {
1251
- if (c.type === "test" || c.type === "custom") {
1274
+ if (c.type === "test") {
1252
1275
  return limitMaxConcurrency(() => runTest(c, runner));
1253
1276
  } else if (c.type === "suite") {
1254
1277
  return runSuite(c, runner);
@@ -1272,10 +1295,11 @@ async function runFiles(files, runner) {
1272
1295
  await runSuite(file, runner);
1273
1296
  }
1274
1297
  }
1275
- async function startTests(paths, runner) {
1298
+ async function startTests(specs, runner) {
1276
1299
  var _a, _b, _c, _d;
1300
+ const paths = specs.map((f) => typeof f === "string" ? f : f.filepath);
1277
1301
  await ((_a = runner.onBeforeCollect) == null ? void 0 : _a.call(runner, paths));
1278
- const files = await collectTests(paths, runner);
1302
+ const files = await collectTests(specs, runner);
1279
1303
  await ((_b = runner.onCollected) == null ? void 0 : _b.call(runner, files));
1280
1304
  await ((_c = runner.onBeforeRunFiles) == null ? void 0 : _c.call(runner, files));
1281
1305
  await runFiles(files, runner);
@@ -1283,10 +1307,11 @@ async function startTests(paths, runner) {
1283
1307
  await sendTasksUpdate(runner);
1284
1308
  return files;
1285
1309
  }
1286
- async function publicCollect(paths, runner) {
1310
+ async function publicCollect(specs, runner) {
1287
1311
  var _a, _b;
1312
+ const paths = specs.map((f) => typeof f === "string" ? f : f.filepath);
1288
1313
  await ((_a = runner.onBeforeCollect) == null ? void 0 : _a.call(runner, paths));
1289
- const files = await collectTests(paths, runner);
1314
+ const files = await collectTests(specs, runner);
1290
1315
  await ((_b = runner.onCollected) == null ? void 0 : _b.call(runner, files));
1291
1316
  return files;
1292
1317
  }
@@ -237,17 +237,8 @@ interface Test<ExtraContext = object> extends TaskPopulated {
237
237
  /**
238
238
  * @deprecated Use `Test` instead. `type: 'custom'` is not used since 2.2
239
239
  */
240
- interface Custom<ExtraContext = object> extends TaskPopulated {
241
- /**
242
- * @deprecated use `test` instead. `custom` is not used since 2.2
243
- */
244
- type: 'custom';
245
- /**
246
- * Task context that will be passed to the test function.
247
- */
248
- context: TaskContext<Test> & ExtraContext & TestContext;
249
- }
250
- type Task = Test | Suite | Custom | File;
240
+ type Custom<ExtraContext = object> = Test<ExtraContext>;
241
+ type Task = Test | Suite | File;
251
242
  /**
252
243
  * @deprecated Vitest doesn't provide `done()` anymore
253
244
  */
@@ -270,9 +261,9 @@ interface EachFunctionReturn<T extends any[]> {
270
261
  /**
271
262
  * @deprecated Use options as the second argument instead
272
263
  */
273
- (name: string | Function, fn: (...args: T) => Awaitable<void>, options: TestOptions): void;
274
- (name: string | Function, fn: (...args: T) => Awaitable<void>, options?: number | TestOptions): void;
275
- (name: string | Function, options: TestOptions, fn: (...args: T) => Awaitable<void>): void;
264
+ (name: string | Function, fn: (...args: T) => Awaitable<void>, options: TestCollectorOptions): void;
265
+ (name: string | Function, fn: (...args: T) => Awaitable<void>, options?: number | TestCollectorOptions): void;
266
+ (name: string | Function, options: TestCollectorOptions, fn: (...args: T) => Awaitable<void>): void;
276
267
  }
277
268
  interface TestEachFunction {
278
269
  <T extends any[] | [any]>(cases: ReadonlyArray<T>): EachFunctionReturn<T>;
@@ -282,7 +273,7 @@ interface TestEachFunction {
282
273
  }
283
274
  interface TestForFunctionReturn<Arg, Context> {
284
275
  (name: string | Function, fn: (arg: Arg, context: Context) => Awaitable<void>): void;
285
- (name: string | Function, options: TestOptions, fn: (args: Arg, context: Context) => Awaitable<void>): void;
276
+ (name: string | Function, options: TestCollectorOptions, fn: (args: Arg, context: Context) => Awaitable<void>): void;
286
277
  }
287
278
  interface TestForFunction<ExtraContext> {
288
279
  <T>(cases: ReadonlyArray<T>): TestForFunctionReturn<T, ExtendedContext<Test> & ExtraContext>;
@@ -292,14 +283,15 @@ interface TestCollectorCallable<C = object> {
292
283
  /**
293
284
  * @deprecated Use options as the second argument instead
294
285
  */
295
- <ExtraContext extends C>(name: string | Function, fn: TestFunction<ExtraContext>, options: TestOptions): void;
296
- <ExtraContext extends C>(name: string | Function, fn?: TestFunction<ExtraContext>, options?: number | TestOptions): void;
297
- <ExtraContext extends C>(name: string | Function, options?: TestOptions, fn?: TestFunction<ExtraContext>): void;
286
+ <ExtraContext extends C>(name: string | Function, fn: TestFunction<ExtraContext>, options: TestCollectorOptions): void;
287
+ <ExtraContext extends C>(name: string | Function, fn?: TestFunction<ExtraContext>, options?: number | TestCollectorOptions): void;
288
+ <ExtraContext extends C>(name: string | Function, options?: TestCollectorOptions, fn?: TestFunction<ExtraContext>): void;
298
289
  }
299
290
  type ChainableTestAPI<ExtraContext = object> = ChainableFunction<'concurrent' | 'sequential' | 'only' | 'skip' | 'todo' | 'fails', TestCollectorCallable<ExtraContext>, {
300
291
  each: TestEachFunction;
301
292
  for: TestForFunction<ExtraContext>;
302
293
  }>;
294
+ type TestCollectorOptions = Omit<TestOptions, 'shuffle'>;
303
295
  interface TestOptions {
304
296
  /**
305
297
  * Test timeout.
@@ -329,6 +321,10 @@ interface TestOptions {
329
321
  * Tests inherit `sequential` from `describe()` and nested `describe()` will inherit from parent's `sequential`.
330
322
  */
331
323
  sequential?: boolean;
324
+ /**
325
+ * Whether the tasks of the suite run in a random order.
326
+ */
327
+ shuffle?: boolean;
332
328
  /**
333
329
  * Whether the test should be skipped.
334
330
  */
@@ -436,7 +432,7 @@ interface SuiteCollector<ExtraContext = object> {
436
432
  options?: TestOptions;
437
433
  type: 'collector';
438
434
  test: TestAPI<ExtraContext>;
439
- tasks: (Suite | Custom<ExtraContext> | Test<ExtraContext> | SuiteCollector<ExtraContext>)[];
435
+ tasks: (Suite | Test<ExtraContext> | SuiteCollector<ExtraContext>)[];
440
436
  task: (name: string, options?: TaskCustomOptions) => Test<ExtraContext>;
441
437
  collect: (file: File) => Promise<Suite>;
442
438
  clear: () => void;
@@ -463,11 +459,11 @@ interface TaskContext<Task extends Test = Test> {
463
459
  /**
464
460
  * Extract hooks on test failed
465
461
  */
466
- onTestFailed: (fn: OnTestFailedHandler) => void;
462
+ onTestFailed: (fn: OnTestFailedHandler, timeout?: number) => void;
467
463
  /**
468
464
  * Extract hooks on test failed
469
465
  */
470
- onTestFinished: (fn: OnTestFinishedHandler) => void;
466
+ onTestFinished: (fn: OnTestFinishedHandler, timeout?: number) => void;
471
467
  /**
472
468
  * Mark tests as skipped. All execution after this call will be skipped.
473
469
  * This function throws an error, so make sure you are not catching it accidentally.
@@ -475,12 +471,12 @@ interface TaskContext<Task extends Test = Test> {
475
471
  skip: (note?: string) => void;
476
472
  }
477
473
  type ExtendedContext<T extends Test> = TaskContext<T> & TestContext;
478
- type OnTestFailedHandler = (result: TaskResult) => Awaitable<void>;
479
- type OnTestFinishedHandler = (result: TaskResult) => Awaitable<void>;
474
+ type OnTestFailedHandler = (context: ExtendedContext<Test>) => Awaitable<void>;
475
+ type OnTestFinishedHandler = (context: ExtendedContext<Test>) => Awaitable<void>;
480
476
  interface TaskHook<HookListener> {
481
477
  (fn: HookListener, timeout?: number): void;
482
478
  }
483
479
  type SequenceHooks = 'stack' | 'list' | 'parallel';
484
480
  type SequenceSetupFiles = 'list' | 'parallel';
485
481
 
486
- export { type AfterAllListener as A, type BeforeAllListener as B, type Custom as C, type DoneCallback as D, type ExtendedContext as E, type File as F, type TaskResultPack as G, type HookCleanupCallback as H, type InferFixturesTypes as I, type TaskState as J, type TestContext as K, type TestFunction as L, type TestOptions as M, type OnTestFailedHandler as O, type RunMode as R, type Suite as S, type Task as T, type Use as U, type Test as a, type ChainableFunction as b, createChainable as c, type BeforeEachListener as d, type AfterEachListener as e, type TaskHook as f, type OnTestFinishedHandler as g, type SuiteHooks as h, type SuiteAPI as i, type TestAPI as j, type SuiteCollector as k, type Fixture as l, type FixtureFn as m, type FixtureOptions as n, type Fixtures as o, type HookListener as p, type RuntimeContext as q, type SequenceHooks as r, type SequenceSetupFiles as s, type SuiteFactory as t, type TaskBase as u, type TaskContext as v, type TaskCustomOptions as w, type TaskMeta as x, type TaskPopulated as y, type TaskResult as z };
482
+ export { type AfterAllListener as A, type BeforeAllListener as B, type ChainableFunction as C, type DoneCallback as D, type ExtendedContext as E, type File as F, type TaskResultPack as G, type HookCleanupCallback as H, type InferFixturesTypes as I, type TaskState as J, type TestContext as K, type TestFunction as L, type TestOptions as M, type OnTestFailedHandler as O, type RunMode as R, type Suite as S, type Task as T, type Use as U, type Test as a, type BeforeEachListener as b, createChainable as c, type AfterEachListener as d, type TaskHook as e, type OnTestFinishedHandler as f, type Custom as g, type SuiteHooks as h, type SuiteAPI as i, type TestAPI as j, type SuiteCollector as k, type Fixture as l, type FixtureFn as m, type FixtureOptions as n, type Fixtures as o, type HookListener as p, type RuntimeContext as q, type SequenceHooks as r, type SequenceSetupFiles as s, type SuiteFactory as t, type TaskBase as u, type TaskContext as v, type TaskCustomOptions as w, type TaskMeta as x, type TaskPopulated as y, type TaskResult as z };
package/dist/types.d.ts CHANGED
@@ -1,6 +1,6 @@
1
1
  import { DiffOptions } from '@vitest/utils/diff';
2
- import { r as SequenceHooks, s as SequenceSetupFiles, F as File, T as Task, a as Test, C as Custom, S as Suite, G as TaskResultPack, v as TaskContext, E as ExtendedContext } from './tasks-CgWT5bp6.js';
3
- export { A as AfterAllListener, e as AfterEachListener, B as BeforeAllListener, d as BeforeEachListener, j as CustomAPI, D as DoneCallback, l as Fixture, m as FixtureFn, n as FixtureOptions, o as Fixtures, H as HookCleanupCallback, p as HookListener, I as InferFixturesTypes, O as OnTestFailedHandler, g as OnTestFinishedHandler, R as RunMode, q as RuntimeContext, i as SuiteAPI, k as SuiteCollector, t as SuiteFactory, h as SuiteHooks, u as TaskBase, w as TaskCustomOptions, f as TaskHook, x as TaskMeta, y as TaskPopulated, z as TaskResult, J as TaskState, j as TestAPI, K as TestContext, L as TestFunction, M as TestOptions, U as Use } from './tasks-CgWT5bp6.js';
2
+ import { r as SequenceHooks, s as SequenceSetupFiles, F as File, T as Task, a as Test, S as Suite, G as TaskResultPack, v as TaskContext, E as ExtendedContext } from './tasks-D_Ah6OyC.js';
3
+ export { A as AfterAllListener, d as AfterEachListener, B as BeforeAllListener, b as BeforeEachListener, g as Custom, j as CustomAPI, D as DoneCallback, l as Fixture, m as FixtureFn, n as FixtureOptions, o as Fixtures, H as HookCleanupCallback, p as HookListener, I as InferFixturesTypes, O as OnTestFailedHandler, f as OnTestFinishedHandler, R as RunMode, q as RuntimeContext, i as SuiteAPI, k as SuiteCollector, t as SuiteFactory, h as SuiteHooks, u as TaskBase, w as TaskCustomOptions, e as TaskHook, x as TaskMeta, y as TaskPopulated, z as TaskResult, J as TaskState, j as TestAPI, K as TestContext, L as TestFunction, M as TestOptions, U as Use } from './tasks-D_Ah6OyC.js';
4
4
  import '@vitest/utils';
5
5
 
6
6
  /**
@@ -30,6 +30,10 @@ interface VitestRunnerConfig {
30
30
  includeTaskLocation?: boolean;
31
31
  diffOptions?: DiffOptions;
32
32
  }
33
+ interface FileSpec {
34
+ filepath: string;
35
+ testLocations: number[] | undefined;
36
+ }
33
37
  type VitestRunnerImportSource = 'collect' | 'setup';
34
38
  interface VitestRunnerConstructor {
35
39
  new (config: VitestRunnerConfig): VitestRunner;
@@ -68,7 +72,7 @@ interface VitestRunner {
68
72
  /**
69
73
  * When the task has finished running, but before cleanup hooks are called
70
74
  */
71
- onTaskFinished?: (test: Test | Custom) => unknown;
75
+ onTaskFinished?: (test: Test) => unknown;
72
76
  /**
73
77
  * Called after result and state are set.
74
78
  */
@@ -137,4 +141,4 @@ interface VitestRunner {
137
141
  pool?: string;
138
142
  }
139
143
 
140
- export { type CancelReason, Custom, ExtendedContext, File, SequenceHooks, SequenceSetupFiles, Suite, Task, TaskContext, TaskResultPack, Test, type VitestRunner, type VitestRunnerConfig, type VitestRunnerConstructor, type VitestRunnerImportSource };
144
+ export { type CancelReason, ExtendedContext, File, type FileSpec, SequenceHooks, SequenceSetupFiles, Suite, Task, TaskContext, TaskResultPack, Test, type VitestRunner, type VitestRunnerConfig, type VitestRunnerConstructor, type VitestRunnerImportSource };
package/dist/utils.d.ts CHANGED
@@ -1,11 +1,11 @@
1
- import { S as Suite, F as File, T as Task, a as Test, C as Custom } from './tasks-CgWT5bp6.js';
2
- export { b as ChainableFunction, c as createChainable } from './tasks-CgWT5bp6.js';
1
+ import { S as Suite, F as File, T as Task, a as Test } from './tasks-D_Ah6OyC.js';
2
+ export { C as ChainableFunction, c as createChainable } from './tasks-D_Ah6OyC.js';
3
3
  import { Arrayable } from '@vitest/utils';
4
4
 
5
5
  /**
6
6
  * If any tasks been marked as `only`, mark all other tasks as `skip`.
7
7
  */
8
- declare function interpretTaskModes(suite: Suite, namePattern?: string | RegExp, onlyMode?: boolean, parentIsOnly?: boolean, allowOnly?: boolean): void;
8
+ declare function interpretTaskModes(file: Suite, namePattern?: string | RegExp, testLocations?: number[] | undefined, onlyMode?: boolean, parentIsOnly?: boolean, allowOnly?: boolean): void;
9
9
  declare function someTasksAreOnly(suite: Suite): boolean;
10
10
  declare function generateHash(str: string): string;
11
11
  declare function calculateSuiteHash(parent: Suite): void;
@@ -24,8 +24,9 @@ declare function partitionSuiteChildren(suite: Suite): Task[][];
24
24
  /**
25
25
  * @deprecated use `isTestCase` instead
26
26
  */
27
- declare function isAtomTest(s: Task): s is Test | Custom;
28
- declare function getTests(suite: Arrayable<Task>): (Test | Custom)[];
27
+ declare function isAtomTest(s: Task): s is Test;
28
+ declare function isTestCase(s: Task): s is Test;
29
+ declare function getTests(suite: Arrayable<Task>): Test[];
29
30
  declare function getTasks(tasks?: Arrayable<Task>): Task[];
30
31
  declare function getSuites(suite: Arrayable<Task>): Suite[];
31
32
  declare function hasTests(suite: Arrayable<Suite>): boolean;
@@ -34,4 +35,4 @@ declare function getNames(task: Task): string[];
34
35
  declare function getFullName(task: Task, separator?: string): string;
35
36
  declare function getTestName(task: Task, separator?: string): string;
36
37
 
37
- export { calculateSuiteHash, createFileTask, generateHash, getFullName, getNames, getSuites, getTasks, getTestName, getTests, hasFailed, hasTests, interpretTaskModes, isAtomTest, limitConcurrency, partitionSuiteChildren, someTasksAreOnly };
38
+ export { calculateSuiteHash, createFileTask, generateHash, getFullName, getNames, getSuites, getTasks, getTestName, getTests, hasFailed, hasTests, interpretTaskModes, isAtomTest, isTestCase, limitConcurrency, partitionSuiteChildren, someTasksAreOnly };
package/dist/utils.js CHANGED
@@ -1,4 +1,4 @@
1
- export { a as calculateSuiteHash, c as createChainable, b as createFileTask, g as generateHash, d as getFullName, e as getNames, f as getSuites, h as getTasks, j as getTestName, k as getTests, m as hasFailed, n as hasTests, i as interpretTaskModes, o as isAtomTest, l as limitConcurrency, p as partitionSuiteChildren, s as someTasksAreOnly } from './chunk-tasks.js';
1
+ export { a as calculateSuiteHash, c as createChainable, b as createFileTask, g as generateHash, d as getFullName, e as getNames, f as getSuites, h as getTasks, j as getTestName, k as getTests, m as hasFailed, n as hasTests, i as interpretTaskModes, o as isAtomTest, q as isTestCase, l as limitConcurrency, p as partitionSuiteChildren, s as someTasksAreOnly } from './chunk-tasks.js';
2
2
  import '@vitest/utils/error';
3
3
  import 'pathe';
4
4
  import '@vitest/utils';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vitest/runner",
3
3
  "type": "module",
4
- "version": "2.2.0-beta.2",
4
+ "version": "3.0.0-beta.1",
5
5
  "description": "Vitest test runner",
6
6
  "license": "MIT",
7
7
  "funding": "https://opencollective.com/vitest",
@@ -39,7 +39,7 @@
39
39
  ],
40
40
  "dependencies": {
41
41
  "pathe": "^1.1.2",
42
- "@vitest/utils": "2.2.0-beta.2"
42
+ "@vitest/utils": "3.0.0-beta.1"
43
43
  },
44
44
  "scripts": {
45
45
  "build": "rimraf dist && rollup -c",