@vitest/runner 2.0.0-beta.1 → 2.0.0-beta.10

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.
@@ -1,4 +1,5 @@
1
1
  import { processError } from '@vitest/utils/error';
2
+ import { relative } from 'pathe';
2
3
  import { toArray } from '@vitest/utils';
3
4
 
4
5
  function partitionSuiteChildren(suite) {
@@ -91,6 +92,22 @@ function calculateSuiteHash(parent) {
91
92
  calculateSuiteHash(t);
92
93
  });
93
94
  }
95
+ function createFileTask(filepath, root, projectName) {
96
+ const path = relative(root, filepath);
97
+ const file = {
98
+ id: generateHash(`${path}${projectName || ""}`),
99
+ name: path,
100
+ type: "suite",
101
+ mode: "run",
102
+ filepath,
103
+ tasks: [],
104
+ meta: /* @__PURE__ */ Object.create(null),
105
+ projectName,
106
+ file: void 0
107
+ };
108
+ file.file = file;
109
+ return file;
110
+ }
94
111
 
95
112
  function createChainable(keys, fn) {
96
113
  function create(context) {
@@ -170,4 +187,4 @@ function getNames(task) {
170
187
  return names;
171
188
  }
172
189
 
173
- export { getTests as a, getTasks as b, calculateSuiteHash as c, getSuites as d, hasFailed as e, getNames as f, generateHash as g, hasTests as h, interpretTaskModes as i, createChainable as j, partitionSuiteChildren as p, someTasksAreOnly as s };
190
+ export { createFileTask as a, getTests as b, calculateSuiteHash as c, getTasks as d, getSuites as e, hasFailed as f, generateHash as g, hasTests as h, interpretTaskModes as i, getNames as j, createChainable as k, partitionSuiteChildren as p, someTasksAreOnly as s };
package/dist/index.d.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  import { VitestRunner } from './types.js';
2
2
  export { CancelReason, VitestRunnerConfig, VitestRunnerConstructor, VitestRunnerImportSource } from './types.js';
3
- import { T as Task, F as File, d as SuiteAPI, e as TestAPI, f as SuiteCollector, g as CustomAPI, h as SuiteHooks, O as OnTestFailedHandler, i as OnTestFinishedHandler, a as Test, C as Custom, S as Suite } from './tasks-Ck0GpLiZ.js';
4
- export { D as DoneCallback, E as ExtendedContext, t as Fixture, s as FixtureFn, r as FixtureOptions, u as Fixtures, v as HookCleanupCallback, H as HookListener, I as InferFixturesTypes, R as RunMode, y as RuntimeContext, B as SequenceHooks, G as SequenceSetupFiles, x as SuiteFactory, k as TaskBase, A as TaskContext, w as TaskCustomOptions, m as TaskMeta, l as TaskPopulated, n as TaskResult, o as TaskResultPack, j as TaskState, z as TestContext, p as TestFunction, q as TestOptions, U as Use } from './tasks-Ck0GpLiZ.js';
3
+ import { T as Task, F as File, d as SuiteAPI, e as TestAPI, f as SuiteCollector, g as CustomAPI, h as SuiteHooks, O as OnTestFailedHandler, i as OnTestFinishedHandler, a as Test, C as Custom, S as Suite } from './tasks-CcHkacEF.js';
4
+ export { D as DoneCallback, E as ExtendedContext, t as Fixture, s as FixtureFn, r as FixtureOptions, u as Fixtures, v as HookCleanupCallback, H as HookListener, I as InferFixturesTypes, R as RunMode, y as RuntimeContext, B as SequenceHooks, G as SequenceSetupFiles, x as SuiteFactory, k as TaskBase, A as TaskContext, w as TaskCustomOptions, m as TaskMeta, l as TaskPopulated, n as TaskResult, o as TaskResultPack, j as TaskState, z as TestContext, p as TestFunction, q as TestOptions, U as Use } from './tasks-CcHkacEF.js';
5
5
  import { Awaitable } from '@vitest/utils';
6
6
  export { processError } from '@vitest/utils/error';
7
7
  import '@vitest/utils/diff';
package/dist/index.js CHANGED
@@ -1,10 +1,10 @@
1
1
  import limit from 'p-limit';
2
- import { getSafeTimers, isObject, createDefer, format, objDisplay, objectAttr, toArray, shuffle } from '@vitest/utils';
2
+ import { getSafeTimers, isObject, createDefer, isNegativeNaN, format, objDisplay, objectAttr, toArray, shuffle } from '@vitest/utils';
3
3
  import { processError } from '@vitest/utils/error';
4
4
  export { processError } from '@vitest/utils/error';
5
- import { j as createChainable, g as generateHash, c as calculateSuiteHash, s as someTasksAreOnly, i as interpretTaskModes, p as partitionSuiteChildren, h as hasTests, e as hasFailed } from './chunk-tasks.js';
6
- import { relative } from 'pathe';
5
+ import { k as createChainable, a as createFileTask, c as calculateSuiteHash, s as someTasksAreOnly, i as interpretTaskModes, p as partitionSuiteChildren, h as hasTests, f as hasFailed } from './chunk-tasks.js';
7
6
  import { parseSingleStack } from '@vitest/utils/source-map';
7
+ import 'pathe';
8
8
 
9
9
  const fnMap = /* @__PURE__ */ new WeakMap();
10
10
  const fixtureMap = /* @__PURE__ */ new WeakMap();
@@ -207,12 +207,17 @@ function getUsedProps(fn) {
207
207
  const args = splitByComma(match[1]);
208
208
  if (!args.length)
209
209
  return [];
210
- const first = args[0];
210
+ let first = args[0];
211
+ if ("__VITEST_FIXTURE_INDEX__" in fn) {
212
+ first = args[fn.__VITEST_FIXTURE_INDEX__];
213
+ if (!first)
214
+ return [];
215
+ }
211
216
  if (!(first.startsWith("{") && first.endsWith("}")))
212
217
  throw new Error(`The first argument inside a fixture must use object destructuring pattern, e.g. ({ test } => {}). Instead, received "${first}".`);
213
218
  const _first = first.slice(1, -1).replace(/\s/g, "");
214
219
  const props = splitByComma(_first).map((prop) => {
215
- return prop.replace(/\:.*|\=.*/g, "");
220
+ return prop.replace(/:.*|=.*/g, "");
216
221
  });
217
222
  const last = props.at(-1);
218
223
  if (last && last.startsWith("..."))
@@ -414,7 +419,8 @@ function createSuiteCollector(name, factory = () => {
414
419
  file: void 0,
415
420
  shuffle,
416
421
  tasks: [],
417
- meta: /* @__PURE__ */ Object.create(null)
422
+ meta: /* @__PURE__ */ Object.create(null),
423
+ concurrent: suiteOptions == null ? void 0 : suiteOptions.concurrent
418
424
  };
419
425
  if (runner && includeLocation && runner.config.includeTaskLocation) {
420
426
  const limit = Error.stackTraceLimit;
@@ -462,8 +468,10 @@ function createSuite() {
462
468
  );
463
469
  if (currentSuite == null ? void 0 : currentSuite.options)
464
470
  options = { ...currentSuite.options, ...options };
465
- options.concurrent = this.concurrent || !this.sequential && (options == null ? void 0 : options.concurrent);
466
- options.sequential = this.sequential || !this.concurrent && (options == null ? void 0 : options.sequential);
471
+ const isConcurrent = options.concurrent || this.concurrent && !this.sequential;
472
+ const isSequential = options.sequential || this.sequential && !this.concurrent;
473
+ options.concurrent = isConcurrent && !isSequential;
474
+ options.sequential = isSequential && !isConcurrent;
467
475
  return createSuiteCollector(formatName(name), factory, mode, this.shuffle, this.each, options);
468
476
  }
469
477
  suiteFn.each = function(cases, ...args) {
@@ -523,6 +531,21 @@ function createTaskCollector(fn, context) {
523
531
  this.setContext("each", void 0);
524
532
  };
525
533
  };
534
+ taskFn.for = function(cases, ...args) {
535
+ const test2 = this.withContext();
536
+ if (Array.isArray(cases) && args.length)
537
+ cases = formatTemplateString(cases, args);
538
+ return (name, optionsOrFn, fnOrOptions) => {
539
+ const _name = formatName(name);
540
+ const { options, handler } = parseArguments(optionsOrFn, fnOrOptions);
541
+ cases.forEach((item, idx) => {
542
+ const handlerWrapper = (ctx) => handler(item, ctx);
543
+ handlerWrapper.__VITEST_FIXTURE_INDEX__ = 1;
544
+ handlerWrapper.toString = () => handler.toString();
545
+ test2(formatTitle(_name, toArray(item), idx), options, handlerWrapper);
546
+ });
547
+ };
548
+ };
526
549
  taskFn.skipIf = function(condition) {
527
550
  return condition ? this.skip : this;
528
551
  };
@@ -554,10 +577,22 @@ function formatTitle(template, items, idx) {
554
577
  template = template.replace(/%%/g, "__vitest_escaped_%__").replace(/%#/g, `${idx}`).replace(/__vitest_escaped_%__/g, "%%");
555
578
  }
556
579
  const count = template.split("%").length - 1;
580
+ if (template.includes("%f")) {
581
+ const placeholders = template.match(/%f/g) || [];
582
+ placeholders.forEach((_, i) => {
583
+ if (isNegativeNaN(items[i]) || Object.is(items[i], -0)) {
584
+ let occurrence = 0;
585
+ template = template.replace(/%f/g, (match) => {
586
+ occurrence++;
587
+ return occurrence === i + 1 ? "-%f" : match;
588
+ });
589
+ }
590
+ });
591
+ }
557
592
  let formatted = format(template, ...items.slice(0, count));
558
593
  if (isObject(items[0])) {
559
594
  formatted = formatted.replace(
560
- /\$([$\w_.]+)/g,
595
+ /\$([$\w.]+)/g,
561
596
  // https://github.com/chaijs/chai/pull/1490
562
597
  (_, key) => {
563
598
  var _a, _b;
@@ -613,22 +648,12 @@ async function runSetupFiles(config, runner) {
613
648
 
614
649
  const now$1 = Date.now;
615
650
  async function collectTests(paths, runner) {
651
+ var _a;
616
652
  const files = [];
617
653
  const config = runner.config;
618
654
  for (const filepath of paths) {
619
- const path = relative(config.root, filepath);
620
- const file = {
621
- id: generateHash(`${path}${config.name || ""}`),
622
- name: path,
623
- type: "suite",
624
- mode: "run",
625
- filepath,
626
- tasks: [],
627
- meta: /* @__PURE__ */ Object.create(null),
628
- projectName: config.name,
629
- file: void 0
630
- };
631
- file.file = file;
655
+ const file = createFileTask(filepath, config.root, config.name);
656
+ (_a = runner.onCollectStart) == null ? void 0 : _a.call(runner, file);
632
657
  clearCollectorContext(filepath, runner);
633
658
  try {
634
659
  const setupStart = now$1();
@@ -665,8 +690,8 @@ async function collectTests(paths, runner) {
665
690
  const hasOnlyTasks = someTasksAreOnly(file);
666
691
  interpretTaskModes(file, config.testNamePattern, hasOnlyTasks, false, config.allowOnly);
667
692
  file.tasks.forEach((task) => {
668
- var _a;
669
- if (((_a = task.suite) == null ? void 0 : _a.id) === "")
693
+ var _a2;
694
+ if (((_a2 = task.suite) == null ? void 0 : _a2.id) === "")
670
695
  delete task.suite;
671
696
  });
672
697
  files.push(file);
@@ -921,8 +946,7 @@ async function runSuite(suite, runner) {
921
946
  } else {
922
947
  for (let tasksGroup of partitionSuiteChildren(suite)) {
923
948
  if (tasksGroup[0].concurrent === true) {
924
- const mutex = limit(runner.config.maxConcurrency);
925
- await Promise.all(tasksGroup.map((c) => mutex(() => runSuiteChild(c, runner))));
949
+ await Promise.all(tasksGroup.map((c) => runSuiteChild(c, runner)));
926
950
  } else {
927
951
  const { sequence } = runner.config;
928
952
  if (sequence.shuffle || suite.shuffle) {
@@ -963,14 +987,16 @@ async function runSuite(suite, runner) {
963
987
  await ((_d = runner.onAfterRunSuite) == null ? void 0 : _d.call(runner, suite));
964
988
  }
965
989
  }
990
+ let limitMaxConcurrency;
966
991
  async function runSuiteChild(c, runner) {
967
992
  if (c.type === "test" || c.type === "custom")
968
- return runTest(c, runner);
993
+ return limitMaxConcurrency(() => runTest(c, runner));
969
994
  else if (c.type === "suite")
970
995
  return runSuite(c, runner);
971
996
  }
972
997
  async function runFiles(files, runner) {
973
998
  var _a, _b;
999
+ limitMaxConcurrency ?? (limitMaxConcurrency = limit(runner.config.maxConcurrency));
974
1000
  for (const file of files) {
975
1001
  if (!file.tasks.length && !runner.config.passWithNoTests) {
976
1002
  if (!((_b = (_a = file.result) == null ? void 0 : _a.errors) == null ? void 0 : _b.length)) {
@@ -72,7 +72,7 @@ interface Suite extends TaskBase {
72
72
  }
73
73
  interface File extends Suite {
74
74
  filepath: string;
75
- projectName: string;
75
+ projectName: string | undefined;
76
76
  collectDuration?: number;
77
77
  setupDuration?: number;
78
78
  }
@@ -114,6 +114,14 @@ interface TestEachFunction {
114
114
  <T>(cases: ReadonlyArray<T>): EachFunctionReturn<T[]>;
115
115
  (...args: [TemplateStringsArray, ...any]): EachFunctionReturn<any[]>;
116
116
  }
117
+ interface TestForFunctionReturn<Arg, Context> {
118
+ (name: string | Function, fn: (arg: Arg, context: Context) => Awaitable<void>): void;
119
+ (name: string | Function, options: TestOptions, fn: (args: Arg, context: Context) => Awaitable<void>): void;
120
+ }
121
+ interface TestForFunction<ExtraContext> {
122
+ <T>(cases: ReadonlyArray<T>): TestForFunctionReturn<T, ExtendedContext<Test> & ExtraContext>;
123
+ (strings: TemplateStringsArray, ...values: any[]): TestForFunctionReturn<any, ExtendedContext<Test> & ExtraContext>;
124
+ }
117
125
  interface TestCollectorCallable<C = {}> {
118
126
  /**
119
127
  * @deprecated Use options as the second argument instead
@@ -124,6 +132,7 @@ interface TestCollectorCallable<C = {}> {
124
132
  }
125
133
  type ChainableTestAPI<ExtraContext = {}> = ChainableFunction<'concurrent' | 'sequential' | 'only' | 'skip' | 'todo' | 'fails', TestCollectorCallable<ExtraContext>, {
126
134
  each: TestEachFunction;
135
+ for: TestForFunction<ExtraContext>;
127
136
  }>;
128
137
  interface TestOptions {
129
138
  /**
@@ -145,7 +154,7 @@ interface TestOptions {
145
154
  */
146
155
  repeats?: number;
147
156
  /**
148
- * Whether tests run concurrently.
157
+ * Whether suites and tests run concurrently.
149
158
  * Tests inherit `concurrent` from `describe()` and nested `describe()` will inherit from parent's `concurrent`.
150
159
  */
151
160
  concurrent?: boolean;
package/dist/types.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { B as SequenceHooks, G as SequenceSetupFiles, F as File, T as Task, S as Suite, o as TaskResultPack, a as Test, C as Custom, A as TaskContext, E as ExtendedContext } from './tasks-Ck0GpLiZ.js';
2
- export { g as CustomAPI, D as DoneCallback, t as Fixture, s as FixtureFn, r as FixtureOptions, u as Fixtures, v as HookCleanupCallback, H as HookListener, I as InferFixturesTypes, O as OnTestFailedHandler, i as OnTestFinishedHandler, R as RunMode, y as RuntimeContext, d as SuiteAPI, f as SuiteCollector, x as SuiteFactory, h as SuiteHooks, k as TaskBase, w as TaskCustomOptions, m as TaskMeta, l as TaskPopulated, n as TaskResult, j as TaskState, e as TestAPI, z as TestContext, p as TestFunction, q as TestOptions, U as Use } from './tasks-Ck0GpLiZ.js';
1
+ import { B as SequenceHooks, G as SequenceSetupFiles, F as File, T as Task, S as Suite, o as TaskResultPack, a as Test, C as Custom, A as TaskContext, E as ExtendedContext } from './tasks-CcHkacEF.js';
2
+ export { g as CustomAPI, D as DoneCallback, t as Fixture, s as FixtureFn, r as FixtureOptions, u as Fixtures, v as HookCleanupCallback, H as HookListener, I as InferFixturesTypes, O as OnTestFailedHandler, i as OnTestFinishedHandler, R as RunMode, y as RuntimeContext, d as SuiteAPI, f as SuiteCollector, x as SuiteFactory, h as SuiteHooks, k as TaskBase, w as TaskCustomOptions, m as TaskMeta, l as TaskPopulated, n as TaskResult, j as TaskState, e as TestAPI, z as TestContext, p as TestFunction, q as TestOptions, U as Use } from './tasks-CcHkacEF.js';
3
3
  import { DiffOptions } from '@vitest/utils/diff';
4
4
  import '@vitest/utils';
5
5
 
@@ -37,6 +37,10 @@ interface VitestRunner {
37
37
  * First thing that's getting called before actually collecting and running tests.
38
38
  */
39
39
  onBeforeCollect?: (paths: string[]) => unknown;
40
+ /**
41
+ * Called after the file task was created but not collected yet.
42
+ */
43
+ onCollectStart?: (file: File) => unknown;
40
44
  /**
41
45
  * Called after collecting tests and before "onBeforeRun".
42
46
  */
package/dist/utils.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { S as Suite, T as Task, a as Test, C as Custom } from './tasks-Ck0GpLiZ.js';
2
- export { b as ChainableFunction, c as createChainable } from './tasks-Ck0GpLiZ.js';
1
+ import { S as Suite, F as File, T as Task, a as Test, C as Custom } from './tasks-CcHkacEF.js';
2
+ export { b as ChainableFunction, c as createChainable } from './tasks-CcHkacEF.js';
3
3
  import { Arrayable } from '@vitest/utils';
4
4
 
5
5
  /**
@@ -9,6 +9,7 @@ declare function interpretTaskModes(suite: Suite, namePattern?: string | RegExp,
9
9
  declare function someTasksAreOnly(suite: Suite): boolean;
10
10
  declare function generateHash(str: string): string;
11
11
  declare function calculateSuiteHash(parent: Suite): void;
12
+ declare function createFileTask(filepath: string, root: string, projectName: string): File;
12
13
 
13
14
  /**
14
15
  * Partition in tasks groups by consecutive concurrent
@@ -22,4 +23,4 @@ declare function hasTests(suite: Arrayable<Suite>): boolean;
22
23
  declare function hasFailed(suite: Arrayable<Task>): boolean;
23
24
  declare function getNames(task: Task): string[];
24
25
 
25
- export { calculateSuiteHash, generateHash, getNames, getSuites, getTasks, getTests, hasFailed, hasTests, interpretTaskModes, partitionSuiteChildren, someTasksAreOnly };
26
+ export { calculateSuiteHash, createFileTask, generateHash, getNames, getSuites, getTasks, getTests, hasFailed, hasTests, interpretTaskModes, partitionSuiteChildren, someTasksAreOnly };
package/dist/utils.js CHANGED
@@ -1,3 +1,4 @@
1
- export { c as calculateSuiteHash, j as createChainable, g as generateHash, f as getNames, d as getSuites, b as getTasks, a as getTests, e as hasFailed, h as hasTests, i as interpretTaskModes, p as partitionSuiteChildren, s as someTasksAreOnly } from './chunk-tasks.js';
1
+ export { c as calculateSuiteHash, k as createChainable, a as createFileTask, g as generateHash, j as getNames, e as getSuites, d as getTasks, b as getTests, f as hasFailed, h as hasTests, i as interpretTaskModes, p as partitionSuiteChildren, s as someTasksAreOnly } from './chunk-tasks.js';
2
2
  import '@vitest/utils/error';
3
+ import 'pathe';
3
4
  import '@vitest/utils';
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vitest/runner",
3
3
  "type": "module",
4
- "version": "2.0.0-beta.1",
4
+ "version": "2.0.0-beta.10",
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
  "p-limit": "^5.0.0",
42
42
  "pathe": "^1.1.2",
43
- "@vitest/utils": "2.0.0-beta.1"
43
+ "@vitest/utils": "2.0.0-beta.10"
44
44
  },
45
45
  "scripts": {
46
46
  "build": "rimraf dist && rollup -c",