vitest 3.0.0-beta.3 → 3.0.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.
Files changed (54) hide show
  1. package/LICENSE.md +1 -315
  2. package/config.d.ts +2 -0
  3. package/dist/browser.d.ts +3 -3
  4. package/dist/browser.js +1 -1
  5. package/dist/chunks/{base.CQ2VEtuH.js → base.CUDzyU2J.js} +2 -2
  6. package/dist/chunks/{cac.e7qW4xLT.js → cac.DZC9WjGM.js} +8 -8
  7. package/dist/chunks/{cli-api.CWDlED-m.js → cli-api.CmJw5Cd_.js} +920 -84
  8. package/dist/chunks/{config.BTPBhmK5.d.ts → config.BRtC-JeT.d.ts} +6 -0
  9. package/dist/chunks/{console.BYGVloWk.js → console.CN7AiMGV.js} +16 -7
  10. package/dist/chunks/{creator.Ot9GlSGw.js → creator.DztqrnyH.js} +1 -1
  11. package/dist/chunks/{execute.2pr0rHgK.js → execute.BMOaRArH.js} +27 -16
  12. package/dist/chunks/global.CnI8_G5V.d.ts +133 -0
  13. package/dist/chunks/{globals.BFncSRNA.js → globals.C5RQxaV3.js} +2 -2
  14. package/dist/chunks/{index.CkWmZCXU.js → index.BQbxGbG9.js} +1 -1
  15. package/dist/chunks/{index.BBoOXW-l.js → index.CUcwvygK.js} +5 -5
  16. package/dist/chunks/{index.DQboAxJm.js → index.D9C26wCk.js} +1 -0
  17. package/dist/chunks/index.TKSL1HjN.js +2460 -0
  18. package/dist/chunks/{reporters.DCiyjXOg.d.ts → reporters.Y8BYiXBN.d.ts} +412 -386
  19. package/dist/chunks/{resolveConfig.C1d7TK-U.js → resolveConfig.CSLLD33d.js} +140 -55
  20. package/dist/chunks/{rpc.C3q9uwRX.js → rpc.TVf73xOu.js} +0 -1
  21. package/dist/chunks/{runBaseTests.qNWRkgHj.js → runBaseTests.C0T_TQwH.js} +9 -7
  22. package/dist/chunks/{setup-common.Cp_bu5q3.js → setup-common.D0zLenuv.js} +1 -1
  23. package/dist/chunks/{RandomSequencer.C6x84bNN.js → typechecker.BJMkWMXo.js} +84 -108
  24. package/dist/chunks/{utils.Coei4Wlj.js → utils.DJWL04yX.js} +9 -20
  25. package/dist/chunks/{vi.S4Fq8wSo.js → vi.Da_PT3Vw.js} +554 -272
  26. package/dist/chunks/{vite.CRSMFy31.d.ts → vite.CQ0dHgkN.d.ts} +1 -1
  27. package/dist/chunks/{vm.DGhTouO3.js → vm.DrFVeTXo.js} +4 -4
  28. package/dist/chunks/{worker.R-PA7DpW.d.ts → worker.B1y96qmv.d.ts} +1 -1
  29. package/dist/chunks/{worker.XbtCXEXv.d.ts → worker.CIpff8Eg.d.ts} +3 -5
  30. package/dist/cli.js +1 -1
  31. package/dist/config.d.ts +4 -4
  32. package/dist/coverage.d.ts +2 -2
  33. package/dist/coverage.js +5 -4
  34. package/dist/execute.d.ts +3 -3
  35. package/dist/execute.js +1 -1
  36. package/dist/index.d.ts +18 -119
  37. package/dist/index.js +2 -2
  38. package/dist/node.d.ts +12 -9
  39. package/dist/node.js +25 -24
  40. package/dist/reporters.d.ts +2 -2
  41. package/dist/reporters.js +4 -10
  42. package/dist/runners.d.ts +2 -1
  43. package/dist/runners.js +9 -16
  44. package/dist/worker.js +1 -1
  45. package/dist/workers/forks.js +2 -2
  46. package/dist/workers/runVmTests.js +8 -6
  47. package/dist/workers/threads.js +2 -2
  48. package/dist/workers/vmForks.js +3 -3
  49. package/dist/workers/vmThreads.js +3 -3
  50. package/dist/workers.d.ts +3 -3
  51. package/dist/workers.js +5 -5
  52. package/package.json +17 -19
  53. package/dist/chunks/index.CzkCSFCy.js +0 -5455
  54. package/dist/chunks/types.BOjykUpq.d.ts +0 -27
@@ -1,10 +1,11 @@
1
1
  import { isCI } from 'std-env';
2
2
  import { writeFile, rm } from 'node:fs/promises';
3
3
  import { performance } from 'node:perf_hooks';
4
- import { generateHash, calculateSuiteHash, someTasksAreOnly, interpretTaskModes, getTasks } from '@vitest/runner/utils';
5
- import { TraceMap, generatedPositionFor } from '@vitest/utils/source-map';
4
+ import { TraceMap, generatedPositionFor, eachMapping } from '@vitest/utils/source-map';
6
5
  import { relative, basename, dirname, resolve, join, extname } from 'pathe';
7
6
  import { x as x$1 } from 'tinyexec';
7
+ import { getTests, generateHash, calculateSuiteHash, someTasksAreOnly, interpretTaskModes } from '@vitest/runner/utils';
8
+ import '@vitest/utils';
8
9
  import { parseAstAsync } from 'vite';
9
10
  import nodeos__default from 'node:os';
10
11
  import url from 'node:url';
@@ -12,11 +13,37 @@ import a$1 from 'node:path';
12
13
  import fs from 'node:fs';
13
14
  import Te from 'node:module';
14
15
  import require$$0 from 'fs';
15
- import { shuffle } from '@vitest/utils';
16
- import { slash } from 'vite-node/utils';
17
- import crypto from 'node:crypto';
18
16
 
19
- const hash = crypto.hash ?? ((algorithm, data, outputEncoding) => crypto.createHash(algorithm).update(data).digest(outputEncoding));
17
+ function hasFailedSnapshot(suite) {
18
+ return getTests(suite).some((s) => {
19
+ return s.result?.errors?.some(
20
+ (e) => typeof e?.message === "string" && e.message.match(/Snapshot .* mismatched/)
21
+ );
22
+ });
23
+ }
24
+ function convertTasksToEvents(file, onTask) {
25
+ const packs = [];
26
+ const events = [];
27
+ function visit(suite) {
28
+ onTask?.(suite);
29
+ packs.push([suite.id, suite.result, suite.meta]);
30
+ events.push([suite.id, "suite-prepare"]);
31
+ suite.tasks.forEach((task) => {
32
+ if (task.type === "suite") {
33
+ visit(task);
34
+ } else {
35
+ onTask?.(task);
36
+ packs.push([task.id, task.result, task.meta]);
37
+ if (task.mode !== "skip" && task.mode !== "todo") {
38
+ events.push([task.id, "test-prepare"], [task.id, "test-finished"]);
39
+ }
40
+ }
41
+ });
42
+ events.push([suite.id, "suite-finished"]);
43
+ }
44
+ visit(file);
45
+ return { packs, events };
46
+ }
20
47
 
21
48
  const isNode = typeof process < "u" && typeof process.stdout < "u" && !process.versions?.deno && !globalThis.window;
22
49
  const isDeno = typeof process < "u" && typeof process.stdout < "u" && process.versions?.deno !== void 0;
@@ -363,17 +390,13 @@ async function collectTests(ctx, filepath) {
363
390
  return getName(callee.tag);
364
391
  }
365
392
  if (callee.type === "MemberExpression") {
366
- const object = callee.object;
367
- if (object?.name?.startsWith("__vite_ssr_")) {
368
- return getName(callee.property);
393
+ if (callee.object?.type === "Identifier" && ["it", "test", "describe", "suite"].includes(callee.object.name)) {
394
+ return callee.object?.name;
369
395
  }
370
- return getName(object?.property);
371
- }
372
- if (callee.type === "SequenceExpression" && callee.expressions.length === 2) {
373
- const [e0, e1] = callee.expressions;
374
- if (e0.type === "Literal" && e0.value === 0) {
375
- return getName(e1);
396
+ if (callee.object?.name?.startsWith("__vite_ssr_")) {
397
+ return getName(callee.property);
376
398
  }
399
+ return getName(callee.object?.property);
377
400
  }
378
401
  return null;
379
402
  };
@@ -388,8 +411,8 @@ async function collectTests(ctx, filepath) {
388
411
  return;
389
412
  }
390
413
  const property = callee?.property?.name;
391
- const mode = !property || property === name ? "run" : property;
392
- if (mode === "each" || mode === "skipIf" || mode === "runIf" || mode === "for") {
414
+ let mode = !property || property === name ? "run" : property;
415
+ if (["each", "for", "skipIf", "runIf"].includes(mode)) {
393
416
  return;
394
417
  }
395
418
  let start;
@@ -404,10 +427,11 @@ async function collectTests(ctx, filepath) {
404
427
  const {
405
428
  arguments: [messageNode]
406
429
  } = node;
407
- if (!messageNode) {
408
- return;
430
+ const isQuoted = messageNode?.type === "Literal" || messageNode?.type === "TemplateLiteral";
431
+ const message = isQuoted ? request.code.slice(messageNode.start + 1, messageNode.end - 1) : request.code.slice(messageNode.start, messageNode.end);
432
+ if (mode === "skipIf" || mode === "runIf") {
433
+ mode = "skip";
409
434
  }
410
- const message = getNodeAsString(messageNode, request.code);
411
435
  definitions.push({
412
436
  start,
413
437
  end,
@@ -487,35 +511,6 @@ async function collectTests(ctx, filepath) {
487
511
  definitions
488
512
  };
489
513
  }
490
- function getNodeAsString(node, code) {
491
- if (node.type === "Literal") {
492
- return String(node.value);
493
- } else if (node.type === "Identifier") {
494
- return node.name;
495
- } else if (node.type === "TemplateLiteral") {
496
- return mergeTemplateLiteral(node, code);
497
- } else {
498
- return code.slice(node.start, node.end);
499
- }
500
- }
501
- function mergeTemplateLiteral(node, code) {
502
- let result = "";
503
- let expressionsIndex = 0;
504
- for (let quasisIndex = 0; quasisIndex < node.quasis.length; quasisIndex++) {
505
- result += node.quasis[quasisIndex].value.raw;
506
- if (expressionsIndex in node.expressions) {
507
- const expression = node.expressions[expressionsIndex];
508
- const string = expression.type === "Literal" ? expression.raw : getNodeAsString(expression, code);
509
- if (expression.type === "TemplateLiteral") {
510
- result += `\${\`${string}\`}`;
511
- } else {
512
- result += `\${${string}}`;
513
- }
514
- expressionsIndex++;
515
- }
516
- }
517
- return result;
518
- }
519
514
 
520
515
  const A=r=>r!==null&&typeof r=="object",a=(r,t)=>Object.assign(new Error(`[${r}]: ${t}`),{code:r}),_="ERR_INVALID_PACKAGE_CONFIG",E="ERR_INVALID_PACKAGE_TARGET",I$1="ERR_PACKAGE_PATH_NOT_EXPORTED",R$1=/^\d+$/,O=/^(\.{1,2}|node_modules)$/i,w=/\/|\\/;var h$1=(r=>(r.Export="exports",r.Import="imports",r))(h$1||{});const f=(r,t,e,o,c)=>{if(t==null)return [];if(typeof t=="string"){const[n,...i]=t.split(w);if(n===".."||i.some(l=>O.test(l)))throw a(E,`Invalid "${r}" target "${t}" defined in the package config`);return [c?t.replace(/\*/g,c):t]}if(Array.isArray(t))return t.flatMap(n=>f(r,n,e,o,c));if(A(t)){for(const n of Object.keys(t)){if(R$1.test(n))throw a(_,"Cannot contain numeric property keys");if(n==="default"||o.includes(n))return f(r,t[n],e,o,c)}return []}throw a(E,`Invalid "${r}" target "${t}"`)},s="*",m=(r,t)=>{const e=r.indexOf(s),o=t.indexOf(s);return e===o?t.length>r.length:o>e};function d(r,t){if(!t.includes(s)&&r.hasOwnProperty(t))return [t];let e,o;for(const c of Object.keys(r))if(c.includes(s)){const[n,i,l]=c.split(s);if(l===void 0&&t.startsWith(n)&&t.endsWith(i)){const g=t.slice(n.length,-i.length||void 0);g&&(!e||m(e,c))&&(e=c,o=g);}}return [e,o]}const p=r=>Object.keys(r).reduce((t,e)=>{const o=e===""||e[0]!==".";if(t===void 0||t===o)return o;throw a(_,'"exports" cannot contain some keys starting with "." and some not')},void 0),u=/^\w+:/,v=(r,t,e)=>{if(!r)throw new Error('"exports" is required');t=t===""?".":`./${t}`,(typeof r=="string"||Array.isArray(r)||A(r)&&p(r))&&(r={".":r});const[o,c]=d(r,t),n=f(h$1.Export,r[o],t,e,c);if(n.length===0)throw a(I$1,t==="."?'No "exports" main defined':`Package subpath '${t}' is not defined by "exports"`);for(const i of n)if(!i.startsWith("./")&&!u.test(i))throw a(E,`Invalid "exports" target "${i}" defined in the package config`);return n};
521
516
 
@@ -573,9 +568,12 @@ async function getTsconfig(root, config) {
573
568
  if (!tsconfig) {
574
569
  throw new Error("no tsconfig.json found");
575
570
  }
571
+ const tsconfigName = basename(tsconfig.path, ".json");
572
+ const tempTsConfigName = `${tsconfigName}.vitest-temp.json`;
573
+ const tempTsbuildinfoName = `${tsconfigName}.tmp.tsbuildinfo`;
576
574
  const tempConfigPath = join(
577
575
  dirname(tsconfig.path),
578
- "tsconfig.vitest-temp.json"
576
+ tempTsConfigName
579
577
  );
580
578
  try {
581
579
  const tmpTsConfig = { ...tsconfig.config };
@@ -584,13 +582,13 @@ async function getTsconfig(root, config) {
584
582
  tmpTsConfig.compilerOptions.incremental = true;
585
583
  tmpTsConfig.compilerOptions.tsBuildInfoFile = join(
586
584
  process.versions.pnp ? join(nodeos__default.tmpdir(), "vitest") : __dirname,
587
- "tsconfig.tmp.tsbuildinfo"
585
+ tempTsbuildinfoName
588
586
  );
589
587
  const tsconfigFinalContent = JSON.stringify(tmpTsConfig, null, 2);
590
588
  await writeFile(tempConfigPath, tsconfigFinalContent);
591
589
  return { path: tempConfigPath, config: tmpTsConfig };
592
590
  } catch (err) {
593
- throw new Error("failed to write tsconfig.temp.json", { cause: err });
591
+ throw new Error(`failed to write ${tempTsConfigName}`, { cause: err });
594
592
  }
595
593
  }
596
594
  async function getRawErrsMapFromTsCompile(tscErrorStdout) {
@@ -751,7 +749,7 @@ class Typechecker {
751
749
  }
752
750
  };
753
751
  errors.forEach(({ error, originalError }) => {
754
- const processedPos = traceMap ? generatedPositionFor(traceMap, {
752
+ const processedPos = traceMap ? findGeneratedPosition(traceMap, {
755
753
  line: originalError.line,
756
754
  column: originalError.column,
757
755
  source: basename(path)
@@ -918,64 +916,42 @@ class Typechecker {
918
916
  getTestFiles() {
919
917
  return Object.values(this._tests || {}).map((i) => i.file);
920
918
  }
921
- getTestPacks() {
922
- return Object.values(this._tests || {}).map(({ file }) => getTasks(file)).flat().map((i) => [i.id, i.result, { typecheck: true }]);
919
+ getTestPacksAndEvents() {
920
+ const packs = [];
921
+ const events = [];
922
+ for (const { file } of Object.values(this._tests || {})) {
923
+ const result = convertTasksToEvents(file);
924
+ packs.push(...result.packs);
925
+ events.push(...result.events);
926
+ }
927
+ return { packs, events };
923
928
  }
924
929
  }
925
-
926
- class BaseSequencer {
927
- ctx;
928
- constructor(ctx) {
929
- this.ctx = ctx;
930
- }
931
- // async so it can be extended by other sequelizers
932
- async shard(files) {
933
- const { config } = this.ctx;
934
- const { index, count } = config.shard;
935
- const shardSize = Math.ceil(files.length / count);
936
- const shardStart = shardSize * (index - 1);
937
- const shardEnd = shardSize * index;
938
- return [...files].map((spec) => {
939
- const fullPath = resolve(slash(config.root), slash(spec.moduleId));
940
- const specPath = fullPath?.slice(config.root.length);
941
- return {
942
- spec,
943
- hash: hash("sha1", specPath, "hex")
944
- };
945
- }).sort((a, b) => a.hash < b.hash ? -1 : a.hash > b.hash ? 1 : 0).slice(shardStart, shardEnd).map(({ spec }) => spec);
946
- }
947
- // async so it can be extended by other sequelizers
948
- async sort(files) {
949
- const cache = this.ctx.cache;
950
- return [...files].sort((a, b) => {
951
- const keyA = `${a.project.name}:${relative(this.ctx.config.root, a.moduleId)}`;
952
- const keyB = `${b.project.name}:${relative(this.ctx.config.root, b.moduleId)}`;
953
- const aState = cache.getFileTestResults(keyA);
954
- const bState = cache.getFileTestResults(keyB);
955
- if (!aState || !bState) {
956
- const statsA = cache.getFileStats(keyA);
957
- const statsB = cache.getFileStats(keyB);
958
- if (!statsA || !statsB) {
959
- return !statsA && statsB ? -1 : !statsB && statsA ? 1 : 0;
960
- }
961
- return statsB.size - statsA.size;
962
- }
963
- if (aState.failed && !bState.failed) {
964
- return -1;
965
- }
966
- if (!aState.failed && bState.failed) {
967
- return 1;
968
- }
969
- return bState.duration - aState.duration;
970
- });
930
+ function findGeneratedPosition(traceMap, { line, column, source }) {
931
+ const found = generatedPositionFor(traceMap, {
932
+ line,
933
+ column,
934
+ source
935
+ });
936
+ if (found.line !== null) {
937
+ return found;
971
938
  }
972
- }
973
-
974
- class RandomSequencer extends BaseSequencer {
975
- async sort(files) {
976
- const { sequence } = this.ctx.config;
977
- return shuffle(files, sequence.seed);
939
+ const mappings = [];
940
+ eachMapping(traceMap, (m) => {
941
+ if (m.source === source && m.originalLine !== null && m.originalColumn !== null && (line === m.originalLine ? column < m.originalColumn : line < m.originalLine)) {
942
+ mappings.push(m);
943
+ }
944
+ });
945
+ const next = mappings.sort(
946
+ (a, b) => a.originalLine === b.originalLine ? a.originalColumn - b.originalColumn : a.originalLine - b.originalLine
947
+ ).at(0);
948
+ if (next) {
949
+ return {
950
+ line: next.generatedLine,
951
+ column: next.generatedColumn
952
+ };
978
953
  }
954
+ return { line: null, column: null };
979
955
  }
980
956
 
981
- export { BaseSequencer as B, RandomSequencer as R, Typechecker as T, TypeCheckError as a, isTTY as b, getOutputFile as g, hash as h, isWindows as i, wrapSerializableConfig as w };
957
+ export { TypeCheckError as T, Typechecker as a, isWindows as b, convertTasksToEvents as c, getOutputFile as g, hasFailedSnapshot as h, isTTY as i, wrapSerializableConfig as w };
@@ -14,7 +14,6 @@ const F_LONG_DASH = "\u23AF";
14
14
  const F_TREE_NODE_MIDDLE = "\u251C\u2500\u2500";
15
15
  const F_TREE_NODE_END = "\u2514\u2500\u2500";
16
16
 
17
- const spinnerMap = /* @__PURE__ */ new WeakMap();
18
17
  const pointer = c.yellow(F_POINTER);
19
18
  const skipped = c.dim(c.gray(F_DOWN));
20
19
  const benchmarkPass = c.green(F_DOT);
@@ -130,12 +129,6 @@ function getStateSymbol(task) {
130
129
  if (task.type === "suite") {
131
130
  return pointer;
132
131
  }
133
- let spinner = spinnerMap.get(task);
134
- if (!spinner) {
135
- spinner = elegantSpinner();
136
- spinnerMap.set(task, spinner);
137
- }
138
- return c.yellow(spinner());
139
132
  }
140
133
  if (task.result.state === "pass") {
141
134
  return task.meta?.benchmark ? benchmarkPass : testPass;
@@ -145,14 +138,6 @@ function getStateSymbol(task) {
145
138
  }
146
139
  return " ";
147
140
  }
148
- const spinnerFrames = process.platform === "win32" ? ["-", "\\", "|", "/"] : ["\u280B", "\u2819", "\u2839", "\u2838", "\u283C", "\u2834", "\u2826", "\u2827", "\u2807", "\u280F"];
149
- function elegantSpinner() {
150
- let index = 0;
151
- return () => {
152
- index = ++index % spinnerFrames.length;
153
- return spinnerFrames[index];
154
- };
155
- }
156
141
  function formatTimeString(date) {
157
142
  return date.toTimeString().split(" ")[0];
158
143
  }
@@ -179,18 +164,23 @@ function withLabel(color, label, message) {
179
164
  function padSummaryTitle(str) {
180
165
  return c.dim(`${str.padStart(11)} `);
181
166
  }
167
+ function truncateString(text, maxLength) {
168
+ const plainText = stripVTControlCharacters(text);
169
+ if (plainText.length <= maxLength) {
170
+ return text;
171
+ }
172
+ return `${plainText.slice(0, maxLength - 1)}\u2026`;
173
+ }
182
174
 
183
175
  var utils = /*#__PURE__*/Object.freeze({
184
176
  __proto__: null,
185
177
  benchmarkPass: benchmarkPass,
186
178
  countTestErrors: countTestErrors,
187
179
  divider: divider,
188
- elegantSpinner: elegantSpinner,
189
180
  formatProjectName: formatProjectName,
190
181
  formatTestPath: formatTestPath,
191
182
  formatTime: formatTime,
192
183
  formatTimeString: formatTimeString,
193
- getCols: getCols,
194
184
  getStateString: getStateString,
195
185
  getStateSymbol: getStateSymbol,
196
186
  padSummaryTitle: padSummaryTitle,
@@ -198,12 +188,11 @@ var utils = /*#__PURE__*/Object.freeze({
198
188
  pointer: pointer,
199
189
  renderSnapshotSummary: renderSnapshotSummary,
200
190
  skipped: skipped,
201
- spinnerFrames: spinnerFrames,
202
- spinnerMap: spinnerMap,
203
191
  suiteFail: suiteFail,
204
192
  taskFail: taskFail,
205
193
  testPass: testPass,
194
+ truncateString: truncateString,
206
195
  withLabel: withLabel
207
196
  });
208
197
 
209
- export { F_POINTER as F, formatTimeString as a, F_RIGHT as b, F_CHECK as c, divider as d, getStateString as e, formatProjectName as f, getStateSymbol as g, formatTime as h, countTestErrors as i, F_TREE_NODE_END as j, F_TREE_NODE_MIDDLE as k, getCols as l, padSummaryTitle as p, renderSnapshotSummary as r, taskFail as t, utils as u, withLabel as w };
198
+ export { F_POINTER as F, formatProjectName as a, taskFail as b, F_RIGHT as c, divider as d, F_CHECK as e, formatTimeString as f, getStateSymbol as g, getStateString as h, formatTime as i, countTestErrors as j, F_TREE_NODE_END as k, F_TREE_NODE_MIDDLE as l, padSummaryTitle as p, renderSnapshotSummary as r, truncateString as t, utils as u, withLabel as w };