@vitest/runner 4.1.0-beta.3 → 4.1.0-beta.5

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.
@@ -3,19 +3,29 @@ import { parseSingleStack } from '@vitest/utils/source-map';
3
3
  import { relative } from 'pathe';
4
4
  import { toArray } from '@vitest/utils/helpers';
5
5
 
6
- function createChainable(keys, fn) {
6
+ const kChainableContext = Symbol("kChainableContext");
7
+ function getChainableContext(chainable) {
8
+ return chainable?.[kChainableContext];
9
+ }
10
+ function createChainable(keys, fn, context) {
7
11
  function create(context) {
8
12
  const chain = function(...args) {
9
13
  return fn.apply(context, args);
10
14
  };
11
15
  Object.assign(chain, fn);
12
- chain.withContext = () => chain.bind(context);
13
- chain.setContext = (key, value) => {
14
- context[key] = value;
15
- };
16
- chain.mergeContext = (ctx) => {
17
- Object.assign(context, ctx);
18
- };
16
+ Object.defineProperty(chain, kChainableContext, {
17
+ value: {
18
+ withContext: () => chain.bind(context),
19
+ getFixtures: () => context.fixtures,
20
+ setContext: (key, value) => {
21
+ context[key] = value;
22
+ },
23
+ mergeContext: (ctx) => {
24
+ Object.assign(context, ctx);
25
+ }
26
+ },
27
+ enumerable: false
28
+ });
19
29
  for (const key of keys) {
20
30
  Object.defineProperty(chain, key, { get() {
21
31
  return create({
@@ -26,8 +36,11 @@ function createChainable(keys, fn) {
26
36
  }
27
37
  return chain;
28
38
  }
29
- const chain = create({});
30
- chain.fn = fn;
39
+ const chain = create(context ?? {});
40
+ Object.defineProperty(chain, "fn", {
41
+ value: fn,
42
+ enumerable: false
43
+ });
31
44
  return chain;
32
45
  }
33
46
 
@@ -63,7 +76,7 @@ function interpretTaskModes(file, namePattern, testLocations, testIds, testTagsF
63
76
  // in `testLocations`. Note: if `includeTaskLocation` is not enabled,
64
77
  // all test will be skipped.
65
78
  if (testLocations !== undefined && testLocations.length !== 0) {
66
- if (t.location && (testLocations === null || testLocations === void 0 ? void 0 : testLocations.includes(t.location.line))) {
79
+ if (t.location && testLocations?.includes(t.location.line)) {
67
80
  t.mode = "run";
68
81
  matchedLocations.push(t.location.line);
69
82
  hasLocationMatch = true;
@@ -101,7 +114,7 @@ function interpretTaskModes(file, namePattern, testLocations, testIds, testTagsF
101
114
  }
102
115
  };
103
116
  traverseSuite(file, parentIsOnly, false);
104
- const nonMatching = testLocations === null || testLocations === void 0 ? void 0 : testLocations.filter((loc) => !matchedLocations.includes(loc));
117
+ const nonMatching = testLocations?.filter((loc) => !matchedLocations.includes(loc));
105
118
  if (nonMatching && nonMatching.length !== 0) {
106
119
  const message = nonMatching.length === 1 ? `line ${nonMatching[0]}` : `lines ${nonMatching.join(", ")}`;
107
120
  if (file.result === undefined) {
@@ -236,28 +249,45 @@ function limitConcurrency(concurrency = Infinity) {
236
249
  tail = head && tail;
237
250
  }
238
251
  };
239
- return (func, ...args) => {
240
- // Create a promise chain that:
241
- // 1. Waits for its turn in the task queue (if necessary).
242
- // 2. Runs the task.
243
- // 3. Allows the next pending task (if any) to run.
252
+ const acquire = () => {
253
+ let released = false;
254
+ const release = () => {
255
+ if (!released) {
256
+ released = true;
257
+ finish();
258
+ }
259
+ };
260
+ if (count++ < concurrency) {
261
+ return release;
262
+ }
244
263
  return new Promise((resolve) => {
245
- if (count++ < concurrency) {
246
- // No need to queue if fewer than maxConcurrency tasks are running.
247
- resolve();
248
- } else if (tail) {
264
+ if (tail) {
249
265
  // There are pending tasks, so append to the queue.
250
- tail = tail[1] = [resolve];
266
+ tail = tail[1] = [() => resolve(release)];
251
267
  } else {
252
268
  // No other pending tasks, initialize the queue with a new tail and head.
253
- head = tail = [resolve];
269
+ head = tail = [() => resolve(release)];
254
270
  }
255
- }).then(() => {
256
- // Running func here ensures that even a non-thenable result or an
257
- // immediately thrown error gets wrapped into a Promise.
258
- return func(...args);
259
- }).finally(finish);
271
+ });
260
272
  };
273
+ const limiterFn = (func, ...args) => {
274
+ function run(release) {
275
+ try {
276
+ const result = func(...args);
277
+ if (result instanceof Promise) {
278
+ return result.finally(release);
279
+ }
280
+ release();
281
+ return Promise.resolve(result);
282
+ } catch (error) {
283
+ release();
284
+ return Promise.reject(error);
285
+ }
286
+ }
287
+ const release = acquire();
288
+ return release instanceof Promise ? release.then(run) : run(release);
289
+ };
290
+ return Object.assign(limiterFn, { acquire });
261
291
  }
262
292
 
263
293
  /**
@@ -549,17 +579,14 @@ function hasTests(suite) {
549
579
  return toArray(suite).some((s) => s.tasks.some((c) => isTestCase(c) || hasTests(c)));
550
580
  }
551
581
  function hasFailed(suite) {
552
- return toArray(suite).some((s) => {
553
- var _s$result;
554
- return ((_s$result = s.result) === null || _s$result === void 0 ? void 0 : _s$result.state) === "fail" || s.type === "suite" && hasFailed(s.tasks);
555
- });
582
+ return toArray(suite).some((s) => s.result?.state === "fail" || s.type === "suite" && hasFailed(s.tasks));
556
583
  }
557
584
  function getNames(task) {
558
585
  const names = [task.name];
559
586
  let current = task;
560
- while (current === null || current === void 0 ? void 0 : current.suite) {
587
+ while (current?.suite) {
561
588
  current = current.suite;
562
- if (current === null || current === void 0 ? void 0 : current.name) {
589
+ if (current?.name) {
563
590
  names.unshift(current.name);
564
591
  }
565
592
  }
@@ -578,4 +605,4 @@ function createTaskName(names, separator = " > ") {
578
605
  return names.filter((name) => name !== undefined).join(separator);
579
606
  }
580
607
 
581
- export { createChainable as a, createFileTask as b, calculateSuiteHash as c, createTagsFilter as d, createTaskName as e, findTestFileStackTrace as f, generateFileHash as g, generateHash as h, getFullName as i, getNames as j, getSuites as k, getTasks as l, getTestName as m, getTests as n, hasFailed as o, hasTests as p, interpretTaskModes as q, isTestCase as r, limitConcurrency as s, partitionSuiteChildren as t, someTasksAreOnly as u, validateTags as v, createNoTagsError as w };
608
+ export { createChainable as a, createFileTask as b, calculateSuiteHash as c, createTagsFilter as d, createTaskName as e, findTestFileStackTrace as f, generateFileHash as g, generateHash as h, getFullName as i, getNames as j, getSuites as k, getTasks as l, getTestName as m, getTests as n, hasFailed as o, hasTests as p, interpretTaskModes as q, isTestCase as r, limitConcurrency as s, partitionSuiteChildren as t, someTasksAreOnly as u, validateTags as v, getChainableContext as w, createNoTagsError as x };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,5 @@
1
- import { T as TestArtifact, a as Test, S as Suite, b as SuiteHooks, F as FileSpecification, V as VitestRunner, c as File, d as TaskUpdateEvent, e as Task, f as TestAPI, g as SuiteAPI, h as SuiteCollector } from './tasks.d-WWG4yDf6.js';
2
- export { A as AfterAllListener, i as AfterEachListener, j as AroundAllListener, k as AroundEachListener, B as BeforeAllListener, l as BeforeEachListener, C as CancelReason, m as Fixture, n as FixtureFn, o as FixtureOptions, p as Fixtures, I as ImportDuration, q as InferFixturesTypes, O as OnTestFailedHandler, r as OnTestFinishedHandler, R as Retry, s as RunMode, t as RuntimeContext, u as SequenceHooks, v as SequenceSetupFiles, w as SerializableRetry, x as SuiteFactory, y as SuiteOptions, z as TaskBase, D as TaskCustomOptions, E as TaskEventPack, G as TaskHook, H as TaskMeta, J as TaskPopulated, K as TaskResult, L as TaskResultPack, M as TaskState, N as TestAnnotation, P as TestAnnotationArtifact, Q as TestAnnotationLocation, U as TestArtifactBase, W as TestArtifactLocation, X as TestArtifactRegistry, Y as TestAttachment, Z as TestContext, _ as TestFunction, $ as TestOptions, a0 as TestTagDefinition, a1 as TestTags, a2 as Use, a3 as VisualRegressionArtifact, a4 as VitestRunnerConfig, a5 as VitestRunnerConstructor, a6 as VitestRunnerImportSource, a7 as afterAll, a8 as afterEach, a9 as aroundAll, aa as aroundEach, ab as beforeAll, ac as beforeEach, ad as onTestFailed, ae as onTestFinished } from './tasks.d-WWG4yDf6.js';
1
+ import { T as TestArtifact, a as Test, S as Suite, b as SuiteHooks, F as FileSpecification, V as VitestRunner, c as File, d as TaskUpdateEvent, e as Task, f as TestAPI, g as SuiteAPI, h as SuiteCollector } from './tasks.d-D2GKpdwQ.js';
2
+ export { A as AfterAllListener, i as AfterEachListener, j as AroundAllListener, k as AroundEachListener, B as BeforeAllListener, l as BeforeEachListener, C as CancelReason, m as FailureScreenshotArtifact, n as Fixture, o as FixtureFn, p as FixtureOptions, q as Fixtures, I as ImportDuration, r as InferFixturesTypes, O as OnTestFailedHandler, s as OnTestFinishedHandler, R as Retry, t as RunMode, u as RuntimeContext, v as SequenceHooks, w as SequenceSetupFiles, x as SerializableRetry, y as SuiteFactory, z as SuiteOptions, D as TaskBase, E as TaskCustomOptions, G as TaskEventPack, H as TaskHook, J as TaskMeta, K as TaskPopulated, L as TaskResult, M as TaskResultPack, N as TaskState, P as TestAnnotation, Q as TestAnnotationArtifact, U as TestAnnotationLocation, W as TestArtifactBase, X as TestArtifactLocation, Y as TestArtifactRegistry, Z as TestAttachment, _ as TestContext, $ as TestFunction, a0 as TestOptions, a1 as TestTagDefinition, a2 as TestTags, a3 as Use, a4 as VisualRegressionArtifact, a5 as VitestRunnerConfig, a6 as VitestRunnerConstructor, a7 as VitestRunnerImportSource, a8 as afterAll, a9 as afterEach, aa as aroundAll, ab as aroundEach, ac as beforeAll, ad as beforeEach, ae as onTestFailed, af as onTestFinished } from './tasks.d-D2GKpdwQ.js';
3
3
  import { Awaitable } from '@vitest/utils';
4
4
  import '@vitest/utils/diff';
5
5
 
@@ -13,12 +13,13 @@ import '@vitest/utils/diff';
13
13
  *
14
14
  * Vitest automatically injects the source location where the artifact was created and manages any attachments you include.
15
15
  *
16
+ * **Note:** artifacts must be recorded before the task is reported. Any artifacts recorded after that will not be included in the task.
17
+ *
16
18
  * @param task - The test task context, typically accessed via `this.task` in custom matchers or `context.task` in tests
17
19
  * @param artifact - The artifact to record. Must extend {@linkcode TestArtifactBase}
18
20
  *
19
21
  * @returns A promise that resolves to the recorded artifact with location injected
20
22
  *
21
- * @throws {Error} If called after the test has finished running
22
23
  * @throws {Error} If the test runner doesn't support artifacts
23
24
  *
24
25
  * @example
@@ -171,7 +172,7 @@ declare const describe: SuiteAPI;
171
172
  */
172
173
  declare const it: TestAPI;
173
174
  declare function getCurrentSuite<ExtraContext = object>(): SuiteCollector<ExtraContext>;
174
- declare function createTaskCollector(fn: (...args: any[]) => any, context?: Record<string, unknown>): TestAPI;
175
+ declare function createTaskCollector(fn: (...args: any[]) => any): TestAPI;
175
176
 
176
177
  declare function getCurrentTest<T extends Test | undefined>(): T;
177
178