@vitest/runner 3.0.0-beta.4 → 3.0.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.
@@ -49,8 +49,8 @@ function interpretTaskModes(file, namePattern, testLocations, onlyMode, parentIs
49
49
  }
50
50
  }
51
51
  let hasLocationMatch = parentMatchedWithLocation;
52
- if (testLocations !== void 0 && testLocations.length !== 0) {
53
- if (t.location && (testLocations == null ? void 0 : testLocations.includes(t.location.line))) {
52
+ if (testLocations !== undefined && testLocations.length !== 0) {
53
+ if (t.location && (testLocations == null ? undefined : testLocations.includes(t.location.line))) {
54
54
  t.mode = "run";
55
55
  matchedLocations.push(t.location.line);
56
56
  hasLocationMatch = true;
@@ -81,16 +81,16 @@ function interpretTaskModes(file, namePattern, testLocations, onlyMode, parentIs
81
81
  }
82
82
  };
83
83
  traverseSuite(file, parentIsOnly, false);
84
- const nonMatching = testLocations == null ? void 0 : testLocations.filter((loc) => !matchedLocations.includes(loc));
84
+ const nonMatching = testLocations == null ? undefined : testLocations.filter((loc) => !matchedLocations.includes(loc));
85
85
  if (nonMatching && nonMatching.length !== 0) {
86
86
  const message = nonMatching.length === 1 ? `line ${nonMatching[0]}` : `lines ${nonMatching.join(", ")}`;
87
- if (file.result === void 0) {
87
+ if (file.result === undefined) {
88
88
  file.result = {
89
89
  state: "fail",
90
90
  errors: []
91
91
  };
92
92
  }
93
- if (file.result.errors === void 0) {
93
+ if (file.result.errors === undefined) {
94
94
  file.result.errors = [];
95
95
  }
96
96
  file.result.errors.push(
@@ -171,7 +171,7 @@ function createFileTask(filepath, root, projectName, pool) {
171
171
  tasks: [],
172
172
  meta: /* @__PURE__ */ Object.create(null),
173
173
  projectName,
174
- file: void 0,
174
+ file: undefined,
175
175
  pool
176
176
  };
177
177
  file.file = file;
@@ -271,16 +271,16 @@ function hasFailed(suite) {
271
271
  return toArray(suite).some(
272
272
  (s) => {
273
273
  var _a;
274
- return ((_a = s.result) == null ? void 0 : _a.state) === "fail" || s.type === "suite" && hasFailed(s.tasks);
274
+ return ((_a = s.result) == null ? undefined : _a.state) === "fail" || s.type === "suite" && hasFailed(s.tasks);
275
275
  }
276
276
  );
277
277
  }
278
278
  function getNames(task) {
279
279
  const names = [task.name];
280
280
  let current = task;
281
- while (current == null ? void 0 : current.suite) {
281
+ while (current == null ? undefined : current.suite) {
282
282
  current = current.suite;
283
- if (current == null ? void 0 : current.name) {
283
+ if (current == null ? undefined : current.name) {
284
284
  names.unshift(current.name);
285
285
  }
286
286
  }
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
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-B64RTJlW.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-B64RTJlW.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, i as TaskUpdateEvent, T as Task, F as File, j as SuiteAPI, k as TestAPI, l as SuiteCollector } from './tasks-CUXfn9LM.js';
2
+ export { D as DoneCallback, E as ExtendedContext, m as Fixture, n as FixtureFn, o as FixtureOptions, p as Fixtures, H as HookCleanupCallback, q as HookListener, I as InferFixturesTypes, R as RunMode, r as RuntimeContext, s as SequenceHooks, t as SequenceSetupFiles, u as SuiteFactory, v as TaskBase, w as TaskContext, x as TaskCustomOptions, y as TaskEventPack, z as TaskMeta, G as TaskPopulated, J as TaskResult, K as TaskResultPack, L as TaskState, M as TestContext, N as TestFunction, P as TestOptions, U as Use } from './tasks-CUXfn9LM.js';
3
3
  import { Awaitable } from '@vitest/utils';
4
4
  import { VitestRunner, FileSpecification } from './types.js';
5
5
  export { CancelReason, VitestRunnerConfig, VitestRunnerConstructor, VitestRunnerImportSource } from './types.js';
@@ -105,6 +105,8 @@ declare const onTestFailed: TaskHook<OnTestFailedHandler>;
105
105
  *
106
106
  * **Note:** The `onTestFinished` hooks are running in reverse order of their registration. You can configure this by changing the `sequence.hooks` option in the config file.
107
107
  *
108
+ * **Note:** The `onTestFinished` hook is not called if the test is canceled with a dynamic `ctx.skip()` call.
109
+ *
108
110
  * @param {Function} fn - The callback function to be executed after a test finishes. The function can receive parameters providing details about the completed test, including its success or failure status.
109
111
  * @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
110
112
  * @throws {Error} Throws an error if the function is not called within a test.
@@ -125,7 +127,7 @@ declare function getFn<Task = Test | Custom>(key: Task): () => Awaitable<void>;
125
127
  declare function setHooks(key: Suite, hooks: SuiteHooks): void;
126
128
  declare function getHooks(key: Suite): SuiteHooks;
127
129
 
128
- declare function updateTask(task: Task, runner: VitestRunner): void;
130
+ declare function updateTask(event: TaskUpdateEvent, task: Task, runner: VitestRunner): void;
129
131
  declare function startTests(specs: string[] | FileSpecification[], runner: VitestRunner): Promise<File[]>;
130
132
  declare function publicCollect(specs: string[] | FileSpecification[], runner: VitestRunner): Promise<File[]>;
131
133
 
@@ -256,4 +258,4 @@ declare function createTaskCollector(fn: (...args: any[]) => any, context?: Reco
256
258
 
257
259
  declare function getCurrentTest<T extends Test | undefined>(): T;
258
260
 
259
- export { AfterAllListener, AfterEachListener, BeforeAllListener, BeforeEachListener, Custom, TestAPI as CustomAPI, File, FileSpecification, 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 };
261
+ export { AfterAllListener, AfterEachListener, BeforeAllListener, BeforeEachListener, Custom, TestAPI as CustomAPI, File, FileSpecification, OnTestFailedHandler, OnTestFinishedHandler, Suite, SuiteAPI, SuiteCollector, SuiteHooks, Task, TaskHook, TaskUpdateEvent, 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
@@ -1,4 +1,4 @@
1
- import { getSafeTimers, isObject, createDefer, isNegativeNaN, format, objDisplay, objectAttr, toArray, assertTypes, shuffle } from '@vitest/utils';
1
+ import { getSafeTimers, isObject, createDefer, toArray, isNegativeNaN, format, objDisplay, objectAttr, assertTypes, shuffle } from '@vitest/utils';
2
2
  import { parseSingleStack } from '@vitest/utils/source-map';
3
3
  import { c as createChainable, b as createFileTask, a as calculateSuiteHash, s as someTasksAreOnly, i as interpretTaskModes, l as limitConcurrency, p as partitionSuiteChildren, o as hasTests, n as hasFailed } from './chunk-tasks.js';
4
4
  import { processError } from '@vitest/utils/error';
@@ -22,7 +22,7 @@ const collectorContext = {
22
22
  };
23
23
  function collectTask(task) {
24
24
  var _a;
25
- (_a = collectorContext.currentSuite) == null ? void 0 : _a.tasks.push(task);
25
+ (_a = collectorContext.currentSuite) == null ? undefined : _a.tasks.push(task);
26
26
  }
27
27
  async function runWithSuite(suite, fn) {
28
28
  const prev = collectorContext.currentSuite;
@@ -43,7 +43,7 @@ function withTimeout(fn, timeout, isHook = false) {
43
43
  clearTimeout(timer);
44
44
  reject(new Error(makeTimeoutMsg(isHook, timeout)));
45
45
  }, timeout);
46
- (_a = timer.unref) == null ? void 0 : _a.call(timer);
46
+ (_a = timer.unref) == null ? undefined : _a.call(timer);
47
47
  }),
48
48
  Promise.resolve(fn(...args)).then((result) => {
49
49
  return new Promise((resolve) => setTimeout(resolve, 0, result));
@@ -58,7 +58,8 @@ function createTestContext(test, runner) {
58
58
  };
59
59
  context.task = test;
60
60
  context.skip = (note) => {
61
- test.pending = true;
61
+ test.result ?? (test.result = { state: "skip" });
62
+ test.result.pending = true;
62
63
  throw new PendingError("test is skipped; abort execution", test, note);
63
64
  };
64
65
  context.onTestFailed = (handler, timeout) => {
@@ -73,7 +74,7 @@ function createTestContext(test, runner) {
73
74
  withTimeout(handler, timeout ?? runner.config.hookTimeout, true)
74
75
  );
75
76
  };
76
- return ((_a = runner.extendTaskContext) == null ? void 0 : _a.call(runner, context)) || context;
77
+ return ((_a = runner.extendTaskContext) == null ? undefined : _a.call(runner, context)) || context;
77
78
  }
78
79
  function makeTimeoutMsg(isHook, timeout) {
79
80
  return `${isHook ? "Hook" : "Test"} timed out in ${timeout}ms.
@@ -150,7 +151,7 @@ function withFixtures(fn, testContext) {
150
151
  return fn({});
151
152
  }
152
153
  const fixtures = getFixture(context);
153
- if (!(fixtures == null ? void 0 : fixtures.length)) {
154
+ if (!(fixtures == null ? undefined : fixtures.length)) {
154
155
  return fn(context);
155
156
  }
156
157
  const usedProps = getUsedProps(fn);
@@ -407,12 +408,12 @@ function createSuiteCollector(name, factory = () => {
407
408
  const task2 = {
408
409
  id: "",
409
410
  name: name2,
410
- suite: void 0,
411
+ suite: undefined,
411
412
  each: options.each,
412
413
  fails: options.fails,
413
- context: void 0,
414
+ context: undefined,
414
415
  type: "test",
415
- file: void 0,
416
+ file: undefined,
416
417
  retry: options.retry ?? runner.config.retry,
417
418
  repeats: options.repeats,
418
419
  mode: options.only ? "only" : options.skip ? "skip" : options.todo ? "todo" : "run",
@@ -422,7 +423,7 @@ function createSuiteCollector(name, factory = () => {
422
423
  if (options.concurrent || !options.sequential && runner.config.sequence.concurrent) {
423
424
  task2.concurrent = true;
424
425
  }
425
- task2.shuffle = suiteOptions == null ? void 0 : suiteOptions.shuffle;
426
+ task2.shuffle = suiteOptions == null ? undefined : suiteOptions.shuffle;
426
427
  const context = createTestContext(task2, runner);
427
428
  Object.defineProperty(task2, "context", {
428
429
  value: context,
@@ -434,7 +435,7 @@ function createSuiteCollector(name, factory = () => {
434
435
  task2,
435
436
  withTimeout(
436
437
  withAwaitAsyncAssertions(withFixtures(handler, context), task2),
437
- (options == null ? void 0 : options.timeout) ?? runner.config.testTimeout
438
+ (options == null ? undefined : options.timeout) ?? runner.config.testTimeout
438
439
  )
439
440
  );
440
441
  }
@@ -456,8 +457,8 @@ function createSuiteCollector(name, factory = () => {
456
457
  if (typeof suiteOptions === "object") {
457
458
  options = Object.assign({}, suiteOptions, options);
458
459
  }
459
- options.concurrent = this.concurrent || !this.sequential && (options == null ? void 0 : options.concurrent);
460
- options.sequential = this.sequential || !this.concurrent && (options == null ? void 0 : options.sequential);
460
+ options.concurrent = this.concurrent || !this.sequential && (options == null ? undefined : options.concurrent);
461
+ options.sequential = this.sequential || !this.concurrent && (options == null ? undefined : options.sequential);
461
462
  const test3 = task(formatName(name2), {
462
463
  ...this,
463
464
  ...options,
@@ -490,11 +491,11 @@ function createSuiteCollector(name, factory = () => {
490
491
  name,
491
492
  mode,
492
493
  each,
493
- file: void 0,
494
- shuffle: suiteOptions == null ? void 0 : suiteOptions.shuffle,
494
+ file: undefined,
495
+ shuffle: suiteOptions == null ? undefined : suiteOptions.shuffle,
495
496
  tasks: [],
496
497
  meta: /* @__PURE__ */ Object.create(null),
497
- concurrent: suiteOptions == null ? void 0 : suiteOptions.concurrent
498
+ concurrent: suiteOptions == null ? undefined : suiteOptions.concurrent
498
499
  };
499
500
  if (runner && includeLocation && runner.config.includeTaskLocation) {
500
501
  const limit = Error.stackTraceLimit;
@@ -538,14 +539,15 @@ function createSuiteCollector(name, factory = () => {
538
539
  }
539
540
  function withAwaitAsyncAssertions(fn, task) {
540
541
  return async (...args) => {
541
- await fn(...args);
542
+ const fnResult = await fn(...args);
542
543
  if (task.promises) {
543
544
  const result = await Promise.allSettled(task.promises);
544
- const errors = result.map((r) => r.status === "rejected" ? r.reason : void 0).filter(Boolean);
545
+ const errors = result.map((r) => r.status === "rejected" ? r.reason : undefined).filter(Boolean);
545
546
  if (errors.length) {
546
547
  throw errors;
547
548
  }
548
549
  }
550
+ return fnResult;
549
551
  };
550
552
  }
551
553
  function createSuite() {
@@ -560,9 +562,9 @@ function createSuite() {
560
562
  const isConcurrentSpecified = options.concurrent || this.concurrent || options.sequential === false;
561
563
  const isSequentialSpecified = options.sequential || this.sequential || options.concurrent === false;
562
564
  options = {
563
- ...currentSuite == null ? void 0 : currentSuite.options,
565
+ ...currentSuite == null ? undefined : currentSuite.options,
564
566
  ...options,
565
- 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)
567
+ shuffle: this.shuffle ?? options.shuffle ?? ((_a = currentSuite == null ? undefined : currentSuite.options) == null ? undefined : _a.shuffle) ?? (runner == null ? undefined : runner.config.sequence.shuffle)
566
568
  };
567
569
  const isConcurrent = isConcurrentSpecified || options.concurrent && !isSequentialSpecified;
568
570
  const isSequential = isSequentialSpecified || options.sequential && !isConcurrentSpecified;
@@ -607,7 +609,19 @@ function createSuite() {
607
609
  }
608
610
  }
609
611
  });
610
- this.setContext("each", void 0);
612
+ this.setContext("each", undefined);
613
+ };
614
+ };
615
+ suiteFn.for = function(cases, ...args) {
616
+ if (Array.isArray(cases) && args.length) {
617
+ cases = formatTemplateString(cases, args);
618
+ }
619
+ return (name, optionsOrFn, fnOrOptions) => {
620
+ const name_ = formatName(name);
621
+ const { options, handler } = parseArguments(optionsOrFn, fnOrOptions);
622
+ cases.forEach((item, idx) => {
623
+ suite(formatTitle(name_, toArray(item), idx), options, () => handler(item));
624
+ });
611
625
  };
612
626
  };
613
627
  suiteFn.skipIf = (condition) => condition ? suite.skip : suite;
@@ -650,7 +664,7 @@ function createTaskCollector(fn, context) {
650
664
  }
651
665
  }
652
666
  });
653
- this.setContext("each", void 0);
667
+ this.setContext("each", undefined);
654
668
  };
655
669
  };
656
670
  taskFn.for = function(cases, ...args) {
@@ -681,7 +695,7 @@ function createTaskCollector(fn, context) {
681
695
  context || {},
682
696
  (key) => {
683
697
  var _a, _b;
684
- return (_b = (_a = getRunner()).injectValue) == null ? void 0 : _b.call(_a, key);
698
+ return (_b = (_a = getRunner()).injectValue) == null ? undefined : _b.call(_a, key);
685
699
  }
686
700
  );
687
701
  return createTest(function fn2(name, optionsOrFn, optionsOrTest) {
@@ -733,7 +747,7 @@ function formatTitle(template, items, idx) {
733
747
  (_, key) => {
734
748
  var _a, _b;
735
749
  return objDisplay(objectAttr(items[0], key), {
736
- truncate: (_b = (_a = runner == null ? void 0 : runner.config) == null ? void 0 : _a.chaiConfig) == null ? void 0 : _b.truncateThreshold
750
+ truncate: (_b = (_a = runner == null ? undefined : runner.config) == null ? undefined : _a.chaiConfig) == null ? undefined : _b.truncateThreshold
737
751
  });
738
752
  }
739
753
  );
@@ -852,10 +866,10 @@ async function collectTests(specs, runner) {
852
866
  const config = runner.config;
853
867
  for (const spec of specs) {
854
868
  const filepath = typeof spec === "string" ? spec : spec.filepath;
855
- const testLocations = typeof spec === "string" ? void 0 : spec.testLocations;
869
+ const testLocations = typeof spec === "string" ? undefined : spec.testLocations;
856
870
  const file = createFileTask(filepath, config.root, config.name, runner.pool);
857
871
  file.shuffle = config.sequence.shuffle;
858
- (_a = runner.onCollectStart) == null ? void 0 : _a.call(runner, file);
872
+ (_a = runner.onCollectStart) == null ? undefined : _a.call(runner, file);
859
873
  clearCollectorContext(filepath, runner);
860
874
  try {
861
875
  const setupFiles = toArray(config.setupFiles);
@@ -897,7 +911,7 @@ async function collectTests(specs, runner) {
897
911
  calculateSuiteHash(file);
898
912
  file.tasks.forEach((task) => {
899
913
  var _a2;
900
- if (((_a2 = task.suite) == null ? void 0 : _a2.id) === "") {
914
+ if (((_a2 = task.suite) == null ? undefined : _a2.id) === "") {
901
915
  delete task.suite;
902
916
  }
903
917
  });
@@ -927,18 +941,25 @@ function mergeHooks(baseHooks, hooks) {
927
941
 
928
942
  const now = globalThis.performance ? globalThis.performance.now.bind(globalThis.performance) : Date.now;
929
943
  const unixNow = Date.now;
930
- function updateSuiteHookState(suite, name, state, runner) {
931
- var _a;
932
- if (!suite.result) {
933
- suite.result = { state: "run" };
944
+ function updateSuiteHookState(task, name, state, runner) {
945
+ if (!task.result) {
946
+ task.result = { state: "run" };
934
947
  }
935
- if (!((_a = suite.result) == null ? void 0 : _a.hooks)) {
936
- suite.result.hooks = {};
948
+ if (!task.result.hooks) {
949
+ task.result.hooks = {};
937
950
  }
938
- const suiteHooks = suite.result.hooks;
951
+ const suiteHooks = task.result.hooks;
939
952
  if (suiteHooks) {
940
953
  suiteHooks[name] = state;
941
- updateTask(suite, runner);
954
+ let event = state === "run" ? "before-hook-start" : "before-hook-end";
955
+ if (name === "afterAll" || name === "afterEach") {
956
+ event = state === "run" ? "after-hook-start" : "after-hook-end";
957
+ }
958
+ updateTask(
959
+ event,
960
+ task,
961
+ runner
962
+ );
942
963
  }
943
964
  }
944
965
  function getSuiteHooks(suite, name, sequence) {
@@ -990,8 +1011,10 @@ async function callSuiteHook(suite, currentTask, name, runner, args) {
990
1011
  ...await callSuiteHook(parentSuite, currentTask, name, runner, args)
991
1012
  );
992
1013
  }
993
- updateSuiteHookState(currentTask, name, "run", runner);
994
1014
  const hooks = getSuiteHooks(suite, name, sequence);
1015
+ if (hooks.length > 0) {
1016
+ updateSuiteHookState(currentTask, name, "run", runner);
1017
+ }
995
1018
  if (sequence === "parallel") {
996
1019
  callbacks.push(
997
1020
  ...await Promise.all(hooks.map((hook) => hook(...args)))
@@ -1001,7 +1024,9 @@ async function callSuiteHook(suite, currentTask, name, runner, args) {
1001
1024
  callbacks.push(await hook(...args));
1002
1025
  }
1003
1026
  }
1004
- updateSuiteHookState(currentTask, name, "pass", runner);
1027
+ if (hooks.length > 0) {
1028
+ updateSuiteHookState(currentTask, name, "pass", runner);
1029
+ }
1005
1030
  if (name === "afterEach" && parentSuite) {
1006
1031
  callbacks.push(
1007
1032
  ...await callSuiteHook(parentSuite, currentTask, name, runner, args)
@@ -1010,9 +1035,11 @@ async function callSuiteHook(suite, currentTask, name, runner, args) {
1010
1035
  return callbacks;
1011
1036
  }
1012
1037
  const packs = /* @__PURE__ */ new Map();
1038
+ const eventsPacks = [];
1013
1039
  let updateTimer;
1014
1040
  let previousUpdate;
1015
- function updateTask(task, runner) {
1041
+ function updateTask(event, task, runner) {
1042
+ eventsPacks.push([task.id, event]);
1016
1043
  packs.set(task.id, [task.result, task.meta]);
1017
1044
  const { clearTimeout, setTimeout } = getSafeTimers();
1018
1045
  clearTimeout(updateTimer);
@@ -1029,7 +1056,8 @@ async function sendTasksUpdate(runner) {
1029
1056
  const taskPacks = Array.from(packs).map(([id, task]) => {
1030
1057
  return [id, task[0], task[1]];
1031
1058
  });
1032
- const p = (_a = runner.onTaskUpdate) == null ? void 0 : _a.call(runner, taskPacks);
1059
+ const p = (_a = runner.onTaskUpdate) == null ? undefined : _a.call(runner, taskPacks, eventsPacks);
1060
+ eventsPacks.length = 0;
1033
1061
  packs.clear();
1034
1062
  return p;
1035
1063
  }
@@ -1045,13 +1073,13 @@ async function callCleanupHooks(cleanups) {
1045
1073
  );
1046
1074
  }
1047
1075
  async function runTest(test, runner) {
1048
- var _a, _b, _c, _d, _e, _f, _g, _h;
1049
- await ((_a = runner.onBeforeRunTask) == null ? void 0 : _a.call(runner, test));
1076
+ var _a, _b, _c, _d, _e, _f, _g, _h, _i;
1077
+ await ((_a = runner.onBeforeRunTask) == null ? undefined : _a.call(runner, test));
1050
1078
  if (test.mode !== "run" && test.mode !== "queued") {
1051
1079
  return;
1052
1080
  }
1053
- if (((_b = test.result) == null ? void 0 : _b.state) === "fail") {
1054
- updateTask(test, runner);
1081
+ if (((_b = test.result) == null ? undefined : _b.state) === "fail") {
1082
+ updateTask("test-failed-early", test, runner);
1055
1083
  return;
1056
1084
  }
1057
1085
  const start = now();
@@ -1060,7 +1088,7 @@ async function runTest(test, runner) {
1060
1088
  startTime: unixNow(),
1061
1089
  retryCount: 0
1062
1090
  };
1063
- updateTask(test, runner);
1091
+ updateTask("test-prepare", test, runner);
1064
1092
  setCurrentTest(test);
1065
1093
  const suite = test.suite || test.file;
1066
1094
  const repeats = test.repeats ?? 0;
@@ -1106,15 +1134,15 @@ async function runTest(test, runner) {
1106
1134
  } catch (e) {
1107
1135
  failTask(test.result, e, runner.config.diffOptions);
1108
1136
  }
1109
- if (test.pending || ((_e = test.result) == null ? void 0 : _e.state) === "skip") {
1137
+ if (((_e = test.result) == null ? undefined : _e.pending) || ((_f = test.result) == null ? undefined : _f.state) === "skip") {
1110
1138
  test.mode = "skip";
1111
- test.result = { state: "skip", note: (_f = test.result) == null ? void 0 : _f.note };
1112
- updateTask(test, runner);
1113
- setCurrentTest(void 0);
1139
+ test.result = { state: "skip", note: (_g = test.result) == null ? undefined : _g.note, pending: true };
1140
+ updateTask("test-finished", test, runner);
1141
+ setCurrentTest(undefined);
1114
1142
  return;
1115
1143
  }
1116
1144
  try {
1117
- await ((_g = runner.onTaskFinished) == null ? void 0 : _g.call(runner, test));
1145
+ await ((_h = runner.onTaskFinished) == null ? void 0 : _h.call(runner, test));
1118
1146
  } catch (e) {
1119
1147
  failTask(test.result, e, runner.config.diffOptions);
1120
1148
  }
@@ -1137,8 +1165,8 @@ async function runTest(test, runner) {
1137
1165
  runner.config.sequence.hooks
1138
1166
  );
1139
1167
  }
1140
- delete test.onFailed;
1141
- delete test.onFinished;
1168
+ test.onFailed = undefined;
1169
+ test.onFinished = undefined;
1142
1170
  if (test.result.state === "pass") {
1143
1171
  break;
1144
1172
  }
@@ -1146,7 +1174,7 @@ async function runTest(test, runner) {
1146
1174
  test.result.state = "run";
1147
1175
  test.result.retryCount = (test.result.retryCount ?? 0) + 1;
1148
1176
  }
1149
- updateTask(test, runner);
1177
+ updateTask("test-retried", test, runner);
1150
1178
  }
1151
1179
  }
1152
1180
  if (test.fails) {
@@ -1156,18 +1184,19 @@ async function runTest(test, runner) {
1156
1184
  test.result.errors = [error];
1157
1185
  } else {
1158
1186
  test.result.state = "pass";
1159
- test.result.errors = void 0;
1187
+ test.result.errors = undefined;
1160
1188
  }
1161
1189
  }
1162
- setCurrentTest(void 0);
1190
+ setCurrentTest(undefined);
1163
1191
  test.result.duration = now() - start;
1164
- await ((_h = runner.onAfterRunTask) == null ? void 0 : _h.call(runner, test));
1165
- updateTask(test, runner);
1192
+ await ((_i = runner.onAfterRunTask) == null ? undefined : _i.call(runner, test));
1193
+ updateTask("test-finished", test, runner);
1166
1194
  }
1167
1195
  function failTask(result, err, diffOptions) {
1168
1196
  if (err instanceof PendingError) {
1169
1197
  result.state = "skip";
1170
1198
  result.note = err.note;
1199
+ result.pending = true;
1171
1200
  return;
1172
1201
  }
1173
1202
  result.state = "fail";
@@ -1182,7 +1211,7 @@ function markTasksAsSkipped(suite, runner) {
1182
1211
  suite.tasks.forEach((t) => {
1183
1212
  t.mode = "skip";
1184
1213
  t.result = { ...t.result, state: "skip" };
1185
- updateTask(t, runner);
1214
+ updateTask("test-finished", t, runner);
1186
1215
  if (t.type === "suite") {
1187
1216
  markTasksAsSkipped(t, runner);
1188
1217
  }
@@ -1190,23 +1219,26 @@ function markTasksAsSkipped(suite, runner) {
1190
1219
  }
1191
1220
  async function runSuite(suite, runner) {
1192
1221
  var _a, _b, _c, _d;
1193
- await ((_a = runner.onBeforeRunSuite) == null ? void 0 : _a.call(runner, suite));
1194
- if (((_b = suite.result) == null ? void 0 : _b.state) === "fail") {
1222
+ await ((_a = runner.onBeforeRunSuite) == null ? undefined : _a.call(runner, suite));
1223
+ if (((_b = suite.result) == null ? undefined : _b.state) === "fail") {
1195
1224
  markTasksAsSkipped(suite, runner);
1196
- updateTask(suite, runner);
1225
+ updateTask("suite-failed-early", suite, runner);
1197
1226
  return;
1198
1227
  }
1199
1228
  const start = now();
1229
+ const mode = suite.mode;
1200
1230
  suite.result = {
1201
- state: "run",
1231
+ state: mode === "skip" || mode === "todo" ? mode : "run",
1202
1232
  startTime: unixNow()
1203
1233
  };
1204
- updateTask(suite, runner);
1234
+ updateTask("suite-prepare", suite, runner);
1205
1235
  let beforeAllCleanups = [];
1206
1236
  if (suite.mode === "skip") {
1207
1237
  suite.result.state = "skip";
1238
+ updateTask("suite-finished", suite, runner);
1208
1239
  } else if (suite.mode === "todo") {
1209
1240
  suite.result.state = "todo";
1241
+ updateTask("suite-finished", suite, runner);
1210
1242
  } else {
1211
1243
  try {
1212
1244
  try {
@@ -1257,7 +1289,7 @@ async function runSuite(suite, runner) {
1257
1289
  if (suite.mode === "run" || suite.mode === "queued") {
1258
1290
  if (!runner.config.passWithNoTests && !hasTests(suite)) {
1259
1291
  suite.result.state = "fail";
1260
- if (!((_c = suite.result.errors) == null ? void 0 : _c.length)) {
1292
+ if (!((_c = suite.result.errors) == null ? undefined : _c.length)) {
1261
1293
  const error = processError(
1262
1294
  new Error(`No test found in suite ${suite.name}`)
1263
1295
  );
@@ -1269,9 +1301,9 @@ async function runSuite(suite, runner) {
1269
1301
  suite.result.state = "pass";
1270
1302
  }
1271
1303
  }
1272
- updateTask(suite, runner);
1273
1304
  suite.result.duration = now() - start;
1274
- await ((_d = runner.onAfterRunSuite) == null ? void 0 : _d.call(runner, suite));
1305
+ updateTask("suite-finished", suite, runner);
1306
+ await ((_d = runner.onAfterRunSuite) == null ? undefined : _d.call(runner, suite));
1275
1307
  }
1276
1308
  }
1277
1309
  let limitMaxConcurrency;
@@ -1287,7 +1319,7 @@ async function runFiles(files, runner) {
1287
1319
  limitMaxConcurrency ?? (limitMaxConcurrency = limitConcurrency(runner.config.maxConcurrency));
1288
1320
  for (const file of files) {
1289
1321
  if (!file.tasks.length && !runner.config.passWithNoTests) {
1290
- if (!((_b = (_a = file.result) == null ? void 0 : _a.errors) == null ? void 0 : _b.length)) {
1322
+ if (!((_b = (_a = file.result) == null ? undefined : _a.errors) == null ? undefined : _b.length)) {
1291
1323
  const error = processError(
1292
1324
  new Error(`No test suite found in file ${file.filepath}`)
1293
1325
  );
@@ -1303,21 +1335,21 @@ async function runFiles(files, runner) {
1303
1335
  async function startTests(specs, runner) {
1304
1336
  var _a, _b, _c, _d;
1305
1337
  const paths = specs.map((f) => typeof f === "string" ? f : f.filepath);
1306
- await ((_a = runner.onBeforeCollect) == null ? void 0 : _a.call(runner, paths));
1338
+ await ((_a = runner.onBeforeCollect) == null ? undefined : _a.call(runner, paths));
1307
1339
  const files = await collectTests(specs, runner);
1308
- await ((_b = runner.onCollected) == null ? void 0 : _b.call(runner, files));
1309
- await ((_c = runner.onBeforeRunFiles) == null ? void 0 : _c.call(runner, files));
1340
+ await ((_b = runner.onCollected) == null ? undefined : _b.call(runner, files));
1341
+ await ((_c = runner.onBeforeRunFiles) == null ? undefined : _c.call(runner, files));
1310
1342
  await runFiles(files, runner);
1311
- await ((_d = runner.onAfterRunFiles) == null ? void 0 : _d.call(runner, files));
1343
+ await ((_d = runner.onAfterRunFiles) == null ? undefined : _d.call(runner, files));
1312
1344
  await sendTasksUpdate(runner);
1313
1345
  return files;
1314
1346
  }
1315
1347
  async function publicCollect(specs, runner) {
1316
1348
  var _a, _b;
1317
1349
  const paths = specs.map((f) => typeof f === "string" ? f : f.filepath);
1318
- await ((_a = runner.onBeforeCollect) == null ? void 0 : _a.call(runner, paths));
1350
+ await ((_a = runner.onBeforeCollect) == null ? undefined : _a.call(runner, paths));
1319
1351
  const files = await collectTests(specs, runner);
1320
- await ((_b = runner.onCollected) == null ? void 0 : _b.call(runner, files));
1352
+ await ((_b = runner.onCollected) == null ? undefined : _b.call(runner, files));
1321
1353
  return files;
1322
1354
  }
1323
1355
 
@@ -94,10 +94,6 @@ interface TaskPopulated extends TaskBase {
94
94
  * File task. It's the root task of the file.
95
95
  */
96
96
  file: File;
97
- /**
98
- * Whether the task was skipped by calling `t.skip()`.
99
- */
100
- pending?: boolean;
101
97
  /**
102
98
  * Whether the task should succeed if it fails. If the task fails, it will be marked as passed.
103
99
  */
@@ -176,6 +172,17 @@ type TaskResultPack = [
176
172
  */
177
173
  meta: TaskMeta
178
174
  ];
175
+ type TaskEventPack = [
176
+ /**
177
+ * Unique task identifier from `task.id`.
178
+ */
179
+ id: string,
180
+ /**
181
+ * The name of the event that triggered the update.
182
+ */
183
+ event: TaskUpdateEvent
184
+ ];
185
+ type TaskUpdateEvent = 'test-failed-early' | 'suite-failed-early' | 'test-prepare' | 'test-finished' | 'test-retried' | 'suite-prepare' | 'suite-finished' | 'before-hook-start' | 'before-hook-end' | 'after-hook-start' | 'after-hook-end';
179
186
  interface Suite extends TaskBase {
180
187
  type: 'suite';
181
188
  /**
@@ -263,6 +270,10 @@ interface TestForFunction<ExtraContext> {
263
270
  <T>(cases: ReadonlyArray<T>): TestForFunctionReturn<T, TestContext & ExtraContext>;
264
271
  (strings: TemplateStringsArray, ...values: any[]): TestForFunctionReturn<any, TestContext & ExtraContext>;
265
272
  }
273
+ interface SuiteForFunction {
274
+ <T>(cases: ReadonlyArray<T>): EachFunctionReturn<[T]>;
275
+ (...args: [TemplateStringsArray, ...any]): EachFunctionReturn<any[]>;
276
+ }
266
277
  interface TestCollectorCallable<C = object> {
267
278
  /**
268
279
  * @deprecated Use options as the second argument instead
@@ -363,6 +374,7 @@ interface SuiteCollectorCallable<ExtraContext = object> {
363
374
  }
364
375
  type ChainableSuiteAPI<ExtraContext = object> = ChainableFunction<'concurrent' | 'sequential' | 'only' | 'skip' | 'todo' | 'shuffle', SuiteCollectorCallable<ExtraContext>, {
365
376
  each: TestEachFunction;
377
+ for: SuiteForFunction;
366
378
  }>;
367
379
  type SuiteAPI<ExtraContext = object> = ChainableSuiteAPI<ExtraContext> & {
368
380
  skipIf: (condition: any) => ChainableSuiteAPI<ExtraContext>;
@@ -469,4 +481,4 @@ interface TaskHook<HookListener> {
469
481
  type SequenceHooks = 'stack' | 'list' | 'parallel';
470
482
  type SequenceSetupFiles = 'list' | 'parallel';
471
483
 
472
- 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 };
484
+ 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 TaskPopulated as G, type HookCleanupCallback as H, type InferFixturesTypes as I, type TaskResult as J, type TaskResultPack as K, type TaskState as L, type TestContext as M, type TestFunction as N, type OnTestFailedHandler as O, type TestOptions as P, 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 TaskUpdateEvent as i, type SuiteAPI as j, type TestAPI as k, type SuiteCollector as l, type Fixture as m, type FixtureFn as n, type FixtureOptions as o, type Fixtures as p, type HookListener as q, type RuntimeContext as r, type SequenceHooks as s, type SequenceSetupFiles as t, type SuiteFactory as u, type TaskBase as v, type TaskContext as w, type TaskCustomOptions as x, type TaskEventPack as y, type TaskMeta 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, S as Suite, G as TaskResultPack, K as TestContext } from './tasks-B64RTJlW.js';
3
- export { A as AfterAllListener, d as AfterEachListener, B as BeforeAllListener, b as BeforeEachListener, g as Custom, j as CustomAPI, 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, 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, v as TaskContext, w as TaskCustomOptions, e as TaskHook, x as TaskMeta, y as TaskPopulated, z as TaskResult, J as TaskState, j as TestAPI, L as TestFunction, M as TestOptions, U as Use } from './tasks-B64RTJlW.js';
2
+ import { s as SequenceHooks, t as SequenceSetupFiles, F as File, T as Task, a as Test, S as Suite, K as TaskResultPack, y as TaskEventPack, M as TestContext } from './tasks-CUXfn9LM.js';
3
+ export { A as AfterAllListener, d as AfterEachListener, B as BeforeAllListener, b as BeforeEachListener, g as Custom, k as CustomAPI, D as DoneCallback, E as ExtendedContext, m as Fixture, n as FixtureFn, o as FixtureOptions, p as Fixtures, H as HookCleanupCallback, q as HookListener, I as InferFixturesTypes, O as OnTestFailedHandler, f as OnTestFinishedHandler, R as RunMode, r as RuntimeContext, j as SuiteAPI, l as SuiteCollector, u as SuiteFactory, h as SuiteHooks, v as TaskBase, w as TaskContext, x as TaskCustomOptions, e as TaskHook, z as TaskMeta, G as TaskPopulated, J as TaskResult, L as TaskState, i as TaskUpdateEvent, k as TestAPI, N as TestFunction, P as TestOptions, U as Use } from './tasks-CUXfn9LM.js';
4
4
  import '@vitest/utils';
5
5
 
6
6
  /**
@@ -108,7 +108,7 @@ interface VitestRunner {
108
108
  /**
109
109
  * Called, when a task is updated. The same as "onTaskUpdate" in a reporter, but this is running in the same thread as tests.
110
110
  */
111
- onTaskUpdate?: (task: TaskResultPack[]) => Promise<void>;
111
+ onTaskUpdate?: (task: TaskResultPack[], events: TaskEventPack[]) => Promise<void>;
112
112
  /**
113
113
  * Called before running all tests in collected paths.
114
114
  */
@@ -142,4 +142,4 @@ interface VitestRunner {
142
142
  pool?: string;
143
143
  }
144
144
 
145
- export { type CancelReason, File, type FileSpecification, SequenceHooks, SequenceSetupFiles, Suite, Task, TaskResultPack, Test, TestContext, type VitestRunner, type VitestRunnerConfig, type VitestRunnerConstructor, type VitestRunnerImportSource };
145
+ export { type CancelReason, File, type FileSpecification, SequenceHooks, SequenceSetupFiles, Suite, Task, TaskEventPack, TaskResultPack, Test, TestContext, type VitestRunner, type VitestRunnerConfig, type VitestRunnerConstructor, type VitestRunnerImportSource };
package/dist/utils.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { S as Suite, F as File, T as Task, a as Test } from './tasks-B64RTJlW.js';
2
- export { C as ChainableFunction, c as createChainable } from './tasks-B64RTJlW.js';
1
+ import { S as Suite, F as File, T as Task, a as Test } from './tasks-CUXfn9LM.js';
2
+ export { C as ChainableFunction, c as createChainable } from './tasks-CUXfn9LM.js';
3
3
  import { Arrayable } from '@vitest/utils';
4
4
 
5
5
  /**
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vitest/runner",
3
3
  "type": "module",
4
- "version": "3.0.0-beta.4",
4
+ "version": "3.0.1",
5
5
  "description": "Vitest test runner",
6
6
  "license": "MIT",
7
7
  "funding": "https://opencollective.com/vitest",
@@ -38,8 +38,8 @@
38
38
  "dist"
39
39
  ],
40
40
  "dependencies": {
41
- "pathe": "^2.0.0",
42
- "@vitest/utils": "3.0.0-beta.4"
41
+ "pathe": "^2.0.1",
42
+ "@vitest/utils": "3.0.1"
43
43
  },
44
44
  "scripts": {
45
45
  "build": "rimraf dist && rollup -c",