import { format, objDisplay } from "../../../../../@vitest_utils@3.2.4/node_modules/@vitest/utils/dist/chunk-_commonjsHelpers.js";
import { assertTypes, createDefer, isNegativeNaN, isObject, objectAttr, toArray } from "../../../../../@vitest_utils@3.2.4/node_modules/@vitest/utils/dist/helpers.js";
import { getSafeTimers } from "../../../../../@vitest_utils@3.2.4/node_modules/@vitest/utils/dist/index.js";
import { parseSingleStack } from "../../../../../@vitest_utils@3.2.4/node_modules/@vitest/utils/dist/source-map.js";
import { stripLiteral } from "../../../../../strip-literal@3.1.0/node_modules/strip-literal/dist/index.js";

//#region ../../node_modules/.pnpm/@vitest+runner@3.2.4/node_modules/@vitest/runner/dist/chunk-hooks.js
var PendingError = class extends Error {
	code = "VITEST_PENDING";
	taskId;
	constructor(message, task, note) {
		super(message);
		this.message = message;
		this.note = note;
		this.taskId = task.id;
	}
};
const fnMap = /* @__PURE__ */ new WeakMap();
const testFixtureMap = /* @__PURE__ */ new WeakMap();
const hooksMap = /* @__PURE__ */ new WeakMap();
function setFn(key, fn) {
	fnMap.set(key, fn);
}
function setTestFixture(key, fixture) {
	testFixtureMap.set(key, fixture);
}
function getTestFixture(key) {
	return testFixtureMap.get(key);
}
function setHooks(key, hooks) {
	hooksMap.set(key, hooks);
}
function getHooks(key) {
	return hooksMap.get(key);
}
function mergeScopedFixtures(testFixtures, scopedFixtures) {
	const scopedFixturesMap = scopedFixtures.reduce((map, fixture) => {
		map[fixture.prop] = fixture;
		return map;
	}, {});
	const newFixtures = {};
	testFixtures.forEach((fixture) => {
		const useFixture = scopedFixturesMap[fixture.prop] || { ...fixture };
		newFixtures[useFixture.prop] = useFixture;
	});
	for (const fixtureKep in newFixtures) {
		var _fixture$deps;
		const fixture = newFixtures[fixtureKep];
		fixture.deps = (_fixture$deps = fixture.deps) === null || _fixture$deps === void 0 ? void 0 : _fixture$deps.map((dep) => newFixtures[dep.prop]);
	}
	return Object.values(newFixtures);
}
function mergeContextFixtures(fixtures, context, runner$1) {
	const fixtureOptionKeys = [
		"auto",
		"injected",
		"scope"
	];
	const fixtureArray = Object.entries(fixtures).map(([prop, value]) => {
		const fixtureItem = { value };
		if (Array.isArray(value) && value.length >= 2 && isObject(value[1]) && Object.keys(value[1]).some((key) => fixtureOptionKeys.includes(key))) {
			var _runner$injectValue;
			Object.assign(fixtureItem, value[1]);
			const userValue = value[0];
			fixtureItem.value = fixtureItem.injected ? ((_runner$injectValue = runner$1.injectValue) === null || _runner$injectValue === void 0 ? void 0 : _runner$injectValue.call(runner$1, prop)) ?? userValue : userValue;
		}
		fixtureItem.scope = fixtureItem.scope || "test";
		if (fixtureItem.scope === "worker" && !runner$1.getWorkerContext) fixtureItem.scope = "file";
		fixtureItem.prop = prop;
		fixtureItem.isFn = typeof fixtureItem.value === "function";
		return fixtureItem;
	});
	if (Array.isArray(context.fixtures)) context.fixtures = context.fixtures.concat(fixtureArray);
	else context.fixtures = fixtureArray;
	fixtureArray.forEach((fixture) => {
		if (fixture.isFn) {
			const usedProps = getUsedProps(fixture.value);
			if (usedProps.length) fixture.deps = context.fixtures.filter(({ prop }) => prop !== fixture.prop && usedProps.includes(prop));
			if (fixture.scope !== "test") {
				var _fixture$deps2;
				(_fixture$deps2 = fixture.deps) === null || _fixture$deps2 === void 0 || _fixture$deps2.forEach((dep) => {
					if (!dep.isFn) return;
					if (fixture.scope === "worker" && dep.scope === "worker") return;
					if (fixture.scope === "file" && dep.scope !== "test") return;
					throw new SyntaxError(`cannot use the ${dep.scope} fixture "${dep.prop}" inside the ${fixture.scope} fixture "${fixture.prop}"`);
				});
			}
		}
	});
	return context;
}
const fixtureValueMaps = /* @__PURE__ */ new Map();
const cleanupFnArrayMap = /* @__PURE__ */ new Map();
function withFixtures(runner$1, fn, testContext) {
	return (hookContext) => {
		const context = hookContext || testContext;
		if (!context) return fn({});
		const fixtures = getTestFixture(context);
		if (!(fixtures === null || fixtures === void 0 ? void 0 : fixtures.length)) return fn(context);
		const usedProps = getUsedProps(fn);
		const hasAutoFixture = fixtures.some(({ auto }) => auto);
		if (!usedProps.length && !hasAutoFixture) return fn(context);
		if (!fixtureValueMaps.get(context)) fixtureValueMaps.set(context, /* @__PURE__ */ new Map());
		const fixtureValueMap = fixtureValueMaps.get(context);
		if (!cleanupFnArrayMap.has(context)) cleanupFnArrayMap.set(context, []);
		const cleanupFnArray = cleanupFnArrayMap.get(context);
		const pendingFixtures = resolveDeps(fixtures.filter(({ prop, auto }) => auto || usedProps.includes(prop)));
		if (!pendingFixtures.length) return fn(context);
		async function resolveFixtures() {
			for (const fixture of pendingFixtures) {
				if (fixtureValueMap.has(fixture)) continue;
				const resolvedValue = await resolveFixtureValue(runner$1, fixture, context, cleanupFnArray);
				context[fixture.prop] = resolvedValue;
				fixtureValueMap.set(fixture, resolvedValue);
				if (fixture.scope === "test") cleanupFnArray.unshift(() => {
					fixtureValueMap.delete(fixture);
				});
			}
		}
		return resolveFixtures().then(() => fn(context));
	};
}
const globalFixturePromise = /* @__PURE__ */ new WeakMap();
function resolveFixtureValue(runner$1, fixture, context, cleanupFnArray) {
	var _runner$getWorkerCont;
	const fileContext = getFileContext(context.task.file);
	const workerContext = (_runner$getWorkerCont = runner$1.getWorkerContext) === null || _runner$getWorkerCont === void 0 ? void 0 : _runner$getWorkerCont.call(runner$1);
	if (!fixture.isFn) {
		var _fixture$prop;
		fileContext[_fixture$prop = fixture.prop] ?? (fileContext[_fixture$prop] = fixture.value);
		if (workerContext) {
			var _fixture$prop2;
			workerContext[_fixture$prop2 = fixture.prop] ?? (workerContext[_fixture$prop2] = fixture.value);
		}
		return fixture.value;
	}
	if (fixture.scope === "test") return resolveFixtureFunction(fixture.value, context, cleanupFnArray);
	if (globalFixturePromise.has(fixture)) return globalFixturePromise.get(fixture);
	let fixtureContext;
	if (fixture.scope === "worker") {
		if (!workerContext) throw new TypeError("[@vitest/runner] The worker context is not available in the current test runner. Please, provide the `getWorkerContext` method when initiating the runner.");
		fixtureContext = workerContext;
	} else fixtureContext = fileContext;
	if (fixture.prop in fixtureContext) return fixtureContext[fixture.prop];
	if (!cleanupFnArrayMap.has(fixtureContext)) cleanupFnArrayMap.set(fixtureContext, []);
	const cleanupFnFileArray = cleanupFnArrayMap.get(fixtureContext);
	const promise = resolveFixtureFunction(fixture.value, fixtureContext, cleanupFnFileArray).then((value) => {
		fixtureContext[fixture.prop] = value;
		globalFixturePromise.delete(fixture);
		return value;
	});
	globalFixturePromise.set(fixture, promise);
	return promise;
}
async function resolveFixtureFunction(fixtureFn, context, cleanupFnArray) {
	const useFnArgPromise = createDefer();
	let isUseFnArgResolved = false;
	const fixtureReturn = fixtureFn(context, async (useFnArg) => {
		isUseFnArgResolved = true;
		useFnArgPromise.resolve(useFnArg);
		const useReturnPromise = createDefer();
		cleanupFnArray.push(async () => {
			useReturnPromise.resolve();
			await fixtureReturn;
		});
		await useReturnPromise;
	}).catch((e) => {
		if (!isUseFnArgResolved) {
			useFnArgPromise.reject(e);
			return;
		}
		throw e;
	});
	return useFnArgPromise;
}
function resolveDeps(fixtures, depSet = /* @__PURE__ */ new Set(), pendingFixtures = []) {
	fixtures.forEach((fixture) => {
		if (pendingFixtures.includes(fixture)) return;
		if (!fixture.isFn || !fixture.deps) {
			pendingFixtures.push(fixture);
			return;
		}
		if (depSet.has(fixture)) throw new Error(`Circular fixture dependency detected: ${fixture.prop} <- ${[...depSet].reverse().map((d) => d.prop).join(" <- ")}`);
		depSet.add(fixture);
		resolveDeps(fixture.deps, depSet, pendingFixtures);
		pendingFixtures.push(fixture);
		depSet.clear();
	});
	return pendingFixtures;
}
function getUsedProps(fn) {
	let fnString = stripLiteral(fn.toString());
	if (/__async\((?:this|null), (?:null|arguments|\[[_0-9, ]*\]), function\*/.test(fnString)) fnString = fnString.split(/__async\((?:this|null),/)[1];
	const match = fnString.match(/[^(]*\(([^)]*)/);
	if (!match) return [];
	const args = splitByComma(match[1]);
	if (!args.length) return [];
	let first = args[0];
	if ("__VITEST_FIXTURE_INDEX__" in fn) {
		first = args[fn.__VITEST_FIXTURE_INDEX__];
		if (!first) return [];
	}
	if (!(first.startsWith("{") && first.endsWith("}"))) throw new Error(`The first argument inside a fixture must use object destructuring pattern, e.g. ({ test } => {}). Instead, received "${first}".`);
	const props = splitByComma(first.slice(1, -1).replace(/\s/g, "")).map((prop) => {
		return prop.replace(/:.*|=.*/g, "");
	});
	const last = props.at(-1);
	if (last && last.startsWith("...")) throw new Error(`Rest parameters are not supported in fixtures, received "${last}".`);
	return props;
}
function splitByComma(s) {
	const result = [];
	const stack = [];
	let start = 0;
	for (let i = 0; i < s.length; i++) if (s[i] === "{" || s[i] === "[") stack.push(s[i] === "{" ? "}" : "]");
	else if (s[i] === stack[stack.length - 1]) stack.pop();
	else if (!stack.length && s[i] === ",") {
		const token = s.substring(start, i).trim();
		if (token) result.push(token);
		start = i + 1;
	}
	const lastToken = s.substring(start).trim();
	if (lastToken) result.push(lastToken);
	return result;
}
let _test;
function getCurrentTest() {
	return _test;
}
function createChainable(keys, fn) {
	function create(context) {
		const chain$1 = function(...args) {
			return fn.apply(context, args);
		};
		Object.assign(chain$1, fn);
		chain$1.withContext = () => chain$1.bind(context);
		chain$1.setContext = (key, value) => {
			context[key] = value;
		};
		chain$1.mergeContext = (ctx) => {
			Object.assign(context, ctx);
		};
		for (const key of keys) Object.defineProperty(chain$1, key, { get() {
			return create({
				...context,
				[key]: true
			});
		} });
		return chain$1;
	}
	const chain = create({});
	chain.fn = fn;
	return chain;
}
/**
* Creates a suite of tests, allowing for grouping and hierarchical organization of tests.
* Suites can contain both tests and other suites, enabling complex test structures.
*
* @param {string} name - The name of the suite, used for identification and reporting.
* @param {Function} fn - A function that defines the tests and suites within this suite.
* @example
* ```ts
* // Define a suite with two tests
* suite('Math operations', () => {
*   test('should add two numbers', () => {
*     expect(add(1, 2)).toBe(3);
*   });
*
*   test('should subtract two numbers', () => {
*     expect(subtract(5, 2)).toBe(3);
*   });
* });
* ```
* @example
* ```ts
* // Define nested suites
* suite('String operations', () => {
*   suite('Trimming', () => {
*     test('should trim whitespace from start and end', () => {
*       expect('  hello  '.trim()).toBe('hello');
*     });
*   });
*
*   suite('Concatenation', () => {
*     test('should concatenate two strings', () => {
*       expect('hello' + ' ' + 'world').toBe('hello world');
*     });
*   });
* });
* ```
*/
const suite = createSuite();
/**
* Defines a test case with a given name and test function. The test function can optionally be configured with test options.
*
* @param {string | Function} name - The name of the test or a function that will be used as a test name.
* @param {TestOptions | TestFunction} [optionsOrFn] - Optional. The test options or the test function if no explicit name is provided.
* @param {number | TestOptions | TestFunction} [optionsOrTest] - Optional. The test function or options, depending on the previous parameters.
* @throws {Error} If called inside another test function.
* @example
* ```ts
* // Define a simple test
* test('should add two numbers', () => {
*   expect(add(1, 2)).toBe(3);
* });
* ```
* @example
* ```ts
* // Define a test with options
* test('should subtract two numbers', { retry: 3 }, () => {
*   expect(subtract(5, 2)).toBe(3);
* });
* ```
*/
const test = createTest(function(name, optionsOrFn, optionsOrTest) {
	if (getCurrentTest()) throw new Error("Calling the test function inside another test function is not allowed. Please put it inside \"describe\" or \"suite\" so it can be properly collected.");
	getCurrentSuite().test.fn.call(this, formatName(name), optionsOrFn, optionsOrTest);
});
let runner;
let defaultSuite;
let currentTestFilepath;
function assert(condition, message) {
	if (!condition) throw new Error(`Vitest failed to find ${message}. This is a bug in Vitest. Please, open an issue with reproduction.`);
}
function getTestFilepath() {
	return currentTestFilepath;
}
function getRunner() {
	assert(runner, "the runner");
	return runner;
}
function getCurrentSuite() {
	const currentSuite = collectorContext.currentSuite || defaultSuite;
	assert(currentSuite, "the current suite");
	return currentSuite;
}
function createSuiteHooks() {
	return {
		beforeAll: [],
		afterAll: [],
		beforeEach: [],
		afterEach: []
	};
}
function parseArguments(optionsOrFn, optionsOrTest) {
	let options = {};
	let fn = () => {};
	if (typeof optionsOrTest === "object") {
		if (typeof optionsOrFn === "object") throw new TypeError("Cannot use two objects as arguments. Please provide options and a function callback in that order.");
		console.warn("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");
		options = optionsOrTest;
	} else if (typeof optionsOrTest === "number") options = { timeout: optionsOrTest };
	else if (typeof optionsOrFn === "object") options = optionsOrFn;
	if (typeof optionsOrFn === "function") {
		if (typeof optionsOrTest === "function") throw new TypeError("Cannot use two functions as arguments. Please use the second argument for options.");
		fn = optionsOrFn;
	} else if (typeof optionsOrTest === "function") fn = optionsOrTest;
	return {
		options,
		handler: fn
	};
}
function createSuiteCollector(name, factory = () => {}, mode, each, suiteOptions, parentCollectorFixtures) {
	const tasks = [];
	let suite$1;
	initSuite(true);
	const task = function(name$1 = "", options = {}) {
		var _collectorContext$cur;
		const timeout = (options === null || options === void 0 ? void 0 : options.timeout) ?? runner.config.testTimeout;
		const task$1 = {
			id: "",
			name: name$1,
			suite: (_collectorContext$cur = collectorContext.currentSuite) === null || _collectorContext$cur === void 0 ? void 0 : _collectorContext$cur.suite,
			each: options.each,
			fails: options.fails,
			context: void 0,
			type: "test",
			file: void 0,
			timeout,
			retry: options.retry ?? runner.config.retry,
			repeats: options.repeats,
			mode: options.only ? "only" : options.skip ? "skip" : options.todo ? "todo" : "run",
			meta: options.meta ?? Object.create(null),
			annotations: []
		};
		const handler = options.handler;
		if (options.concurrent || !options.sequential && runner.config.sequence.concurrent) task$1.concurrent = true;
		task$1.shuffle = suiteOptions === null || suiteOptions === void 0 ? void 0 : suiteOptions.shuffle;
		const context = createTestContext(task$1, runner);
		Object.defineProperty(task$1, "context", {
			value: context,
			enumerable: false
		});
		setTestFixture(context, options.fixtures);
		const limit = Error.stackTraceLimit;
		Error.stackTraceLimit = 15;
		const stackTraceError = /* @__PURE__ */ new Error("STACK_TRACE_ERROR");
		Error.stackTraceLimit = limit;
		if (handler) setFn(task$1, withTimeout(withAwaitAsyncAssertions(withFixtures(runner, handler, context), task$1), timeout, false, stackTraceError, (_, error) => abortIfTimeout([context], error)));
		if (runner.config.includeTaskLocation) {
			const error = stackTraceError.stack;
			const stack = findTestFileStackTrace(error);
			if (stack) task$1.location = stack;
		}
		tasks.push(task$1);
		return task$1;
	};
	const test$1 = createTest(function(name$1, optionsOrFn, optionsOrTest) {
		let { options, handler } = parseArguments(optionsOrFn, optionsOrTest);
		if (typeof suiteOptions === "object") options = Object.assign({}, suiteOptions, options);
		options.concurrent = this.concurrent || !this.sequential && (options === null || options === void 0 ? void 0 : options.concurrent);
		options.sequential = this.sequential || !this.concurrent && (options === null || options === void 0 ? void 0 : options.sequential);
		const test$2 = task(formatName(name$1), {
			...this,
			...options,
			handler
		});
		test$2.type = "test";
	});
	let collectorFixtures = parentCollectorFixtures;
	const collector = {
		type: "collector",
		name,
		mode,
		suite: suite$1,
		options: suiteOptions,
		test: test$1,
		tasks,
		collect,
		task,
		clear,
		on: addHook,
		fixtures() {
			return collectorFixtures;
		},
		scoped(fixtures) {
			const parsed = mergeContextFixtures(fixtures, { fixtures: collectorFixtures }, runner);
			if (parsed.fixtures) collectorFixtures = parsed.fixtures;
		}
	};
	function addHook(name$1, ...fn) {
		getHooks(suite$1)[name$1].push(...fn);
	}
	function initSuite(includeLocation) {
		var _collectorContext$cur2;
		if (typeof suiteOptions === "number") suiteOptions = { timeout: suiteOptions };
		suite$1 = {
			id: "",
			type: "suite",
			name,
			suite: (_collectorContext$cur2 = collectorContext.currentSuite) === null || _collectorContext$cur2 === void 0 ? void 0 : _collectorContext$cur2.suite,
			mode,
			each,
			file: void 0,
			shuffle: suiteOptions === null || suiteOptions === void 0 ? void 0 : suiteOptions.shuffle,
			tasks: [],
			meta: Object.create(null),
			concurrent: suiteOptions === null || suiteOptions === void 0 ? void 0 : suiteOptions.concurrent
		};
		if (runner && includeLocation && runner.config.includeTaskLocation) {
			const limit = Error.stackTraceLimit;
			Error.stackTraceLimit = 15;
			const error = (/* @__PURE__ */ new Error("stacktrace")).stack;
			Error.stackTraceLimit = limit;
			const stack = findTestFileStackTrace(error);
			if (stack) suite$1.location = stack;
		}
		setHooks(suite$1, createSuiteHooks());
	}
	function clear() {
		tasks.length = 0;
		initSuite(false);
	}
	async function collect(file) {
		if (!file) throw new TypeError("File is required to collect tasks.");
		if (factory) await runWithSuite(collector, () => factory(test$1));
		const allChildren = [];
		for (const i of tasks) allChildren.push(i.type === "collector" ? await i.collect(file) : i);
		suite$1.file = file;
		suite$1.tasks = allChildren;
		allChildren.forEach((task$1) => {
			task$1.file = file;
		});
		return suite$1;
	}
	collectTask(collector);
	return collector;
}
function withAwaitAsyncAssertions(fn, task) {
	return async (...args) => {
		const fnResult = await fn(...args);
		if (task.promises) {
			const errors = (await Promise.allSettled(task.promises)).map((r) => r.status === "rejected" ? r.reason : void 0).filter(Boolean);
			if (errors.length) throw errors;
		}
		return fnResult;
	};
}
function createSuite() {
	function suiteFn(name, factoryOrOptions, optionsOrFactory) {
		var _currentSuite$options;
		const mode = this.only ? "only" : this.skip ? "skip" : this.todo ? "todo" : "run";
		const currentSuite = collectorContext.currentSuite || defaultSuite;
		let { options, handler: factory } = parseArguments(factoryOrOptions, optionsOrFactory);
		const isConcurrentSpecified = options.concurrent || this.concurrent || options.sequential === false;
		const isSequentialSpecified = options.sequential || this.sequential || options.concurrent === false;
		options = {
			...currentSuite === null || currentSuite === void 0 ? void 0 : currentSuite.options,
			...options,
			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)
		};
		const isConcurrent = isConcurrentSpecified || options.concurrent && !isSequentialSpecified;
		const isSequential = isSequentialSpecified || options.sequential && !isConcurrentSpecified;
		options.concurrent = isConcurrent && !isSequential;
		options.sequential = isSequential && !isConcurrent;
		return createSuiteCollector(formatName(name), factory, mode, this.each, options, currentSuite === null || currentSuite === void 0 ? void 0 : currentSuite.fixtures());
	}
	suiteFn.each = function(cases, ...args) {
		const suite$1 = this.withContext();
		this.setContext("each", true);
		if (Array.isArray(cases) && args.length) cases = formatTemplateString(cases, args);
		return (name, optionsOrFn, fnOrOptions) => {
			const _name = formatName(name);
			const arrayOnlyCases = cases.every(Array.isArray);
			const { options, handler } = parseArguments(optionsOrFn, fnOrOptions);
			const fnFirst = typeof optionsOrFn === "function" && typeof fnOrOptions === "object";
			cases.forEach((i, idx) => {
				const items = Array.isArray(i) ? i : [i];
				if (fnFirst) if (arrayOnlyCases) suite$1(formatTitle(_name, items, idx), () => handler(...items), options);
				else suite$1(formatTitle(_name, items, idx), () => handler(i), options);
				else if (arrayOnlyCases) suite$1(formatTitle(_name, items, idx), options, () => handler(...items));
				else suite$1(formatTitle(_name, items, idx), options, () => handler(i));
			});
			this.setContext("each", void 0);
		};
	};
	suiteFn.for = function(cases, ...args) {
		if (Array.isArray(cases) && args.length) cases = formatTemplateString(cases, args);
		return (name, optionsOrFn, fnOrOptions) => {
			const name_ = formatName(name);
			const { options, handler } = parseArguments(optionsOrFn, fnOrOptions);
			cases.forEach((item, idx) => {
				suite(formatTitle(name_, toArray(item), idx), options, () => handler(item));
			});
		};
	};
	suiteFn.skipIf = (condition) => condition ? suite.skip : suite;
	suiteFn.runIf = (condition) => condition ? suite : suite.skip;
	return createChainable([
		"concurrent",
		"sequential",
		"shuffle",
		"skip",
		"only",
		"todo"
	], suiteFn);
}
function createTaskCollector(fn, context) {
	const taskFn = fn;
	taskFn.each = function(cases, ...args) {
		const test$1 = this.withContext();
		this.setContext("each", true);
		if (Array.isArray(cases) && args.length) cases = formatTemplateString(cases, args);
		return (name, optionsOrFn, fnOrOptions) => {
			const _name = formatName(name);
			const arrayOnlyCases = cases.every(Array.isArray);
			const { options, handler } = parseArguments(optionsOrFn, fnOrOptions);
			const fnFirst = typeof optionsOrFn === "function" && typeof fnOrOptions === "object";
			cases.forEach((i, idx) => {
				const items = Array.isArray(i) ? i : [i];
				if (fnFirst) if (arrayOnlyCases) test$1(formatTitle(_name, items, idx), () => handler(...items), options);
				else test$1(formatTitle(_name, items, idx), () => handler(i), options);
				else if (arrayOnlyCases) test$1(formatTitle(_name, items, idx), options, () => handler(...items));
				else test$1(formatTitle(_name, items, idx), options, () => handler(i));
			});
			this.setContext("each", void 0);
		};
	};
	taskFn.for = function(cases, ...args) {
		const test$1 = this.withContext();
		if (Array.isArray(cases) && args.length) cases = formatTemplateString(cases, args);
		return (name, optionsOrFn, fnOrOptions) => {
			const _name = formatName(name);
			const { options, handler } = parseArguments(optionsOrFn, fnOrOptions);
			cases.forEach((item, idx) => {
				const handlerWrapper = (ctx) => handler(item, ctx);
				handlerWrapper.__VITEST_FIXTURE_INDEX__ = 1;
				handlerWrapper.toString = () => handler.toString();
				test$1(formatTitle(_name, toArray(item), idx), options, handlerWrapper);
			});
		};
	};
	taskFn.skipIf = function(condition) {
		return condition ? this.skip : this;
	};
	taskFn.runIf = function(condition) {
		return condition ? this : this.skip;
	};
	taskFn.scoped = function(fixtures) {
		getCurrentSuite().scoped(fixtures);
	};
	taskFn.extend = function(fixtures) {
		const _context = mergeContextFixtures(fixtures, context || {}, runner);
		const originalWrapper = fn;
		return createTest(function(name, optionsOrFn, optionsOrTest) {
			const scopedFixtures = getCurrentSuite().fixtures();
			const context$1 = { ...this };
			if (scopedFixtures) context$1.fixtures = mergeScopedFixtures(context$1.fixtures || [], scopedFixtures);
			const { handler, options } = parseArguments(optionsOrFn, optionsOrTest);
			const timeout = options.timeout ?? (runner === null || runner === void 0 ? void 0 : runner.config.testTimeout);
			originalWrapper.call(context$1, formatName(name), handler, timeout);
		}, _context);
	};
	const _test$1 = createChainable([
		"concurrent",
		"sequential",
		"skip",
		"only",
		"todo",
		"fails"
	], taskFn);
	if (context) _test$1.mergeContext(context);
	return _test$1;
}
function createTest(fn, context) {
	return createTaskCollector(fn, context);
}
function formatName(name) {
	return typeof name === "string" ? name : typeof name === "function" ? name.name || "<anonymous>" : String(name);
}
function formatTitle(template, items, idx) {
	if (template.includes("%#") || template.includes("%$")) template = template.replace(/%%/g, "__vitest_escaped_%__").replace(/%#/g, `${idx}`).replace(/%\$/g, `${idx + 1}`).replace(/__vitest_escaped_%__/g, "%%");
	const count = template.split("%").length - 1;
	if (template.includes("%f")) (template.match(/%f/g) || []).forEach((_, i) => {
		if (isNegativeNaN(items[i]) || Object.is(items[i], -0)) {
			let occurrence = 0;
			template = template.replace(/%f/g, (match) => {
				occurrence++;
				return occurrence === i + 1 ? "-%f" : match;
			});
		}
	});
	let formatted = format(template, ...items.slice(0, count));
	const isObjectItem = isObject(items[0]);
	formatted = formatted.replace(/\$([$\w.]+)/g, (_, key) => {
		var _runner$config;
		const isArrayKey = /^\d+$/.test(key);
		if (!isObjectItem && !isArrayKey) return `$${key}`;
		const arrayElement = isArrayKey ? objectAttr(items, key) : void 0;
		return objDisplay(isObjectItem ? objectAttr(items[0], key, arrayElement) : arrayElement, { truncate: runner === null || runner === void 0 || (_runner$config = runner.config) === null || _runner$config === void 0 || (_runner$config = _runner$config.chaiConfig) === null || _runner$config === void 0 ? void 0 : _runner$config.truncateThreshold });
	});
	return formatted;
}
function formatTemplateString(cases, args) {
	const header = cases.join("").trim().replace(/ /g, "").split("\n").map((i) => i.split("|"))[0];
	const res = [];
	for (let i = 0; i < Math.floor(args.length / header.length); i++) {
		const oneCase = {};
		for (let j = 0; j < header.length; j++) oneCase[header[j]] = args[i * header.length + j];
		res.push(oneCase);
	}
	return res;
}
function findTestFileStackTrace(error) {
	const testFilePath = getTestFilepath();
	const lines = error.split("\n").slice(1);
	for (const line of lines) {
		const stack = parseSingleStack(line);
		if (stack && stack.file === testFilePath) return {
			line: stack.line,
			column: stack.column
		};
	}
}
const now$2 = globalThis.performance ? globalThis.performance.now.bind(globalThis.performance) : Date.now;
function getNames(task) {
	const names = [task.name];
	let current = task;
	while (current === null || current === void 0 ? void 0 : current.suite) {
		current = current.suite;
		if (current === null || current === void 0 ? void 0 : current.name) names.unshift(current.name);
	}
	if (current !== task.file) names.unshift(task.file.name);
	return names;
}
function getTestName(task, separator = " > ") {
	return getNames(task).slice(1).join(separator);
}
const now$1 = globalThis.performance ? globalThis.performance.now.bind(globalThis.performance) : Date.now;
const unixNow = Date.now;
const { clearTimeout, setTimeout } = getSafeTimers();
const packs = /* @__PURE__ */ new Map();
const eventsPacks = [];
const pendingTasksUpdates = [];
function sendTasksUpdate(runner$1) {
	if (packs.size) {
		var _runner$onTaskUpdate;
		const taskPacks = Array.from(packs).map(([id, task]) => {
			return [
				id,
				task[0],
				task[1]
			];
		});
		const p = (_runner$onTaskUpdate = runner$1.onTaskUpdate) === null || _runner$onTaskUpdate === void 0 ? void 0 : _runner$onTaskUpdate.call(runner$1, taskPacks, eventsPacks);
		if (p) {
			pendingTasksUpdates.push(p);
			p.then(() => pendingTasksUpdates.splice(pendingTasksUpdates.indexOf(p), 1), () => {});
		}
		eventsPacks.length = 0;
		packs.clear();
	}
}
async function finishSendTasksUpdate(runner$1) {
	sendTasksUpdate(runner$1);
	await Promise.all(pendingTasksUpdates);
}
function throttle(fn, ms) {
	let last = 0;
	let pendingCall;
	return function call(...args) {
		const now$3 = unixNow();
		if (now$3 - last > ms) {
			last = now$3;
			clearTimeout(pendingCall);
			pendingCall = void 0;
			return fn.apply(this, args);
		}
		pendingCall ?? (pendingCall = setTimeout(() => call.bind(this)(...args), ms));
	};
}
const sendTasksUpdateThrottled = throttle(sendTasksUpdate, 100);
const now = Date.now;
const collectorContext = {
	tasks: [],
	currentSuite: null
};
function collectTask(task) {
	var _collectorContext$cur;
	(_collectorContext$cur = collectorContext.currentSuite) === null || _collectorContext$cur === void 0 || _collectorContext$cur.tasks.push(task);
}
async function runWithSuite(suite$1, fn) {
	const prev = collectorContext.currentSuite;
	collectorContext.currentSuite = suite$1;
	await fn();
	collectorContext.currentSuite = prev;
}
function withTimeout(fn, timeout, isHook = false, stackTraceError, onTimeout) {
	if (timeout <= 0 || timeout === Number.POSITIVE_INFINITY) return fn;
	const { setTimeout: setTimeout$1, clearTimeout: clearTimeout$1 } = getSafeTimers();
	return function runWithTimeout(...args) {
		const startTime = now();
		const runner$1 = getRunner();
		runner$1._currentTaskStartTime = startTime;
		runner$1._currentTaskTimeout = timeout;
		return new Promise((resolve_, reject_) => {
			var _timer$unref;
			const timer = setTimeout$1(() => {
				clearTimeout$1(timer);
				rejectTimeoutError();
			}, timeout);
			(_timer$unref = timer.unref) === null || _timer$unref === void 0 || _timer$unref.call(timer);
			function rejectTimeoutError() {
				const error = makeTimeoutError(isHook, timeout, stackTraceError);
				onTimeout === null || onTimeout === void 0 || onTimeout(args, error);
				reject_(error);
			}
			function resolve(result) {
				runner$1._currentTaskStartTime = void 0;
				runner$1._currentTaskTimeout = void 0;
				clearTimeout$1(timer);
				if (now() - startTime >= timeout) {
					rejectTimeoutError();
					return;
				}
				resolve_(result);
			}
			function reject(error) {
				runner$1._currentTaskStartTime = void 0;
				runner$1._currentTaskTimeout = void 0;
				clearTimeout$1(timer);
				reject_(error);
			}
			try {
				const result = fn(...args);
				if (typeof result === "object" && result != null && typeof result.then === "function") result.then(resolve, reject);
				else resolve(result);
			} catch (error) {
				reject(error);
			}
		});
	};
}
const abortControllers = /* @__PURE__ */ new WeakMap();
function abortIfTimeout([context], error) {
	if (context) abortContextSignal(context, error);
}
function abortContextSignal(context, error) {
	const abortController = abortControllers.get(context);
	abortController === null || abortController === void 0 || abortController.abort(error);
}
function createTestContext(test$1, runner$1) {
	var _runner$extendTaskCon;
	const context = function() {
		throw new Error("done() callback is deprecated, use promise instead");
	};
	let abortController = abortControllers.get(context);
	if (!abortController) {
		abortController = new AbortController();
		abortControllers.set(context, abortController);
	}
	context.signal = abortController.signal;
	context.task = test$1;
	context.skip = (condition, note) => {
		if (condition === false) return;
		test$1.result ?? (test$1.result = { state: "skip" });
		test$1.result.pending = true;
		throw new PendingError("test is skipped; abort execution", test$1, typeof condition === "string" ? condition : note);
	};
	async function annotate(message, location, type, attachment) {
		const annotation = {
			message,
			type: type || "notice"
		};
		if (attachment) {
			if (!attachment.body && !attachment.path) throw new TypeError(`Test attachment requires body or path to be set. Both are missing.`);
			if (attachment.body && attachment.path) throw new TypeError(`Test attachment requires only one of "body" or "path" to be set. Both are specified.`);
			annotation.attachment = attachment;
			if (attachment.body instanceof Uint8Array) attachment.body = encodeUint8Array(attachment.body);
		}
		if (location) annotation.location = location;
		if (!runner$1.onTestAnnotate) throw new Error(`Test runner doesn't support test annotations.`);
		await finishSendTasksUpdate(runner$1);
		const resolvedAnnotation = await runner$1.onTestAnnotate(test$1, annotation);
		test$1.annotations.push(resolvedAnnotation);
		return resolvedAnnotation;
	}
	context.annotate = (message, type, attachment) => {
		if (test$1.result && test$1.result.state !== "run") throw new Error(`Cannot annotate tests outside of the test run. The test "${test$1.name}" finished running with the "${test$1.result.state}" state already.`);
		let location;
		const stack = (/* @__PURE__ */ new Error("STACK_TRACE")).stack;
		const index = stack.includes("STACK_TRACE") ? 2 : 1;
		const stackLine = stack.split("\n")[index];
		const parsed = parseSingleStack(stackLine);
		if (parsed) location = {
			file: parsed.file,
			line: parsed.line,
			column: parsed.column
		};
		if (typeof type === "object") return recordAsyncAnnotation(test$1, annotate(message, location, void 0, type));
		else return recordAsyncAnnotation(test$1, annotate(message, location, type, attachment));
	};
	context.onTestFailed = (handler, timeout) => {
		test$1.onFailed || (test$1.onFailed = []);
		test$1.onFailed.push(withTimeout(handler, timeout ?? runner$1.config.hookTimeout, true, /* @__PURE__ */ new Error("STACK_TRACE_ERROR"), (_, error) => abortController.abort(error)));
	};
	context.onTestFinished = (handler, timeout) => {
		test$1.onFinished || (test$1.onFinished = []);
		test$1.onFinished.push(withTimeout(handler, timeout ?? runner$1.config.hookTimeout, true, /* @__PURE__ */ new Error("STACK_TRACE_ERROR"), (_, error) => abortController.abort(error)));
	};
	return ((_runner$extendTaskCon = runner$1.extendTaskContext) === null || _runner$extendTaskCon === void 0 ? void 0 : _runner$extendTaskCon.call(runner$1, context)) || context;
}
function makeTimeoutError(isHook, timeout, stackTraceError) {
	const message = `${isHook ? "Hook" : "Test"} timed out in ${timeout}ms.\nIf this is a long-running ${isHook ? "hook" : "test"}, pass a timeout value as the last argument or configure it globally with "${isHook ? "hookTimeout" : "testTimeout"}".`;
	const error = new Error(message);
	if (stackTraceError === null || stackTraceError === void 0 ? void 0 : stackTraceError.stack) error.stack = stackTraceError.stack.replace(error.message, stackTraceError.message);
	return error;
}
const fileContexts = /* @__PURE__ */ new WeakMap();
function getFileContext(file) {
	const context = fileContexts.get(file);
	if (!context) throw new Error(`Cannot find file context for ${file.name}`);
	return context;
}
const table = [];
for (let i = 65; i < 91; i++) table.push(String.fromCharCode(i));
for (let i = 97; i < 123; i++) table.push(String.fromCharCode(i));
for (let i = 0; i < 10; i++) table.push(i.toString(10));
function encodeUint8Array(bytes) {
	let base64 = "";
	const len = bytes.byteLength;
	for (let i = 0; i < len; i += 3) if (len === i + 1) {
		const a = (bytes[i] & 252) >> 2;
		const b = (bytes[i] & 3) << 4;
		base64 += table[a];
		base64 += table[b];
		base64 += "==";
	} else if (len === i + 2) {
		const a = (bytes[i] & 252) >> 2;
		const b = (bytes[i] & 3) << 4 | (bytes[i + 1] & 240) >> 4;
		const c = (bytes[i + 1] & 15) << 2;
		base64 += table[a];
		base64 += table[b];
		base64 += table[c];
		base64 += "=";
	} else {
		const a = (bytes[i] & 252) >> 2;
		const b = (bytes[i] & 3) << 4 | (bytes[i + 1] & 240) >> 4;
		const c = (bytes[i + 1] & 15) << 2 | (bytes[i + 2] & 192) >> 6;
		const d = bytes[i + 2] & 63;
		base64 += table[a];
		base64 += table[b];
		base64 += table[c];
		base64 += table[d];
	}
	return base64;
}
function recordAsyncAnnotation(test$1, promise) {
	promise = promise.finally(() => {
		if (!test$1.promises) return;
		const index = test$1.promises.indexOf(promise);
		if (index !== -1) test$1.promises.splice(index, 1);
	});
	if (!test$1.promises) test$1.promises = [];
	test$1.promises.push(promise);
	return promise;
}
function getDefaultHookTimeout() {
	return getRunner().config.hookTimeout;
}
const CLEANUP_TIMEOUT_KEY = Symbol.for("VITEST_CLEANUP_TIMEOUT");
const CLEANUP_STACK_TRACE_KEY = Symbol.for("VITEST_CLEANUP_STACK_TRACE");
/**
* Registers a callback function to be executed when a test fails within the current suite.
* This function allows for custom actions to be performed in response to test failures, such as logging, cleanup, or additional diagnostics.
*
* **Note:** The `onTestFailed` hooks are running in reverse order of their registration. You can configure this by changing the `sequence.hooks` option in the config file.
*
* @param {Function} fn - The callback function to be executed upon a test failure. The function receives the test result (including errors).
* @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
* @throws {Error} Throws an error if the function is not called within a test.
* @returns {void}
* @example
* ```ts
* // Example of using onTestFailed to log failure details
* onTestFailed(({ errors }) => {
*   console.log(`Test failed: ${test.name}`, errors);
* });
* ```
*/
const onTestFailed = createTestHook("onTestFailed", (test$1, handler, timeout) => {
	test$1.onFailed || (test$1.onFailed = []);
	test$1.onFailed.push(withTimeout(handler, timeout ?? getDefaultHookTimeout(), true, /* @__PURE__ */ new Error("STACK_TRACE_ERROR"), abortIfTimeout));
});
/**
* Registers a callback function to be executed when the current test finishes, regardless of the outcome (pass or fail).
* This function is ideal for performing actions that should occur after every test execution, such as cleanup, logging, or resetting shared resources.
*
* This hook is useful if you have access to a resource in the test itself and you want to clean it up after the test finishes. It is a more compact way to clean up resources than using the combination of `beforeEach` and `afterEach`.
*
* **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.
*
* **Note:** The `onTestFinished` hook is not called if the test is canceled with a dynamic `ctx.skip()` call.
*
* @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.
* @param {number} [timeout] - Optional timeout in milliseconds for the hook. If not provided, the default hook timeout from the runner's configuration is used.
* @throws {Error} Throws an error if the function is not called within a test.
* @returns {void}
* @example
* ```ts
* // Example of using onTestFinished for cleanup
* const db = await connectToDatabase();
* onTestFinished(async () => {
*   await db.disconnect();
* });
* ```
*/
const onTestFinished = createTestHook("onTestFinished", (test$1, handler, timeout) => {
	test$1.onFinished || (test$1.onFinished = []);
	test$1.onFinished.push(withTimeout(handler, timeout ?? getDefaultHookTimeout(), true, /* @__PURE__ */ new Error("STACK_TRACE_ERROR"), abortIfTimeout));
});
function createTestHook(name, handler) {
	return (fn, timeout) => {
		assertTypes(fn, `"${name}" callback`, ["function"]);
		const current = getCurrentTest();
		if (!current) throw new Error(`Hook ${name}() can only be called inside a test`);
		return handler(current, fn, timeout);
	};
}

//#endregion
export { createChainable, createTaskCollector, getCurrentSuite, getCurrentTest, getHooks, getNames, getTestName, setFn, setHooks, suite };