vitest 3.2.0-beta.2 → 3.2.0
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/LICENSE.md +29 -0
- package/dist/browser.d.ts +3 -3
- package/dist/browser.js +2 -2
- package/dist/chunks/{base.DwtwORaC.js → base.Cg0miDlQ.js} +11 -14
- package/dist/chunks/{benchmark.BoF7jW0Q.js → benchmark.CYdenmiT.js} +4 -6
- package/dist/chunks/{cac.I9MLYfT-.js → cac.6rXCxFY1.js} +76 -143
- package/dist/chunks/{cli-api.d6IK1pnk.js → cli-api.Cej3MBjA.js} +1460 -1344
- package/dist/chunks/{config.d.UqE-KR0o.d.ts → config.d.D2ROskhv.d.ts} +2 -0
- package/dist/chunks/{console.K1NMVOSc.js → console.CtFJOzRO.js} +25 -45
- package/dist/chunks/{constants.BZZyIeIE.js → constants.DnKduX2e.js} +1 -0
- package/dist/chunks/{coverage.0iPg4Wrz.js → coverage.DVF1vEu8.js} +4 -12
- package/dist/chunks/{coverage.OGU09Jbh.js → coverage.EIiagJJP.js} +578 -993
- package/dist/chunks/{creator.DGAdZ4Hj.js → creator.GK6I-cL4.js} +39 -83
- package/dist/chunks/date.Bq6ZW5rf.js +73 -0
- package/dist/chunks/{defaults.DSxsTG0h.js → defaults.B7q_naMc.js} +2 -1
- package/dist/chunks/{env.Dq0hM4Xv.js → env.D4Lgay0q.js} +1 -1
- package/dist/chunks/{environment.d.D8YDy2v5.d.ts → environment.d.cL3nLXbE.d.ts} +1 -0
- package/dist/chunks/{execute.JlGHLJZT.js → execute.B7h3T_Hc.js} +126 -217
- package/dist/chunks/{git.DXfdBEfR.js → git.BVQ8w_Sw.js} +1 -3
- package/dist/chunks/{global.d.BPa1eL3O.d.ts → global.d.MAmajcmJ.d.ts} +5 -1
- package/dist/chunks/{globals.CpxW8ccg.js → globals.DEHgCU4V.js} +7 -6
- package/dist/chunks/{index.CV36oG_L.js → index.BZ0g1JD2.js} +430 -625
- package/dist/chunks/{index.DswW_LEs.js → index.BbB8_kAK.js} +25 -24
- package/dist/chunks/{index.CmC5OK9L.js → index.CIyJn3t1.js} +38 -82
- package/dist/chunks/{index.CfXMNXHg.js → index.CdQS2e2Q.js} +4 -2
- package/dist/chunks/{index.DFXFpH3w.js → index.CmSc2RE5.js} +85 -105
- package/dist/chunks/index.D3XRDfWc.js +213 -0
- package/dist/chunks/{inspector.DbDkSkFn.js → inspector.C914Efll.js} +4 -1
- package/dist/chunks/{node.3xsWotC9.js → node.fjCdwEIl.js} +1 -1
- package/dist/chunks/{reporters.d.CLC9rhKy.d.ts → reporters.d.C1ogPriE.d.ts} +47 -9
- package/dist/chunks/{rpc.D9_013TY.js → rpc.Iovn4oWe.js} +10 -19
- package/dist/chunks/{runBaseTests.Dn2vyej_.js → runBaseTests.Dd85QTll.js} +27 -31
- package/dist/chunks/{setup-common.CYo3Y0dD.js → setup-common.Dd054P77.js} +16 -42
- package/dist/chunks/{typechecker.DnTrplSJ.js → typechecker.DRKU1-1g.js} +163 -186
- package/dist/chunks/{utils.BfxieIyZ.js → utils.CAioKnHs.js} +9 -14
- package/dist/chunks/{utils.CgTj3MsC.js → utils.XdZDrNZV.js} +6 -13
- package/dist/chunks/{vi.BFR5YIgu.js → vi.bdSIJ99Y.js} +137 -263
- package/dist/chunks/{vite.d.CBZ3M_ru.d.ts → vite.d.DqE4-hhK.d.ts} +3 -1
- package/dist/chunks/{vm.C1HHjtNS.js → vm.BThCzidc.js} +164 -212
- package/dist/chunks/{worker.d.D5Xdi-Zr.d.ts → worker.d.DvqK5Vmu.d.ts} +1 -1
- package/dist/chunks/{worker.d.CoCI7hzP.d.ts → worker.d.tQu2eJQy.d.ts} +5 -3
- package/dist/cli.js +5 -5
- package/dist/config.cjs +3 -1
- package/dist/config.d.ts +7 -6
- package/dist/config.js +3 -3
- package/dist/coverage.d.ts +4 -4
- package/dist/coverage.js +7 -7
- package/dist/environments.d.ts +6 -2
- package/dist/environments.js +1 -1
- package/dist/execute.d.ts +9 -3
- package/dist/execute.js +1 -1
- package/dist/index.d.ts +28 -15
- package/dist/index.js +5 -5
- package/dist/node.d.ts +18 -10
- package/dist/node.js +17 -17
- package/dist/reporters.d.ts +4 -4
- package/dist/reporters.js +4 -4
- package/dist/runners.d.ts +6 -3
- package/dist/runners.js +59 -80
- package/dist/snapshot.js +2 -2
- package/dist/suite.js +2 -2
- package/dist/worker.js +39 -41
- package/dist/workers/forks.js +6 -4
- package/dist/workers/runVmTests.js +20 -21
- package/dist/workers/threads.js +4 -4
- package/dist/workers/vmForks.js +6 -6
- package/dist/workers/vmThreads.js +6 -6
- package/dist/workers.d.ts +4 -4
- package/dist/workers.js +10 -10
- package/package.json +21 -19
- package/dist/chunks/date.CDOsz-HY.js +0 -53
- package/dist/chunks/index.CK1YOQaa.js +0 -143
|
@@ -23,11 +23,14 @@ function convertTasksToEvents(file, onTask) {
|
|
|
23
23
|
suite.result,
|
|
24
24
|
suite.meta
|
|
25
25
|
]);
|
|
26
|
-
events.push([
|
|
26
|
+
events.push([
|
|
27
|
+
suite.id,
|
|
28
|
+
"suite-prepare",
|
|
29
|
+
void 0
|
|
30
|
+
]);
|
|
27
31
|
suite.tasks.forEach((task) => {
|
|
28
|
-
if (task.type === "suite")
|
|
29
|
-
|
|
30
|
-
} else {
|
|
32
|
+
if (task.type === "suite") visit(task);
|
|
33
|
+
else {
|
|
31
34
|
onTask?.(task);
|
|
32
35
|
if (suite.mode !== "skip" && suite.mode !== "todo") {
|
|
33
36
|
packs.push([
|
|
@@ -35,11 +38,31 @@ function convertTasksToEvents(file, onTask) {
|
|
|
35
38
|
task.result,
|
|
36
39
|
task.meta
|
|
37
40
|
]);
|
|
38
|
-
events.push([
|
|
41
|
+
events.push([
|
|
42
|
+
task.id,
|
|
43
|
+
"test-prepare",
|
|
44
|
+
void 0
|
|
45
|
+
]);
|
|
46
|
+
task.annotations.forEach((annotation) => {
|
|
47
|
+
events.push([
|
|
48
|
+
task.id,
|
|
49
|
+
"test-annotation",
|
|
50
|
+
{ annotation }
|
|
51
|
+
]);
|
|
52
|
+
});
|
|
53
|
+
events.push([
|
|
54
|
+
task.id,
|
|
55
|
+
"test-finished",
|
|
56
|
+
void 0
|
|
57
|
+
]);
|
|
39
58
|
}
|
|
40
59
|
}
|
|
41
60
|
});
|
|
42
|
-
events.push([
|
|
61
|
+
events.push([
|
|
62
|
+
suite.id,
|
|
63
|
+
"suite-finished",
|
|
64
|
+
void 0
|
|
65
|
+
]);
|
|
43
66
|
}
|
|
44
67
|
visit(file);
|
|
45
68
|
return {
|
|
@@ -50,12 +73,8 @@ function convertTasksToEvents(file, onTask) {
|
|
|
50
73
|
|
|
51
74
|
const REGEXP_WRAP_PREFIX = "$$vitest:";
|
|
52
75
|
function getOutputFile(config, reporter) {
|
|
53
|
-
if (!config?.outputFile)
|
|
54
|
-
|
|
55
|
-
}
|
|
56
|
-
if (typeof config.outputFile === "string") {
|
|
57
|
-
return config.outputFile;
|
|
58
|
-
}
|
|
76
|
+
if (!config?.outputFile) return;
|
|
77
|
+
if (typeof config.outputFile === "string") return config.outputFile;
|
|
59
78
|
return config.outputFile[reporter];
|
|
60
79
|
}
|
|
61
80
|
/**
|
|
@@ -64,15 +83,13 @@ function getOutputFile(config, reporter) {
|
|
|
64
83
|
function wrapSerializableConfig(config) {
|
|
65
84
|
let testNamePattern = config.testNamePattern;
|
|
66
85
|
let defines = config.defines;
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
if (defines) {
|
|
71
|
-
defines
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
};
|
|
75
|
-
}
|
|
86
|
+
// v8 serialize does not support regex
|
|
87
|
+
if (testNamePattern && typeof testNamePattern !== "string") testNamePattern = `${REGEXP_WRAP_PREFIX}${testNamePattern.toString()}`;
|
|
88
|
+
// v8 serialize drops properties with undefined value
|
|
89
|
+
if (defines) defines = {
|
|
90
|
+
keys: Object.keys(defines),
|
|
91
|
+
original: defines
|
|
92
|
+
};
|
|
76
93
|
return {
|
|
77
94
|
...config,
|
|
78
95
|
testNamePattern,
|
|
@@ -358,9 +375,7 @@ base.MethodDefinition = base.PropertyDefinition = base.Property = function (node
|
|
|
358
375
|
|
|
359
376
|
async function collectTests(ctx, filepath) {
|
|
360
377
|
const request = await ctx.vitenode.transformRequest(filepath, filepath);
|
|
361
|
-
if (!request)
|
|
362
|
-
return null;
|
|
363
|
-
}
|
|
378
|
+
if (!request) return null;
|
|
364
379
|
const ast = await parseAstAsync(request.code);
|
|
365
380
|
const testFilepath = relative(ctx.config.root, filepath);
|
|
366
381
|
const projectName = ctx.name;
|
|
@@ -381,79 +396,59 @@ async function collectTests(ctx, filepath) {
|
|
|
381
396
|
file.file = file;
|
|
382
397
|
const definitions = [];
|
|
383
398
|
const getName = (callee) => {
|
|
384
|
-
if (!callee)
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
if (callee.type === "
|
|
388
|
-
return callee.name;
|
|
389
|
-
}
|
|
390
|
-
if (callee.type === "CallExpression") {
|
|
391
|
-
return getName(callee.callee);
|
|
392
|
-
}
|
|
393
|
-
if (callee.type === "TaggedTemplateExpression") {
|
|
394
|
-
return getName(callee.tag);
|
|
395
|
-
}
|
|
399
|
+
if (!callee) return null;
|
|
400
|
+
if (callee.type === "Identifier") return callee.name;
|
|
401
|
+
if (callee.type === "CallExpression") return getName(callee.callee);
|
|
402
|
+
if (callee.type === "TaggedTemplateExpression") return getName(callee.tag);
|
|
396
403
|
if (callee.type === "MemberExpression") {
|
|
397
404
|
if (callee.object?.type === "Identifier" && [
|
|
398
405
|
"it",
|
|
399
406
|
"test",
|
|
400
407
|
"describe",
|
|
401
408
|
"suite"
|
|
402
|
-
].includes(callee.object.name))
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
return getName(callee.property);
|
|
407
|
-
}
|
|
409
|
+
].includes(callee.object.name)) return callee.object?.name;
|
|
410
|
+
// direct call as `__vite_ssr_exports_0__.test()`
|
|
411
|
+
if (callee.object?.name?.startsWith("__vite_ssr_")) return getName(callee.property);
|
|
412
|
+
// call as `__vite_ssr__.test.skip()`
|
|
408
413
|
return getName(callee.object?.property);
|
|
409
414
|
}
|
|
415
|
+
// unwrap (0, ...)
|
|
410
416
|
if (callee.type === "SequenceExpression" && callee.expressions.length === 2) {
|
|
411
417
|
const [e0, e1] = callee.expressions;
|
|
412
|
-
if (e0.type === "Literal" && e0.value === 0)
|
|
413
|
-
return getName(e1);
|
|
414
|
-
}
|
|
418
|
+
if (e0.type === "Literal" && e0.value === 0) return getName(e1);
|
|
415
419
|
}
|
|
416
420
|
return null;
|
|
417
421
|
};
|
|
418
422
|
ancestor(ast, { CallExpression(node) {
|
|
419
423
|
const { callee } = node;
|
|
420
424
|
const name = getName(callee);
|
|
421
|
-
if (!name)
|
|
422
|
-
return;
|
|
423
|
-
}
|
|
425
|
+
if (!name) return;
|
|
424
426
|
if (![
|
|
425
427
|
"it",
|
|
426
428
|
"test",
|
|
427
429
|
"describe",
|
|
428
430
|
"suite"
|
|
429
|
-
].includes(name))
|
|
430
|
-
return;
|
|
431
|
-
}
|
|
431
|
+
].includes(name)) return;
|
|
432
432
|
const property = callee?.property?.name;
|
|
433
433
|
let mode = !property || property === name ? "run" : property;
|
|
434
|
+
// they will be picked up in the next iteration
|
|
434
435
|
if ([
|
|
435
436
|
"each",
|
|
436
437
|
"for",
|
|
437
438
|
"skipIf",
|
|
438
439
|
"runIf"
|
|
439
|
-
].includes(mode))
|
|
440
|
-
return;
|
|
441
|
-
}
|
|
440
|
+
].includes(mode)) return;
|
|
442
441
|
let start;
|
|
443
442
|
const end = node.end;
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
} else {
|
|
449
|
-
start = node.start;
|
|
450
|
-
}
|
|
443
|
+
// .each
|
|
444
|
+
if (callee.type === "CallExpression") start = callee.end;
|
|
445
|
+
else if (callee.type === "TaggedTemplateExpression") start = callee.end + 1;
|
|
446
|
+
else start = node.start;
|
|
451
447
|
const { arguments: [messageNode] } = node;
|
|
452
448
|
const isQuoted = messageNode?.type === "Literal" || messageNode?.type === "TemplateLiteral";
|
|
453
449
|
const message = isQuoted ? request.code.slice(messageNode.start + 1, messageNode.end - 1) : request.code.slice(messageNode.start, messageNode.end);
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
}
|
|
450
|
+
// cannot statically analyze, so we always skip it
|
|
451
|
+
if (mode === "skipIf" || mode === "runIf") mode = "skip";
|
|
457
452
|
definitions.push({
|
|
458
453
|
start,
|
|
459
454
|
end,
|
|
@@ -465,17 +460,15 @@ async function collectTests(ctx, filepath) {
|
|
|
465
460
|
} });
|
|
466
461
|
let lastSuite = file;
|
|
467
462
|
const updateLatestSuite = (index) => {
|
|
468
|
-
while (lastSuite.suite && lastSuite.end < index)
|
|
469
|
-
lastSuite = lastSuite.suite;
|
|
470
|
-
}
|
|
463
|
+
while (lastSuite.suite && lastSuite.end < index) lastSuite = lastSuite.suite;
|
|
471
464
|
return lastSuite;
|
|
472
465
|
};
|
|
473
466
|
definitions.sort((a, b) => a.start - b.start).forEach((definition) => {
|
|
474
467
|
const latestSuite = updateLatestSuite(definition.start);
|
|
475
468
|
let mode = definition.mode;
|
|
476
|
-
if (latestSuite.mode !== "run")
|
|
477
|
-
|
|
478
|
-
|
|
469
|
+
if (latestSuite.mode !== "run")
|
|
470
|
+
// inherit suite mode, if it's set
|
|
471
|
+
mode = latestSuite.mode;
|
|
479
472
|
if (definition.type === "suite") {
|
|
480
473
|
const task = {
|
|
481
474
|
type: definition.type,
|
|
@@ -505,6 +498,7 @@ async function collectTests(ctx, filepath) {
|
|
|
505
498
|
name: definition.name,
|
|
506
499
|
end: definition.end,
|
|
507
500
|
start: definition.start,
|
|
501
|
+
annotations: [],
|
|
508
502
|
meta: { typecheck: true }
|
|
509
503
|
};
|
|
510
504
|
definition.task = task;
|
|
@@ -512,7 +506,7 @@ async function collectTests(ctx, filepath) {
|
|
|
512
506
|
});
|
|
513
507
|
calculateSuiteHash(file);
|
|
514
508
|
const hasOnly = someTasksAreOnly(file);
|
|
515
|
-
interpretTaskModes(file, ctx.config.testNamePattern,
|
|
509
|
+
interpretTaskModes(file, ctx.config.testNamePattern, void 0, hasOnly, false, ctx.config.allowOnly);
|
|
516
510
|
return {
|
|
517
511
|
file,
|
|
518
512
|
parsed: request.code,
|
|
@@ -526,26 +520,18 @@ const newLineRegExp = /\r?\n/;
|
|
|
526
520
|
const errCodeRegExp = /error TS(?<errCode>\d+)/;
|
|
527
521
|
async function makeTscErrorInfo(errInfo) {
|
|
528
522
|
const [errFilePathPos = "", ...errMsgRawArr] = errInfo.split(":");
|
|
529
|
-
if (!errFilePathPos || errMsgRawArr.length === 0 || errMsgRawArr.join("").length === 0)
|
|
530
|
-
return ["unknown filepath", null];
|
|
531
|
-
}
|
|
523
|
+
if (!errFilePathPos || errMsgRawArr.length === 0 || errMsgRawArr.join("").length === 0) return ["unknown filepath", null];
|
|
532
524
|
const errMsgRaw = errMsgRawArr.join("").trim();
|
|
525
|
+
// get filePath, line, col
|
|
533
526
|
const [errFilePath, errPos] = errFilePathPos.slice(0, -1).split("(");
|
|
534
|
-
if (!errFilePath || !errPos)
|
|
535
|
-
return ["unknown filepath", null];
|
|
536
|
-
}
|
|
527
|
+
if (!errFilePath || !errPos) return ["unknown filepath", null];
|
|
537
528
|
const [errLine, errCol] = errPos.split(",");
|
|
538
|
-
if (!errLine || !errCol)
|
|
539
|
-
|
|
540
|
-
}
|
|
529
|
+
if (!errLine || !errCol) return [errFilePath, null];
|
|
530
|
+
// get errCode, errMsg
|
|
541
531
|
const execArr = errCodeRegExp.exec(errMsgRaw);
|
|
542
|
-
if (!execArr)
|
|
543
|
-
return [errFilePath, null];
|
|
544
|
-
}
|
|
532
|
+
if (!execArr) return [errFilePath, null];
|
|
545
533
|
const errCodeStr = execArr.groups?.errCode ?? "";
|
|
546
|
-
if (!errCodeStr)
|
|
547
|
-
return [errFilePath, null];
|
|
548
|
-
}
|
|
534
|
+
if (!errCodeStr) return [errFilePath, null];
|
|
549
535
|
const line = Number(errLine);
|
|
550
536
|
const col = Number(errCol);
|
|
551
537
|
const errCode = Number(errCodeStr);
|
|
@@ -558,32 +544,24 @@ async function makeTscErrorInfo(errInfo) {
|
|
|
558
544
|
}];
|
|
559
545
|
}
|
|
560
546
|
async function getRawErrsMapFromTsCompile(tscErrorStdout) {
|
|
561
|
-
const rawErrsMap = new Map();
|
|
547
|
+
const rawErrsMap = /* @__PURE__ */ new Map();
|
|
548
|
+
// Merge details line with main line (i.e. which contains file path)
|
|
562
549
|
const infos = await Promise.all(tscErrorStdout.split(newLineRegExp).reduce((prev, next) => {
|
|
563
|
-
if (!next)
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
prev.push(next);
|
|
567
|
-
} else {
|
|
568
|
-
prev[prev.length - 1] += `\n${next}`;
|
|
569
|
-
}
|
|
550
|
+
if (!next) return prev;
|
|
551
|
+
else if (!next.startsWith(" ")) prev.push(next);
|
|
552
|
+
else prev[prev.length - 1] += `\n${next}`;
|
|
570
553
|
return prev;
|
|
571
554
|
}, []).map((errInfoLine) => makeTscErrorInfo(errInfoLine)));
|
|
572
555
|
infos.forEach(([errFilePath, errInfo]) => {
|
|
573
|
-
if (!errInfo)
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
if (!rawErrsMap.has(errFilePath)) {
|
|
577
|
-
rawErrsMap.set(errFilePath, [errInfo]);
|
|
578
|
-
} else {
|
|
579
|
-
rawErrsMap.get(errFilePath)?.push(errInfo);
|
|
580
|
-
}
|
|
556
|
+
if (!errInfo) return;
|
|
557
|
+
if (!rawErrsMap.has(errFilePath)) rawErrsMap.set(errFilePath, [errInfo]);
|
|
558
|
+
else rawErrsMap.get(errFilePath)?.push(errInfo);
|
|
581
559
|
});
|
|
582
560
|
return rawErrsMap;
|
|
583
561
|
}
|
|
584
562
|
|
|
585
563
|
function createIndexMap(source) {
|
|
586
|
-
const map = new Map();
|
|
564
|
+
const map = /* @__PURE__ */ new Map();
|
|
587
565
|
let index = 0;
|
|
588
566
|
let line = 1;
|
|
589
567
|
let column = 1;
|
|
@@ -592,9 +570,7 @@ function createIndexMap(source) {
|
|
|
592
570
|
if (char === "\n" || char === "\r\n") {
|
|
593
571
|
line++;
|
|
594
572
|
column = 0;
|
|
595
|
-
} else
|
|
596
|
-
column++;
|
|
597
|
-
}
|
|
573
|
+
} else column++;
|
|
598
574
|
}
|
|
599
575
|
return map;
|
|
600
576
|
}
|
|
@@ -644,9 +620,7 @@ class Typechecker {
|
|
|
644
620
|
}
|
|
645
621
|
async collectTests() {
|
|
646
622
|
const tests = (await Promise.all(this.getFiles().map((filepath) => this.collectFileTests(filepath)))).reduce((acc, data) => {
|
|
647
|
-
if (!data)
|
|
648
|
-
return acc;
|
|
649
|
-
}
|
|
623
|
+
if (!data) return acc;
|
|
650
624
|
acc[data.filepath] = data;
|
|
651
625
|
return acc;
|
|
652
626
|
}, {});
|
|
@@ -654,17 +628,11 @@ class Typechecker {
|
|
|
654
628
|
return tests;
|
|
655
629
|
}
|
|
656
630
|
markPassed(file) {
|
|
657
|
-
if (!file.result?.state) {
|
|
658
|
-
file.result = { state: "pass" };
|
|
659
|
-
}
|
|
631
|
+
if (!file.result?.state) file.result = { state: "pass" };
|
|
660
632
|
const markTasks = (tasks) => {
|
|
661
633
|
for (const task of tasks) {
|
|
662
|
-
if ("tasks" in task)
|
|
663
|
-
|
|
664
|
-
}
|
|
665
|
-
if (!task.result?.state && (task.mode === "run" || task.mode === "queued")) {
|
|
666
|
-
task.result = { state: "pass" };
|
|
667
|
-
}
|
|
634
|
+
if ("tasks" in task) markTasks(task.tasks);
|
|
635
|
+
if (!task.result?.state && (task.mode === "run" || task.mode === "queued")) task.result = { state: "pass" };
|
|
668
636
|
}
|
|
669
637
|
};
|
|
670
638
|
markTasks(file.tasks);
|
|
@@ -672,9 +640,7 @@ class Typechecker {
|
|
|
672
640
|
async prepareResults(output) {
|
|
673
641
|
const typeErrors = await this.parseTscLikeOutput(output);
|
|
674
642
|
const testFiles = new Set(this.getFiles());
|
|
675
|
-
if (!this._tests)
|
|
676
|
-
this._tests = await this.collectTests();
|
|
677
|
-
}
|
|
643
|
+
if (!this._tests) this._tests = await this.collectTests();
|
|
678
644
|
const sourceErrors = [];
|
|
679
645
|
const files = [];
|
|
680
646
|
testFiles.forEach((path) => {
|
|
@@ -686,15 +652,13 @@ class Typechecker {
|
|
|
686
652
|
return;
|
|
687
653
|
}
|
|
688
654
|
const sortedDefinitions = [...definitions.sort((a, b) => b.start - a.start)];
|
|
655
|
+
// has no map for ".js" files that use // @ts-check
|
|
689
656
|
const traceMap = map && new TraceMap(map);
|
|
690
657
|
const indexMap = createIndexMap(parsed);
|
|
691
658
|
const markState = (task, state) => {
|
|
692
659
|
task.result = { state: task.mode === "run" || task.mode === "only" ? state : task.mode };
|
|
693
|
-
if (task.suite)
|
|
694
|
-
|
|
695
|
-
} else if (task.file && task !== task.file) {
|
|
696
|
-
markState(task.file, state);
|
|
697
|
-
}
|
|
660
|
+
if (task.suite) markState(task.suite, state);
|
|
661
|
+
else if (task.file && task !== task.file) markState(task.file, state);
|
|
698
662
|
};
|
|
699
663
|
errors.forEach(({ error, originalError }) => {
|
|
700
664
|
const processedPos = traceMap ? findGeneratedPosition(traceMap, {
|
|
@@ -715,19 +679,14 @@ class Typechecker {
|
|
|
715
679
|
};
|
|
716
680
|
errors.push(error);
|
|
717
681
|
if (state === "fail") {
|
|
718
|
-
if (suite.suite)
|
|
719
|
-
|
|
720
|
-
} else if (suite.file && suite !== suite.file) {
|
|
721
|
-
markState(suite.file, "fail");
|
|
722
|
-
}
|
|
682
|
+
if (suite.suite) markState(suite.suite, "fail");
|
|
683
|
+
else if (suite.file && suite !== suite.file) markState(suite.file, "fail");
|
|
723
684
|
}
|
|
724
685
|
});
|
|
725
686
|
this.markPassed(file);
|
|
726
687
|
});
|
|
727
688
|
typeErrors.forEach((errors, path) => {
|
|
728
|
-
if (!testFiles.has(path)) {
|
|
729
|
-
sourceErrors.push(...errors.map(({ error }) => error));
|
|
730
|
-
}
|
|
689
|
+
if (!testFiles.has(path)) sourceErrors.push(...errors.map(({ error }) => error));
|
|
731
690
|
});
|
|
732
691
|
return {
|
|
733
692
|
files,
|
|
@@ -737,12 +696,13 @@ class Typechecker {
|
|
|
737
696
|
}
|
|
738
697
|
async parseTscLikeOutput(output) {
|
|
739
698
|
const errorsMap = await getRawErrsMapFromTsCompile(output);
|
|
740
|
-
const typesErrors = new Map();
|
|
699
|
+
const typesErrors = /* @__PURE__ */ new Map();
|
|
741
700
|
errorsMap.forEach((errors, path) => {
|
|
742
701
|
const filepath = resolve(this.project.config.root, path);
|
|
743
702
|
const suiteErrors = errors.map((info) => {
|
|
744
703
|
const limit = Error.stackTraceLimit;
|
|
745
704
|
Error.stackTraceLimit = 0;
|
|
705
|
+
// Some expect-type errors have the most useful information on the second line e.g. `This expression is not callable.\n Type 'ExpectString<number>' has no call signatures.`
|
|
746
706
|
const errMsg = info.errMsg.replace(/\r?\n\s*(Type .* has no call signatures)/g, " $1");
|
|
747
707
|
const error = new TypeCheckError(errMsg, [{
|
|
748
708
|
file: filepath,
|
|
@@ -755,11 +715,9 @@ class Typechecker {
|
|
|
755
715
|
originalError: info,
|
|
756
716
|
error: {
|
|
757
717
|
name: error.name,
|
|
758
|
-
nameStr: String(error.name),
|
|
759
718
|
message: errMsg,
|
|
760
719
|
stacks: error.stacks,
|
|
761
|
-
stack: ""
|
|
762
|
-
stackStr: ""
|
|
720
|
+
stack: ""
|
|
763
721
|
}
|
|
764
722
|
};
|
|
765
723
|
});
|
|
@@ -769,12 +727,10 @@ class Typechecker {
|
|
|
769
727
|
}
|
|
770
728
|
async stop() {
|
|
771
729
|
this.process?.kill();
|
|
772
|
-
this.process =
|
|
730
|
+
this.process = void 0;
|
|
773
731
|
}
|
|
774
732
|
async ensurePackageInstalled(ctx, checker) {
|
|
775
|
-
if (checker !== "tsc" && checker !== "vue-tsc")
|
|
776
|
-
return;
|
|
777
|
-
}
|
|
733
|
+
if (checker !== "tsc" && checker !== "vue-tsc") return;
|
|
778
734
|
const packageName = checker === "tsc" ? "typescript" : "vue-tsc";
|
|
779
735
|
await ctx.packageInstaller.ensureInstalled(packageName, ctx.config.root);
|
|
780
736
|
}
|
|
@@ -784,10 +740,7 @@ class Typechecker {
|
|
|
784
740
|
getOutput() {
|
|
785
741
|
return this._output;
|
|
786
742
|
}
|
|
787
|
-
async
|
|
788
|
-
if (this.process) {
|
|
789
|
-
return;
|
|
790
|
-
}
|
|
743
|
+
async spawn() {
|
|
791
744
|
const { root, watch, typecheck } = this.project.config;
|
|
792
745
|
const args = [
|
|
793
746
|
"--noEmit",
|
|
@@ -797,15 +750,10 @@ class Typechecker {
|
|
|
797
750
|
"--tsBuildInfoFile",
|
|
798
751
|
join(process.versions.pnp ? join(nodeos__default.tmpdir(), this.project.hash) : distDir, "tsconfig.tmp.tsbuildinfo")
|
|
799
752
|
];
|
|
800
|
-
|
|
801
|
-
|
|
802
|
-
|
|
803
|
-
if (typecheck.
|
|
804
|
-
args.push("--allowJs", "--checkJs");
|
|
805
|
-
}
|
|
806
|
-
if (typecheck.tsconfig) {
|
|
807
|
-
args.push("-p", resolve(root, typecheck.tsconfig));
|
|
808
|
-
}
|
|
753
|
+
// use builtin watcher because it's faster
|
|
754
|
+
if (watch) args.push("--watch");
|
|
755
|
+
if (typecheck.allowJs) args.push("--allowJs", "--checkJs");
|
|
756
|
+
if (typecheck.tsconfig) args.push("-p", resolve(root, typecheck.tsconfig));
|
|
809
757
|
this._output = "";
|
|
810
758
|
this._startTime = performance.now();
|
|
811
759
|
const child = x(typecheck.checker, args, {
|
|
@@ -816,30 +764,62 @@ class Typechecker {
|
|
|
816
764
|
throwOnError: false
|
|
817
765
|
});
|
|
818
766
|
this.process = child.process;
|
|
819
|
-
await this._onParseStart?.();
|
|
820
767
|
let rerunTriggered = false;
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
if (!
|
|
768
|
+
let dataReceived = false;
|
|
769
|
+
return new Promise((resolve, reject) => {
|
|
770
|
+
if (!child.process || !child.process.stdout) {
|
|
771
|
+
reject(new Error(`Failed to initialize ${typecheck.checker}. This is a bug in Vitest - please, open an issue with reproduction.`));
|
|
824
772
|
return;
|
|
825
773
|
}
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
this.
|
|
829
|
-
|
|
830
|
-
this.
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
774
|
+
child.process.stdout.on("data", (chunk) => {
|
|
775
|
+
dataReceived = true;
|
|
776
|
+
this._output += chunk;
|
|
777
|
+
if (!watch) return;
|
|
778
|
+
if (this._output.includes("File change detected") && !rerunTriggered) {
|
|
779
|
+
this._onWatcherRerun?.();
|
|
780
|
+
this._startTime = performance.now();
|
|
781
|
+
this._result.sourceErrors = [];
|
|
782
|
+
this._result.files = [];
|
|
783
|
+
this._tests = null;
|
|
784
|
+
rerunTriggered = true;
|
|
785
|
+
}
|
|
786
|
+
if (/Found \w+ errors*. Watching for/.test(this._output)) {
|
|
787
|
+
rerunTriggered = false;
|
|
788
|
+
this.prepareResults(this._output).then((result) => {
|
|
789
|
+
this._result = result;
|
|
790
|
+
this._onParseEnd?.(result);
|
|
791
|
+
});
|
|
792
|
+
this._output = "";
|
|
793
|
+
}
|
|
794
|
+
});
|
|
795
|
+
const timeout = setTimeout(() => reject(new Error(`${typecheck.checker} spawn timed out`)), this.project.config.typecheck.spawnTimeout);
|
|
796
|
+
function onError(cause) {
|
|
797
|
+
clearTimeout(timeout);
|
|
798
|
+
reject(new Error("Spawning typechecker failed - is typescript installed?", { cause }));
|
|
841
799
|
}
|
|
800
|
+
child.process.once("spawn", () => {
|
|
801
|
+
this._onParseStart?.();
|
|
802
|
+
child.process?.off("error", onError);
|
|
803
|
+
clearTimeout(timeout);
|
|
804
|
+
if (process.platform === "win32")
|
|
805
|
+
// on Windows, the process might be spawned but fail to start
|
|
806
|
+
// we wait for a potential error here. if "close" event didn't trigger,
|
|
807
|
+
// we resolve the promise
|
|
808
|
+
setTimeout(() => {
|
|
809
|
+
resolve({ result: child });
|
|
810
|
+
}, 200);
|
|
811
|
+
else resolve({ result: child });
|
|
812
|
+
});
|
|
813
|
+
if (process.platform === "win32") child.process.once("close", (code) => {
|
|
814
|
+
if (code != null && code !== 0 && !dataReceived) onError(new Error(`The ${typecheck.checker} command exited with code ${code}.`));
|
|
815
|
+
});
|
|
816
|
+
child.process.once("error", onError);
|
|
842
817
|
});
|
|
818
|
+
}
|
|
819
|
+
async start() {
|
|
820
|
+
if (this.process) return;
|
|
821
|
+
const { watch } = this.project.config;
|
|
822
|
+
const { result: child } = await this.spawn();
|
|
843
823
|
if (!watch) {
|
|
844
824
|
await child;
|
|
845
825
|
this._result = await this.prepareResults(this._output);
|
|
@@ -872,22 +852,19 @@ function findGeneratedPosition(traceMap, { line, column, source }) {
|
|
|
872
852
|
column,
|
|
873
853
|
source
|
|
874
854
|
});
|
|
875
|
-
if (found.line !== null)
|
|
876
|
-
|
|
877
|
-
|
|
855
|
+
if (found.line !== null) return found;
|
|
856
|
+
// find the next source token position when the exact error position doesn't exist in source map.
|
|
857
|
+
// this can happen, for example, when the type error is in the comment "// @ts-expect-error"
|
|
858
|
+
// and comments are stripped away in the generated code.
|
|
878
859
|
const mappings = [];
|
|
879
860
|
eachMapping(traceMap, (m) => {
|
|
880
|
-
if (m.source === source && m.originalLine !== null && m.originalColumn !== null && (line === m.originalLine ? column < m.originalColumn : line < m.originalLine))
|
|
881
|
-
mappings.push(m);
|
|
882
|
-
}
|
|
861
|
+
if (m.source === source && m.originalLine !== null && m.originalColumn !== null && (line === m.originalLine ? column < m.originalColumn : line < m.originalLine)) mappings.push(m);
|
|
883
862
|
});
|
|
884
863
|
const next = mappings.sort((a, b) => a.originalLine === b.originalLine ? a.originalColumn - b.originalColumn : a.originalLine - b.originalLine).at(0);
|
|
885
|
-
if (next) {
|
|
886
|
-
|
|
887
|
-
|
|
888
|
-
|
|
889
|
-
};
|
|
890
|
-
}
|
|
864
|
+
if (next) return {
|
|
865
|
+
line: next.generatedLine,
|
|
866
|
+
column: next.generatedColumn
|
|
867
|
+
};
|
|
891
868
|
return {
|
|
892
869
|
line: null,
|
|
893
870
|
column: null
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { parseRegexp } from '@vitest/utils';
|
|
2
2
|
|
|
3
3
|
const REGEXP_WRAP_PREFIX = "$$vitest:";
|
|
4
|
+
// Store global APIs in case process is overwritten by tests
|
|
4
5
|
const processSend = process.send?.bind(process);
|
|
5
6
|
const processOn = process.on?.bind(process);
|
|
6
7
|
const processOff = process.off?.bind(process);
|
|
@@ -16,11 +17,9 @@ function createThreadsRpcOptions({ port }) {
|
|
|
16
17
|
};
|
|
17
18
|
}
|
|
18
19
|
function disposeInternalListeners() {
|
|
19
|
-
for (const fn of dispose) {
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
} catch {}
|
|
23
|
-
}
|
|
20
|
+
for (const fn of dispose) try {
|
|
21
|
+
fn();
|
|
22
|
+
} catch {}
|
|
24
23
|
dispose.length = 0;
|
|
25
24
|
}
|
|
26
25
|
function createForksRpcOptions(nodeV8) {
|
|
@@ -32,9 +31,8 @@ function createForksRpcOptions(nodeV8) {
|
|
|
32
31
|
},
|
|
33
32
|
on(fn) {
|
|
34
33
|
const handler = (message, ...extras) => {
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
}
|
|
34
|
+
// Do not react on Tinypool's internal messaging
|
|
35
|
+
if (message?.__tinypool_worker_message__) return;
|
|
38
36
|
return fn(message, ...extras);
|
|
39
37
|
};
|
|
40
38
|
processOn("message", handler);
|
|
@@ -48,16 +46,13 @@ function createForksRpcOptions(nodeV8) {
|
|
|
48
46
|
function unwrapSerializableConfig(config) {
|
|
49
47
|
if (config.testNamePattern && typeof config.testNamePattern === "string") {
|
|
50
48
|
const testNamePattern = config.testNamePattern;
|
|
51
|
-
if (testNamePattern.startsWith(REGEXP_WRAP_PREFIX))
|
|
52
|
-
config.testNamePattern = parseRegexp(testNamePattern.slice(REGEXP_WRAP_PREFIX.length));
|
|
53
|
-
}
|
|
49
|
+
if (testNamePattern.startsWith(REGEXP_WRAP_PREFIX)) config.testNamePattern = parseRegexp(testNamePattern.slice(REGEXP_WRAP_PREFIX.length));
|
|
54
50
|
}
|
|
55
51
|
if (config.defines && Array.isArray(config.defines.keys) && config.defines.original) {
|
|
56
52
|
const { keys, original } = config.defines;
|
|
57
53
|
const defines = {};
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
}
|
|
54
|
+
// Apply all keys from the original. Entries which had undefined value are missing from original now
|
|
55
|
+
for (const key of keys) defines[key] = original[key];
|
|
61
56
|
config.defines = defines;
|
|
62
57
|
}
|
|
63
58
|
return config;
|