@vitest/runner 4.0.0-beta.2 → 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 +369 -372
- package/dist/index.d.ts +2 -2
- package/dist/index.js +1 -1
- package/dist/{tasks.d-BPS2nWLO.d.ts → tasks.d-B1vSIWO6.d.ts} +26 -26
- 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
|
};
|
@@ -915,236 +1222,63 @@ function createTaskCollector(fn, context) {
|
|
915
1222
|
"skip",
|
916
1223
|
"only",
|
917
1224
|
"todo",
|
918
|
-
"fails"
|
919
|
-
], 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}`)));
|
1225
|
+
"fails"
|
1226
|
+
], taskFn);
|
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();
|
@@ -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, 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-
|
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-
|
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';
|
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 {
|
@@ -247,17 +247,17 @@ type Task = Test | Suite | File;
|
|
247
247
|
type TestFunction<ExtraContext = object> = (context: TestContext & ExtraContext) => Awaitable<any> | void;
|
248
248
|
// jest's ExtractEachCallbackArgs
|
249
249
|
type ExtractEachCallbackArgs<T extends ReadonlyArray<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
|
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>;
|
261
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"];
|
262
262
|
interface EachFunctionReturn<T extends any[]> {
|
263
263
|
/**
|
@@ -304,8 +304,8 @@ interface TestCollectorCallable<C = object> {
|
|
304
304
|
<ExtraContext extends C>(name: string | Function, options?: TestCollectorOptions, fn?: TestFunction<ExtraContext>): void;
|
305
305
|
}
|
306
306
|
type ChainableTestAPI<ExtraContext = object> = ChainableFunction<"concurrent" | "sequential" | "only" | "skip" | "todo" | "fails", TestCollectorCallable<ExtraContext>, {
|
307
|
-
each: TestEachFunction
|
308
|
-
for: TestForFunction<ExtraContext
|
307
|
+
each: TestEachFunction;
|
308
|
+
for: TestForFunction<ExtraContext>;
|
309
309
|
}>;
|
310
310
|
type TestCollectorOptions = Omit<TestOptions, "shuffle">;
|
311
311
|
interface TestOptions {
|
@@ -363,8 +363,8 @@ interface ExtendedAPI<ExtraContext> {
|
|
363
363
|
runIf: (condition: any) => ChainableTestAPI<ExtraContext>;
|
364
364
|
}
|
365
365
|
type TestAPI<ExtraContext = object> = ChainableTestAPI<ExtraContext> & ExtendedAPI<ExtraContext> & {
|
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
|
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;
|
368
368
|
};
|
369
369
|
interface FixtureOptions {
|
370
370
|
/**
|
@@ -412,12 +412,12 @@ interface SuiteCollectorCallable<ExtraContext = object> {
|
|
412
412
|
<OverrideExtraContext extends ExtraContext = ExtraContext>(name: string | Function, options: TestOptions, fn?: SuiteFactory<OverrideExtraContext>): SuiteCollector<OverrideExtraContext>;
|
413
413
|
}
|
414
414
|
type ChainableSuiteAPI<ExtraContext = object> = ChainableFunction<"concurrent" | "sequential" | "only" | "skip" | "todo" | "shuffle", SuiteCollectorCallable<ExtraContext>, {
|
415
|
-
each: TestEachFunction
|
416
|
-
for: SuiteForFunction
|
415
|
+
each: TestEachFunction;
|
416
|
+
for: SuiteForFunction;
|
417
417
|
}>;
|
418
418
|
type SuiteAPI<ExtraContext = object> = ChainableSuiteAPI<ExtraContext> & {
|
419
|
-
skipIf: (condition: any) => ChainableSuiteAPI<ExtraContext
|
420
|
-
runIf: (condition: any) => ChainableSuiteAPI<ExtraContext
|
419
|
+
skipIf: (condition: any) => ChainableSuiteAPI<ExtraContext>;
|
420
|
+
runIf: (condition: any) => ChainableSuiteAPI<ExtraContext>;
|
421
421
|
};
|
422
422
|
/**
|
423
423
|
* @deprecated
|
@@ -518,16 +518,16 @@ interface TestContext {
|
|
518
518
|
* @see {@link https://vitest.dev/guide/test-context#skip}
|
519
519
|
*/
|
520
520
|
readonly skip: {
|
521
|
-
(note?: string): never
|
522
|
-
(condition: boolean, note?: string): void
|
521
|
+
(note?: string): never;
|
522
|
+
(condition: boolean, note?: string): void;
|
523
523
|
};
|
524
524
|
/**
|
525
525
|
* Add a test annotation that will be displayed by your reporter.
|
526
526
|
* @see {@link https://vitest.dev/guide/test-context#annotate}
|
527
527
|
*/
|
528
528
|
readonly annotate: {
|
529
|
-
(message: string, type?: string, attachment?: TestAttachment): Promise<TestAnnotation
|
530
|
-
(message: string, attachment?: TestAttachment): Promise<TestAnnotation
|
529
|
+
(message: string, type?: string, attachment?: TestAttachment): Promise<TestAnnotation>;
|
530
|
+
(message: string, attachment?: TestAttachment): Promise<TestAnnotation>;
|
531
531
|
};
|
532
532
|
}
|
533
533
|
type OnTestFailedHandler = (context: TestContext) => Awaitable<void>;
|
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, E as TaskResultPack, x as TaskEventPack, J as TestAnnotation, M as TestContext, I as ImportDuration, s as SequenceHooks, t as SequenceSetupFiles } from './tasks.d-
|
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-
|
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",
|