@vitest/runner 3.2.0-beta.3 → 3.2.1
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 +2243 -0
- package/dist/index.d.ts +2 -2
- package/dist/index.js +3 -1699
- package/dist/{tasks.d-CItyFU3G.d.ts → tasks.d-CkscK4of.d.ts} +59 -5
- package/dist/types.d.ts +21 -8
- package/dist/utils.d.ts +2 -2
- package/dist/utils.js +3 -2
- package/package.json +2 -2
- package/dist/chunk-tasks.js +0 -325
@@ -3,6 +3,7 @@ import { ErrorWithDiff, Awaitable } from '@vitest/utils';
|
|
3
3
|
interface FixtureItem extends FixtureOptions {
|
4
4
|
prop: string;
|
5
5
|
value: any;
|
6
|
+
scope: "test" | "file" | "worker";
|
6
7
|
/**
|
7
8
|
* Indicates whether the fixture is a function
|
8
9
|
*/
|
@@ -156,16 +157,24 @@ interface TaskResult {
|
|
156
157
|
* `repeats` option is set. This number also contains `retryCount`.
|
157
158
|
*/
|
158
159
|
repeatCount?: number;
|
159
|
-
|
160
|
-
|
160
|
+
}
|
161
|
+
/** The time spent importing & executing a non-externalized file. */
|
162
|
+
interface ImportDuration {
|
163
|
+
/** The time spent importing & executing the file itself, not counting all non-externalized imports that the file does. */
|
164
|
+
selfTime: number;
|
165
|
+
/** The time spent importing & executing the file and all its imports. */
|
166
|
+
totalTime: number;
|
161
167
|
}
|
162
168
|
/**
|
163
169
|
* The tuple representing a single task update.
|
164
170
|
* Usually reported after the task finishes.
|
165
171
|
*/
|
166
172
|
type TaskResultPack = [id: string, result: TaskResult | undefined, meta: TaskMeta];
|
167
|
-
|
168
|
-
|
173
|
+
interface TaskEventData {
|
174
|
+
annotation?: TestAnnotation | undefined;
|
175
|
+
}
|
176
|
+
type TaskEventPack = [id: string, event: TaskUpdateEvent, data: TaskEventData | undefined];
|
177
|
+
type TaskUpdateEvent = "test-failed-early" | "suite-failed-early" | "test-prepare" | "test-finished" | "test-retried" | "suite-prepare" | "suite-finished" | "before-hook-start" | "before-hook-end" | "after-hook-start" | "after-hook-end" | "test-annotation";
|
169
178
|
interface Suite extends TaskBase {
|
170
179
|
type: "suite";
|
171
180
|
/**
|
@@ -200,6 +209,8 @@ interface File extends Suite {
|
|
200
209
|
* The time it took to import the setup file.
|
201
210
|
*/
|
202
211
|
setupDuration?: number;
|
212
|
+
/** The time spent importing every non-externalized dependency that Vitest has processed. */
|
213
|
+
importDurations?: Record<string, ImportDuration>;
|
203
214
|
}
|
204
215
|
interface Test<ExtraContext = object> extends TaskPopulated {
|
205
216
|
type: "test";
|
@@ -211,6 +222,26 @@ interface Test<ExtraContext = object> extends TaskPopulated {
|
|
211
222
|
* The test timeout in milliseconds.
|
212
223
|
*/
|
213
224
|
timeout: number;
|
225
|
+
/**
|
226
|
+
* An array of custom annotations.
|
227
|
+
*/
|
228
|
+
annotations: TestAnnotation[];
|
229
|
+
}
|
230
|
+
interface TestAttachment {
|
231
|
+
contentType?: string;
|
232
|
+
path?: string;
|
233
|
+
body?: string | Uint8Array;
|
234
|
+
}
|
235
|
+
interface TestAnnotationLocation {
|
236
|
+
line: number;
|
237
|
+
column: number;
|
238
|
+
file: string;
|
239
|
+
}
|
240
|
+
interface TestAnnotation {
|
241
|
+
message: string;
|
242
|
+
type: string;
|
243
|
+
location?: TestAnnotationLocation;
|
244
|
+
attachment?: TestAttachment;
|
214
245
|
}
|
215
246
|
/**
|
216
247
|
* @deprecated Use `Test` instead. `type: 'custom'` is not used since 2.2
|
@@ -347,12 +378,23 @@ type TestAPI<ExtraContext = object> = ChainableTestAPI<ExtraContext> & ExtendedA
|
|
347
378
|
interface FixtureOptions {
|
348
379
|
/**
|
349
380
|
* Whether to automatically set up current fixture, even though it's not being used in tests.
|
381
|
+
* @default false
|
350
382
|
*/
|
351
383
|
auto?: boolean;
|
352
384
|
/**
|
353
385
|
* Indicated if the injected value from the config should be preferred over the fixture value
|
354
386
|
*/
|
355
387
|
injected?: boolean;
|
388
|
+
/**
|
389
|
+
* When should the fixture be set up.
|
390
|
+
* - **test**: fixture will be set up before every test
|
391
|
+
* - **worker**: fixture will be set up once per worker
|
392
|
+
* - **file**: fixture will be set up once per file
|
393
|
+
*
|
394
|
+
* **Warning:** The `vmThreads` and `vmForks` pools initiate worker fixtures once per test file.
|
395
|
+
* @default 'test'
|
396
|
+
*/
|
397
|
+
scope?: "test" | "worker" | "file";
|
356
398
|
}
|
357
399
|
type Use<T> = (value: T) => Promise<void>;
|
358
400
|
type FixtureFn<
|
@@ -466,24 +508,36 @@ interface TestContext {
|
|
466
508
|
/**
|
467
509
|
* An [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal) that will be aborted if the test times out or
|
468
510
|
* the test run was cancelled.
|
511
|
+
* @see {@link https://vitest.dev/guide/test-context#signal}
|
469
512
|
*/
|
470
513
|
readonly signal: AbortSignal;
|
471
514
|
/**
|
472
515
|
* Extract hooks on test failed
|
516
|
+
* @see {@link https://vitest.dev/guide/test-context#ontestfailed}
|
473
517
|
*/
|
474
518
|
readonly onTestFailed: (fn: OnTestFailedHandler, timeout?: number) => void;
|
475
519
|
/**
|
476
520
|
* Extract hooks on test failed
|
521
|
+
* @see {@link https://vitest.dev/guide/test-context#ontestfinished}
|
477
522
|
*/
|
478
523
|
readonly onTestFinished: (fn: OnTestFinishedHandler, timeout?: number) => void;
|
479
524
|
/**
|
480
525
|
* Mark tests as skipped. All execution after this call will be skipped.
|
481
526
|
* This function throws an error, so make sure you are not catching it accidentally.
|
527
|
+
* @see {@link https://vitest.dev/guide/test-context#skip}
|
482
528
|
*/
|
483
529
|
readonly skip: {
|
484
530
|
(note?: string): never
|
485
531
|
(condition: boolean, note?: string): void
|
486
532
|
};
|
533
|
+
/**
|
534
|
+
* Add a test annotation that will be displayed by your reporter.
|
535
|
+
* @see {@link https://vitest.dev/guide/test-context#annotate}
|
536
|
+
*/
|
537
|
+
readonly annotate: {
|
538
|
+
(message: string, type?: string, attachment?: TestAttachment): Promise<TestAnnotation>
|
539
|
+
(message: string, attachment?: TestAttachment): Promise<TestAnnotation>
|
540
|
+
};
|
487
541
|
}
|
488
542
|
/**
|
489
543
|
* Context that's always available in the test function.
|
@@ -501,4 +555,4 @@ type SequenceHooks = "stack" | "list" | "parallel";
|
|
501
555
|
type SequenceSetupFiles = "list" | "parallel";
|
502
556
|
|
503
557
|
export { createChainable as c };
|
504
|
-
export type { AfterAllListener as A, BeforeAllListener as B, ChainableFunction as C, DoneCallback as D, ExtendedContext as E, File as F,
|
558
|
+
export type { AfterAllListener as A, BeforeAllListener as B, ChainableFunction as C, DoneCallback as D, ExtendedContext as E, File as F, TaskMeta as G, HookCleanupCallback as H, ImportDuration as I, TaskPopulated as J, TaskResult as K, TaskResultPack as L, TaskState as M, TestAnnotation as N, OnTestFailedHandler as O, TestAnnotationLocation as P, TestAttachment as Q, RunMode as R, Suite as S, Task as T, TestContext as U, TestFunction as V, TestOptions as W, Use as X, Test as a, AfterEachListener as b, BeforeEachListener as d, TaskHook as e, OnTestFinishedHandler as f, Custom as g, SuiteHooks as h, TaskUpdateEvent as i, TestAPI as j, SuiteAPI as k, SuiteCollector as l, Fixture as m, FixtureFn as n, FixtureOptions as o, Fixtures as p, HookListener as q, InferFixturesTypes as r, RuntimeContext as s, SequenceHooks as t, SequenceSetupFiles as u, SuiteFactory as v, TaskBase as w, TaskContext as x, TaskCustomOptions as y, TaskEventPack as z };
|
package/dist/types.d.ts
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
import { DiffOptions } from '@vitest/utils/diff';
|
2
|
-
import { F as File,
|
3
|
-
export { A as AfterAllListener, b as AfterEachListener, B as BeforeAllListener, d as BeforeEachListener, g as Custom, j as CustomAPI, D as DoneCallback, E as ExtendedContext, m as Fixture, n as FixtureFn, o as FixtureOptions, p as Fixtures, H as HookCleanupCallback, q as HookListener,
|
2
|
+
import { F as File, a as Test, S as Suite, L as TaskResultPack, z as TaskEventPack, N as TestAnnotation, U as TestContext, I as ImportDuration, t as SequenceHooks, u as SequenceSetupFiles } from './tasks.d-CkscK4of.js';
|
3
|
+
export { A as AfterAllListener, b as AfterEachListener, B as BeforeAllListener, d as BeforeEachListener, g as Custom, j as CustomAPI, D as DoneCallback, E as ExtendedContext, m as Fixture, n as FixtureFn, o as FixtureOptions, p as Fixtures, H as HookCleanupCallback, q as HookListener, r as InferFixturesTypes, O as OnTestFailedHandler, f as OnTestFinishedHandler, R as RunMode, s as RuntimeContext, k as SuiteAPI, l as SuiteCollector, v as SuiteFactory, h as SuiteHooks, T as Task, w as TaskBase, x as TaskContext, y as TaskCustomOptions, e as TaskHook, G as TaskMeta, J as TaskPopulated, K as TaskResult, M as TaskState, i as TaskUpdateEvent, j as TestAPI, P as TestAnnotationLocation, Q as TestAttachment, V as TestFunction, W as TestOptions, X as Use } from './tasks.d-CkscK4of.js';
|
4
4
|
import '@vitest/utils';
|
5
5
|
|
6
6
|
/**
|
@@ -64,11 +64,11 @@ interface VitestRunner {
|
|
64
64
|
/**
|
65
65
|
* Called before running a single test. Doesn't have "result" yet.
|
66
66
|
*/
|
67
|
-
onBeforeRunTask?: (test:
|
67
|
+
onBeforeRunTask?: (test: Test) => unknown;
|
68
68
|
/**
|
69
69
|
* Called before actually running the test function. Already has "result" with "state" and "startTime".
|
70
70
|
*/
|
71
|
-
onBeforeTryTask?: (test:
|
71
|
+
onBeforeTryTask?: (test: Test, options: {
|
72
72
|
retry: number
|
73
73
|
repeats: number
|
74
74
|
}) => unknown;
|
@@ -79,11 +79,11 @@ interface VitestRunner {
|
|
79
79
|
/**
|
80
80
|
* Called after result and state are set.
|
81
81
|
*/
|
82
|
-
onAfterRunTask?: (test:
|
82
|
+
onAfterRunTask?: (test: Test) => unknown;
|
83
83
|
/**
|
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
|
-
onAfterTryTask?: (test:
|
86
|
+
onAfterTryTask?: (test: Test, options: {
|
87
87
|
retry: number
|
88
88
|
repeats: number
|
89
89
|
}) => unknown;
|
@@ -104,12 +104,16 @@ interface VitestRunner {
|
|
104
104
|
* If defined, will be called instead of usual Vitest handling. Useful, if you have your custom test function.
|
105
105
|
* "before" and "after" hooks will not be ignored.
|
106
106
|
*/
|
107
|
-
runTask?: (test:
|
107
|
+
runTask?: (test: Test) => Promise<void>;
|
108
108
|
/**
|
109
109
|
* Called, when a task is updated. The same as "onTaskUpdate" in a reporter, but this is running in the same thread as tests.
|
110
110
|
*/
|
111
111
|
onTaskUpdate?: (task: TaskResultPack[], events: TaskEventPack[]) => Promise<void>;
|
112
112
|
/**
|
113
|
+
* Called when annotation is added via the `context.annotate` method.
|
114
|
+
*/
|
115
|
+
onTestAnnotate?: (test: Test, annotation: TestAnnotation) => Promise<TestAnnotation>;
|
116
|
+
/**
|
113
117
|
* Called before running all tests in collected paths.
|
114
118
|
*/
|
115
119
|
onBeforeRunFiles?: (files: File[]) => unknown;
|
@@ -133,6 +137,10 @@ interface VitestRunner {
|
|
133
137
|
*/
|
134
138
|
injectValue?: (key: string) => unknown;
|
135
139
|
/**
|
140
|
+
* Gets the time spent importing each individual non-externalized file that Vitest collected.
|
141
|
+
*/
|
142
|
+
getImportDurations?: () => Record<string, ImportDuration>;
|
143
|
+
/**
|
136
144
|
* Publicly available configuration.
|
137
145
|
*/
|
138
146
|
config: VitestRunnerConfig;
|
@@ -140,11 +148,16 @@ interface VitestRunner {
|
|
140
148
|
* The name of the current pool. Can affect how stack trace is inferred on the server side.
|
141
149
|
*/
|
142
150
|
pool?: string;
|
151
|
+
/**
|
152
|
+
* Return the worker context for fixtures specified with `scope: 'worker'`
|
153
|
+
*/
|
154
|
+
getWorkerContext?: () => Record<string, unknown>;
|
155
|
+
onCleanupWorkerContext?: (cleanup: () => unknown) => void;
|
143
156
|
/** @private */
|
144
157
|
_currentTaskStartTime?: number;
|
145
158
|
/** @private */
|
146
159
|
_currentTaskTimeout?: number;
|
147
160
|
}
|
148
161
|
|
149
|
-
export { File, SequenceHooks, SequenceSetupFiles, Suite,
|
162
|
+
export { File, ImportDuration, SequenceHooks, SequenceSetupFiles, Suite, TaskEventPack, TaskResultPack, Test, TestAnnotation, TestContext };
|
150
163
|
export type { CancelReason, FileSpecification, VitestRunner, VitestRunnerConfig, VitestRunnerConstructor, VitestRunnerImportSource };
|
package/dist/utils.d.ts
CHANGED
@@ -1,5 +1,5 @@
|
|
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-
|
1
|
+
import { S as Suite, F as File, T as Task, a as Test } from './tasks.d-CkscK4of.js';
|
2
|
+
export { C as ChainableFunction, c as createChainable } from './tasks.d-CkscK4of.js';
|
3
3
|
import { Arrayable } from '@vitest/utils';
|
4
4
|
|
5
5
|
/**
|
package/dist/utils.js
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
export {
|
1
|
+
export { v as calculateSuiteHash, r as createChainable, w as createFileTask, x as generateFileHash, y as generateHash, D as getFullName, E as getNames, F as getSuites, G as getTasks, H as getTestName, I as getTests, J as hasFailed, K as hasTests, z as interpretTaskModes, L as isAtomTest, M as isTestCase, B as limitConcurrency, C as partitionSuiteChildren, A as someTasksAreOnly } from './chunk-hooks.js';
|
2
|
+
import '@vitest/utils';
|
3
|
+
import '@vitest/utils/source-map';
|
2
4
|
import '@vitest/utils/error';
|
3
5
|
import 'pathe';
|
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": "3.2.
|
4
|
+
"version": "3.2.1",
|
5
5
|
"description": "Vitest test runner",
|
6
6
|
"license": "MIT",
|
7
7
|
"funding": "https://opencollective.com/vitest",
|
@@ -39,7 +39,7 @@
|
|
39
39
|
],
|
40
40
|
"dependencies": {
|
41
41
|
"pathe": "^2.0.3",
|
42
|
-
"@vitest/utils": "3.2.
|
42
|
+
"@vitest/utils": "3.2.1"
|
43
43
|
},
|
44
44
|
"scripts": {
|
45
45
|
"build": "rimraf dist && rollup -c",
|
package/dist/chunk-tasks.js
DELETED
@@ -1,325 +0,0 @@
|
|
1
|
-
import { processError } from '@vitest/utils/error';
|
2
|
-
import { relative } from 'pathe';
|
3
|
-
import { toArray } from '@vitest/utils';
|
4
|
-
|
5
|
-
function createChainable(keys, fn) {
|
6
|
-
function create(context) {
|
7
|
-
const chain = function(...args) {
|
8
|
-
return fn.apply(context, args);
|
9
|
-
};
|
10
|
-
Object.assign(chain, fn);
|
11
|
-
chain.withContext = () => chain.bind(context);
|
12
|
-
chain.setContext = (key, value) => {
|
13
|
-
context[key] = value;
|
14
|
-
};
|
15
|
-
chain.mergeContext = (ctx) => {
|
16
|
-
Object.assign(context, ctx);
|
17
|
-
};
|
18
|
-
for (const key of keys) {
|
19
|
-
Object.defineProperty(chain, key, { get() {
|
20
|
-
return create({
|
21
|
-
...context,
|
22
|
-
[key]: true
|
23
|
-
});
|
24
|
-
} });
|
25
|
-
}
|
26
|
-
return chain;
|
27
|
-
}
|
28
|
-
const chain = create({});
|
29
|
-
chain.fn = fn;
|
30
|
-
return chain;
|
31
|
-
}
|
32
|
-
|
33
|
-
/**
|
34
|
-
* If any tasks been marked as `only`, mark all other tasks as `skip`.
|
35
|
-
*/
|
36
|
-
function interpretTaskModes(file, namePattern, testLocations, onlyMode, parentIsOnly, allowOnly) {
|
37
|
-
const matchedLocations = [];
|
38
|
-
const traverseSuite = (suite, parentIsOnly, parentMatchedWithLocation) => {
|
39
|
-
const suiteIsOnly = parentIsOnly || suite.mode === "only";
|
40
|
-
suite.tasks.forEach((t) => {
|
41
|
-
// Check if either the parent suite or the task itself are marked as included
|
42
|
-
const includeTask = suiteIsOnly || t.mode === "only";
|
43
|
-
if (onlyMode) {
|
44
|
-
if (t.type === "suite" && (includeTask || someTasksAreOnly(t))) {
|
45
|
-
// Don't skip this suite
|
46
|
-
if (t.mode === "only") {
|
47
|
-
checkAllowOnly(t, allowOnly);
|
48
|
-
t.mode = "run";
|
49
|
-
}
|
50
|
-
} else if (t.mode === "run" && !includeTask) {
|
51
|
-
t.mode = "skip";
|
52
|
-
} else if (t.mode === "only") {
|
53
|
-
checkAllowOnly(t, allowOnly);
|
54
|
-
t.mode = "run";
|
55
|
-
}
|
56
|
-
}
|
57
|
-
let hasLocationMatch = parentMatchedWithLocation;
|
58
|
-
// Match test location against provided locations, only run if present
|
59
|
-
// in `testLocations`. Note: if `includeTaskLocations` is not enabled,
|
60
|
-
// all test will be skipped.
|
61
|
-
if (testLocations !== undefined && testLocations.length !== 0) {
|
62
|
-
if (t.location && (testLocations === null || testLocations === void 0 ? void 0 : testLocations.includes(t.location.line))) {
|
63
|
-
t.mode = "run";
|
64
|
-
matchedLocations.push(t.location.line);
|
65
|
-
hasLocationMatch = true;
|
66
|
-
} else if (parentMatchedWithLocation) {
|
67
|
-
t.mode = "run";
|
68
|
-
} else if (t.type === "test") {
|
69
|
-
t.mode = "skip";
|
70
|
-
}
|
71
|
-
}
|
72
|
-
if (t.type === "test") {
|
73
|
-
if (namePattern && !getTaskFullName(t).match(namePattern)) {
|
74
|
-
t.mode = "skip";
|
75
|
-
}
|
76
|
-
} else if (t.type === "suite") {
|
77
|
-
if (t.mode === "skip") {
|
78
|
-
skipAllTasks(t);
|
79
|
-
} else if (t.mode === "todo") {
|
80
|
-
todoAllTasks(t);
|
81
|
-
} else {
|
82
|
-
traverseSuite(t, includeTask, hasLocationMatch);
|
83
|
-
}
|
84
|
-
}
|
85
|
-
});
|
86
|
-
// if all subtasks are skipped, mark as skip
|
87
|
-
if (suite.mode === "run" || suite.mode === "queued") {
|
88
|
-
if (suite.tasks.length && suite.tasks.every((i) => i.mode !== "run" && i.mode !== "queued")) {
|
89
|
-
suite.mode = "skip";
|
90
|
-
}
|
91
|
-
}
|
92
|
-
};
|
93
|
-
traverseSuite(file, parentIsOnly, false);
|
94
|
-
const nonMatching = testLocations === null || testLocations === void 0 ? void 0 : testLocations.filter((loc) => !matchedLocations.includes(loc));
|
95
|
-
if (nonMatching && nonMatching.length !== 0) {
|
96
|
-
const message = nonMatching.length === 1 ? `line ${nonMatching[0]}` : `lines ${nonMatching.join(", ")}`;
|
97
|
-
if (file.result === undefined) {
|
98
|
-
file.result = {
|
99
|
-
state: "fail",
|
100
|
-
errors: []
|
101
|
-
};
|
102
|
-
}
|
103
|
-
if (file.result.errors === undefined) {
|
104
|
-
file.result.errors = [];
|
105
|
-
}
|
106
|
-
file.result.errors.push(processError(new Error(`No test found in ${file.name} in ${message}`)));
|
107
|
-
}
|
108
|
-
}
|
109
|
-
function getTaskFullName(task) {
|
110
|
-
return `${task.suite ? `${getTaskFullName(task.suite)} ` : ""}${task.name}`;
|
111
|
-
}
|
112
|
-
function someTasksAreOnly(suite) {
|
113
|
-
return suite.tasks.some((t) => t.mode === "only" || t.type === "suite" && someTasksAreOnly(t));
|
114
|
-
}
|
115
|
-
function skipAllTasks(suite) {
|
116
|
-
suite.tasks.forEach((t) => {
|
117
|
-
if (t.mode === "run" || t.mode === "queued") {
|
118
|
-
t.mode = "skip";
|
119
|
-
if (t.type === "suite") {
|
120
|
-
skipAllTasks(t);
|
121
|
-
}
|
122
|
-
}
|
123
|
-
});
|
124
|
-
}
|
125
|
-
function todoAllTasks(suite) {
|
126
|
-
suite.tasks.forEach((t) => {
|
127
|
-
if (t.mode === "run" || t.mode === "queued") {
|
128
|
-
t.mode = "todo";
|
129
|
-
if (t.type === "suite") {
|
130
|
-
todoAllTasks(t);
|
131
|
-
}
|
132
|
-
}
|
133
|
-
});
|
134
|
-
}
|
135
|
-
function checkAllowOnly(task, allowOnly) {
|
136
|
-
if (allowOnly) {
|
137
|
-
return;
|
138
|
-
}
|
139
|
-
const error = processError(new Error("[Vitest] Unexpected .only modifier. Remove it or pass --allowOnly argument to bypass this error"));
|
140
|
-
task.result = {
|
141
|
-
state: "fail",
|
142
|
-
errors: [error]
|
143
|
-
};
|
144
|
-
}
|
145
|
-
function generateHash(str) {
|
146
|
-
let hash = 0;
|
147
|
-
if (str.length === 0) {
|
148
|
-
return `${hash}`;
|
149
|
-
}
|
150
|
-
for (let i = 0; i < str.length; i++) {
|
151
|
-
const char = str.charCodeAt(i);
|
152
|
-
hash = (hash << 5) - hash + char;
|
153
|
-
hash = hash & hash;
|
154
|
-
}
|
155
|
-
return `${hash}`;
|
156
|
-
}
|
157
|
-
function calculateSuiteHash(parent) {
|
158
|
-
parent.tasks.forEach((t, idx) => {
|
159
|
-
t.id = `${parent.id}_${idx}`;
|
160
|
-
if (t.type === "suite") {
|
161
|
-
calculateSuiteHash(t);
|
162
|
-
}
|
163
|
-
});
|
164
|
-
}
|
165
|
-
function createFileTask(filepath, root, projectName, pool) {
|
166
|
-
const path = relative(root, filepath);
|
167
|
-
const file = {
|
168
|
-
id: generateFileHash(path, projectName),
|
169
|
-
name: path,
|
170
|
-
type: "suite",
|
171
|
-
mode: "queued",
|
172
|
-
filepath,
|
173
|
-
tasks: [],
|
174
|
-
meta: Object.create(null),
|
175
|
-
projectName,
|
176
|
-
file: undefined,
|
177
|
-
pool
|
178
|
-
};
|
179
|
-
file.file = file;
|
180
|
-
return file;
|
181
|
-
}
|
182
|
-
/**
|
183
|
-
* Generate a unique ID for a file based on its path and project name
|
184
|
-
* @param file File relative to the root of the project to keep ID the same between different machines
|
185
|
-
* @param projectName The name of the test project
|
186
|
-
*/
|
187
|
-
function generateFileHash(file, projectName) {
|
188
|
-
return generateHash(`${file}${projectName || ""}`);
|
189
|
-
}
|
190
|
-
|
191
|
-
/**
|
192
|
-
* Return a function for running multiple async operations with limited concurrency.
|
193
|
-
*/
|
194
|
-
function limitConcurrency(concurrency = Infinity) {
|
195
|
-
// The number of currently active + pending tasks.
|
196
|
-
let count = 0;
|
197
|
-
// The head and tail of the pending task queue, built using a singly linked list.
|
198
|
-
// Both head and tail are initially undefined, signifying an empty queue.
|
199
|
-
// They both become undefined again whenever there are no pending tasks.
|
200
|
-
let head;
|
201
|
-
let tail;
|
202
|
-
// A bookkeeping function executed whenever a task has been run to completion.
|
203
|
-
const finish = () => {
|
204
|
-
count--;
|
205
|
-
// Check if there are further pending tasks in the queue.
|
206
|
-
if (head) {
|
207
|
-
// Allow the next pending task to run and pop it from the queue.
|
208
|
-
head[0]();
|
209
|
-
head = head[1];
|
210
|
-
// The head may now be undefined if there are no further pending tasks.
|
211
|
-
// In that case, set tail to undefined as well.
|
212
|
-
tail = head && tail;
|
213
|
-
}
|
214
|
-
};
|
215
|
-
return (func, ...args) => {
|
216
|
-
// Create a promise chain that:
|
217
|
-
// 1. Waits for its turn in the task queue (if necessary).
|
218
|
-
// 2. Runs the task.
|
219
|
-
// 3. Allows the next pending task (if any) to run.
|
220
|
-
return new Promise((resolve) => {
|
221
|
-
if (count++ < concurrency) {
|
222
|
-
// No need to queue if fewer than maxConcurrency tasks are running.
|
223
|
-
resolve();
|
224
|
-
} else if (tail) {
|
225
|
-
// There are pending tasks, so append to the queue.
|
226
|
-
tail = tail[1] = [resolve];
|
227
|
-
} else {
|
228
|
-
// No other pending tasks, initialize the queue with a new tail and head.
|
229
|
-
head = tail = [resolve];
|
230
|
-
}
|
231
|
-
}).then(() => {
|
232
|
-
// Running func here ensures that even a non-thenable result or an
|
233
|
-
// immediately thrown error gets wrapped into a Promise.
|
234
|
-
return func(...args);
|
235
|
-
}).finally(finish);
|
236
|
-
};
|
237
|
-
}
|
238
|
-
|
239
|
-
/**
|
240
|
-
* Partition in tasks groups by consecutive concurrent
|
241
|
-
*/
|
242
|
-
function partitionSuiteChildren(suite) {
|
243
|
-
let tasksGroup = [];
|
244
|
-
const tasksGroups = [];
|
245
|
-
for (const c of suite.tasks) {
|
246
|
-
if (tasksGroup.length === 0 || c.concurrent === tasksGroup[0].concurrent) {
|
247
|
-
tasksGroup.push(c);
|
248
|
-
} else {
|
249
|
-
tasksGroups.push(tasksGroup);
|
250
|
-
tasksGroup = [c];
|
251
|
-
}
|
252
|
-
}
|
253
|
-
if (tasksGroup.length > 0) {
|
254
|
-
tasksGroups.push(tasksGroup);
|
255
|
-
}
|
256
|
-
return tasksGroups;
|
257
|
-
}
|
258
|
-
|
259
|
-
/**
|
260
|
-
* @deprecated use `isTestCase` instead
|
261
|
-
*/
|
262
|
-
function isAtomTest(s) {
|
263
|
-
return isTestCase(s);
|
264
|
-
}
|
265
|
-
function isTestCase(s) {
|
266
|
-
return s.type === "test";
|
267
|
-
}
|
268
|
-
function getTests(suite) {
|
269
|
-
const tests = [];
|
270
|
-
const arraySuites = toArray(suite);
|
271
|
-
for (const s of arraySuites) {
|
272
|
-
if (isTestCase(s)) {
|
273
|
-
tests.push(s);
|
274
|
-
} else {
|
275
|
-
for (const task of s.tasks) {
|
276
|
-
if (isTestCase(task)) {
|
277
|
-
tests.push(task);
|
278
|
-
} else {
|
279
|
-
const taskTests = getTests(task);
|
280
|
-
for (const test of taskTests) {
|
281
|
-
tests.push(test);
|
282
|
-
}
|
283
|
-
}
|
284
|
-
}
|
285
|
-
}
|
286
|
-
}
|
287
|
-
return tests;
|
288
|
-
}
|
289
|
-
function getTasks(tasks = []) {
|
290
|
-
return toArray(tasks).flatMap((s) => isTestCase(s) ? [s] : [s, ...getTasks(s.tasks)]);
|
291
|
-
}
|
292
|
-
function getSuites(suite) {
|
293
|
-
return toArray(suite).flatMap((s) => s.type === "suite" ? [s, ...getSuites(s.tasks)] : []);
|
294
|
-
}
|
295
|
-
function hasTests(suite) {
|
296
|
-
return toArray(suite).some((s) => s.tasks.some((c) => isTestCase(c) || hasTests(c)));
|
297
|
-
}
|
298
|
-
function hasFailed(suite) {
|
299
|
-
return toArray(suite).some((s) => {
|
300
|
-
var _s$result;
|
301
|
-
return ((_s$result = s.result) === null || _s$result === void 0 ? void 0 : _s$result.state) === "fail" || s.type === "suite" && hasFailed(s.tasks);
|
302
|
-
});
|
303
|
-
}
|
304
|
-
function getNames(task) {
|
305
|
-
const names = [task.name];
|
306
|
-
let current = task;
|
307
|
-
while (current === null || current === void 0 ? void 0 : current.suite) {
|
308
|
-
current = current.suite;
|
309
|
-
if (current === null || current === void 0 ? void 0 : current.name) {
|
310
|
-
names.unshift(current.name);
|
311
|
-
}
|
312
|
-
}
|
313
|
-
if (current !== task.file) {
|
314
|
-
names.unshift(task.file.name);
|
315
|
-
}
|
316
|
-
return names;
|
317
|
-
}
|
318
|
-
function getFullName(task, separator = " > ") {
|
319
|
-
return getNames(task).join(separator);
|
320
|
-
}
|
321
|
-
function getTestName(task, separator = " > ") {
|
322
|
-
return getNames(task).slice(1).join(separator);
|
323
|
-
}
|
324
|
-
|
325
|
-
export { calculateSuiteHash as a, createFileTask as b, createChainable as c, generateHash as d, getFullName as e, getNames as f, generateFileHash as g, getSuites as h, interpretTaskModes as i, getTasks as j, getTestName as k, limitConcurrency as l, getTests as m, hasFailed as n, hasTests as o, partitionSuiteChildren as p, isAtomTest as q, isTestCase as r, someTasksAreOnly as s };
|