@vitest/runner 4.1.0-beta.2 → 4.1.0-beta.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/chunk-tasks.js +1 -1
- package/dist/index.d.ts +2 -2
- package/dist/index.js +443 -89
- package/dist/{tasks.d-CLPU8HE4.d.ts → tasks.d-WWG4yDf6.d.ts} +76 -7
- package/dist/types.d.ts +1 -1
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +1 -1
- package/package.json +2 -2
package/dist/chunk-tasks.js
CHANGED
|
@@ -578,4 +578,4 @@ function createTaskName(names, separator = " > ") {
|
|
|
578
578
|
return names.filter((name) => name !== undefined).join(separator);
|
|
579
579
|
}
|
|
580
580
|
|
|
581
|
-
export {
|
|
581
|
+
export { createChainable as a, createFileTask as b, calculateSuiteHash as c, createTagsFilter as d, createTaskName as e, findTestFileStackTrace as f, generateFileHash as g, generateHash as h, getFullName as i, getNames as j, getSuites as k, getTasks as l, getTestName as m, getTests as n, hasFailed as o, hasTests as p, interpretTaskModes as q, isTestCase as r, limitConcurrency as s, partitionSuiteChildren as t, someTasksAreOnly as u, validateTags as v, createNoTagsError as w };
|
package/dist/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { T as TestArtifact, a as Test, S as Suite, b as SuiteHooks, F as FileSpecification, V as VitestRunner, c as File, d as TaskUpdateEvent, e as Task, f as TestAPI, g as SuiteAPI, h as SuiteCollector } from './tasks.d-
|
|
2
|
-
export { A as AfterAllListener,
|
|
1
|
+
import { T as TestArtifact, a as Test, S as Suite, b as SuiteHooks, F as FileSpecification, V as VitestRunner, c as File, d as TaskUpdateEvent, e as Task, f as TestAPI, g as SuiteAPI, h as SuiteCollector } from './tasks.d-WWG4yDf6.js';
|
|
2
|
+
export { A as AfterAllListener, i as AfterEachListener, j as AroundAllListener, k as AroundEachListener, B as BeforeAllListener, l as BeforeEachListener, C as CancelReason, m as Fixture, n as FixtureFn, o as FixtureOptions, p as Fixtures, I as ImportDuration, q as InferFixturesTypes, O as OnTestFailedHandler, r as OnTestFinishedHandler, R as Retry, s as RunMode, t as RuntimeContext, u as SequenceHooks, v as SequenceSetupFiles, w as SerializableRetry, x as SuiteFactory, y as SuiteOptions, z as TaskBase, D as TaskCustomOptions, E as TaskEventPack, G as TaskHook, H as TaskMeta, J as TaskPopulated, K as TaskResult, L as TaskResultPack, M as TaskState, N as TestAnnotation, P as TestAnnotationArtifact, Q as TestAnnotationLocation, U as TestArtifactBase, W as TestArtifactLocation, X as TestArtifactRegistry, Y as TestAttachment, Z as TestContext, _ as TestFunction, $ as TestOptions, a0 as TestTagDefinition, a1 as TestTags, a2 as Use, a3 as VisualRegressionArtifact, a4 as VitestRunnerConfig, a5 as VitestRunnerConstructor, a6 as VitestRunnerImportSource, a7 as afterAll, a8 as afterEach, a9 as aroundAll, aa as aroundEach, ab as beforeAll, ac as beforeEach, ad as onTestFailed, ae as onTestFinished } from './tasks.d-WWG4yDf6.js';
|
|
3
3
|
import { Awaitable } from '@vitest/utils';
|
|
4
4
|
import '@vitest/utils/diff';
|
|
5
5
|
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@ import { processError } from '@vitest/utils/error';
|
|
|
2
2
|
import { isObject, filterOutComments, createDefer, assertTypes, toArray, isNegativeNaN, unique, objectAttr, shuffle } from '@vitest/utils/helpers';
|
|
3
3
|
import { getSafeTimers } from '@vitest/utils/timers';
|
|
4
4
|
import { format, formatRegExp, objDisplay } from '@vitest/utils/display';
|
|
5
|
-
import {
|
|
5
|
+
import { a as createChainable, v as validateTags, e as createTaskName, w as createNoTagsError, f as findTestFileStackTrace, d as createTagsFilter, b as createFileTask, c as calculateSuiteHash, u as someTasksAreOnly, q as interpretTaskModes, s as limitConcurrency, t as partitionSuiteChildren, p as hasTests, o as hasFailed } from './chunk-tasks.js';
|
|
6
6
|
import '@vitest/utils/source-map';
|
|
7
7
|
import 'pathe';
|
|
8
8
|
|
|
@@ -24,6 +24,15 @@ class TestRunAbortError extends Error {
|
|
|
24
24
|
this.reason = reason;
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
|
+
class AroundHookSetupError extends Error {
|
|
28
|
+
name = "AroundHookSetupError";
|
|
29
|
+
}
|
|
30
|
+
class AroundHookTeardownError extends Error {
|
|
31
|
+
name = "AroundHookTeardownError";
|
|
32
|
+
}
|
|
33
|
+
class AroundHookMultipleCallsError extends Error {
|
|
34
|
+
name = "AroundHookMultipleCallsError";
|
|
35
|
+
}
|
|
27
36
|
|
|
28
37
|
// use WeakMap here to make the Test and Suite object serializable
|
|
29
38
|
const fnMap = new WeakMap();
|
|
@@ -134,6 +143,33 @@ async function callFixtureCleanup(context) {
|
|
|
134
143
|
}
|
|
135
144
|
cleanupFnArrayMap.delete(context);
|
|
136
145
|
}
|
|
146
|
+
/**
|
|
147
|
+
* Returns the current number of cleanup functions registered for the context.
|
|
148
|
+
* This can be used as a checkpoint to later clean up only fixtures added after this point.
|
|
149
|
+
*/
|
|
150
|
+
function getFixtureCleanupCount(context) {
|
|
151
|
+
var _cleanupFnArrayMap$ge;
|
|
152
|
+
return ((_cleanupFnArrayMap$ge = cleanupFnArrayMap.get(context)) === null || _cleanupFnArrayMap$ge === void 0 ? void 0 : _cleanupFnArrayMap$ge.length) ?? 0;
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Cleans up only fixtures that were added after the given checkpoint index.
|
|
156
|
+
* This is used by aroundEach to clean up fixtures created inside runTest()
|
|
157
|
+
* while preserving fixtures that were created for aroundEach itself.
|
|
158
|
+
*/
|
|
159
|
+
async function callFixtureCleanupFrom(context, fromIndex) {
|
|
160
|
+
const cleanupFnArray = cleanupFnArrayMap.get(context);
|
|
161
|
+
if (!cleanupFnArray || cleanupFnArray.length <= fromIndex) {
|
|
162
|
+
return;
|
|
163
|
+
}
|
|
164
|
+
// Get items added after the checkpoint
|
|
165
|
+
const toCleanup = cleanupFnArray.slice(fromIndex);
|
|
166
|
+
// Clean up in reverse order
|
|
167
|
+
for (const cleanup of toCleanup.reverse()) {
|
|
168
|
+
await cleanup();
|
|
169
|
+
}
|
|
170
|
+
// Remove cleaned up items from the array, keeping items before checkpoint
|
|
171
|
+
cleanupFnArray.length = fromIndex;
|
|
172
|
+
}
|
|
137
173
|
function withFixtures(runner, fn, testContext) {
|
|
138
174
|
return (hookContext) => {
|
|
139
175
|
const context = hookContext || testContext;
|
|
@@ -358,6 +394,8 @@ function getDefaultHookTimeout() {
|
|
|
358
394
|
}
|
|
359
395
|
const CLEANUP_TIMEOUT_KEY = Symbol.for("VITEST_CLEANUP_TIMEOUT");
|
|
360
396
|
const CLEANUP_STACK_TRACE_KEY = Symbol.for("VITEST_CLEANUP_STACK_TRACE");
|
|
397
|
+
const AROUND_TIMEOUT_KEY = Symbol.for("VITEST_AROUND_TIMEOUT");
|
|
398
|
+
const AROUND_STACK_TRACE_KEY = Symbol.for("VITEST_AROUND_STACK_TRACE");
|
|
361
399
|
function getBeforeHookCleanupCallback(hook, result, context) {
|
|
362
400
|
if (typeof result === "function") {
|
|
363
401
|
const timeout = CLEANUP_TIMEOUT_KEY in hook && typeof hook[CLEANUP_TIMEOUT_KEY] === "number" ? hook[CLEANUP_TIMEOUT_KEY] : getDefaultHookTimeout();
|
|
@@ -512,6 +550,113 @@ const onTestFinished = createTestHook("onTestFinished", (test, handler, timeout)
|
|
|
512
550
|
test.onFinished || (test.onFinished = []);
|
|
513
551
|
test.onFinished.push(withTimeout(handler, timeout ?? getDefaultHookTimeout(), true, new Error("STACK_TRACE_ERROR"), abortIfTimeout));
|
|
514
552
|
});
|
|
553
|
+
/**
|
|
554
|
+
* Registers a callback function that wraps around all tests within the current suite.
|
|
555
|
+
* The callback receives a `runSuite` function that must be called to run the suite's tests.
|
|
556
|
+
* This hook is useful for scenarios where you need to wrap an entire suite in a context
|
|
557
|
+
* (e.g., starting a server, opening a database connection that all tests share).
|
|
558
|
+
*
|
|
559
|
+
* **Note:** When multiple `aroundAll` hooks are registered, they are nested inside each other.
|
|
560
|
+
* The first registered hook is the outermost wrapper.
|
|
561
|
+
*
|
|
562
|
+
* **Note:** Unlike `aroundEach`, the `aroundAll` hook does not receive test context or support fixtures,
|
|
563
|
+
* as it runs at the suite level before any individual test context is created.
|
|
564
|
+
*
|
|
565
|
+
* @param {Function} fn - The callback function that wraps the suite. Must call `runSuite()` to run the tests.
|
|
566
|
+
* @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
|
|
567
|
+
* @returns {void}
|
|
568
|
+
* @example
|
|
569
|
+
* ```ts
|
|
570
|
+
* // Example of using aroundAll to wrap suite in a tracing span
|
|
571
|
+
* aroundAll(async (runSuite) => {
|
|
572
|
+
* await tracer.trace('test-suite', runSuite);
|
|
573
|
+
* });
|
|
574
|
+
* ```
|
|
575
|
+
* @example
|
|
576
|
+
* ```ts
|
|
577
|
+
* // Example of using aroundAll with AsyncLocalStorage context
|
|
578
|
+
* aroundAll(async (runSuite) => {
|
|
579
|
+
* await asyncLocalStorage.run({ suiteId: 'my-suite' }, runSuite);
|
|
580
|
+
* });
|
|
581
|
+
* ```
|
|
582
|
+
*/
|
|
583
|
+
function aroundAll(fn, timeout) {
|
|
584
|
+
assertTypes(fn, "\"aroundAll\" callback", ["function"]);
|
|
585
|
+
const stackTraceError = new Error("STACK_TRACE_ERROR");
|
|
586
|
+
const resolvedTimeout = timeout ?? getDefaultHookTimeout();
|
|
587
|
+
return getCurrentSuite().on("aroundAll", Object.assign(fn, {
|
|
588
|
+
[AROUND_TIMEOUT_KEY]: resolvedTimeout,
|
|
589
|
+
[AROUND_STACK_TRACE_KEY]: stackTraceError
|
|
590
|
+
}));
|
|
591
|
+
}
|
|
592
|
+
/**
|
|
593
|
+
* Registers a callback function that wraps around each test within the current suite.
|
|
594
|
+
* The callback receives a `runTest` function that must be called to run the test.
|
|
595
|
+
* This hook is useful for scenarios where you need to wrap tests in a context (e.g., database transactions).
|
|
596
|
+
*
|
|
597
|
+
* **Note:** When multiple `aroundEach` hooks are registered, they are nested inside each other.
|
|
598
|
+
* The first registered hook is the outermost wrapper.
|
|
599
|
+
*
|
|
600
|
+
* @param {Function} fn - The callback function that wraps the test. Must call `runTest()` to run the test.
|
|
601
|
+
* @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
|
|
602
|
+
* @returns {void}
|
|
603
|
+
* @example
|
|
604
|
+
* ```ts
|
|
605
|
+
* // Example of using aroundEach to wrap tests in a database transaction
|
|
606
|
+
* aroundEach(async (runTest) => {
|
|
607
|
+
* await database.transaction(() => runTest());
|
|
608
|
+
* });
|
|
609
|
+
* ```
|
|
610
|
+
* @example
|
|
611
|
+
* ```ts
|
|
612
|
+
* // Example of using aroundEach with fixtures
|
|
613
|
+
* aroundEach(async (runTest, { db }) => {
|
|
614
|
+
* await db.transaction(() => runTest());
|
|
615
|
+
* });
|
|
616
|
+
* ```
|
|
617
|
+
*/
|
|
618
|
+
function aroundEach(fn, timeout) {
|
|
619
|
+
assertTypes(fn, "\"aroundEach\" callback", ["function"]);
|
|
620
|
+
const stackTraceError = new Error("STACK_TRACE_ERROR");
|
|
621
|
+
const resolvedTimeout = timeout ?? getDefaultHookTimeout();
|
|
622
|
+
const runner = getRunner();
|
|
623
|
+
// Create a wrapper function that supports fixtures in the second argument (context)
|
|
624
|
+
// withFixtures resolves fixtures into context, then we call fn with all 3 args
|
|
625
|
+
const wrappedFn = withAroundEachFixtures(runner, fn);
|
|
626
|
+
// Store timeout and stack trace on the function for use in callAroundEachHooks
|
|
627
|
+
// Setup and teardown phases will each have their own timeout
|
|
628
|
+
return getCurrentSuite().on("aroundEach", Object.assign(wrappedFn, {
|
|
629
|
+
[AROUND_TIMEOUT_KEY]: resolvedTimeout,
|
|
630
|
+
[AROUND_STACK_TRACE_KEY]: stackTraceError
|
|
631
|
+
}));
|
|
632
|
+
}
|
|
633
|
+
/**
|
|
634
|
+
* Wraps an aroundEach listener to support fixtures.
|
|
635
|
+
* Similar to withFixtures, but handles the aroundEach signature where:
|
|
636
|
+
* - First arg is runTest function
|
|
637
|
+
* - Second arg is context (where fixtures are destructured from)
|
|
638
|
+
* - Third arg is suite
|
|
639
|
+
*/
|
|
640
|
+
function withAroundEachFixtures(runner, fn) {
|
|
641
|
+
// Create the wrapper that will be returned
|
|
642
|
+
const wrapper = (runTest, context, suite) => {
|
|
643
|
+
// Create inner function that will be passed to withFixtures
|
|
644
|
+
// This function receives context (with fixtures resolved) and calls original fn
|
|
645
|
+
const innerFn = (ctx) => fn(runTest, ctx, suite);
|
|
646
|
+
innerFn.__VITEST_FIXTURE_INDEX__ = 1;
|
|
647
|
+
innerFn.toString = () => fn.toString();
|
|
648
|
+
// Use withFixtures to resolve fixtures, passing context as the hook context
|
|
649
|
+
const fixtureResolver = withFixtures(runner, innerFn);
|
|
650
|
+
return fixtureResolver(context);
|
|
651
|
+
};
|
|
652
|
+
return wrapper;
|
|
653
|
+
}
|
|
654
|
+
function getAroundHookTimeout(hook) {
|
|
655
|
+
return AROUND_TIMEOUT_KEY in hook && typeof hook[AROUND_TIMEOUT_KEY] === "number" ? hook[AROUND_TIMEOUT_KEY] : getDefaultHookTimeout();
|
|
656
|
+
}
|
|
657
|
+
function getAroundHookStackTrace(hook) {
|
|
658
|
+
return AROUND_STACK_TRACE_KEY in hook && hook[AROUND_STACK_TRACE_KEY] instanceof Error ? hook[AROUND_STACK_TRACE_KEY] : undefined;
|
|
659
|
+
}
|
|
515
660
|
function createTestHook(name, handler) {
|
|
516
661
|
return (fn, timeout) => {
|
|
517
662
|
assertTypes(fn, `"${name}" callback`, ["function"]);
|
|
@@ -698,7 +843,9 @@ function createSuiteHooks() {
|
|
|
698
843
|
beforeAll: [],
|
|
699
844
|
afterAll: [],
|
|
700
845
|
beforeEach: [],
|
|
701
|
-
afterEach: []
|
|
846
|
+
afterEach: [],
|
|
847
|
+
aroundEach: [],
|
|
848
|
+
aroundAll: []
|
|
702
849
|
};
|
|
703
850
|
}
|
|
704
851
|
const POSITIVE_INFINITY = Number.POSITIVE_INFINITY;
|
|
@@ -746,15 +893,31 @@ function createSuiteCollector(name, factory = () => {}, mode, each, suiteOptions
|
|
|
746
893
|
}
|
|
747
894
|
return tagDefinition;
|
|
748
895
|
}).filter((r) => r != null).sort((tag1, tag2) => (tag2.priority ?? POSITIVE_INFINITY) - (tag1.priority ?? POSITIVE_INFINITY)).reduce((acc, tag) => {
|
|
749
|
-
const { name, description, priority, ...options } = tag;
|
|
896
|
+
const { name, description, priority, meta, ...options } = tag;
|
|
750
897
|
Object.assign(acc, options);
|
|
898
|
+
if (meta) {
|
|
899
|
+
acc.meta = Object.assign(acc.meta ?? Object.create(null), meta);
|
|
900
|
+
}
|
|
751
901
|
return acc;
|
|
752
902
|
}, {});
|
|
903
|
+
const testOwnMeta = options.meta;
|
|
753
904
|
options = {
|
|
754
905
|
...tagsOptions,
|
|
755
906
|
...options
|
|
756
907
|
};
|
|
757
908
|
const timeout = options.timeout ?? runner.config.testTimeout;
|
|
909
|
+
const parentMeta = currentSuite === null || currentSuite === void 0 ? void 0 : currentSuite.meta;
|
|
910
|
+
const tagMeta = tagsOptions.meta;
|
|
911
|
+
const testMeta = Object.create(null);
|
|
912
|
+
if (tagMeta) {
|
|
913
|
+
Object.assign(testMeta, tagMeta);
|
|
914
|
+
}
|
|
915
|
+
if (parentMeta) {
|
|
916
|
+
Object.assign(testMeta, parentMeta);
|
|
917
|
+
}
|
|
918
|
+
if (testOwnMeta) {
|
|
919
|
+
Object.assign(testMeta, testOwnMeta);
|
|
920
|
+
}
|
|
758
921
|
const task = {
|
|
759
922
|
id: "",
|
|
760
923
|
name,
|
|
@@ -770,7 +933,7 @@ function createSuiteCollector(name, factory = () => {}, mode, each, suiteOptions
|
|
|
770
933
|
retry: options.retry ?? runner.config.retry,
|
|
771
934
|
repeats: options.repeats,
|
|
772
935
|
mode: options.only ? "only" : options.skip ? "skip" : options.todo ? "todo" : "run",
|
|
773
|
-
meta:
|
|
936
|
+
meta: testMeta,
|
|
774
937
|
annotations: [],
|
|
775
938
|
artifacts: [],
|
|
776
939
|
tags: testTags
|
|
@@ -880,7 +1043,7 @@ function createSuiteCollector(name, factory = () => {}, mode, each, suiteOptions
|
|
|
880
1043
|
file: (currentSuite === null || currentSuite === void 0 ? void 0 : currentSuite.file) ?? ((_collectorContext$cur8 = collectorContext.currentSuite) === null || _collectorContext$cur8 === void 0 ? void 0 : _collectorContext$cur8.file),
|
|
881
1044
|
shuffle: suiteOptions === null || suiteOptions === void 0 ? void 0 : suiteOptions.shuffle,
|
|
882
1045
|
tasks: [],
|
|
883
|
-
meta: Object.create(null),
|
|
1046
|
+
meta: (suiteOptions === null || suiteOptions === void 0 ? void 0 : suiteOptions.meta) ?? Object.create(null),
|
|
884
1047
|
concurrent: suiteOptions === null || suiteOptions === void 0 ? void 0 : suiteOptions.concurrent,
|
|
885
1048
|
tags: unique([...(parentTask === null || parentTask === void 0 ? void 0 : parentTask.tags) || [], ...suiteTags])
|
|
886
1049
|
};
|
|
@@ -944,9 +1107,10 @@ function createSuite() {
|
|
|
944
1107
|
let { options, handler: factory } = parseArguments(factoryOrOptions, optionsOrFactory);
|
|
945
1108
|
const isConcurrentSpecified = options.concurrent || this.concurrent || options.sequential === false;
|
|
946
1109
|
const isSequentialSpecified = options.sequential || this.sequential || options.concurrent === false;
|
|
1110
|
+
const { meta: parentMeta, ...parentOptions } = (currentSuite === null || currentSuite === void 0 ? void 0 : currentSuite.options) || {};
|
|
947
1111
|
// inherit options from current suite
|
|
948
1112
|
options = {
|
|
949
|
-
...
|
|
1113
|
+
...parentOptions,
|
|
950
1114
|
...options
|
|
951
1115
|
};
|
|
952
1116
|
const shuffle = this.shuffle ?? options.shuffle ?? (currentSuite === null || currentSuite === void 0 || (_currentSuite$options = currentSuite.options) === null || _currentSuite$options === void 0 ? void 0 : _currentSuite$options.shuffle) ?? (runner === null || runner === void 0 ? void 0 : runner.config.sequence.shuffle);
|
|
@@ -967,6 +1131,9 @@ function createSuite() {
|
|
|
967
1131
|
if (isSequential != null) {
|
|
968
1132
|
options.sequential = isSequential && !isConcurrent;
|
|
969
1133
|
}
|
|
1134
|
+
if (parentMeta) {
|
|
1135
|
+
options.meta = Object.assign(Object.create(null), parentMeta, options.meta);
|
|
1136
|
+
}
|
|
970
1137
|
return createSuiteCollector(formatName(name), factory, mode, this.each, options, currentSuite === null || currentSuite === void 0 ? void 0 : currentSuite.fixtures());
|
|
971
1138
|
}
|
|
972
1139
|
suiteFn.each = function(cases, ...args) {
|
|
@@ -1096,10 +1263,13 @@ function createTaskCollector(fn, context) {
|
|
|
1096
1263
|
originalWrapper.call(context, formatName(name), optionsOrFn, optionsOrTest);
|
|
1097
1264
|
}, _context);
|
|
1098
1265
|
};
|
|
1266
|
+
taskFn.describe = suite;
|
|
1099
1267
|
taskFn.beforeEach = beforeEach;
|
|
1100
1268
|
taskFn.afterEach = afterEach;
|
|
1101
1269
|
taskFn.beforeAll = beforeAll;
|
|
1102
1270
|
taskFn.afterAll = afterAll;
|
|
1271
|
+
taskFn.aroundEach = aroundEach;
|
|
1272
|
+
taskFn.aroundAll = aroundAll;
|
|
1103
1273
|
const _test = createChainable([
|
|
1104
1274
|
"concurrent",
|
|
1105
1275
|
"sequential",
|
|
@@ -1586,6 +1756,157 @@ async function callSuiteHook(suite, currentTask, name, runner, args) {
|
|
|
1586
1756
|
}
|
|
1587
1757
|
return callbacks;
|
|
1588
1758
|
}
|
|
1759
|
+
function getAroundEachHooks(suite) {
|
|
1760
|
+
const hooks = [];
|
|
1761
|
+
const parentSuite = "filepath" in suite ? null : suite.suite || suite.file;
|
|
1762
|
+
if (parentSuite) {
|
|
1763
|
+
hooks.push(...getAroundEachHooks(parentSuite));
|
|
1764
|
+
}
|
|
1765
|
+
hooks.push(...getHooks(suite).aroundEach);
|
|
1766
|
+
return hooks;
|
|
1767
|
+
}
|
|
1768
|
+
function getAroundAllHooks(suite) {
|
|
1769
|
+
return getHooks(suite).aroundAll;
|
|
1770
|
+
}
|
|
1771
|
+
function makeAroundHookTimeoutError(hookName, phase, timeout, stackTraceError) {
|
|
1772
|
+
const message = `The ${phase} phase of "${hookName}" hook timed out after ${timeout}ms.`;
|
|
1773
|
+
const ErrorClass = phase === "setup" ? AroundHookSetupError : AroundHookTeardownError;
|
|
1774
|
+
const error = new ErrorClass(message);
|
|
1775
|
+
if (stackTraceError === null || stackTraceError === void 0 ? void 0 : stackTraceError.stack) {
|
|
1776
|
+
error.stack = stackTraceError.stack.replace(stackTraceError.message, error.message);
|
|
1777
|
+
}
|
|
1778
|
+
return error;
|
|
1779
|
+
}
|
|
1780
|
+
async function callAroundHooks(runInner, options) {
|
|
1781
|
+
const { hooks, hookName, callbackName, onTimeout, invokeHook } = options;
|
|
1782
|
+
if (!hooks.length) {
|
|
1783
|
+
await runInner();
|
|
1784
|
+
return;
|
|
1785
|
+
}
|
|
1786
|
+
const createTimeoutPromise = (timeout, phase, stackTraceError) => {
|
|
1787
|
+
let timer;
|
|
1788
|
+
const promise = new Promise((_, reject) => {
|
|
1789
|
+
if (timeout > 0 && timeout !== Number.POSITIVE_INFINITY) {
|
|
1790
|
+
var _timer$unref;
|
|
1791
|
+
timer = setTimeout(() => {
|
|
1792
|
+
const error = makeAroundHookTimeoutError(hookName, phase, timeout, stackTraceError);
|
|
1793
|
+
onTimeout === null || onTimeout === void 0 ? void 0 : onTimeout(error);
|
|
1794
|
+
reject(error);
|
|
1795
|
+
}, timeout);
|
|
1796
|
+
(_timer$unref = timer.unref) === null || _timer$unref === void 0 ? void 0 : _timer$unref.call(timer);
|
|
1797
|
+
}
|
|
1798
|
+
});
|
|
1799
|
+
const clear = () => {
|
|
1800
|
+
if (timer) {
|
|
1801
|
+
clearTimeout(timer);
|
|
1802
|
+
timer = undefined;
|
|
1803
|
+
}
|
|
1804
|
+
};
|
|
1805
|
+
return {
|
|
1806
|
+
promise,
|
|
1807
|
+
clear
|
|
1808
|
+
};
|
|
1809
|
+
};
|
|
1810
|
+
const runNextHook = async (index) => {
|
|
1811
|
+
if (index >= hooks.length) {
|
|
1812
|
+
return runInner();
|
|
1813
|
+
}
|
|
1814
|
+
const hook = hooks[index];
|
|
1815
|
+
const timeout = getAroundHookTimeout(hook);
|
|
1816
|
+
const stackTraceError = getAroundHookStackTrace(hook);
|
|
1817
|
+
let useCalled = false;
|
|
1818
|
+
let setupTimeout;
|
|
1819
|
+
let teardownTimeout;
|
|
1820
|
+
// Promise that resolves when use() is called (setup phase complete)
|
|
1821
|
+
let resolveUseCalled;
|
|
1822
|
+
const useCalledPromise = new Promise((resolve) => {
|
|
1823
|
+
resolveUseCalled = resolve;
|
|
1824
|
+
});
|
|
1825
|
+
// Promise that resolves when use() returns (inner hooks complete, teardown phase starts)
|
|
1826
|
+
let resolveUseReturned;
|
|
1827
|
+
const useReturnedPromise = new Promise((resolve) => {
|
|
1828
|
+
resolveUseReturned = resolve;
|
|
1829
|
+
});
|
|
1830
|
+
// Promise that resolves when hook completes
|
|
1831
|
+
let resolveHookComplete;
|
|
1832
|
+
let rejectHookComplete;
|
|
1833
|
+
const hookCompletePromise = new Promise((resolve, reject) => {
|
|
1834
|
+
resolveHookComplete = resolve;
|
|
1835
|
+
rejectHookComplete = reject;
|
|
1836
|
+
});
|
|
1837
|
+
const use = async () => {
|
|
1838
|
+
if (useCalled) {
|
|
1839
|
+
throw new AroundHookMultipleCallsError(`The \`${callbackName}\` callback was called multiple times in the \`${hookName}\` hook. ` + `The callback can only be called once per hook.`);
|
|
1840
|
+
}
|
|
1841
|
+
useCalled = true;
|
|
1842
|
+
resolveUseCalled();
|
|
1843
|
+
// Setup phase completed - clear setup timer
|
|
1844
|
+
setupTimeout.clear();
|
|
1845
|
+
// Run inner hooks - don't time this against our teardown timeout
|
|
1846
|
+
await runNextHook(index + 1);
|
|
1847
|
+
// Start teardown timer after inner hooks complete - only times this hook's teardown code
|
|
1848
|
+
teardownTimeout = createTimeoutPromise(timeout, "teardown", stackTraceError);
|
|
1849
|
+
// Signal that use() is returning (teardown phase starting)
|
|
1850
|
+
resolveUseReturned();
|
|
1851
|
+
};
|
|
1852
|
+
// Start setup timeout
|
|
1853
|
+
setupTimeout = createTimeoutPromise(timeout, "setup", stackTraceError);
|
|
1854
|
+
(async () => {
|
|
1855
|
+
try {
|
|
1856
|
+
await invokeHook(hook, use);
|
|
1857
|
+
if (!useCalled) {
|
|
1858
|
+
throw new AroundHookSetupError(`The \`${callbackName}\` callback was not called in the \`${hookName}\` hook. ` + `Make sure to call \`${callbackName}\` to run the ${hookName === "aroundEach" ? "test" : "suite"}.`);
|
|
1859
|
+
}
|
|
1860
|
+
resolveHookComplete();
|
|
1861
|
+
} catch (error) {
|
|
1862
|
+
rejectHookComplete(error);
|
|
1863
|
+
}
|
|
1864
|
+
})();
|
|
1865
|
+
// Wait for either: use() to be called OR hook to complete (error) OR setup timeout
|
|
1866
|
+
try {
|
|
1867
|
+
await Promise.race([
|
|
1868
|
+
useCalledPromise,
|
|
1869
|
+
hookCompletePromise,
|
|
1870
|
+
setupTimeout.promise
|
|
1871
|
+
]);
|
|
1872
|
+
} finally {
|
|
1873
|
+
setupTimeout.clear();
|
|
1874
|
+
}
|
|
1875
|
+
// Wait for use() to return (inner hooks complete) OR hook to complete (error during inner hooks)
|
|
1876
|
+
await Promise.race([useReturnedPromise, hookCompletePromise]);
|
|
1877
|
+
// Now teardownTimeout is guaranteed to be set
|
|
1878
|
+
// Wait for hook to complete (teardown) OR teardown timeout
|
|
1879
|
+
try {
|
|
1880
|
+
await Promise.race([hookCompletePromise, teardownTimeout.promise]);
|
|
1881
|
+
} finally {
|
|
1882
|
+
teardownTimeout.clear();
|
|
1883
|
+
}
|
|
1884
|
+
};
|
|
1885
|
+
await runNextHook(0);
|
|
1886
|
+
}
|
|
1887
|
+
async function callAroundAllHooks(suite, runSuiteInner) {
|
|
1888
|
+
await callAroundHooks(runSuiteInner, {
|
|
1889
|
+
hooks: getAroundAllHooks(suite),
|
|
1890
|
+
hookName: "aroundAll",
|
|
1891
|
+
callbackName: "runSuite()",
|
|
1892
|
+
invokeHook: (hook, use) => hook(use, suite)
|
|
1893
|
+
});
|
|
1894
|
+
}
|
|
1895
|
+
async function callAroundEachHooks(suite, test, runTest) {
|
|
1896
|
+
await callAroundHooks(
|
|
1897
|
+
// Take checkpoint right before runTest - at this point all aroundEach fixtures
|
|
1898
|
+
// have been resolved, so we can correctly identify which fixtures belong to
|
|
1899
|
+
// aroundEach (before checkpoint) vs inside runTest (after checkpoint)
|
|
1900
|
+
() => runTest(getFixtureCleanupCount(test.context)),
|
|
1901
|
+
{
|
|
1902
|
+
hooks: getAroundEachHooks(suite),
|
|
1903
|
+
hookName: "aroundEach",
|
|
1904
|
+
callbackName: "runTest()",
|
|
1905
|
+
onTimeout: (error) => abortContextSignal(test.context, error),
|
|
1906
|
+
invokeHook: (hook, use) => hook(use, test.context, suite)
|
|
1907
|
+
}
|
|
1908
|
+
);
|
|
1909
|
+
}
|
|
1589
1910
|
const packs = new Map();
|
|
1590
1911
|
const eventsPacks = [];
|
|
1591
1912
|
const pendingTasksUpdates = [];
|
|
@@ -1710,66 +2031,84 @@ async function runTest(test, runner) {
|
|
|
1710
2031
|
for (let repeatCount = 0; repeatCount <= repeats; repeatCount++) {
|
|
1711
2032
|
const retry = getRetryCount(test.retry);
|
|
1712
2033
|
for (let retryCount = 0; retryCount <= retry; retryCount++) {
|
|
1713
|
-
var _test$
|
|
2034
|
+
var _test$result2, _test$result3;
|
|
1714
2035
|
let beforeEachCleanups = [];
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
2036
|
+
// fixtureCheckpoint is passed by callAroundEachHooks - it represents the count
|
|
2037
|
+
// of fixture cleanup functions AFTER all aroundEach fixtures have been resolved
|
|
2038
|
+
// but BEFORE the test runs. This allows us to clean up only fixtures created
|
|
2039
|
+
// inside runTest while preserving aroundEach fixtures for teardown.
|
|
2040
|
+
await callAroundEachHooks(suite, test, async (fixtureCheckpoint) => {
|
|
2041
|
+
var _test$onFinished, _test$onFailed, _runner$onAfterRetryT;
|
|
2042
|
+
try {
|
|
2043
|
+
var _runner$onBeforeTryTa, _runner$onAfterTryTas;
|
|
2044
|
+
await ((_runner$onBeforeTryTa = runner.onBeforeTryTask) === null || _runner$onBeforeTryTa === void 0 ? void 0 : _runner$onBeforeTryTa.call(runner, test, {
|
|
2045
|
+
retry: retryCount,
|
|
2046
|
+
repeats: repeatCount
|
|
2047
|
+
}));
|
|
2048
|
+
test.result.repeatCount = repeatCount;
|
|
2049
|
+
beforeEachCleanups = await $("test.beforeEach", () => callSuiteHook(suite, test, "beforeEach", runner, [test.context, suite]));
|
|
2050
|
+
if (runner.runTask) {
|
|
2051
|
+
await $("test.callback", () => runner.runTask(test));
|
|
2052
|
+
} else {
|
|
2053
|
+
const fn = getFn(test);
|
|
2054
|
+
if (!fn) {
|
|
2055
|
+
throw new Error("Test function is not found. Did you add it using `setFn`?");
|
|
2056
|
+
}
|
|
2057
|
+
await $("test.callback", () => fn());
|
|
2058
|
+
}
|
|
2059
|
+
await ((_runner$onAfterTryTas = runner.onAfterTryTask) === null || _runner$onAfterTryTas === void 0 ? void 0 : _runner$onAfterTryTas.call(runner, test, {
|
|
2060
|
+
retry: retryCount,
|
|
2061
|
+
repeats: repeatCount
|
|
2062
|
+
}));
|
|
2063
|
+
if (test.result.state !== "fail") {
|
|
2064
|
+
if (!test.repeats) {
|
|
2065
|
+
test.result.state = "pass";
|
|
2066
|
+
} else if (test.repeats && retry === retryCount) {
|
|
2067
|
+
test.result.state = "pass";
|
|
2068
|
+
}
|
|
2069
|
+
}
|
|
2070
|
+
} catch (e) {
|
|
2071
|
+
failTask(test.result, e, runner.config.diffOptions);
|
|
2072
|
+
}
|
|
2073
|
+
try {
|
|
2074
|
+
var _runner$onTaskFinishe;
|
|
2075
|
+
await ((_runner$onTaskFinishe = runner.onTaskFinished) === null || _runner$onTaskFinishe === void 0 ? void 0 : _runner$onTaskFinishe.call(runner, test));
|
|
2076
|
+
} catch (e) {
|
|
2077
|
+
failTask(test.result, e, runner.config.diffOptions);
|
|
2078
|
+
}
|
|
2079
|
+
try {
|
|
2080
|
+
await $("test.afterEach", () => callSuiteHook(suite, test, "afterEach", runner, [test.context, suite]));
|
|
2081
|
+
if (beforeEachCleanups.length) {
|
|
2082
|
+
await $("test.cleanup", () => callCleanupHooks(runner, beforeEachCleanups));
|
|
1729
2083
|
}
|
|
1730
|
-
|
|
2084
|
+
// Only clean up fixtures created inside runTest (after the checkpoint)
|
|
2085
|
+
// Fixtures created for aroundEach will be cleaned up after aroundEach teardown
|
|
2086
|
+
await callFixtureCleanupFrom(test.context, fixtureCheckpoint);
|
|
2087
|
+
} catch (e) {
|
|
2088
|
+
failTask(test.result, e, runner.config.diffOptions);
|
|
2089
|
+
}
|
|
2090
|
+
if ((_test$onFinished = test.onFinished) === null || _test$onFinished === void 0 ? void 0 : _test$onFinished.length) {
|
|
2091
|
+
await $("test.onFinished", () => callTestHooks(runner, test, test.onFinished, "stack"));
|
|
1731
2092
|
}
|
|
1732
|
-
|
|
2093
|
+
if (test.result.state === "fail" && ((_test$onFailed = test.onFailed) === null || _test$onFailed === void 0 ? void 0 : _test$onFailed.length)) {
|
|
2094
|
+
await $("test.onFailed", () => callTestHooks(runner, test, test.onFailed, runner.config.sequence.hooks));
|
|
2095
|
+
}
|
|
2096
|
+
test.onFailed = undefined;
|
|
2097
|
+
test.onFinished = undefined;
|
|
2098
|
+
await ((_runner$onAfterRetryT = runner.onAfterRetryTask) === null || _runner$onAfterRetryT === void 0 ? void 0 : _runner$onAfterRetryT.call(runner, test, {
|
|
1733
2099
|
retry: retryCount,
|
|
1734
2100
|
repeats: repeatCount
|
|
1735
2101
|
}));
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
}
|
|
1742
|
-
}
|
|
1743
|
-
} catch (e) {
|
|
1744
|
-
failTask(test.result, e, runner.config.diffOptions);
|
|
1745
|
-
}
|
|
1746
|
-
try {
|
|
1747
|
-
var _runner$onTaskFinishe;
|
|
1748
|
-
await ((_runner$onTaskFinishe = runner.onTaskFinished) === null || _runner$onTaskFinishe === void 0 ? void 0 : _runner$onTaskFinishe.call(runner, test));
|
|
1749
|
-
} catch (e) {
|
|
1750
|
-
failTask(test.result, e, runner.config.diffOptions);
|
|
1751
|
-
}
|
|
2102
|
+
}).catch((error) => {
|
|
2103
|
+
failTask(test.result, error, runner.config.diffOptions);
|
|
2104
|
+
});
|
|
2105
|
+
// Clean up fixtures that were created for aroundEach (before the checkpoint)
|
|
2106
|
+
// This runs after aroundEach teardown has completed
|
|
1752
2107
|
try {
|
|
1753
|
-
await $("test.afterEach", () => callSuiteHook(suite, test, "afterEach", runner, [test.context, suite]));
|
|
1754
|
-
if (beforeEachCleanups.length) {
|
|
1755
|
-
await $("test.cleanup", () => callCleanupHooks(runner, beforeEachCleanups));
|
|
1756
|
-
}
|
|
1757
2108
|
await callFixtureCleanup(test.context);
|
|
1758
2109
|
} catch (e) {
|
|
1759
2110
|
failTask(test.result, e, runner.config.diffOptions);
|
|
1760
2111
|
}
|
|
1761
|
-
if ((_test$onFinished = test.onFinished) === null || _test$onFinished === void 0 ? void 0 : _test$onFinished.length) {
|
|
1762
|
-
await $("test.onFinished", () => callTestHooks(runner, test, test.onFinished, "stack"));
|
|
1763
|
-
}
|
|
1764
|
-
if (test.result.state === "fail" && ((_test$onFailed = test.onFailed) === null || _test$onFailed === void 0 ? void 0 : _test$onFailed.length)) {
|
|
1765
|
-
await $("test.onFailed", () => callTestHooks(runner, test, test.onFailed, runner.config.sequence.hooks));
|
|
1766
|
-
}
|
|
1767
|
-
test.onFailed = undefined;
|
|
1768
|
-
test.onFinished = undefined;
|
|
1769
|
-
await ((_runner$onAfterRetryT = runner.onAfterRetryTask) === null || _runner$onAfterRetryT === void 0 ? void 0 : _runner$onAfterRetryT.call(runner, test, {
|
|
1770
|
-
retry: retryCount,
|
|
1771
|
-
repeats: repeatCount
|
|
1772
|
-
}));
|
|
1773
2112
|
// skipped with new PendingError
|
|
1774
2113
|
if (((_test$result2 = test.result) === null || _test$result2 === void 0 ? void 0 : _test$result2.pending) || ((_test$result3 = test.result) === null || _test$result3 === void 0 ? void 0 : _test$result3.state) === "skip") {
|
|
1775
2114
|
var _test$result4;
|
|
@@ -1875,47 +2214,62 @@ async function runSuite(suite, runner) {
|
|
|
1875
2214
|
updateTask("suite-finished", suite, runner);
|
|
1876
2215
|
} else {
|
|
1877
2216
|
var _runner$onAfterRunSui;
|
|
2217
|
+
let suiteRan = false;
|
|
1878
2218
|
try {
|
|
1879
|
-
|
|
1880
|
-
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
2219
|
+
await callAroundAllHooks(suite, async () => {
|
|
2220
|
+
suiteRan = true;
|
|
2221
|
+
try {
|
|
2222
|
+
// beforeAll
|
|
2223
|
+
try {
|
|
2224
|
+
beforeAllCleanups = await $("suite.beforeAll", () => callSuiteHook(suite, suite, "beforeAll", runner, [suite]));
|
|
2225
|
+
} catch (e) {
|
|
2226
|
+
failTask(suite.result, e, runner.config.diffOptions);
|
|
2227
|
+
markTasksAsSkipped(suite, runner);
|
|
2228
|
+
return;
|
|
2229
|
+
}
|
|
2230
|
+
// run suite children
|
|
2231
|
+
if (runner.runSuite) {
|
|
2232
|
+
await runner.runSuite(suite);
|
|
1891
2233
|
} else {
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1897
|
-
|
|
1898
|
-
|
|
2234
|
+
for (let tasksGroup of partitionSuiteChildren(suite)) {
|
|
2235
|
+
if (tasksGroup[0].concurrent === true) {
|
|
2236
|
+
await Promise.all(tasksGroup.map((c) => runSuiteChild(c, runner)));
|
|
2237
|
+
} else {
|
|
2238
|
+
const { sequence } = runner.config;
|
|
2239
|
+
if (suite.shuffle) {
|
|
2240
|
+
// run describe block independently from tests
|
|
2241
|
+
const suites = tasksGroup.filter((group) => group.type === "suite");
|
|
2242
|
+
const tests = tasksGroup.filter((group) => group.type === "test");
|
|
2243
|
+
const groups = shuffle([suites, tests], sequence.seed);
|
|
2244
|
+
tasksGroup = groups.flatMap((group) => shuffle(group, sequence.seed));
|
|
2245
|
+
}
|
|
2246
|
+
for (const c of tasksGroup) {
|
|
2247
|
+
await runSuiteChild(c, runner);
|
|
2248
|
+
}
|
|
2249
|
+
}
|
|
2250
|
+
}
|
|
2251
|
+
}
|
|
2252
|
+
} finally {
|
|
2253
|
+
// afterAll runs even if beforeAll or suite children fail
|
|
2254
|
+
try {
|
|
2255
|
+
await $("suite.afterAll", () => callSuiteHook(suite, suite, "afterAll", runner, [suite]));
|
|
2256
|
+
if (beforeAllCleanups.length) {
|
|
2257
|
+
await $("suite.cleanup", () => callCleanupHooks(runner, beforeAllCleanups));
|
|
1899
2258
|
}
|
|
1900
|
-
|
|
1901
|
-
|
|
2259
|
+
if (suite.file === suite) {
|
|
2260
|
+
const context = getFileContext(suite);
|
|
2261
|
+
await callFixtureCleanup(context);
|
|
1902
2262
|
}
|
|
2263
|
+
} catch (e) {
|
|
2264
|
+
failTask(suite.result, e, runner.config.diffOptions);
|
|
1903
2265
|
}
|
|
1904
2266
|
}
|
|
1905
|
-
}
|
|
2267
|
+
});
|
|
1906
2268
|
} catch (e) {
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
await $("suite.afterAll", () => callSuiteHook(suite, suite, "afterAll", runner, [suite]));
|
|
1911
|
-
if (beforeAllCleanups.length) {
|
|
1912
|
-
await $("suite.cleanup", () => callCleanupHooks(runner, beforeAllCleanups));
|
|
1913
|
-
}
|
|
1914
|
-
if (suite.file === suite) {
|
|
1915
|
-
const context = getFileContext(suite);
|
|
1916
|
-
await callFixtureCleanup(context);
|
|
2269
|
+
// mark tasks as skipped if aroundAll failed before the suite callback was executed
|
|
2270
|
+
if (!suiteRan) {
|
|
2271
|
+
markTasksAsSkipped(suite, runner);
|
|
1917
2272
|
}
|
|
1918
|
-
} catch (e) {
|
|
1919
2273
|
failTask(suite.result, e, runner.config.diffOptions);
|
|
1920
2274
|
}
|
|
1921
2275
|
if (suite.mode === "run" || suite.mode === "queued") {
|
|
@@ -2195,4 +2549,4 @@ function manageArtifactAttachment(attachment) {
|
|
|
2195
2549
|
}
|
|
2196
2550
|
}
|
|
2197
2551
|
|
|
2198
|
-
export { afterAll, afterEach, beforeAll, beforeEach, publicCollect as collectTests, createTaskCollector, describe, getCurrentSuite, getCurrentTest, getFn, getHooks, it, onTestFailed, onTestFinished, recordArtifact, setFn, setHooks, startTests, suite, test, updateTask };
|
|
2552
|
+
export { afterAll, afterEach, aroundAll, aroundEach, beforeAll, beforeEach, publicCollect as collectTests, createTaskCollector, describe, getCurrentSuite, getCurrentTest, getFn, getHooks, it, onTestFailed, onTestFinished, recordArtifact, setFn, setHooks, startTests, suite, test, updateTask };
|
|
@@ -109,7 +109,7 @@ interface VitestRunner {
|
|
|
109
109
|
repeats: number;
|
|
110
110
|
}) => unknown;
|
|
111
111
|
/**
|
|
112
|
-
* Called after the retry resolution
|
|
112
|
+
* Called after the retry resolution happened. Unlike `onAfterTryTask`, the test now has a new state.
|
|
113
113
|
* All `after` hooks were also called by this point.
|
|
114
114
|
*/
|
|
115
115
|
onAfterRetryTask?: (test: Test, options: {
|
|
@@ -329,6 +329,64 @@ declare const onTestFailed: TaskHook<OnTestFailedHandler>;
|
|
|
329
329
|
* ```
|
|
330
330
|
*/
|
|
331
331
|
declare const onTestFinished: TaskHook<OnTestFinishedHandler>;
|
|
332
|
+
/**
|
|
333
|
+
* Registers a callback function that wraps around all tests within the current suite.
|
|
334
|
+
* The callback receives a `runSuite` function that must be called to run the suite's tests.
|
|
335
|
+
* This hook is useful for scenarios where you need to wrap an entire suite in a context
|
|
336
|
+
* (e.g., starting a server, opening a database connection that all tests share).
|
|
337
|
+
*
|
|
338
|
+
* **Note:** When multiple `aroundAll` hooks are registered, they are nested inside each other.
|
|
339
|
+
* The first registered hook is the outermost wrapper.
|
|
340
|
+
*
|
|
341
|
+
* **Note:** Unlike `aroundEach`, the `aroundAll` hook does not receive test context or support fixtures,
|
|
342
|
+
* as it runs at the suite level before any individual test context is created.
|
|
343
|
+
*
|
|
344
|
+
* @param {Function} fn - The callback function that wraps the suite. Must call `runSuite()` to run the tests.
|
|
345
|
+
* @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
|
|
346
|
+
* @returns {void}
|
|
347
|
+
* @example
|
|
348
|
+
* ```ts
|
|
349
|
+
* // Example of using aroundAll to wrap suite in a tracing span
|
|
350
|
+
* aroundAll(async (runSuite) => {
|
|
351
|
+
* await tracer.trace('test-suite', runSuite);
|
|
352
|
+
* });
|
|
353
|
+
* ```
|
|
354
|
+
* @example
|
|
355
|
+
* ```ts
|
|
356
|
+
* // Example of using aroundAll with AsyncLocalStorage context
|
|
357
|
+
* aroundAll(async (runSuite) => {
|
|
358
|
+
* await asyncLocalStorage.run({ suiteId: 'my-suite' }, runSuite);
|
|
359
|
+
* });
|
|
360
|
+
* ```
|
|
361
|
+
*/
|
|
362
|
+
declare function aroundAll(fn: AroundAllListener, timeout?: number): void;
|
|
363
|
+
/**
|
|
364
|
+
* Registers a callback function that wraps around each test within the current suite.
|
|
365
|
+
* The callback receives a `runTest` function that must be called to run the test.
|
|
366
|
+
* This hook is useful for scenarios where you need to wrap tests in a context (e.g., database transactions).
|
|
367
|
+
*
|
|
368
|
+
* **Note:** When multiple `aroundEach` hooks are registered, they are nested inside each other.
|
|
369
|
+
* The first registered hook is the outermost wrapper.
|
|
370
|
+
*
|
|
371
|
+
* @param {Function} fn - The callback function that wraps the test. Must call `runTest()` to run the test.
|
|
372
|
+
* @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
|
|
373
|
+
* @returns {void}
|
|
374
|
+
* @example
|
|
375
|
+
* ```ts
|
|
376
|
+
* // Example of using aroundEach to wrap tests in a database transaction
|
|
377
|
+
* aroundEach(async (runTest) => {
|
|
378
|
+
* await database.transaction(() => runTest());
|
|
379
|
+
* });
|
|
380
|
+
* ```
|
|
381
|
+
* @example
|
|
382
|
+
* ```ts
|
|
383
|
+
* // Example of using aroundEach with fixtures
|
|
384
|
+
* aroundEach(async (runTest, { db }) => {
|
|
385
|
+
* await db.transaction(() => runTest());
|
|
386
|
+
* });
|
|
387
|
+
* ```
|
|
388
|
+
*/
|
|
389
|
+
declare function aroundEach<ExtraContext = object>(fn: AroundEachListener<ExtraContext>, timeout?: number): void;
|
|
332
390
|
|
|
333
391
|
type ChainableFunction<
|
|
334
392
|
T extends string,
|
|
@@ -753,6 +811,10 @@ interface TestOptions {
|
|
|
753
811
|
* Custom tags of the test. Useful for filtering tests.
|
|
754
812
|
*/
|
|
755
813
|
tags?: keyof TestTags extends never ? string[] | string : TestTags[keyof TestTags] | TestTags[keyof TestTags][];
|
|
814
|
+
/**
|
|
815
|
+
* Custom test metadata available to reporters.
|
|
816
|
+
*/
|
|
817
|
+
meta?: Partial<TaskMeta>;
|
|
756
818
|
}
|
|
757
819
|
interface TestTags {}
|
|
758
820
|
interface SuiteOptions extends TestOptions {
|
|
@@ -770,10 +832,13 @@ interface Hooks<ExtraContext> {
|
|
|
770
832
|
afterAll: typeof afterAll;
|
|
771
833
|
beforeEach: typeof beforeEach<ExtraContext>;
|
|
772
834
|
afterEach: typeof afterEach<ExtraContext>;
|
|
835
|
+
aroundEach: typeof aroundEach<ExtraContext>;
|
|
836
|
+
aroundAll: typeof aroundAll;
|
|
773
837
|
}
|
|
774
838
|
type TestAPI<ExtraContext = object> = ChainableTestAPI<ExtraContext> & ExtendedAPI<ExtraContext> & Hooks<ExtraContext> & {
|
|
775
839
|
extend: <T extends Record<string, any> = object>(fixtures: Fixtures<T, ExtraContext>) => TestAPI<{ [K in keyof T | keyof ExtraContext] : K extends keyof T ? T[K] : K extends keyof ExtraContext ? ExtraContext[K] : never }>;
|
|
776
840
|
scoped: (fixtures: Partial<Fixtures<ExtraContext>>) => void;
|
|
841
|
+
describe: SuiteAPI<ExtraContext>;
|
|
777
842
|
};
|
|
778
843
|
interface FixtureOptions {
|
|
779
844
|
/**
|
|
@@ -836,11 +901,19 @@ interface BeforeEachListener<ExtraContext = object> {
|
|
|
836
901
|
interface AfterEachListener<ExtraContext = object> {
|
|
837
902
|
(context: TestContext & ExtraContext, suite: Readonly<Suite>): Awaitable<unknown>;
|
|
838
903
|
}
|
|
904
|
+
interface AroundEachListener<ExtraContext = object> {
|
|
905
|
+
(runTest: () => Promise<void>, context: TestContext & ExtraContext, suite: Readonly<Suite>): Awaitable<unknown>;
|
|
906
|
+
}
|
|
907
|
+
interface AroundAllListener {
|
|
908
|
+
(runSuite: () => Promise<void>, suite: Readonly<Suite | File>): Awaitable<unknown>;
|
|
909
|
+
}
|
|
839
910
|
interface SuiteHooks<ExtraContext = object> {
|
|
840
911
|
beforeAll: BeforeAllListener[];
|
|
841
912
|
afterAll: AfterAllListener[];
|
|
842
913
|
beforeEach: BeforeEachListener<ExtraContext>[];
|
|
843
914
|
afterEach: AfterEachListener<ExtraContext>[];
|
|
915
|
+
aroundEach: AroundEachListener<ExtraContext>[];
|
|
916
|
+
aroundAll: AroundAllListener[];
|
|
844
917
|
}
|
|
845
918
|
interface TaskCustomOptions extends TestOptions {
|
|
846
919
|
/**
|
|
@@ -848,10 +921,6 @@ interface TaskCustomOptions extends TestOptions {
|
|
|
848
921
|
*/
|
|
849
922
|
each?: boolean;
|
|
850
923
|
/**
|
|
851
|
-
* Custom metadata for the task that will be assigned to `task.meta`.
|
|
852
|
-
*/
|
|
853
|
-
meta?: Record<string, unknown>;
|
|
854
|
-
/**
|
|
855
924
|
* Task fixtures.
|
|
856
925
|
*/
|
|
857
926
|
fixtures?: FixtureItem[];
|
|
@@ -1093,5 +1162,5 @@ interface TestArtifactRegistry {}
|
|
|
1093
1162
|
*/
|
|
1094
1163
|
type TestArtifact = TestAnnotationArtifact | VisualRegressionArtifact | TestArtifactRegistry[keyof TestArtifactRegistry];
|
|
1095
1164
|
|
|
1096
|
-
export {
|
|
1097
|
-
export type {
|
|
1165
|
+
export { afterAll as a7, afterEach as a8, aroundAll as a9, aroundEach as aa, beforeAll as ab, beforeEach as ac, onTestFailed as ad, onTestFinished as ae, createChainable as ag };
|
|
1166
|
+
export type { TestOptions as $, AfterAllListener as A, BeforeAllListener as B, CancelReason as C, TaskCustomOptions as D, TaskEventPack as E, FileSpecification as F, TaskHook as G, TaskMeta as H, ImportDuration as I, TaskPopulated as J, TaskResult as K, TaskResultPack as L, TaskState as M, TestAnnotation as N, OnTestFailedHandler as O, TestAnnotationArtifact as P, TestAnnotationLocation as Q, Retry as R, Suite as S, TestArtifact as T, TestArtifactBase as U, VitestRunner as V, TestArtifactLocation as W, TestArtifactRegistry as X, TestAttachment as Y, TestContext as Z, TestFunction as _, Test as a, TestTagDefinition as a0, TestTags as a1, Use as a2, VisualRegressionArtifact as a3, VitestRunnerConfig as a4, VitestRunnerConstructor as a5, VitestRunnerImportSource as a6, ChainableFunction as af, SuiteHooks as b, File as c, TaskUpdateEvent as d, Task as e, TestAPI as f, SuiteAPI as g, SuiteCollector as h, AfterEachListener as i, AroundAllListener as j, AroundEachListener as k, BeforeEachListener as l, Fixture as m, FixtureFn as n, FixtureOptions as o, Fixtures as p, InferFixturesTypes as q, OnTestFinishedHandler as r, RunMode as s, RuntimeContext as t, SequenceHooks as u, SequenceSetupFiles as v, SerializableRetry as w, SuiteFactory as x, SuiteOptions as y, TaskBase as z };
|
package/dist/types.d.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { A as AfterAllListener,
|
|
1
|
+
export { A as AfterAllListener, i as AfterEachListener, j as AroundAllListener, k as AroundEachListener, B as BeforeAllListener, l as BeforeEachListener, C as CancelReason, c as File, F as FileSpecification, m as Fixture, n as FixtureFn, o as FixtureOptions, p as Fixtures, I as ImportDuration, q as InferFixturesTypes, O as OnTestFailedHandler, r as OnTestFinishedHandler, R as Retry, s as RunMode, t as RuntimeContext, u as SequenceHooks, v as SequenceSetupFiles, w as SerializableRetry, S as Suite, g as SuiteAPI, h as SuiteCollector, x as SuiteFactory, b as SuiteHooks, y as SuiteOptions, e as Task, z as TaskBase, D as TaskCustomOptions, E as TaskEventPack, G as TaskHook, H as TaskMeta, J as TaskPopulated, K as TaskResult, L as TaskResultPack, M as TaskState, d as TaskUpdateEvent, a as Test, f as TestAPI, N as TestAnnotation, P as TestAnnotationArtifact, Q as TestAnnotationLocation, T as TestArtifact, U as TestArtifactBase, W as TestArtifactLocation, X as TestArtifactRegistry, Y as TestAttachment, Z as TestContext, _ as TestFunction, $ as TestOptions, a0 as TestTagDefinition, a1 as TestTags, a2 as Use, a3 as VisualRegressionArtifact, V as VitestRunner, a4 as VitestRunnerConfig, a5 as VitestRunnerConstructor, a6 as VitestRunnerImportSource } from './tasks.d-WWG4yDf6.js';
|
|
2
2
|
import '@vitest/utils/diff';
|
|
3
3
|
import '@vitest/utils';
|
package/dist/utils.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { S as Suite, c as File, e as Task,
|
|
2
|
-
export {
|
|
1
|
+
import { S as Suite, c as File, e as Task, a0 as TestTagDefinition, a4 as VitestRunnerConfig, a as Test } from './tasks.d-WWG4yDf6.js';
|
|
2
|
+
export { af as ChainableFunction, ag as createChainable } from './tasks.d-WWG4yDf6.js';
|
|
3
3
|
import { ParsedStack, Arrayable } from '@vitest/utils';
|
|
4
4
|
import '@vitest/utils/diff';
|
|
5
5
|
|
package/dist/utils.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export {
|
|
1
|
+
export { c as calculateSuiteHash, a as createChainable, b as createFileTask, d as createTagsFilter, e as createTaskName, f as findTestFileStackTrace, g as generateFileHash, h as generateHash, i as getFullName, j as getNames, k as getSuites, l as getTasks, m as getTestName, n as getTests, o as hasFailed, p as hasTests, q as interpretTaskModes, r as isTestCase, s as limitConcurrency, t as partitionSuiteChildren, u as someTasksAreOnly, v as validateTags } from './chunk-tasks.js';
|
|
2
2
|
import '@vitest/utils/error';
|
|
3
3
|
import '@vitest/utils/source-map';
|
|
4
4
|
import 'pathe';
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vitest/runner",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "4.1.0-beta.
|
|
4
|
+
"version": "4.1.0-beta.3",
|
|
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": "^2.0.3",
|
|
42
|
-
"@vitest/utils": "4.1.0-beta.
|
|
42
|
+
"@vitest/utils": "4.1.0-beta.3"
|
|
43
43
|
},
|
|
44
44
|
"scripts": {
|
|
45
45
|
"build": "premove dist && rollup -c",
|