@vitest/runner 4.0.0-beta.1 → 4.0.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-hooks.js +368 -371
- package/dist/index.d.ts +5 -5
- package/dist/index.js +1 -1
- package/dist/{tasks.d-ZIXcbWf9.d.ts → tasks.d-B1vSIWO6.d.ts} +27 -43
- package/dist/types.d.ts +12 -12
- package/dist/utils.d.ts +5 -4
- package/dist/utils.js +2 -2
- package/package.json +2 -2
package/dist/chunk-hooks.js
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
import { isObject, createDefer, toArray, isNegativeNaN, format, objectAttr, objDisplay, getSafeTimers, shuffle, assertTypes } from '@vitest/utils';
|
2
|
-
import { parseSingleStack } from '@vitest/utils/source-map';
|
3
2
|
import { processError } from '@vitest/utils/error';
|
4
3
|
import { stripLiteral } from 'strip-literal';
|
4
|
+
import { parseSingleStack } from '@vitest/utils/source-map';
|
5
5
|
import { relative } from 'pathe';
|
6
6
|
|
7
7
|
class PendingError extends Error {
|
@@ -391,6 +391,309 @@ function createChainable(keys, fn) {
|
|
391
391
|
return chain;
|
392
392
|
}
|
393
393
|
|
394
|
+
/**
|
395
|
+
* If any tasks been marked as `only`, mark all other tasks as `skip`.
|
396
|
+
*/
|
397
|
+
function interpretTaskModes(file, namePattern, testLocations, onlyMode, parentIsOnly, allowOnly) {
|
398
|
+
const matchedLocations = [];
|
399
|
+
const traverseSuite = (suite, parentIsOnly, parentMatchedWithLocation) => {
|
400
|
+
const suiteIsOnly = parentIsOnly || suite.mode === "only";
|
401
|
+
suite.tasks.forEach((t) => {
|
402
|
+
// Check if either the parent suite or the task itself are marked as included
|
403
|
+
const includeTask = suiteIsOnly || t.mode === "only";
|
404
|
+
if (onlyMode) {
|
405
|
+
if (t.type === "suite" && (includeTask || someTasksAreOnly(t))) {
|
406
|
+
// Don't skip this suite
|
407
|
+
if (t.mode === "only") {
|
408
|
+
checkAllowOnly(t, allowOnly);
|
409
|
+
t.mode = "run";
|
410
|
+
}
|
411
|
+
} else if (t.mode === "run" && !includeTask) {
|
412
|
+
t.mode = "skip";
|
413
|
+
} else if (t.mode === "only") {
|
414
|
+
checkAllowOnly(t, allowOnly);
|
415
|
+
t.mode = "run";
|
416
|
+
}
|
417
|
+
}
|
418
|
+
let hasLocationMatch = parentMatchedWithLocation;
|
419
|
+
// Match test location against provided locations, only run if present
|
420
|
+
// in `testLocations`. Note: if `includeTaskLocations` is not enabled,
|
421
|
+
// all test will be skipped.
|
422
|
+
if (testLocations !== undefined && testLocations.length !== 0) {
|
423
|
+
if (t.location && (testLocations === null || testLocations === void 0 ? void 0 : testLocations.includes(t.location.line))) {
|
424
|
+
t.mode = "run";
|
425
|
+
matchedLocations.push(t.location.line);
|
426
|
+
hasLocationMatch = true;
|
427
|
+
} else if (parentMatchedWithLocation) {
|
428
|
+
t.mode = "run";
|
429
|
+
} else if (t.type === "test") {
|
430
|
+
t.mode = "skip";
|
431
|
+
}
|
432
|
+
}
|
433
|
+
if (t.type === "test") {
|
434
|
+
if (namePattern && !getTaskFullName(t).match(namePattern)) {
|
435
|
+
t.mode = "skip";
|
436
|
+
}
|
437
|
+
} else if (t.type === "suite") {
|
438
|
+
if (t.mode === "skip") {
|
439
|
+
skipAllTasks(t);
|
440
|
+
} else if (t.mode === "todo") {
|
441
|
+
todoAllTasks(t);
|
442
|
+
} else {
|
443
|
+
traverseSuite(t, includeTask, hasLocationMatch);
|
444
|
+
}
|
445
|
+
}
|
446
|
+
});
|
447
|
+
// if all subtasks are skipped, mark as skip
|
448
|
+
if (suite.mode === "run" || suite.mode === "queued") {
|
449
|
+
if (suite.tasks.length && suite.tasks.every((i) => i.mode !== "run" && i.mode !== "queued")) {
|
450
|
+
suite.mode = "skip";
|
451
|
+
}
|
452
|
+
}
|
453
|
+
};
|
454
|
+
traverseSuite(file, parentIsOnly, false);
|
455
|
+
const nonMatching = testLocations === null || testLocations === void 0 ? void 0 : testLocations.filter((loc) => !matchedLocations.includes(loc));
|
456
|
+
if (nonMatching && nonMatching.length !== 0) {
|
457
|
+
const message = nonMatching.length === 1 ? `line ${nonMatching[0]}` : `lines ${nonMatching.join(", ")}`;
|
458
|
+
if (file.result === undefined) {
|
459
|
+
file.result = {
|
460
|
+
state: "fail",
|
461
|
+
errors: []
|
462
|
+
};
|
463
|
+
}
|
464
|
+
if (file.result.errors === undefined) {
|
465
|
+
file.result.errors = [];
|
466
|
+
}
|
467
|
+
file.result.errors.push(processError(new Error(`No test found in ${file.name} in ${message}`)));
|
468
|
+
}
|
469
|
+
}
|
470
|
+
function getTaskFullName(task) {
|
471
|
+
return `${task.suite ? `${getTaskFullName(task.suite)} ` : ""}${task.name}`;
|
472
|
+
}
|
473
|
+
function someTasksAreOnly(suite) {
|
474
|
+
return suite.tasks.some((t) => t.mode === "only" || t.type === "suite" && someTasksAreOnly(t));
|
475
|
+
}
|
476
|
+
function skipAllTasks(suite) {
|
477
|
+
suite.tasks.forEach((t) => {
|
478
|
+
if (t.mode === "run" || t.mode === "queued") {
|
479
|
+
t.mode = "skip";
|
480
|
+
if (t.type === "suite") {
|
481
|
+
skipAllTasks(t);
|
482
|
+
}
|
483
|
+
}
|
484
|
+
});
|
485
|
+
}
|
486
|
+
function todoAllTasks(suite) {
|
487
|
+
suite.tasks.forEach((t) => {
|
488
|
+
if (t.mode === "run" || t.mode === "queued") {
|
489
|
+
t.mode = "todo";
|
490
|
+
if (t.type === "suite") {
|
491
|
+
todoAllTasks(t);
|
492
|
+
}
|
493
|
+
}
|
494
|
+
});
|
495
|
+
}
|
496
|
+
function checkAllowOnly(task, allowOnly) {
|
497
|
+
if (allowOnly) {
|
498
|
+
return;
|
499
|
+
}
|
500
|
+
const error = processError(new Error("[Vitest] Unexpected .only modifier. Remove it or pass --allowOnly argument to bypass this error"));
|
501
|
+
task.result = {
|
502
|
+
state: "fail",
|
503
|
+
errors: [error]
|
504
|
+
};
|
505
|
+
}
|
506
|
+
function generateHash(str) {
|
507
|
+
let hash = 0;
|
508
|
+
if (str.length === 0) {
|
509
|
+
return `${hash}`;
|
510
|
+
}
|
511
|
+
for (let i = 0; i < str.length; i++) {
|
512
|
+
const char = str.charCodeAt(i);
|
513
|
+
hash = (hash << 5) - hash + char;
|
514
|
+
hash = hash & hash;
|
515
|
+
}
|
516
|
+
return `${hash}`;
|
517
|
+
}
|
518
|
+
function calculateSuiteHash(parent) {
|
519
|
+
parent.tasks.forEach((t, idx) => {
|
520
|
+
t.id = `${parent.id}_${idx}`;
|
521
|
+
if (t.type === "suite") {
|
522
|
+
calculateSuiteHash(t);
|
523
|
+
}
|
524
|
+
});
|
525
|
+
}
|
526
|
+
function createFileTask(filepath, root, projectName, pool) {
|
527
|
+
const path = relative(root, filepath);
|
528
|
+
const file = {
|
529
|
+
id: generateFileHash(path, projectName),
|
530
|
+
name: path,
|
531
|
+
type: "suite",
|
532
|
+
mode: "queued",
|
533
|
+
filepath,
|
534
|
+
tasks: [],
|
535
|
+
meta: Object.create(null),
|
536
|
+
projectName,
|
537
|
+
file: undefined,
|
538
|
+
pool
|
539
|
+
};
|
540
|
+
file.file = file;
|
541
|
+
setFileContext(file, Object.create(null));
|
542
|
+
return file;
|
543
|
+
}
|
544
|
+
/**
|
545
|
+
* Generate a unique ID for a file based on its path and project name
|
546
|
+
* @param file File relative to the root of the project to keep ID the same between different machines
|
547
|
+
* @param projectName The name of the test project
|
548
|
+
*/
|
549
|
+
function generateFileHash(file, projectName) {
|
550
|
+
return generateHash(`${file}${projectName || ""}`);
|
551
|
+
}
|
552
|
+
function findTestFileStackTrace(testFilePath, error) {
|
553
|
+
// first line is the error message
|
554
|
+
const lines = error.split("\n").slice(1);
|
555
|
+
for (const line of lines) {
|
556
|
+
const stack = parseSingleStack(line);
|
557
|
+
if (stack && stack.file === testFilePath) {
|
558
|
+
return stack;
|
559
|
+
}
|
560
|
+
}
|
561
|
+
}
|
562
|
+
|
563
|
+
/**
|
564
|
+
* Return a function for running multiple async operations with limited concurrency.
|
565
|
+
*/
|
566
|
+
function limitConcurrency(concurrency = Infinity) {
|
567
|
+
// The number of currently active + pending tasks.
|
568
|
+
let count = 0;
|
569
|
+
// The head and tail of the pending task queue, built using a singly linked list.
|
570
|
+
// Both head and tail are initially undefined, signifying an empty queue.
|
571
|
+
// They both become undefined again whenever there are no pending tasks.
|
572
|
+
let head;
|
573
|
+
let tail;
|
574
|
+
// A bookkeeping function executed whenever a task has been run to completion.
|
575
|
+
const finish = () => {
|
576
|
+
count--;
|
577
|
+
// Check if there are further pending tasks in the queue.
|
578
|
+
if (head) {
|
579
|
+
// Allow the next pending task to run and pop it from the queue.
|
580
|
+
head[0]();
|
581
|
+
head = head[1];
|
582
|
+
// The head may now be undefined if there are no further pending tasks.
|
583
|
+
// In that case, set tail to undefined as well.
|
584
|
+
tail = head && tail;
|
585
|
+
}
|
586
|
+
};
|
587
|
+
return (func, ...args) => {
|
588
|
+
// Create a promise chain that:
|
589
|
+
// 1. Waits for its turn in the task queue (if necessary).
|
590
|
+
// 2. Runs the task.
|
591
|
+
// 3. Allows the next pending task (if any) to run.
|
592
|
+
return new Promise((resolve) => {
|
593
|
+
if (count++ < concurrency) {
|
594
|
+
// No need to queue if fewer than maxConcurrency tasks are running.
|
595
|
+
resolve();
|
596
|
+
} else if (tail) {
|
597
|
+
// There are pending tasks, so append to the queue.
|
598
|
+
tail = tail[1] = [resolve];
|
599
|
+
} else {
|
600
|
+
// No other pending tasks, initialize the queue with a new tail and head.
|
601
|
+
head = tail = [resolve];
|
602
|
+
}
|
603
|
+
}).then(() => {
|
604
|
+
// Running func here ensures that even a non-thenable result or an
|
605
|
+
// immediately thrown error gets wrapped into a Promise.
|
606
|
+
return func(...args);
|
607
|
+
}).finally(finish);
|
608
|
+
};
|
609
|
+
}
|
610
|
+
|
611
|
+
/**
|
612
|
+
* Partition in tasks groups by consecutive concurrent
|
613
|
+
*/
|
614
|
+
function partitionSuiteChildren(suite) {
|
615
|
+
let tasksGroup = [];
|
616
|
+
const tasksGroups = [];
|
617
|
+
for (const c of suite.tasks) {
|
618
|
+
if (tasksGroup.length === 0 || c.concurrent === tasksGroup[0].concurrent) {
|
619
|
+
tasksGroup.push(c);
|
620
|
+
} else {
|
621
|
+
tasksGroups.push(tasksGroup);
|
622
|
+
tasksGroup = [c];
|
623
|
+
}
|
624
|
+
}
|
625
|
+
if (tasksGroup.length > 0) {
|
626
|
+
tasksGroups.push(tasksGroup);
|
627
|
+
}
|
628
|
+
return tasksGroups;
|
629
|
+
}
|
630
|
+
|
631
|
+
/**
|
632
|
+
* @deprecated use `isTestCase` instead
|
633
|
+
*/
|
634
|
+
function isAtomTest(s) {
|
635
|
+
return isTestCase(s);
|
636
|
+
}
|
637
|
+
function isTestCase(s) {
|
638
|
+
return s.type === "test";
|
639
|
+
}
|
640
|
+
function getTests(suite) {
|
641
|
+
const tests = [];
|
642
|
+
const arraySuites = toArray(suite);
|
643
|
+
for (const s of arraySuites) {
|
644
|
+
if (isTestCase(s)) {
|
645
|
+
tests.push(s);
|
646
|
+
} else {
|
647
|
+
for (const task of s.tasks) {
|
648
|
+
if (isTestCase(task)) {
|
649
|
+
tests.push(task);
|
650
|
+
} else {
|
651
|
+
const taskTests = getTests(task);
|
652
|
+
for (const test of taskTests) {
|
653
|
+
tests.push(test);
|
654
|
+
}
|
655
|
+
}
|
656
|
+
}
|
657
|
+
}
|
658
|
+
}
|
659
|
+
return tests;
|
660
|
+
}
|
661
|
+
function getTasks(tasks = []) {
|
662
|
+
return toArray(tasks).flatMap((s) => isTestCase(s) ? [s] : [s, ...getTasks(s.tasks)]);
|
663
|
+
}
|
664
|
+
function getSuites(suite) {
|
665
|
+
return toArray(suite).flatMap((s) => s.type === "suite" ? [s, ...getSuites(s.tasks)] : []);
|
666
|
+
}
|
667
|
+
function hasTests(suite) {
|
668
|
+
return toArray(suite).some((s) => s.tasks.some((c) => isTestCase(c) || hasTests(c)));
|
669
|
+
}
|
670
|
+
function hasFailed(suite) {
|
671
|
+
return toArray(suite).some((s) => {
|
672
|
+
var _s$result;
|
673
|
+
return ((_s$result = s.result) === null || _s$result === void 0 ? void 0 : _s$result.state) === "fail" || s.type === "suite" && hasFailed(s.tasks);
|
674
|
+
});
|
675
|
+
}
|
676
|
+
function getNames(task) {
|
677
|
+
const names = [task.name];
|
678
|
+
let current = task;
|
679
|
+
while (current === null || current === void 0 ? void 0 : current.suite) {
|
680
|
+
current = current.suite;
|
681
|
+
if (current === null || current === void 0 ? void 0 : current.name) {
|
682
|
+
names.unshift(current.name);
|
683
|
+
}
|
684
|
+
}
|
685
|
+
if (current !== task.file) {
|
686
|
+
names.unshift(task.file.name);
|
687
|
+
}
|
688
|
+
return names;
|
689
|
+
}
|
690
|
+
function getFullName(task, separator = " > ") {
|
691
|
+
return getNames(task).join(separator);
|
692
|
+
}
|
693
|
+
function getTestName(task, separator = " > ") {
|
694
|
+
return getNames(task).slice(1).join(separator);
|
695
|
+
}
|
696
|
+
|
394
697
|
/**
|
395
698
|
* Creates a suite of tests, allowing for grouping and hierarchical organization of tests.
|
396
699
|
* Suites can contain both tests and other suites, enabling complex test structures.
|
@@ -530,9 +833,6 @@ function getDefaultSuite() {
|
|
530
833
|
assert(defaultSuite, "the default suite");
|
531
834
|
return defaultSuite;
|
532
835
|
}
|
533
|
-
function getTestFilepath() {
|
534
|
-
return currentTestFilepath;
|
535
|
-
}
|
536
836
|
function getRunner() {
|
537
837
|
assert(runner, "the runner");
|
538
838
|
return runner;
|
@@ -642,9 +942,12 @@ function createSuiteCollector(name, factory = () => {}, mode, each, suiteOptions
|
|
642
942
|
}
|
643
943
|
if (runner.config.includeTaskLocation) {
|
644
944
|
const error = stackTraceError.stack;
|
645
|
-
const stack = findTestFileStackTrace(error);
|
945
|
+
const stack = findTestFileStackTrace(currentTestFilepath, error);
|
646
946
|
if (stack) {
|
647
|
-
task.location =
|
947
|
+
task.location = {
|
948
|
+
line: stack.line,
|
949
|
+
column: stack.column
|
950
|
+
};
|
648
951
|
}
|
649
952
|
}
|
650
953
|
tasks.push(task);
|
@@ -715,9 +1018,12 @@ function createSuiteCollector(name, factory = () => {}, mode, each, suiteOptions
|
|
715
1018
|
Error.stackTraceLimit = 15;
|
716
1019
|
const error = new Error("stacktrace").stack;
|
717
1020
|
Error.stackTraceLimit = limit;
|
718
|
-
const stack = findTestFileStackTrace(error);
|
1021
|
+
const stack = findTestFileStackTrace(currentTestFilepath, error);
|
719
1022
|
if (stack) {
|
720
|
-
suite.location =
|
1023
|
+
suite.location = {
|
1024
|
+
line: stack.line,
|
1025
|
+
column: stack.column
|
1026
|
+
};
|
721
1027
|
}
|
722
1028
|
}
|
723
1029
|
setHooks(suite, createSuiteHooks());
|
@@ -898,6 +1204,7 @@ function createTaskCollector(fn, context) {
|
|
898
1204
|
const _context = mergeContextFixtures(fixtures, context || {}, runner);
|
899
1205
|
const originalWrapper = fn;
|
900
1206
|
return createTest(function(name, optionsOrFn, optionsOrTest) {
|
1207
|
+
var _collector$options;
|
901
1208
|
const collector = getCurrentSuite();
|
902
1209
|
const scopedFixtures = collector.fixtures();
|
903
1210
|
const context = { ...this };
|
@@ -905,7 +1212,7 @@ function createTaskCollector(fn, context) {
|
|
905
1212
|
context.fixtures = mergeScopedFixtures(context.fixtures || [], scopedFixtures);
|
906
1213
|
}
|
907
1214
|
const { handler, options } = parseArguments(optionsOrFn, optionsOrTest);
|
908
|
-
const timeout = options.timeout ?? (runner === null || runner === void 0 ? void 0 : runner.config.testTimeout);
|
1215
|
+
const timeout = options.timeout ?? ((_collector$options = collector.options) === null || _collector$options === void 0 ? void 0 : _collector$options.timeout) ?? (runner === null || runner === void 0 ? void 0 : runner.config.testTimeout);
|
909
1216
|
originalWrapper.call(context, formatName(name), handler, timeout);
|
910
1217
|
}, _context);
|
911
1218
|
};
|
@@ -917,234 +1224,61 @@ function createTaskCollector(fn, context) {
|
|
917
1224
|
"todo",
|
918
1225
|
"fails"
|
919
1226
|
], taskFn);
|
920
|
-
if (context) {
|
921
|
-
_test.mergeContext(context);
|
922
|
-
}
|
923
|
-
return _test;
|
924
|
-
}
|
925
|
-
function createTest(fn, context) {
|
926
|
-
return createTaskCollector(fn, context);
|
927
|
-
}
|
928
|
-
function formatName(name) {
|
929
|
-
return typeof name === "string" ? name : typeof name === "function" ? name.name || "<anonymous>" : String(name);
|
930
|
-
}
|
931
|
-
function formatTitle(template, items, idx) {
|
932
|
-
if (template.includes("%#") || template.includes("%$")) {
|
933
|
-
// '%#' match index of the test case
|
934
|
-
template = template.replace(/%%/g, "__vitest_escaped_%__").replace(/%#/g, `${idx}`).replace(/%\$/g, `${idx + 1}`).replace(/__vitest_escaped_%__/g, "%%");
|
935
|
-
}
|
936
|
-
const count = template.split("%").length - 1;
|
937
|
-
if (template.includes("%f")) {
|
938
|
-
const placeholders = template.match(/%f/g) || [];
|
939
|
-
placeholders.forEach((_, i) => {
|
940
|
-
if (isNegativeNaN(items[i]) || Object.is(items[i], -0)) {
|
941
|
-
// Replace the i-th occurrence of '%f' with '-%f'
|
942
|
-
let occurrence = 0;
|
943
|
-
template = template.replace(/%f/g, (match) => {
|
944
|
-
occurrence++;
|
945
|
-
return occurrence === i + 1 ? "-%f" : match;
|
946
|
-
});
|
947
|
-
}
|
948
|
-
});
|
949
|
-
}
|
950
|
-
let formatted = format(template, ...items.slice(0, count));
|
951
|
-
const isObjectItem = isObject(items[0]);
|
952
|
-
formatted = formatted.replace(/\$([$\w.]+)/g, (_, key) => {
|
953
|
-
var _runner$config;
|
954
|
-
const isArrayKey = /^\d+$/.test(key);
|
955
|
-
if (!isObjectItem && !isArrayKey) {
|
956
|
-
return `$${key}`;
|
957
|
-
}
|
958
|
-
const arrayElement = isArrayKey ? objectAttr(items, key) : undefined;
|
959
|
-
const value = isObjectItem ? objectAttr(items[0], key, arrayElement) : arrayElement;
|
960
|
-
return objDisplay(value, { 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 });
|
961
|
-
});
|
962
|
-
return formatted;
|
963
|
-
}
|
964
|
-
function formatTemplateString(cases, args) {
|
965
|
-
const header = cases.join("").trim().replace(/ /g, "").split("\n").map((i) => i.split("|"))[0];
|
966
|
-
const res = [];
|
967
|
-
for (let i = 0; i < Math.floor(args.length / header.length); i++) {
|
968
|
-
const oneCase = {};
|
969
|
-
for (let j = 0; j < header.length; j++) {
|
970
|
-
oneCase[header[j]] = args[i * header.length + j];
|
971
|
-
}
|
972
|
-
res.push(oneCase);
|
973
|
-
}
|
974
|
-
return res;
|
975
|
-
}
|
976
|
-
function findTestFileStackTrace(error) {
|
977
|
-
const testFilePath = getTestFilepath();
|
978
|
-
// first line is the error message
|
979
|
-
const lines = error.split("\n").slice(1);
|
980
|
-
for (const line of lines) {
|
981
|
-
const stack = parseSingleStack(line);
|
982
|
-
if (stack && stack.file === testFilePath) {
|
983
|
-
return {
|
984
|
-
line: stack.line,
|
985
|
-
column: stack.column
|
986
|
-
};
|
987
|
-
}
|
988
|
-
}
|
989
|
-
}
|
990
|
-
|
991
|
-
/**
|
992
|
-
* If any tasks been marked as `only`, mark all other tasks as `skip`.
|
993
|
-
*/
|
994
|
-
function interpretTaskModes(file, namePattern, testLocations, onlyMode, parentIsOnly, allowOnly) {
|
995
|
-
const matchedLocations = [];
|
996
|
-
const traverseSuite = (suite, parentIsOnly, parentMatchedWithLocation) => {
|
997
|
-
const suiteIsOnly = parentIsOnly || suite.mode === "only";
|
998
|
-
suite.tasks.forEach((t) => {
|
999
|
-
// Check if either the parent suite or the task itself are marked as included
|
1000
|
-
const includeTask = suiteIsOnly || t.mode === "only";
|
1001
|
-
if (onlyMode) {
|
1002
|
-
if (t.type === "suite" && (includeTask || someTasksAreOnly(t))) {
|
1003
|
-
// Don't skip this suite
|
1004
|
-
if (t.mode === "only") {
|
1005
|
-
checkAllowOnly(t, allowOnly);
|
1006
|
-
t.mode = "run";
|
1007
|
-
}
|
1008
|
-
} else if (t.mode === "run" && !includeTask) {
|
1009
|
-
t.mode = "skip";
|
1010
|
-
} else if (t.mode === "only") {
|
1011
|
-
checkAllowOnly(t, allowOnly);
|
1012
|
-
t.mode = "run";
|
1013
|
-
}
|
1014
|
-
}
|
1015
|
-
let hasLocationMatch = parentMatchedWithLocation;
|
1016
|
-
// Match test location against provided locations, only run if present
|
1017
|
-
// in `testLocations`. Note: if `includeTaskLocations` is not enabled,
|
1018
|
-
// all test will be skipped.
|
1019
|
-
if (testLocations !== undefined && testLocations.length !== 0) {
|
1020
|
-
if (t.location && (testLocations === null || testLocations === void 0 ? void 0 : testLocations.includes(t.location.line))) {
|
1021
|
-
t.mode = "run";
|
1022
|
-
matchedLocations.push(t.location.line);
|
1023
|
-
hasLocationMatch = true;
|
1024
|
-
} else if (parentMatchedWithLocation) {
|
1025
|
-
t.mode = "run";
|
1026
|
-
} else if (t.type === "test") {
|
1027
|
-
t.mode = "skip";
|
1028
|
-
}
|
1029
|
-
}
|
1030
|
-
if (t.type === "test") {
|
1031
|
-
if (namePattern && !getTaskFullName(t).match(namePattern)) {
|
1032
|
-
t.mode = "skip";
|
1033
|
-
}
|
1034
|
-
} else if (t.type === "suite") {
|
1035
|
-
if (t.mode === "skip") {
|
1036
|
-
skipAllTasks(t);
|
1037
|
-
} else if (t.mode === "todo") {
|
1038
|
-
todoAllTasks(t);
|
1039
|
-
} else {
|
1040
|
-
traverseSuite(t, includeTask, hasLocationMatch);
|
1041
|
-
}
|
1042
|
-
}
|
1043
|
-
});
|
1044
|
-
// if all subtasks are skipped, mark as skip
|
1045
|
-
if (suite.mode === "run" || suite.mode === "queued") {
|
1046
|
-
if (suite.tasks.length && suite.tasks.every((i) => i.mode !== "run" && i.mode !== "queued")) {
|
1047
|
-
suite.mode = "skip";
|
1048
|
-
}
|
1049
|
-
}
|
1050
|
-
};
|
1051
|
-
traverseSuite(file, parentIsOnly, false);
|
1052
|
-
const nonMatching = testLocations === null || testLocations === void 0 ? void 0 : testLocations.filter((loc) => !matchedLocations.includes(loc));
|
1053
|
-
if (nonMatching && nonMatching.length !== 0) {
|
1054
|
-
const message = nonMatching.length === 1 ? `line ${nonMatching[0]}` : `lines ${nonMatching.join(", ")}`;
|
1055
|
-
if (file.result === undefined) {
|
1056
|
-
file.result = {
|
1057
|
-
state: "fail",
|
1058
|
-
errors: []
|
1059
|
-
};
|
1060
|
-
}
|
1061
|
-
if (file.result.errors === undefined) {
|
1062
|
-
file.result.errors = [];
|
1063
|
-
}
|
1064
|
-
file.result.errors.push(processError(new Error(`No test found in ${file.name} in ${message}`)));
|
1227
|
+
if (context) {
|
1228
|
+
_test.mergeContext(context);
|
1065
1229
|
}
|
1230
|
+
return _test;
|
1066
1231
|
}
|
1067
|
-
function
|
1068
|
-
return
|
1232
|
+
function createTest(fn, context) {
|
1233
|
+
return createTaskCollector(fn, context);
|
1069
1234
|
}
|
1070
|
-
function
|
1071
|
-
return
|
1235
|
+
function formatName(name) {
|
1236
|
+
return typeof name === "string" ? name : typeof name === "function" ? name.name || "<anonymous>" : String(name);
|
1072
1237
|
}
|
1073
|
-
function
|
1074
|
-
|
1075
|
-
|
1076
|
-
|
1077
|
-
|
1078
|
-
|
1238
|
+
function formatTitle(template, items, idx) {
|
1239
|
+
if (template.includes("%#") || template.includes("%$")) {
|
1240
|
+
// '%#' match index of the test case
|
1241
|
+
template = template.replace(/%%/g, "__vitest_escaped_%__").replace(/%#/g, `${idx}`).replace(/%\$/g, `${idx + 1}`).replace(/__vitest_escaped_%__/g, "%%");
|
1242
|
+
}
|
1243
|
+
const count = template.split("%").length - 1;
|
1244
|
+
if (template.includes("%f")) {
|
1245
|
+
const placeholders = template.match(/%f/g) || [];
|
1246
|
+
placeholders.forEach((_, i) => {
|
1247
|
+
if (isNegativeNaN(items[i]) || Object.is(items[i], -0)) {
|
1248
|
+
// Replace the i-th occurrence of '%f' with '-%f'
|
1249
|
+
let occurrence = 0;
|
1250
|
+
template = template.replace(/%f/g, (match) => {
|
1251
|
+
occurrence++;
|
1252
|
+
return occurrence === i + 1 ? "-%f" : match;
|
1253
|
+
});
|
1079
1254
|
}
|
1255
|
+
});
|
1256
|
+
}
|
1257
|
+
let formatted = format(template, ...items.slice(0, count));
|
1258
|
+
const isObjectItem = isObject(items[0]);
|
1259
|
+
formatted = formatted.replace(/\$([$\w.]+)/g, (_, key) => {
|
1260
|
+
var _runner$config;
|
1261
|
+
const isArrayKey = /^\d+$/.test(key);
|
1262
|
+
if (!isObjectItem && !isArrayKey) {
|
1263
|
+
return `$${key}`;
|
1080
1264
|
}
|
1265
|
+
const arrayElement = isArrayKey ? objectAttr(items, key) : undefined;
|
1266
|
+
const value = isObjectItem ? objectAttr(items[0], key, arrayElement) : arrayElement;
|
1267
|
+
return objDisplay(value, { 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 });
|
1081
1268
|
});
|
1269
|
+
return formatted;
|
1082
1270
|
}
|
1083
|
-
function
|
1084
|
-
|
1085
|
-
|
1086
|
-
|
1087
|
-
|
1088
|
-
|
1089
|
-
|
1271
|
+
function formatTemplateString(cases, args) {
|
1272
|
+
const header = cases.join("").trim().replace(/ /g, "").split("\n").map((i) => i.split("|"))[0];
|
1273
|
+
const res = [];
|
1274
|
+
for (let i = 0; i < Math.floor(args.length / header.length); i++) {
|
1275
|
+
const oneCase = {};
|
1276
|
+
for (let j = 0; j < header.length; j++) {
|
1277
|
+
oneCase[header[j]] = args[i * header.length + j];
|
1090
1278
|
}
|
1091
|
-
|
1092
|
-
}
|
1093
|
-
function checkAllowOnly(task, allowOnly) {
|
1094
|
-
if (allowOnly) {
|
1095
|
-
return;
|
1096
|
-
}
|
1097
|
-
const error = processError(new Error("[Vitest] Unexpected .only modifier. Remove it or pass --allowOnly argument to bypass this error"));
|
1098
|
-
task.result = {
|
1099
|
-
state: "fail",
|
1100
|
-
errors: [error]
|
1101
|
-
};
|
1102
|
-
}
|
1103
|
-
function generateHash(str) {
|
1104
|
-
let hash = 0;
|
1105
|
-
if (str.length === 0) {
|
1106
|
-
return `${hash}`;
|
1107
|
-
}
|
1108
|
-
for (let i = 0; i < str.length; i++) {
|
1109
|
-
const char = str.charCodeAt(i);
|
1110
|
-
hash = (hash << 5) - hash + char;
|
1111
|
-
hash = hash & hash;
|
1279
|
+
res.push(oneCase);
|
1112
1280
|
}
|
1113
|
-
return
|
1114
|
-
}
|
1115
|
-
function calculateSuiteHash(parent) {
|
1116
|
-
parent.tasks.forEach((t, idx) => {
|
1117
|
-
t.id = `${parent.id}_${idx}`;
|
1118
|
-
if (t.type === "suite") {
|
1119
|
-
calculateSuiteHash(t);
|
1120
|
-
}
|
1121
|
-
});
|
1122
|
-
}
|
1123
|
-
function createFileTask(filepath, root, projectName, pool) {
|
1124
|
-
const path = relative(root, filepath);
|
1125
|
-
const file = {
|
1126
|
-
id: generateFileHash(path, projectName),
|
1127
|
-
name: path,
|
1128
|
-
type: "suite",
|
1129
|
-
mode: "queued",
|
1130
|
-
filepath,
|
1131
|
-
tasks: [],
|
1132
|
-
meta: Object.create(null),
|
1133
|
-
projectName,
|
1134
|
-
file: undefined,
|
1135
|
-
pool
|
1136
|
-
};
|
1137
|
-
file.file = file;
|
1138
|
-
setFileContext(file, Object.create(null));
|
1139
|
-
return file;
|
1140
|
-
}
|
1141
|
-
/**
|
1142
|
-
* Generate a unique ID for a file based on its path and project name
|
1143
|
-
* @param file File relative to the root of the project to keep ID the same between different machines
|
1144
|
-
* @param projectName The name of the test project
|
1145
|
-
*/
|
1146
|
-
function generateFileHash(file, projectName) {
|
1147
|
-
return generateHash(`${file}${projectName || ""}`);
|
1281
|
+
return res;
|
1148
1282
|
}
|
1149
1283
|
|
1150
1284
|
const now$2 = globalThis.performance ? globalThis.performance.now.bind(globalThis.performance) : Date.now;
|
@@ -1225,140 +1359,6 @@ function mergeHooks(baseHooks, hooks) {
|
|
1225
1359
|
return baseHooks;
|
1226
1360
|
}
|
1227
1361
|
|
1228
|
-
/**
|
1229
|
-
* Return a function for running multiple async operations with limited concurrency.
|
1230
|
-
*/
|
1231
|
-
function limitConcurrency(concurrency = Infinity) {
|
1232
|
-
// The number of currently active + pending tasks.
|
1233
|
-
let count = 0;
|
1234
|
-
// The head and tail of the pending task queue, built using a singly linked list.
|
1235
|
-
// Both head and tail are initially undefined, signifying an empty queue.
|
1236
|
-
// They both become undefined again whenever there are no pending tasks.
|
1237
|
-
let head;
|
1238
|
-
let tail;
|
1239
|
-
// A bookkeeping function executed whenever a task has been run to completion.
|
1240
|
-
const finish = () => {
|
1241
|
-
count--;
|
1242
|
-
// Check if there are further pending tasks in the queue.
|
1243
|
-
if (head) {
|
1244
|
-
// Allow the next pending task to run and pop it from the queue.
|
1245
|
-
head[0]();
|
1246
|
-
head = head[1];
|
1247
|
-
// The head may now be undefined if there are no further pending tasks.
|
1248
|
-
// In that case, set tail to undefined as well.
|
1249
|
-
tail = head && tail;
|
1250
|
-
}
|
1251
|
-
};
|
1252
|
-
return (func, ...args) => {
|
1253
|
-
// Create a promise chain that:
|
1254
|
-
// 1. Waits for its turn in the task queue (if necessary).
|
1255
|
-
// 2. Runs the task.
|
1256
|
-
// 3. Allows the next pending task (if any) to run.
|
1257
|
-
return new Promise((resolve) => {
|
1258
|
-
if (count++ < concurrency) {
|
1259
|
-
// No need to queue if fewer than maxConcurrency tasks are running.
|
1260
|
-
resolve();
|
1261
|
-
} else if (tail) {
|
1262
|
-
// There are pending tasks, so append to the queue.
|
1263
|
-
tail = tail[1] = [resolve];
|
1264
|
-
} else {
|
1265
|
-
// No other pending tasks, initialize the queue with a new tail and head.
|
1266
|
-
head = tail = [resolve];
|
1267
|
-
}
|
1268
|
-
}).then(() => {
|
1269
|
-
// Running func here ensures that even a non-thenable result or an
|
1270
|
-
// immediately thrown error gets wrapped into a Promise.
|
1271
|
-
return func(...args);
|
1272
|
-
}).finally(finish);
|
1273
|
-
};
|
1274
|
-
}
|
1275
|
-
|
1276
|
-
/**
|
1277
|
-
* Partition in tasks groups by consecutive concurrent
|
1278
|
-
*/
|
1279
|
-
function partitionSuiteChildren(suite) {
|
1280
|
-
let tasksGroup = [];
|
1281
|
-
const tasksGroups = [];
|
1282
|
-
for (const c of suite.tasks) {
|
1283
|
-
if (tasksGroup.length === 0 || c.concurrent === tasksGroup[0].concurrent) {
|
1284
|
-
tasksGroup.push(c);
|
1285
|
-
} else {
|
1286
|
-
tasksGroups.push(tasksGroup);
|
1287
|
-
tasksGroup = [c];
|
1288
|
-
}
|
1289
|
-
}
|
1290
|
-
if (tasksGroup.length > 0) {
|
1291
|
-
tasksGroups.push(tasksGroup);
|
1292
|
-
}
|
1293
|
-
return tasksGroups;
|
1294
|
-
}
|
1295
|
-
|
1296
|
-
/**
|
1297
|
-
* @deprecated use `isTestCase` instead
|
1298
|
-
*/
|
1299
|
-
function isAtomTest(s) {
|
1300
|
-
return isTestCase(s);
|
1301
|
-
}
|
1302
|
-
function isTestCase(s) {
|
1303
|
-
return s.type === "test";
|
1304
|
-
}
|
1305
|
-
function getTests(suite) {
|
1306
|
-
const tests = [];
|
1307
|
-
const arraySuites = toArray(suite);
|
1308
|
-
for (const s of arraySuites) {
|
1309
|
-
if (isTestCase(s)) {
|
1310
|
-
tests.push(s);
|
1311
|
-
} else {
|
1312
|
-
for (const task of s.tasks) {
|
1313
|
-
if (isTestCase(task)) {
|
1314
|
-
tests.push(task);
|
1315
|
-
} else {
|
1316
|
-
const taskTests = getTests(task);
|
1317
|
-
for (const test of taskTests) {
|
1318
|
-
tests.push(test);
|
1319
|
-
}
|
1320
|
-
}
|
1321
|
-
}
|
1322
|
-
}
|
1323
|
-
}
|
1324
|
-
return tests;
|
1325
|
-
}
|
1326
|
-
function getTasks(tasks = []) {
|
1327
|
-
return toArray(tasks).flatMap((s) => isTestCase(s) ? [s] : [s, ...getTasks(s.tasks)]);
|
1328
|
-
}
|
1329
|
-
function getSuites(suite) {
|
1330
|
-
return toArray(suite).flatMap((s) => s.type === "suite" ? [s, ...getSuites(s.tasks)] : []);
|
1331
|
-
}
|
1332
|
-
function hasTests(suite) {
|
1333
|
-
return toArray(suite).some((s) => s.tasks.some((c) => isTestCase(c) || hasTests(c)));
|
1334
|
-
}
|
1335
|
-
function hasFailed(suite) {
|
1336
|
-
return toArray(suite).some((s) => {
|
1337
|
-
var _s$result;
|
1338
|
-
return ((_s$result = s.result) === null || _s$result === void 0 ? void 0 : _s$result.state) === "fail" || s.type === "suite" && hasFailed(s.tasks);
|
1339
|
-
});
|
1340
|
-
}
|
1341
|
-
function getNames(task) {
|
1342
|
-
const names = [task.name];
|
1343
|
-
let current = task;
|
1344
|
-
while (current === null || current === void 0 ? void 0 : current.suite) {
|
1345
|
-
current = current.suite;
|
1346
|
-
if (current === null || current === void 0 ? void 0 : current.name) {
|
1347
|
-
names.unshift(current.name);
|
1348
|
-
}
|
1349
|
-
}
|
1350
|
-
if (current !== task.file) {
|
1351
|
-
names.unshift(task.file.name);
|
1352
|
-
}
|
1353
|
-
return names;
|
1354
|
-
}
|
1355
|
-
function getFullName(task, separator = " > ") {
|
1356
|
-
return getNames(task).join(separator);
|
1357
|
-
}
|
1358
|
-
function getTestName(task, separator = " > ") {
|
1359
|
-
return getNames(task).slice(1).join(separator);
|
1360
|
-
}
|
1361
|
-
|
1362
1362
|
const now$1 = globalThis.performance ? globalThis.performance.now.bind(globalThis.performance) : Date.now;
|
1363
1363
|
const unixNow = Date.now;
|
1364
1364
|
const { clearTimeout, setTimeout } = getSafeTimers();
|
@@ -1759,8 +1759,8 @@ async function runSuite(suite, runner) {
|
|
1759
1759
|
}
|
1760
1760
|
}
|
1761
1761
|
suite.result.duration = now$1() - start;
|
1762
|
-
updateTask("suite-finished", suite, runner);
|
1763
1762
|
await ((_runner$onAfterRunSui = runner.onAfterRunSuite) === null || _runner$onAfterRunSui === void 0 ? void 0 : _runner$onAfterRunSui.call(runner, suite));
|
1763
|
+
updateTask("suite-finished", suite, runner);
|
1764
1764
|
}
|
1765
1765
|
}
|
1766
1766
|
let limitMaxConcurrency;
|
@@ -1974,16 +1974,13 @@ function createTestContext(test, runner) {
|
|
1974
1974
|
if (test.result && test.result.state !== "run") {
|
1975
1975
|
throw new Error(`Cannot annotate tests outside of the test run. The test "${test.name}" finished running with the "${test.result.state}" state already.`);
|
1976
1976
|
}
|
1977
|
+
const stack = findTestFileStackTrace(test.file.filepath, new Error("STACK_TRACE").stack);
|
1977
1978
|
let location;
|
1978
|
-
|
1979
|
-
const index = stack.includes("STACK_TRACE") ? 2 : 1;
|
1980
|
-
const stackLine = stack.split("\n")[index];
|
1981
|
-
const parsed = parseSingleStack(stackLine);
|
1982
|
-
if (parsed) {
|
1979
|
+
if (stack) {
|
1983
1980
|
location = {
|
1984
|
-
file:
|
1985
|
-
line:
|
1986
|
-
column:
|
1981
|
+
file: stack.file,
|
1982
|
+
line: stack.line,
|
1983
|
+
column: stack.column
|
1987
1984
|
};
|
1988
1985
|
}
|
1989
1986
|
if (typeof type === "object") {
|
@@ -2251,4 +2248,4 @@ function createTestHook(name, handler) {
|
|
2251
2248
|
};
|
2252
2249
|
}
|
2253
2250
|
|
2254
|
-
export {
|
2251
|
+
export { interpretTaskModes as A, someTasksAreOnly as B, limitConcurrency as C, partitionSuiteChildren as D, getFullName as E, getNames as F, getSuites as G, getTasks as H, getTestName as I, getTests as J, hasFailed as K, hasTests as L, isAtomTest as M, isTestCase as N, afterAll as a, afterEach as b, beforeAll as c, beforeEach as d, onTestFinished as e, getHooks as f, getFn as g, setHooks as h, startTests as i, createTaskCollector as j, describe as k, getCurrentSuite as l, it as m, suite as n, onTestFailed as o, publicCollect as p, getCurrentTest as q, createChainable as r, setFn as s, test as t, updateTask as u, calculateSuiteHash as v, createFileTask as w, findTestFileStackTrace as x, generateFileHash as y, generateHash as z };
|
package/dist/index.d.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
1
|
-
import { A as AfterAllListener, b as AfterEachListener, B as BeforeAllListener, d as BeforeEachListener, e as TaskHook, O as OnTestFailedHandler, f as OnTestFinishedHandler, a as Test,
|
2
|
-
export {
|
1
|
+
import { A as AfterAllListener, b as AfterEachListener, B as BeforeAllListener, d as BeforeEachListener, e as TaskHook, O as OnTestFailedHandler, f as OnTestFinishedHandler, a as Test, S as Suite, g as SuiteHooks, F as File, h as TaskUpdateEvent, T as Task, i as TestAPI, j as SuiteAPI, k as SuiteCollector } from './tasks.d-B1vSIWO6.js';
|
2
|
+
export { l as Fixture, m as FixtureFn, n as FixtureOptions, o as Fixtures, H as HookCleanupCallback, p as HookListener, I as ImportDuration, q as InferFixturesTypes, R as RunMode, r as RuntimeContext, s as SequenceHooks, t as SequenceSetupFiles, u as SuiteFactory, v as TaskBase, w as TaskCustomOptions, x as TaskEventPack, y as TaskMeta, z as TaskPopulated, D as TaskResult, E as TaskResultPack, G as TaskState, J as TestAnnotation, K as TestAnnotationLocation, L as TestAttachment, M as TestContext, N as TestFunction, P as TestOptions, U as Use } from './tasks.d-B1vSIWO6.js';
|
3
3
|
import { Awaitable } from '@vitest/utils';
|
4
4
|
import { FileSpecification, VitestRunner } from './types.js';
|
5
5
|
export { CancelReason, VitestRunnerConfig, VitestRunnerConstructor, VitestRunnerImportSource } from './types.js';
|
@@ -122,8 +122,8 @@ declare const onTestFailed: TaskHook<OnTestFailedHandler>;
|
|
122
122
|
*/
|
123
123
|
declare const onTestFinished: TaskHook<OnTestFinishedHandler>;
|
124
124
|
|
125
|
-
declare function setFn(key: Test
|
126
|
-
declare function getFn<Task = Test
|
125
|
+
declare function setFn(key: Test, fn: () => Awaitable<void>): void;
|
126
|
+
declare function getFn<Task = Test>(key: Task): () => Awaitable<void>;
|
127
127
|
declare function setHooks(key: Suite, hooks: SuiteHooks): void;
|
128
128
|
declare function getHooks(key: Suite): SuiteHooks;
|
129
129
|
|
@@ -258,4 +258,4 @@ declare function createTaskCollector(fn: (...args: any[]) => any, context?: Reco
|
|
258
258
|
|
259
259
|
declare function getCurrentTest<T extends Test | undefined>(): T;
|
260
260
|
|
261
|
-
export { AfterAllListener, AfterEachListener, BeforeAllListener, BeforeEachListener,
|
261
|
+
export { AfterAllListener, AfterEachListener, BeforeAllListener, BeforeEachListener, 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,6 +1,6 @@
|
|
1
1
|
export { a as afterAll, b as afterEach, c as beforeAll, d as beforeEach, p as collectTests, j as createTaskCollector, k as describe, l as getCurrentSuite, q as getCurrentTest, g as getFn, f as getHooks, m as it, o as onTestFailed, e as onTestFinished, s as setFn, h as setHooks, i as startTests, n as suite, t as test, u as updateTask } from './chunk-hooks.js';
|
2
2
|
export { processError } from '@vitest/utils/error';
|
3
3
|
import '@vitest/utils';
|
4
|
-
import '@vitest/utils/source-map';
|
5
4
|
import 'strip-literal';
|
5
|
+
import '@vitest/utils/source-map';
|
6
6
|
import 'pathe';
|
@@ -19,7 +19,7 @@ type ChainableFunction<
|
|
19
19
|
F extends (...args: any) => any,
|
20
20
|
C = object
|
21
21
|
> = F & { [x in T] : ChainableFunction<T, F, C> } & {
|
22
|
-
fn: (this: Record<T, any>, ...args: Parameters<F>) => ReturnType<F
|
22
|
+
fn: (this: Record<T, any>, ...args: Parameters<F>) => ReturnType<F>;
|
23
23
|
} & C;
|
24
24
|
declare function createChainable<
|
25
25
|
T extends string,
|
@@ -92,8 +92,8 @@ interface TaskBase {
|
|
92
92
|
* and parsing the stack trace, so the location might differ depending on the runtime.
|
93
93
|
*/
|
94
94
|
location?: {
|
95
|
-
line: number
|
96
|
-
column: number
|
95
|
+
line: number;
|
96
|
+
column: number;
|
97
97
|
};
|
98
98
|
}
|
99
99
|
interface TaskPopulated extends TaskBase {
|
@@ -243,29 +243,21 @@ interface TestAnnotation {
|
|
243
243
|
location?: TestAnnotationLocation;
|
244
244
|
attachment?: TestAttachment;
|
245
245
|
}
|
246
|
-
/**
|
247
|
-
* @deprecated Use `Test` instead. `type: 'custom'` is not used since 2.2
|
248
|
-
*/
|
249
|
-
type Custom<ExtraContext = object> = Test<ExtraContext>;
|
250
246
|
type Task = Test | Suite | File;
|
251
|
-
/**
|
252
|
-
* @deprecated Vitest doesn't provide `done()` anymore
|
253
|
-
*/
|
254
|
-
type DoneCallback = (error?: any) => void;
|
255
247
|
type TestFunction<ExtraContext = object> = (context: TestContext & ExtraContext) => Awaitable<any> | void;
|
256
248
|
// jest's ExtractEachCallbackArgs
|
257
249
|
type ExtractEachCallbackArgs<T extends ReadonlyArray<any>> = {
|
258
|
-
1: [T[0]]
|
259
|
-
2: [T[0], T[1]]
|
260
|
-
3: [T[0], T[1], T[2]]
|
261
|
-
4: [T[0], T[1], T[2], T[3]]
|
262
|
-
5: [T[0], T[1], T[2], T[3], T[4]]
|
263
|
-
6: [T[0], T[1], T[2], T[3], T[4], T[5]]
|
264
|
-
7: [T[0], T[1], T[2], T[3], T[4], T[5], T[6]]
|
265
|
-
8: [T[0], T[1], T[2], T[3], T[4], T[5], T[6], T[7]]
|
266
|
-
9: [T[0], T[1], T[2], T[3], T[4], T[5], T[6], T[7], T[8]]
|
267
|
-
10: [T[0], T[1], T[2], T[3], T[4], T[5], T[6], T[7], T[8], T[9]]
|
268
|
-
fallback: Array<T extends ReadonlyArray<infer U> ? U : any
|
250
|
+
1: [T[0]];
|
251
|
+
2: [T[0], T[1]];
|
252
|
+
3: [T[0], T[1], T[2]];
|
253
|
+
4: [T[0], T[1], T[2], T[3]];
|
254
|
+
5: [T[0], T[1], T[2], T[3], T[4]];
|
255
|
+
6: [T[0], T[1], T[2], T[3], T[4], T[5]];
|
256
|
+
7: [T[0], T[1], T[2], T[3], T[4], T[5], T[6]];
|
257
|
+
8: [T[0], T[1], T[2], T[3], T[4], T[5], T[6], T[7]];
|
258
|
+
9: [T[0], T[1], T[2], T[3], T[4], T[5], T[6], T[7], T[8]];
|
259
|
+
10: [T[0], T[1], T[2], T[3], T[4], T[5], T[6], T[7], T[8], T[9]];
|
260
|
+
fallback: Array<T extends ReadonlyArray<infer U> ? U : any>;
|
269
261
|
}[T extends Readonly<[any]> ? 1 : T extends Readonly<[any, any]> ? 2 : T extends Readonly<[any, any, any]> ? 3 : T extends Readonly<[any, any, any, any]> ? 4 : T extends Readonly<[any, any, any, any, any]> ? 5 : T extends Readonly<[any, any, any, any, any, any]> ? 6 : T extends Readonly<[any, any, any, any, any, any, any]> ? 7 : T extends Readonly<[any, any, any, any, any, any, any, any]> ? 8 : T extends Readonly<[any, any, any, any, any, any, any, any, any]> ? 9 : T extends Readonly<[any, any, any, any, any, any, any, any, any, any]> ? 10 : "fallback"];
|
270
262
|
interface EachFunctionReturn<T extends any[]> {
|
271
263
|
/**
|
@@ -312,8 +304,8 @@ interface TestCollectorCallable<C = object> {
|
|
312
304
|
<ExtraContext extends C>(name: string | Function, options?: TestCollectorOptions, fn?: TestFunction<ExtraContext>): void;
|
313
305
|
}
|
314
306
|
type ChainableTestAPI<ExtraContext = object> = ChainableFunction<"concurrent" | "sequential" | "only" | "skip" | "todo" | "fails", TestCollectorCallable<ExtraContext>, {
|
315
|
-
each: TestEachFunction
|
316
|
-
for: TestForFunction<ExtraContext
|
307
|
+
each: TestEachFunction;
|
308
|
+
for: TestForFunction<ExtraContext>;
|
317
309
|
}>;
|
318
310
|
type TestCollectorOptions = Omit<TestOptions, "shuffle">;
|
319
311
|
interface TestOptions {
|
@@ -371,10 +363,9 @@ interface ExtendedAPI<ExtraContext> {
|
|
371
363
|
runIf: (condition: any) => ChainableTestAPI<ExtraContext>;
|
372
364
|
}
|
373
365
|
type TestAPI<ExtraContext = object> = ChainableTestAPI<ExtraContext> & ExtendedAPI<ExtraContext> & {
|
374
|
-
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 }
|
375
|
-
scoped: (fixtures: Fixtures<Partial<ExtraContext>>) => void
|
366
|
+
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 }>;
|
367
|
+
scoped: (fixtures: Fixtures<Partial<ExtraContext>>) => void;
|
376
368
|
};
|
377
|
-
|
378
369
|
interface FixtureOptions {
|
379
370
|
/**
|
380
371
|
* Whether to automatically set up current fixture, even though it's not being used in tests.
|
@@ -421,12 +412,12 @@ interface SuiteCollectorCallable<ExtraContext = object> {
|
|
421
412
|
<OverrideExtraContext extends ExtraContext = ExtraContext>(name: string | Function, options: TestOptions, fn?: SuiteFactory<OverrideExtraContext>): SuiteCollector<OverrideExtraContext>;
|
422
413
|
}
|
423
414
|
type ChainableSuiteAPI<ExtraContext = object> = ChainableFunction<"concurrent" | "sequential" | "only" | "skip" | "todo" | "shuffle", SuiteCollectorCallable<ExtraContext>, {
|
424
|
-
each: TestEachFunction
|
425
|
-
for: SuiteForFunction
|
415
|
+
each: TestEachFunction;
|
416
|
+
for: SuiteForFunction;
|
426
417
|
}>;
|
427
418
|
type SuiteAPI<ExtraContext = object> = ChainableSuiteAPI<ExtraContext> & {
|
428
|
-
skipIf: (condition: any) => ChainableSuiteAPI<ExtraContext
|
429
|
-
runIf: (condition: any) => ChainableSuiteAPI<ExtraContext
|
419
|
+
skipIf: (condition: any) => ChainableSuiteAPI<ExtraContext>;
|
420
|
+
runIf: (condition: any) => ChainableSuiteAPI<ExtraContext>;
|
430
421
|
};
|
431
422
|
/**
|
432
423
|
* @deprecated
|
@@ -527,25 +518,18 @@ interface TestContext {
|
|
527
518
|
* @see {@link https://vitest.dev/guide/test-context#skip}
|
528
519
|
*/
|
529
520
|
readonly skip: {
|
530
|
-
(note?: string): never
|
531
|
-
(condition: boolean, note?: string): void
|
521
|
+
(note?: string): never;
|
522
|
+
(condition: boolean, note?: string): void;
|
532
523
|
};
|
533
524
|
/**
|
534
525
|
* Add a test annotation that will be displayed by your reporter.
|
535
526
|
* @see {@link https://vitest.dev/guide/test-context#annotate}
|
536
527
|
*/
|
537
528
|
readonly annotate: {
|
538
|
-
(message: string, type?: string, attachment?: TestAttachment): Promise<TestAnnotation
|
539
|
-
(message: string, attachment?: TestAttachment): Promise<TestAnnotation
|
529
|
+
(message: string, type?: string, attachment?: TestAttachment): Promise<TestAnnotation>;
|
530
|
+
(message: string, attachment?: TestAttachment): Promise<TestAnnotation>;
|
540
531
|
};
|
541
532
|
}
|
542
|
-
/**
|
543
|
-
* Context that's always available in the test function.
|
544
|
-
* @deprecated use `TestContext` instead
|
545
|
-
*/
|
546
|
-
interface TaskContext extends TestContext {}
|
547
|
-
/** @deprecated use `TestContext` instead */
|
548
|
-
type ExtendedContext = TaskContext & TestContext;
|
549
533
|
type OnTestFailedHandler = (context: TestContext) => Awaitable<void>;
|
550
534
|
type OnTestFinishedHandler = (context: TestContext) => Awaitable<void>;
|
551
535
|
interface TaskHook<HookListener> {
|
@@ -555,4 +539,4 @@ type SequenceHooks = "stack" | "list" | "parallel";
|
|
555
539
|
type SequenceSetupFiles = "list" | "parallel";
|
556
540
|
|
557
541
|
export { createChainable as c };
|
558
|
-
export type { AfterAllListener as A, BeforeAllListener as B, ChainableFunction as C,
|
542
|
+
export type { AfterAllListener as A, BeforeAllListener as B, ChainableFunction as C, TaskResult as D, TaskResultPack as E, File as F, TaskState as G, HookCleanupCallback as H, ImportDuration as I, TestAnnotation as J, TestAnnotationLocation as K, TestAttachment as L, TestContext as M, TestFunction as N, OnTestFailedHandler as O, TestOptions as P, RunMode as R, Suite as S, Task as T, Use as U, Test as a, AfterEachListener as b, BeforeEachListener as d, TaskHook as e, OnTestFinishedHandler as f, SuiteHooks as g, TaskUpdateEvent as h, TestAPI as i, SuiteAPI as j, SuiteCollector as k, Fixture as l, FixtureFn as m, FixtureOptions as n, Fixtures as o, HookListener as p, InferFixturesTypes as q, RuntimeContext as r, SequenceHooks as s, SequenceSetupFiles as t, SuiteFactory as u, TaskBase as v, TaskCustomOptions as w, TaskEventPack as x, TaskMeta as y, TaskPopulated as z };
|
package/dist/types.d.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import { DiffOptions } from '@vitest/utils/diff';
|
2
|
-
import { F as File, a as Test, S as Suite,
|
3
|
-
export { A as AfterAllListener, b as AfterEachListener, B as BeforeAllListener, d as BeforeEachListener,
|
2
|
+
import { F as File, a as Test, S as Suite, E as TaskResultPack, x as TaskEventPack, J as TestAnnotation, M as TestContext, I as ImportDuration, s as SequenceHooks, t as SequenceSetupFiles } from './tasks.d-B1vSIWO6.js';
|
3
|
+
export { A as AfterAllListener, b as AfterEachListener, B as BeforeAllListener, d as BeforeEachListener, l as Fixture, m as FixtureFn, n as FixtureOptions, o as Fixtures, H as HookCleanupCallback, p as HookListener, q as InferFixturesTypes, O as OnTestFailedHandler, f as OnTestFinishedHandler, R as RunMode, r as RuntimeContext, j as SuiteAPI, k as SuiteCollector, u as SuiteFactory, g as SuiteHooks, T as Task, v as TaskBase, w as TaskCustomOptions, e as TaskHook, y as TaskMeta, z as TaskPopulated, D as TaskResult, G as TaskState, h as TaskUpdateEvent, i as TestAPI, K as TestAnnotationLocation, L as TestAttachment, N as TestFunction, P as TestOptions, U as Use } from './tasks.d-B1vSIWO6.js';
|
4
4
|
import '@vitest/utils';
|
5
5
|
|
6
6
|
/**
|
@@ -14,14 +14,14 @@ interface VitestRunnerConfig {
|
|
14
14
|
testNamePattern?: RegExp;
|
15
15
|
allowOnly?: boolean;
|
16
16
|
sequence: {
|
17
|
-
shuffle?: boolean
|
18
|
-
concurrent?: boolean
|
19
|
-
seed: number
|
20
|
-
hooks: SequenceHooks
|
21
|
-
setupFiles: SequenceSetupFiles
|
17
|
+
shuffle?: boolean;
|
18
|
+
concurrent?: boolean;
|
19
|
+
seed: number;
|
20
|
+
hooks: SequenceHooks;
|
21
|
+
setupFiles: SequenceSetupFiles;
|
22
22
|
};
|
23
23
|
chaiConfig?: {
|
24
|
-
truncateThreshold?: number
|
24
|
+
truncateThreshold?: number;
|
25
25
|
};
|
26
26
|
maxConcurrency: number;
|
27
27
|
testTimeout: number;
|
@@ -69,8 +69,8 @@ interface VitestRunner {
|
|
69
69
|
* Called before actually running the test function. Already has "result" with "state" and "startTime".
|
70
70
|
*/
|
71
71
|
onBeforeTryTask?: (test: Test, options: {
|
72
|
-
retry: number
|
73
|
-
repeats: number
|
72
|
+
retry: number;
|
73
|
+
repeats: number;
|
74
74
|
}) => unknown;
|
75
75
|
/**
|
76
76
|
* When the task has finished running, but before cleanup hooks are called
|
@@ -84,8 +84,8 @@ interface VitestRunner {
|
|
84
84
|
* Called right after running the test function. Doesn't have new state yet. Will not be called, if the test function throws.
|
85
85
|
*/
|
86
86
|
onAfterTryTask?: (test: Test, options: {
|
87
|
-
retry: number
|
88
|
-
repeats: number
|
87
|
+
retry: number;
|
88
|
+
repeats: number;
|
89
89
|
}) => unknown;
|
90
90
|
/**
|
91
91
|
* Called before running a single suite. Doesn't have "result" yet.
|
package/dist/utils.d.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
import { S as Suite, F as File, T as Task, a as Test } from './tasks.d-
|
2
|
-
export { C as ChainableFunction, c as createChainable } from './tasks.d-
|
3
|
-
import { Arrayable } from '@vitest/utils';
|
1
|
+
import { S as Suite, F as File, T as Task, a as Test } from './tasks.d-B1vSIWO6.js';
|
2
|
+
export { C as ChainableFunction, c as createChainable } from './tasks.d-B1vSIWO6.js';
|
3
|
+
import { ParsedStack, Arrayable } from '@vitest/utils';
|
4
4
|
|
5
5
|
/**
|
6
6
|
* If any tasks been marked as `only`, mark all other tasks as `skip`.
|
@@ -16,6 +16,7 @@ declare function createFileTask(filepath: string, root: string, projectName: str
|
|
16
16
|
* @param projectName The name of the test project
|
17
17
|
*/
|
18
18
|
declare function generateFileHash(file: string, projectName: string | undefined): string;
|
19
|
+
declare function findTestFileStackTrace(testFilePath: string, error: string): ParsedStack | undefined;
|
19
20
|
|
20
21
|
/**
|
21
22
|
* Return a function for running multiple async operations with limited concurrency.
|
@@ -44,4 +45,4 @@ declare function getNames(task: Task): string[];
|
|
44
45
|
declare function getFullName(task: Task, separator?: string): string;
|
45
46
|
declare function getTestName(task: Task, separator?: string): string;
|
46
47
|
|
47
|
-
export { calculateSuiteHash, createFileTask, generateFileHash, generateHash, getFullName, getNames, getSuites, getTasks, getTestName, getTests, hasFailed, hasTests, interpretTaskModes, isAtomTest, isTestCase, limitConcurrency, partitionSuiteChildren, someTasksAreOnly };
|
48
|
+
export { calculateSuiteHash, createFileTask, findTestFileStackTrace, generateFileHash, generateHash, getFullName, getNames, getSuites, getTasks, getTestName, getTests, hasFailed, hasTests, interpretTaskModes, isAtomTest, isTestCase, limitConcurrency, partitionSuiteChildren, someTasksAreOnly };
|
package/dist/utils.js
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
export { v as calculateSuiteHash, r as createChainable, w as createFileTask, x as
|
1
|
+
export { v as calculateSuiteHash, r as createChainable, w as createFileTask, x as findTestFileStackTrace, y as generateFileHash, z as generateHash, E as getFullName, F as getNames, G as getSuites, H as getTasks, I as getTestName, J as getTests, K as hasFailed, L as hasTests, A as interpretTaskModes, M as isAtomTest, N as isTestCase, C as limitConcurrency, D as partitionSuiteChildren, B as someTasksAreOnly } from './chunk-hooks.js';
|
2
2
|
import '@vitest/utils';
|
3
|
-
import '@vitest/utils/source-map';
|
4
3
|
import '@vitest/utils/error';
|
5
4
|
import 'strip-literal';
|
5
|
+
import '@vitest/utils/source-map';
|
6
6
|
import 'pathe';
|
package/package.json
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
{
|
2
2
|
"name": "@vitest/runner",
|
3
3
|
"type": "module",
|
4
|
-
"version": "4.0.0-beta.
|
4
|
+
"version": "4.0.0-beta.3",
|
5
5
|
"description": "Vitest test runner",
|
6
6
|
"license": "MIT",
|
7
7
|
"funding": "https://opencollective.com/vitest",
|
@@ -40,7 +40,7 @@
|
|
40
40
|
"dependencies": {
|
41
41
|
"pathe": "^2.0.3",
|
42
42
|
"strip-literal": "^3.0.0",
|
43
|
-
"@vitest/utils": "4.0.0-beta.
|
43
|
+
"@vitest/utils": "4.0.0-beta.3"
|
44
44
|
},
|
45
45
|
"scripts": {
|
46
46
|
"build": "rimraf dist && rollup -c",
|