vitest 4.0.16 → 4.1.0-beta.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/browser.d.ts +2 -1
- package/dist/browser.js +2 -1
- package/dist/chunks/{base.Bin-9uYm.js → base.CBRNZa3k.js} +8 -7
- package/dist/chunks/{browser.d.Bz3lxTX-.d.ts → browser.d.8hOapKZr.d.ts} +5 -1
- package/dist/chunks/{cac.BGonGPac.js → cac.B1v3xxoC.js} +26 -8
- package/dist/chunks/{cli-api.BKg19Fvw.js → cli-api.B4CqEpI6.js} +225 -110
- package/dist/chunks/{config.d.CzIjkicf.d.ts → config.d.idH22YSr.d.ts} +13 -11
- package/dist/chunks/{console.Cf-YriPC.js → console.uGgdMhyZ.js} +2 -1
- package/dist/chunks/{coverage.BuJUwVtg.js → coverage.BMlOMIWl.js} +18 -4
- package/dist/chunks/{creator.DAmOKTvJ.js → creator.C7WwjkuR.js} +32 -1
- package/dist/chunks/{globals.DOayXfHP.js → globals.DjuGMoMc.js} +10 -9
- package/dist/chunks/{index.Z5E_ObnR.js → index.BEFi2-_3.js} +3 -1
- package/dist/chunks/{index.6Qv1eEA6.js → index.BiOAd_ki.js} +16 -4
- package/dist/chunks/{index.BspFP3mn.js → index.CyBMJtT7.js} +1 -1
- package/dist/chunks/{index.456_DGfR.js → index.Dm4xqZ0s.js} +28 -4
- package/dist/chunks/{index.Drsj_6e7.js → index.DyBZXrH3.js} +1 -1
- package/dist/chunks/{init-forks.v9UONQS6.js → init-forks.CHeQ9Moq.js} +1 -1
- package/dist/chunks/{init-threads.DqYg3Trk.js → init-threads.uZiNAuPk.js} +1 -1
- package/dist/chunks/{init.KmQZdqFg.js → init.DVtKdFty.js} +24 -11
- package/dist/chunks/{plugin.d.v1sC_bv1.d.ts → plugin.d.D8KU2PY_.d.ts} +1 -1
- package/dist/chunks/{reporters.d.Rsi0PyxX.d.ts → reporters.d.Db3MiIWX.d.ts} +51 -22
- package/dist/chunks/rpc.HLmECnw_.js +148 -0
- package/dist/chunks/{setup-common.Cm-kSBVi.js → setup-common.BcqLPsn5.js} +1 -1
- package/dist/chunks/{startModuleRunner.DpqpB8k3.js → startModuleRunner.C5CcWyXW.js} +23 -23
- package/dist/chunks/{vi.2VT5v0um.js → test.prxIahgM.js} +500 -119
- package/dist/chunks/{traces.U4xDYhzZ.js → traces.CCmnQaNT.js} +46 -1
- package/dist/chunks/{vm.qFl6P1nF.js → vm.CrifS09m.js} +5 -8
- package/dist/chunks/{worker.d.5JNaocaN.d.ts → worker.d.Bji1eq5g.d.ts} +2 -1
- package/dist/cli.js +2 -2
- package/dist/config.d.ts +9 -9
- package/dist/coverage.d.ts +8 -8
- package/dist/coverage.js +3 -1
- package/dist/environments.js +3 -1
- package/dist/index.d.ts +22 -10
- package/dist/index.js +8 -7
- package/dist/module-evaluator.js +2 -6
- package/dist/node.d.ts +14 -11
- package/dist/node.js +20 -20
- package/dist/reporters.d.ts +7 -7
- package/dist/reporters.js +4 -2
- package/dist/runners.d.ts +23 -4
- package/dist/runners.js +4 -4
- package/dist/runtime.d.ts +6 -0
- package/dist/runtime.js +36 -0
- package/dist/snapshot.js +2 -0
- package/dist/suite.js +2 -0
- package/dist/worker.d.ts +4 -3
- package/dist/worker.js +10 -12
- package/dist/workers/forks.js +11 -13
- package/dist/workers/runVmTests.js +10 -12
- package/dist/workers/threads.js +11 -13
- package/dist/workers/vmForks.js +8 -9
- package/dist/workers/vmThreads.js +8 -9
- package/package.json +23 -27
- package/dist/chunks/date.Bq6ZW5rf.js +0 -73
- package/dist/chunks/rpc.BoxB0q7B.js +0 -76
- package/dist/chunks/test.B8ej_ZHS.js +0 -254
- package/dist/mocker.d.ts +0 -1
- package/dist/mocker.js +0 -1
- package/dist/module-runner.js +0 -17
|
@@ -4,7 +4,7 @@ import { C as CoverageProviderMap } from './coverage.D_JHT54q.js';
|
|
|
4
4
|
import path, { resolve as resolve$1 } from 'node:path';
|
|
5
5
|
import { noop, createDefer, slash, withTrailingSlash, cleanUrl, wrapId, isExternalUrl, unwrapId, toArray, deepMerge, nanoid, deepClone, isPrimitive, notNullish } from '@vitest/utils/helpers';
|
|
6
6
|
import { a as any, p as prompt } from './index.D4KonVSU.js';
|
|
7
|
-
import { h as hash, R as RandomSequencer, i as isPackageExists, c as isBrowserEnabled, r as resolveConfig, g as getCoverageProvider, a as resolveApiServerConfig, d as resolveModule } from './coverage.
|
|
7
|
+
import { h as hash, R as RandomSequencer, i as isPackageExists, c as isBrowserEnabled, r as resolveConfig, g as getCoverageProvider, a as resolveApiServerConfig, d as resolveModule } from './coverage.BMlOMIWl.js';
|
|
8
8
|
import * as vite from 'vite';
|
|
9
9
|
import { isFileServingAllowed as isFileServingAllowed$1, parseAst, searchForWorkspaceRoot, fetchModule, version, mergeConfig, createServer, isFileLoadingAllowed, normalizePath } from 'vite';
|
|
10
10
|
import { A as API_PATH, c as configFiles, d as defaultBrowserPort, a as defaultPort } from './constants.D_Q9UYh-.js';
|
|
@@ -12,10 +12,10 @@ import * as nodeos from 'node:os';
|
|
|
12
12
|
import nodeos__default, { tmpdir } from 'node:os';
|
|
13
13
|
import { generateHash as generateHash$1, createTaskName, calculateSuiteHash, someTasksAreOnly, interpretTaskModes, hasFailed, generateFileHash, limitConcurrency, createFileTask as createFileTask$1, getTasks, isTestCase } from '@vitest/runner/utils';
|
|
14
14
|
import { SnapshotManager } from '@vitest/snapshot/manager';
|
|
15
|
-
import { v as version$1 } from './cac.
|
|
15
|
+
import { v as version$1 } from './cac.B1v3xxoC.js';
|
|
16
16
|
import { performance as performance$1 } from 'node:perf_hooks';
|
|
17
17
|
import { c as createBirpc } from './index.Chj8NDwU.js';
|
|
18
|
-
import { p as parse, d as stringify, e as createIndexLocationsMap, h as TraceMap, o as originalPositionFor, i as ancestor, j as printError, f as formatProjectName, w as withLabel, k as errorBanner, l as divider, m as Typechecker, n as generateCodeFrame, q as escapeRegExp, r as createDefinesScript, R as ReportersMap, u as groupBy, B as BlobReporter, v as readBlobs, x as convertTasksToEvents, H as HangingProcessReporter, y as wildcardPatternToRegExp, z as stdout } from './index.
|
|
18
|
+
import { p as parse, d as stringify, e as createIndexLocationsMap, h as TraceMap, o as originalPositionFor, i as ancestor, j as printError, f as formatProjectName, w as withLabel, k as errorBanner, l as divider, m as Typechecker, n as generateCodeFrame, q as escapeRegExp, r as createDefinesScript, R as ReportersMap, u as groupBy, B as BlobReporter, v as readBlobs, x as convertTasksToEvents, H as HangingProcessReporter, y as wildcardPatternToRegExp, z as stdout } from './index.Dm4xqZ0s.js';
|
|
19
19
|
import require$$0$3 from 'events';
|
|
20
20
|
import require$$1$1 from 'https';
|
|
21
21
|
import require$$2 from 'http';
|
|
@@ -29,7 +29,7 @@ import require$$0$1 from 'buffer';
|
|
|
29
29
|
import { g as getDefaultExportFromCjs } from './_commonjsHelpers.D26ty3Ew.js';
|
|
30
30
|
import crypto, { createHash } from 'node:crypto';
|
|
31
31
|
import { rootDir, distDir } from '../path.js';
|
|
32
|
-
import { T as Traces } from './traces.
|
|
32
|
+
import { T as Traces } from './traces.CCmnQaNT.js';
|
|
33
33
|
import { createDebug } from 'obug';
|
|
34
34
|
import { rm, readFile, writeFile, rename, stat, unlink, mkdir, copyFile } from 'node:fs/promises';
|
|
35
35
|
import c from 'tinyrainbow';
|
|
@@ -53,7 +53,7 @@ import { c as configDefaults } from './defaults.BOqNVLsY.js';
|
|
|
53
53
|
import { KNOWN_ASSET_RE } from '@vitest/utils/constants';
|
|
54
54
|
import { findNearestPackageData } from '@vitest/utils/resolver';
|
|
55
55
|
import * as esModuleLexer from 'es-module-lexer';
|
|
56
|
-
import { a as BenchmarkReportsMap } from './index.
|
|
56
|
+
import { a as BenchmarkReportsMap } from './index.DyBZXrH3.js';
|
|
57
57
|
import assert$1 from 'node:assert';
|
|
58
58
|
import { serializeValue } from '@vitest/utils/serialize';
|
|
59
59
|
import { parseErrorStacktrace } from '@vitest/utils/source-map';
|
|
@@ -76,6 +76,7 @@ function requireConstants () {
|
|
|
76
76
|
|
|
77
77
|
constants = {
|
|
78
78
|
BINARY_TYPES,
|
|
79
|
+
CLOSE_TIMEOUT: 30000,
|
|
79
80
|
EMPTY_BUFFER: Buffer.alloc(0),
|
|
80
81
|
GUID: '258EAFA5-E914-47DA-95CA-C5AB0DC85B11',
|
|
81
82
|
hasBlob,
|
|
@@ -2846,6 +2847,7 @@ function requireWebsocket () {
|
|
|
2846
2847
|
|
|
2847
2848
|
const {
|
|
2848
2849
|
BINARY_TYPES,
|
|
2850
|
+
CLOSE_TIMEOUT,
|
|
2849
2851
|
EMPTY_BUFFER,
|
|
2850
2852
|
GUID,
|
|
2851
2853
|
kForOnEventAttribute,
|
|
@@ -2860,7 +2862,6 @@ function requireWebsocket () {
|
|
|
2860
2862
|
const { format, parse } = requireExtension();
|
|
2861
2863
|
const { toBuffer } = requireBufferUtil();
|
|
2862
2864
|
|
|
2863
|
-
const closeTimeout = 30 * 1000;
|
|
2864
2865
|
const kAborted = Symbol('kAborted');
|
|
2865
2866
|
const protocolVersions = [8, 13];
|
|
2866
2867
|
const readyStates = ['CONNECTING', 'OPEN', 'CLOSING', 'CLOSED'];
|
|
@@ -2916,6 +2917,7 @@ function requireWebsocket () {
|
|
|
2916
2917
|
initAsClient(this, address, protocols, options);
|
|
2917
2918
|
} else {
|
|
2918
2919
|
this._autoPong = options.autoPong;
|
|
2920
|
+
this._closeTimeout = options.closeTimeout;
|
|
2919
2921
|
this._isServer = true;
|
|
2920
2922
|
}
|
|
2921
2923
|
}
|
|
@@ -3457,6 +3459,8 @@ function requireWebsocket () {
|
|
|
3457
3459
|
* times in the same tick
|
|
3458
3460
|
* @param {Boolean} [options.autoPong=true] Specifies whether or not to
|
|
3459
3461
|
* automatically send a pong in response to a ping
|
|
3462
|
+
* @param {Number} [options.closeTimeout=30000] Duration in milliseconds to wait
|
|
3463
|
+
* for the closing handshake to finish after `websocket.close()` is called
|
|
3460
3464
|
* @param {Function} [options.finishRequest] A function which can be used to
|
|
3461
3465
|
* customize the headers of each http request before it is sent
|
|
3462
3466
|
* @param {Boolean} [options.followRedirects=false] Whether or not to follow
|
|
@@ -3483,6 +3487,7 @@ function requireWebsocket () {
|
|
|
3483
3487
|
const opts = {
|
|
3484
3488
|
allowSynchronousEvents: true,
|
|
3485
3489
|
autoPong: true,
|
|
3490
|
+
closeTimeout: CLOSE_TIMEOUT,
|
|
3486
3491
|
protocolVersion: protocolVersions[1],
|
|
3487
3492
|
maxPayload: 100 * 1024 * 1024,
|
|
3488
3493
|
skipUTF8Validation: false,
|
|
@@ -3501,6 +3506,7 @@ function requireWebsocket () {
|
|
|
3501
3506
|
};
|
|
3502
3507
|
|
|
3503
3508
|
websocket._autoPong = opts.autoPong;
|
|
3509
|
+
websocket._closeTimeout = opts.closeTimeout;
|
|
3504
3510
|
|
|
3505
3511
|
if (!protocolVersions.includes(opts.protocolVersion)) {
|
|
3506
3512
|
throw new RangeError(
|
|
@@ -4118,7 +4124,7 @@ function requireWebsocket () {
|
|
|
4118
4124
|
function setCloseTimer(websocket) {
|
|
4119
4125
|
websocket._closeTimer = setTimeout(
|
|
4120
4126
|
websocket._socket.destroy.bind(websocket._socket),
|
|
4121
|
-
|
|
4127
|
+
websocket._closeTimeout
|
|
4122
4128
|
);
|
|
4123
4129
|
}
|
|
4124
4130
|
|
|
@@ -4136,23 +4142,23 @@ function requireWebsocket () {
|
|
|
4136
4142
|
|
|
4137
4143
|
websocket._readyState = WebSocket.CLOSING;
|
|
4138
4144
|
|
|
4139
|
-
let chunk;
|
|
4140
|
-
|
|
4141
4145
|
//
|
|
4142
4146
|
// The close frame might not have been received or the `'end'` event emitted,
|
|
4143
4147
|
// for example, if the socket was destroyed due to an error. Ensure that the
|
|
4144
4148
|
// `receiver` stream is closed after writing any remaining buffered data to
|
|
4145
4149
|
// it. If the readable side of the socket is in flowing mode then there is no
|
|
4146
|
-
// buffered data as everything has been already written
|
|
4147
|
-
//
|
|
4148
|
-
//
|
|
4150
|
+
// buffered data as everything has been already written. If instead, the
|
|
4151
|
+
// socket is paused, any possible buffered data will be read as a single
|
|
4152
|
+
// chunk.
|
|
4149
4153
|
//
|
|
4150
4154
|
if (
|
|
4151
4155
|
!this._readableState.endEmitted &&
|
|
4152
4156
|
!websocket._closeFrameReceived &&
|
|
4153
4157
|
!websocket._receiver._writableState.errorEmitted &&
|
|
4154
|
-
|
|
4158
|
+
this._readableState.length !== 0
|
|
4155
4159
|
) {
|
|
4160
|
+
const chunk = this.read(this._readableState.length);
|
|
4161
|
+
|
|
4156
4162
|
websocket._receiver.write(chunk);
|
|
4157
4163
|
}
|
|
4158
4164
|
|
|
@@ -4483,7 +4489,7 @@ function requireWebsocketServer () {
|
|
|
4483
4489
|
const PerMessageDeflate = requirePermessageDeflate();
|
|
4484
4490
|
const subprotocol = requireSubprotocol();
|
|
4485
4491
|
const WebSocket = requireWebsocket();
|
|
4486
|
-
const { GUID, kWebSocket } = requireConstants();
|
|
4492
|
+
const { CLOSE_TIMEOUT, GUID, kWebSocket } = requireConstants();
|
|
4487
4493
|
|
|
4488
4494
|
const keyRegex = /^[+/0-9A-Za-z]{22}==$/;
|
|
4489
4495
|
|
|
@@ -4510,6 +4516,9 @@ function requireWebsocketServer () {
|
|
|
4510
4516
|
* pending connections
|
|
4511
4517
|
* @param {Boolean} [options.clientTracking=true] Specifies whether or not to
|
|
4512
4518
|
* track clients
|
|
4519
|
+
* @param {Number} [options.closeTimeout=30000] Duration in milliseconds to
|
|
4520
|
+
* wait for the closing handshake to finish after `websocket.close()` is
|
|
4521
|
+
* called
|
|
4513
4522
|
* @param {Function} [options.handleProtocols] A hook to handle protocols
|
|
4514
4523
|
* @param {String} [options.host] The hostname where to bind the server
|
|
4515
4524
|
* @param {Number} [options.maxPayload=104857600] The maximum allowed message
|
|
@@ -4539,6 +4548,7 @@ function requireWebsocketServer () {
|
|
|
4539
4548
|
perMessageDeflate: false,
|
|
4540
4549
|
handleProtocols: null,
|
|
4541
4550
|
clientTracking: true,
|
|
4551
|
+
closeTimeout: CLOSE_TIMEOUT,
|
|
4542
4552
|
verifyClient: null,
|
|
4543
4553
|
noServer: false,
|
|
4544
4554
|
backlog: null, // use default (511 as implemented in net.js)
|
|
@@ -5327,6 +5337,12 @@ function createDebugger(namespace) {
|
|
|
5327
5337
|
|
|
5328
5338
|
const debug$1 = createDebugger("vitest:ast-collect-info");
|
|
5329
5339
|
const verbose = createDebugger("vitest:ast-collect-verbose");
|
|
5340
|
+
function isTestFunctionName(name) {
|
|
5341
|
+
return name === "it" || name === "test" || name.startsWith("test") || name.endsWith("Test");
|
|
5342
|
+
}
|
|
5343
|
+
function isVitestFunctionName(name) {
|
|
5344
|
+
return name === "describe" || name === "suite" || isTestFunctionName(name);
|
|
5345
|
+
}
|
|
5330
5346
|
function astParseFile(filepath, code) {
|
|
5331
5347
|
const ast = parseAst(code);
|
|
5332
5348
|
if (verbose) verbose("Collecting", filepath, code);
|
|
@@ -5338,12 +5354,7 @@ function astParseFile(filepath, code) {
|
|
|
5338
5354
|
if (callee.type === "CallExpression") return getName(callee.callee);
|
|
5339
5355
|
if (callee.type === "TaggedTemplateExpression") return getName(callee.tag);
|
|
5340
5356
|
if (callee.type === "MemberExpression") {
|
|
5341
|
-
if (callee.object?.type === "Identifier" &&
|
|
5342
|
-
"it",
|
|
5343
|
-
"test",
|
|
5344
|
-
"describe",
|
|
5345
|
-
"suite"
|
|
5346
|
-
].includes(callee.object.name)) return callee.object?.name;
|
|
5357
|
+
if (callee.object?.type === "Identifier" && isVitestFunctionName(callee.object.name)) return callee.object?.name;
|
|
5347
5358
|
if (callee.object?.name?.startsWith("__vite_ssr_") || callee.object?.object?.name?.startsWith("__vite_ssr_") && callee.object?.property?.name === "Vitest") return getName(callee.property);
|
|
5348
5359
|
// call as `__vite_ssr__.test.skip()`
|
|
5349
5360
|
return getName(callee.object?.property);
|
|
@@ -5359,12 +5370,7 @@ function astParseFile(filepath, code) {
|
|
|
5359
5370
|
const { callee } = node;
|
|
5360
5371
|
const name = getName(callee);
|
|
5361
5372
|
if (!name) return;
|
|
5362
|
-
if (!
|
|
5363
|
-
"it",
|
|
5364
|
-
"test",
|
|
5365
|
-
"describe",
|
|
5366
|
-
"suite"
|
|
5367
|
-
].includes(name)) {
|
|
5373
|
+
if (!isVitestFunctionName(name)) {
|
|
5368
5374
|
verbose?.(`Skipping ${name} (unknown call)`);
|
|
5369
5375
|
return;
|
|
5370
5376
|
}
|
|
@@ -5375,7 +5381,9 @@ function astParseFile(filepath, code) {
|
|
|
5375
5381
|
"each",
|
|
5376
5382
|
"for",
|
|
5377
5383
|
"skipIf",
|
|
5378
|
-
"runIf"
|
|
5384
|
+
"runIf",
|
|
5385
|
+
"extend",
|
|
5386
|
+
"scoped"
|
|
5379
5387
|
].includes(mode)) return;
|
|
5380
5388
|
let start;
|
|
5381
5389
|
const end = node.end;
|
|
@@ -5405,7 +5413,7 @@ function astParseFile(filepath, code) {
|
|
|
5405
5413
|
start,
|
|
5406
5414
|
end,
|
|
5407
5415
|
name: message,
|
|
5408
|
-
type: name
|
|
5416
|
+
type: isTestFunctionName(name) ? "test" : "suite",
|
|
5409
5417
|
mode,
|
|
5410
5418
|
task: null,
|
|
5411
5419
|
dynamic: isDynamicEach
|
|
@@ -5494,7 +5502,10 @@ function createFileTask(testFilepath, code, requestMap, options) {
|
|
|
5494
5502
|
});
|
|
5495
5503
|
if (originalLocation.column != null) {
|
|
5496
5504
|
verbose?.(`Found location for`, definition.type, definition.name, `${processedLocation.line}:${processedLocation.column}`, "->", `${originalLocation.line}:${originalLocation.column}`);
|
|
5497
|
-
location =
|
|
5505
|
+
location = {
|
|
5506
|
+
line: originalLocation.line,
|
|
5507
|
+
column: originalLocation.column
|
|
5508
|
+
};
|
|
5498
5509
|
} else debug$1?.("Cannot find original location for", definition.type, definition.name, `${processedLocation.column}:${processedLocation.line}`);
|
|
5499
5510
|
} else debug$1?.("Cannot find original location for", definition.type, definition.name, `${definition.start}`);
|
|
5500
5511
|
if (definition.type === "suite") {
|
|
@@ -5543,7 +5554,7 @@ function createFileTask(testFilepath, code, requestMap, options) {
|
|
|
5543
5554
|
});
|
|
5544
5555
|
calculateSuiteHash(file);
|
|
5545
5556
|
const hasOnly = someTasksAreOnly(file);
|
|
5546
|
-
interpretTaskModes(file, options.testNamePattern, void 0, hasOnly, false, options.allowOnly);
|
|
5557
|
+
interpretTaskModes(file, options.testNamePattern, void 0, void 0, hasOnly, false, options.allowOnly);
|
|
5547
5558
|
markDynamicTests(file.tasks);
|
|
5548
5559
|
if (!file.tasks.length) file.result = {
|
|
5549
5560
|
state: "fail",
|
|
@@ -5570,9 +5581,9 @@ async function astCollectTests(project, filepath) {
|
|
|
5570
5581
|
});
|
|
5571
5582
|
}
|
|
5572
5583
|
async function transformSSR(project, filepath) {
|
|
5573
|
-
const
|
|
5574
|
-
if (
|
|
5575
|
-
return
|
|
5584
|
+
const environment = project.config.environment;
|
|
5585
|
+
if (environment === "jsdom" || environment === "happy-dom") return project.vite.environments.client.transformRequest(filepath);
|
|
5586
|
+
return project.vite.environments.ssr.transformRequest(filepath);
|
|
5576
5587
|
}
|
|
5577
5588
|
function markDynamicTests(tasks) {
|
|
5578
5589
|
for (const task of tasks) {
|
|
@@ -5771,7 +5782,7 @@ class FileSystemModuleCache {
|
|
|
5771
5782
|
*/
|
|
5772
5783
|
rootCache;
|
|
5773
5784
|
metadataFilePath;
|
|
5774
|
-
version = "1.0.0-beta.
|
|
5785
|
+
version = "1.0.0-beta.4";
|
|
5775
5786
|
fsCacheRoots = /* @__PURE__ */ new WeakMap();
|
|
5776
5787
|
fsEnvironmentHashMap = /* @__PURE__ */ new WeakMap();
|
|
5777
5788
|
fsCacheKeyGenerators = /* @__PURE__ */ new Set();
|
|
@@ -5828,18 +5839,16 @@ class FileSystemModuleCache {
|
|
|
5828
5839
|
url: meta.url,
|
|
5829
5840
|
file: meta.file,
|
|
5830
5841
|
code,
|
|
5831
|
-
importers: meta.importers,
|
|
5832
5842
|
importedUrls: meta.importedUrls,
|
|
5833
5843
|
mappings: meta.mappings
|
|
5834
5844
|
};
|
|
5835
5845
|
}
|
|
5836
|
-
async saveCachedModule(cachedFilePath, fetchResult,
|
|
5846
|
+
async saveCachedModule(cachedFilePath, fetchResult, importedUrls = [], mappings = false) {
|
|
5837
5847
|
if ("code" in fetchResult) {
|
|
5838
5848
|
const result = {
|
|
5839
5849
|
file: fetchResult.file,
|
|
5840
5850
|
id: fetchResult.id,
|
|
5841
5851
|
url: fetchResult.url,
|
|
5842
|
-
importers,
|
|
5843
5852
|
importedUrls,
|
|
5844
5853
|
mappings
|
|
5845
5854
|
};
|
|
@@ -6178,17 +6187,16 @@ class ModuleFetcher {
|
|
|
6178
6187
|
this.recordResult(trace, result);
|
|
6179
6188
|
return result;
|
|
6180
6189
|
});
|
|
6181
|
-
const cachedModule = await this.getCachedModule(cachePath, environment, moduleGraphModule);
|
|
6190
|
+
const cachedModule = await this.getCachedModule(cachePath, environment, moduleGraphModule, importer);
|
|
6182
6191
|
if (cachedModule) {
|
|
6183
6192
|
this.recordResult(trace, cachedModule);
|
|
6184
6193
|
return cachedModule;
|
|
6185
6194
|
}
|
|
6186
6195
|
const result = await this.fetchAndProcess(environment, url, importer, moduleGraphModule, options);
|
|
6187
|
-
const importers = this.getSerializedDependencies(moduleGraphModule);
|
|
6188
6196
|
const importedUrls = this.getSerializedImports(moduleGraphModule);
|
|
6189
6197
|
const map = moduleGraphModule.transformResult?.map;
|
|
6190
6198
|
const mappings = map && !("version" in map) && map.mappings === "";
|
|
6191
|
-
return this.cacheResult(result, cachePath,
|
|
6199
|
+
return this.cacheResult(result, cachePath, importedUrls, !!mappings);
|
|
6192
6200
|
}
|
|
6193
6201
|
// we need this for UI to be able to show a module graph
|
|
6194
6202
|
getSerializedImports(node) {
|
|
@@ -6198,14 +6206,6 @@ class ModuleFetcher {
|
|
|
6198
6206
|
});
|
|
6199
6207
|
return imports;
|
|
6200
6208
|
}
|
|
6201
|
-
// we need this for the watcher to be able to find the related test file
|
|
6202
|
-
getSerializedDependencies(node) {
|
|
6203
|
-
const dependencies = [];
|
|
6204
|
-
node.importers.forEach((importer) => {
|
|
6205
|
-
if (importer.id) dependencies.push(importer.id);
|
|
6206
|
-
});
|
|
6207
|
-
return dependencies;
|
|
6208
|
-
}
|
|
6209
6209
|
recordResult(trace, result) {
|
|
6210
6210
|
if ("externalize" in result) trace.setAttributes({
|
|
6211
6211
|
"vitest.fetched_module.external": result.externalize,
|
|
@@ -6242,7 +6242,7 @@ class ModuleFetcher {
|
|
|
6242
6242
|
if (loadResult != null) return loadResult.code;
|
|
6243
6243
|
return "";
|
|
6244
6244
|
}
|
|
6245
|
-
async getCachedModule(cachePath, environment, moduleGraphModule) {
|
|
6245
|
+
async getCachedModule(cachePath, environment, moduleGraphModule, importer) {
|
|
6246
6246
|
if (moduleGraphModule.transformResult?.__vitestTmp) return {
|
|
6247
6247
|
cached: true,
|
|
6248
6248
|
file: moduleGraphModule.file,
|
|
@@ -6265,13 +6265,16 @@ class ModuleFetcher {
|
|
|
6265
6265
|
__vitestTmp: cachePath
|
|
6266
6266
|
};
|
|
6267
6267
|
// we populate the module graph to make the watch mode work because it relies on importers
|
|
6268
|
-
|
|
6268
|
+
if (importer) {
|
|
6269
6269
|
const environmentNode = environment.moduleGraph.getModuleById(importer);
|
|
6270
6270
|
if (environmentNode) moduleGraphModule.importers.add(environmentNode);
|
|
6271
|
-
}
|
|
6271
|
+
}
|
|
6272
6272
|
await Promise.all(cachedModule.importedUrls.map(async (url) => {
|
|
6273
6273
|
const moduleNode = await environment.moduleGraph.ensureEntryFromUrl(url).catch(() => null);
|
|
6274
|
-
if (moduleNode)
|
|
6274
|
+
if (moduleNode) {
|
|
6275
|
+
moduleNode.importers.add(moduleGraphModule);
|
|
6276
|
+
moduleGraphModule.importedModules.add(moduleNode);
|
|
6277
|
+
}
|
|
6275
6278
|
}));
|
|
6276
6279
|
return {
|
|
6277
6280
|
cached: true,
|
|
@@ -6288,13 +6291,13 @@ class ModuleFetcher {
|
|
|
6288
6291
|
inlineSourceMap: false
|
|
6289
6292
|
}).catch(handleRollupError));
|
|
6290
6293
|
}
|
|
6291
|
-
async cacheResult(result, cachePath,
|
|
6294
|
+
async cacheResult(result, cachePath, importedUrls = [], mappings = false) {
|
|
6292
6295
|
const returnResult = "code" in result ? getCachedResult(result, cachePath) : result;
|
|
6293
6296
|
if (saveCachePromises.has(cachePath)) {
|
|
6294
6297
|
await saveCachePromises.get(cachePath);
|
|
6295
6298
|
return returnResult;
|
|
6296
6299
|
}
|
|
6297
|
-
const savePromise = this.fsCache.saveCachedModule(cachePath, result,
|
|
6300
|
+
const savePromise = this.fsCache.saveCachedModule(cachePath, result, importedUrls, mappings).then(() => result).finally(() => {
|
|
6298
6301
|
saveCachePromises.delete(cachePath);
|
|
6299
6302
|
});
|
|
6300
6303
|
saveCachePromises.set(cachePath, savePromise);
|
|
@@ -7056,11 +7059,13 @@ function createBrowserPool(vitest) {
|
|
|
7056
7059
|
};
|
|
7057
7060
|
const runWorkspaceTests = async (method, specs) => {
|
|
7058
7061
|
const groupedFiles = /* @__PURE__ */ new Map();
|
|
7059
|
-
for (const { project, moduleId, testLines } of specs) {
|
|
7062
|
+
for (const { project, moduleId, testLines, testIds, testNamePattern } of specs) {
|
|
7060
7063
|
const files = groupedFiles.get(project) || [];
|
|
7061
7064
|
files.push({
|
|
7062
7065
|
filepath: moduleId,
|
|
7063
|
-
testLocations: testLines
|
|
7066
|
+
testLocations: testLines,
|
|
7067
|
+
testIds,
|
|
7068
|
+
testNamePattern
|
|
7064
7069
|
});
|
|
7065
7070
|
groupedFiles.set(project, files);
|
|
7066
7071
|
}
|
|
@@ -7129,12 +7134,21 @@ class BrowserPool {
|
|
|
7129
7134
|
_promise;
|
|
7130
7135
|
_providedContext;
|
|
7131
7136
|
readySessions = /* @__PURE__ */ new Set();
|
|
7137
|
+
_traces;
|
|
7138
|
+
_otel;
|
|
7132
7139
|
constructor(project, options) {
|
|
7133
7140
|
this.project = project;
|
|
7134
7141
|
this.options = options;
|
|
7142
|
+
this._traces = project.vitest._traces;
|
|
7143
|
+
this._otel = this._traces.startContextSpan("vitest.browser");
|
|
7144
|
+
this._otel.span.setAttributes({
|
|
7145
|
+
"vitest.project": project.name,
|
|
7146
|
+
"vitest.browser.provider": this.project.browser.provider.name
|
|
7147
|
+
});
|
|
7135
7148
|
}
|
|
7136
7149
|
cancel() {
|
|
7137
7150
|
this._queue = [];
|
|
7151
|
+
this._otel.span.end();
|
|
7138
7152
|
}
|
|
7139
7153
|
reject(error) {
|
|
7140
7154
|
this._promise?.reject(error);
|
|
@@ -7172,7 +7186,11 @@ class BrowserPool {
|
|
|
7172
7186
|
this.project.vitest._browserSessions.sessionIds.add(sessionId);
|
|
7173
7187
|
const project = this.project.name;
|
|
7174
7188
|
debug?.("[%s] creating session for %s", sessionId, project);
|
|
7175
|
-
|
|
7189
|
+
let page = this._traces.$(`vitest.browser.open`, {
|
|
7190
|
+
context: this._otel.context,
|
|
7191
|
+
attributes: { "vitest.browser.session_id": sessionId }
|
|
7192
|
+
}, () => this.openPage(sessionId));
|
|
7193
|
+
page = page.then(() => {
|
|
7176
7194
|
// start running tests on the page when it's ready
|
|
7177
7195
|
this.runNextTest(method, sessionId);
|
|
7178
7196
|
});
|
|
@@ -7187,6 +7205,8 @@ class BrowserPool {
|
|
|
7187
7205
|
const browser = this.project.browser;
|
|
7188
7206
|
const url = new URL("/__vitest_test__/", this.options.origin);
|
|
7189
7207
|
url.searchParams.set("sessionId", sessionId);
|
|
7208
|
+
const otelCarrier = this._traces.getContextCarrier();
|
|
7209
|
+
if (otelCarrier) url.searchParams.set("otelCarrier", JSON.stringify(otelCarrier));
|
|
7190
7210
|
const pagePromise = browser.provider.openPage(sessionId, url.toString());
|
|
7191
7211
|
await Promise.all([sessionPromise, pagePromise]);
|
|
7192
7212
|
}
|
|
@@ -7199,6 +7219,7 @@ class BrowserPool {
|
|
|
7199
7219
|
this.readySessions.add(sessionId);
|
|
7200
7220
|
// the last worker finished running tests
|
|
7201
7221
|
if (this.readySessions.size === this.orchestrators.size) {
|
|
7222
|
+
this._otel.span.end();
|
|
7202
7223
|
this._promise?.resolve();
|
|
7203
7224
|
this._promise = void 0;
|
|
7204
7225
|
debug?.("[%s] all tests finished running", sessionId);
|
|
@@ -7221,11 +7242,16 @@ class BrowserPool {
|
|
|
7221
7242
|
const orchestrator = this.getOrchestrator(sessionId);
|
|
7222
7243
|
debug?.("[%s] run test %s", sessionId, file);
|
|
7223
7244
|
this.setBreakpoint(sessionId, file.filepath).then(() => {
|
|
7224
|
-
|
|
7225
|
-
|
|
7226
|
-
|
|
7227
|
-
|
|
7228
|
-
|
|
7245
|
+
this._traces.$(`vitest.browser.run`, {
|
|
7246
|
+
context: this._otel.context,
|
|
7247
|
+
attributes: { "code.file.path": file.filepath }
|
|
7248
|
+
}, async () => {
|
|
7249
|
+
return orchestrator.createTesters({
|
|
7250
|
+
method,
|
|
7251
|
+
files: [file],
|
|
7252
|
+
providedContext: this._providedContext || "[{}]",
|
|
7253
|
+
otelCarrier: this._traces.getContextCarrier()
|
|
7254
|
+
});
|
|
7229
7255
|
}).then(() => {
|
|
7230
7256
|
debug?.("[%s] test %s finished running", sessionId, file);
|
|
7231
7257
|
this.runNextTest(method, sessionId);
|
|
@@ -7359,6 +7385,7 @@ var RunnerState = /* @__PURE__ */ function(RunnerState) {
|
|
|
7359
7385
|
RunnerState["IDLE"] = "idle";
|
|
7360
7386
|
RunnerState["STARTING"] = "starting";
|
|
7361
7387
|
RunnerState["STARTED"] = "started";
|
|
7388
|
+
RunnerState["START_FAILURE"] = "start_failure";
|
|
7362
7389
|
RunnerState["STOPPING"] = "stopping";
|
|
7363
7390
|
RunnerState["STOPPED"] = "stopped";
|
|
7364
7391
|
return RunnerState;
|
|
@@ -7420,6 +7447,14 @@ class PoolRunner {
|
|
|
7420
7447
|
});
|
|
7421
7448
|
this._offCancel = vitest.onCancel((reason) => this._rpc.onCancel(reason));
|
|
7422
7449
|
}
|
|
7450
|
+
/**
|
|
7451
|
+
* "reconfigure" can only be called if `environment` is different, since different project always
|
|
7452
|
+
* requires a new PoolRunner instance.
|
|
7453
|
+
*/
|
|
7454
|
+
reconfigure(task) {
|
|
7455
|
+
this.environment = task.context.environment;
|
|
7456
|
+
this._otel?.span.setAttribute("vitest.environment", this.environment.name);
|
|
7457
|
+
}
|
|
7423
7458
|
postMessage(message) {
|
|
7424
7459
|
// Only send messages when runner is active (not fully stopped)
|
|
7425
7460
|
// Allow sending during STOPPING state for the 'stop' message itself
|
|
@@ -7495,7 +7530,7 @@ class PoolRunner {
|
|
|
7495
7530
|
await startPromise;
|
|
7496
7531
|
this._state = RunnerState.STARTED;
|
|
7497
7532
|
} catch (error) {
|
|
7498
|
-
this._state = RunnerState.
|
|
7533
|
+
this._state = RunnerState.START_FAILURE;
|
|
7499
7534
|
startSpan?.recordException(error);
|
|
7500
7535
|
throw error;
|
|
7501
7536
|
} finally {
|
|
@@ -7932,6 +7967,9 @@ class VmForksPoolWorker extends ForksPoolWorker {
|
|
|
7932
7967
|
/** Loads {@link file://./../../../runtime/workers/vmForks.ts} */
|
|
7933
7968
|
this.entrypoint = resolve$1(options.distPath, "workers/vmForks.js");
|
|
7934
7969
|
}
|
|
7970
|
+
canReuse() {
|
|
7971
|
+
return true;
|
|
7972
|
+
}
|
|
7935
7973
|
}
|
|
7936
7974
|
|
|
7937
7975
|
/** @experimental */
|
|
@@ -7947,6 +7985,9 @@ class VmThreadsPoolWorker extends ThreadsPoolWorker {
|
|
|
7947
7985
|
/** Loads {@link file://./../../../runtime/workers/vmThreads.ts} */
|
|
7948
7986
|
this.entrypoint = resolve$1(options.distPath, "workers/vmThreads.js");
|
|
7949
7987
|
}
|
|
7988
|
+
canReuse() {
|
|
7989
|
+
return true;
|
|
7990
|
+
}
|
|
7950
7991
|
}
|
|
7951
7992
|
|
|
7952
7993
|
const WORKER_START_TIMEOUT = 9e4;
|
|
@@ -8015,17 +8056,15 @@ class Pool {
|
|
|
8015
8056
|
resolver.reject(new Error(`[vitest-pool]: Worker ${task.worker} emitted error.`, { cause: error }));
|
|
8016
8057
|
});
|
|
8017
8058
|
const id = setTimeout(() => resolver.reject(/* @__PURE__ */ new Error(`[vitest-pool]: Timeout starting ${task.worker} runner.`)), WORKER_START_TIMEOUT);
|
|
8018
|
-
await runner.start({ workerId: task.context.workerId }).finally(() => clearTimeout(id));
|
|
8059
|
+
await runner.start({ workerId: task.context.workerId }).catch((error) => resolver.reject(new Error(`[vitest-pool]: Failed to start ${task.worker} worker for test files ${formatFiles(task)}.`, { cause: error }))).finally(() => clearTimeout(id));
|
|
8019
8060
|
}
|
|
8020
|
-
|
|
8021
|
-
|
|
8022
|
-
|
|
8023
|
-
|
|
8024
|
-
|
|
8025
|
-
|
|
8026
|
-
|
|
8027
|
-
span.end();
|
|
8028
|
-
});
|
|
8061
|
+
let span;
|
|
8062
|
+
if (!resolver.isRejected) {
|
|
8063
|
+
span = runner.startTracesSpan(`vitest.worker.${method}`);
|
|
8064
|
+
// Start running the test in the worker
|
|
8065
|
+
runner.request(method, task.context);
|
|
8066
|
+
}
|
|
8067
|
+
await resolver.promise.catch((error) => span?.recordException(error)).finally(() => span?.end());
|
|
8029
8068
|
const index = this.activeTasks.indexOf(activeTask);
|
|
8030
8069
|
if (index !== -1) this.activeTasks.splice(index, 1);
|
|
8031
8070
|
if (!task.isolate && !isMemoryLimitReached && this.queue[0]?.task.isolate === false && isEqualRunner(runner, this.queue[0].task)) {
|
|
@@ -8036,7 +8075,7 @@ class Pool {
|
|
|
8036
8075
|
// Runner termination can also already start from task cancellation.
|
|
8037
8076
|
if (!runner.isTerminated) {
|
|
8038
8077
|
const id = setTimeout(() => this.logger.error(`[vitest-pool]: Timeout terminating ${task.worker} worker for test files ${formatFiles(task)}.`), this.options.teardownTimeout);
|
|
8039
|
-
this.exitPromises.push(runner.stop().then(() => clearTimeout(id)).catch((error) => this.logger.error(`[vitest-pool]: Failed to terminate ${task.worker} worker for test files ${formatFiles(task)}.`, error)));
|
|
8078
|
+
this.exitPromises.push(runner.stop({ force: resolver.isRejected }).then(() => clearTimeout(id)).catch((error) => this.logger.error(`[vitest-pool]: Failed to terminate ${task.worker} worker for test files ${formatFiles(task)}.`, error)));
|
|
8040
8079
|
}
|
|
8041
8080
|
this.freeWorkerId(poolId);
|
|
8042
8081
|
}
|
|
@@ -8073,13 +8112,17 @@ catch (error) {
|
|
|
8073
8112
|
getPoolRunner(task, method) {
|
|
8074
8113
|
if (task.isolate === false) {
|
|
8075
8114
|
const index = this.sharedRunners.findIndex((runner) => isEqualRunner(runner, task));
|
|
8076
|
-
if (index !== -1)
|
|
8115
|
+
if (index !== -1) {
|
|
8116
|
+
const runner = this.sharedRunners.splice(index, 1)[0];
|
|
8117
|
+
runner.reconfigure(task);
|
|
8118
|
+
return runner;
|
|
8119
|
+
}
|
|
8077
8120
|
}
|
|
8078
8121
|
const options = {
|
|
8079
8122
|
distPath: this.options.distPath,
|
|
8080
8123
|
project: task.project,
|
|
8081
8124
|
method,
|
|
8082
|
-
environment: task.environment,
|
|
8125
|
+
environment: task.context.environment,
|
|
8083
8126
|
env: task.env,
|
|
8084
8127
|
execArgv: task.execArgv
|
|
8085
8128
|
};
|
|
@@ -8111,22 +8154,44 @@ catch (error) {
|
|
|
8111
8154
|
function withResolvers() {
|
|
8112
8155
|
let resolve = () => {};
|
|
8113
8156
|
let reject = (_error) => {};
|
|
8114
|
-
const
|
|
8115
|
-
|
|
8116
|
-
|
|
8117
|
-
|
|
8118
|
-
|
|
8157
|
+
const resolver = {
|
|
8158
|
+
promise: new Promise((res, rej) => {
|
|
8159
|
+
resolve = res;
|
|
8160
|
+
reject = rej;
|
|
8161
|
+
}),
|
|
8119
8162
|
resolve,
|
|
8120
|
-
reject
|
|
8121
|
-
|
|
8163
|
+
reject: (reason) => {
|
|
8164
|
+
resolver.isRejected = true;
|
|
8165
|
+
reject(reason);
|
|
8166
|
+
},
|
|
8167
|
+
isRejected: false
|
|
8122
8168
|
};
|
|
8169
|
+
return resolver;
|
|
8123
8170
|
}
|
|
8124
8171
|
function formatFiles(task) {
|
|
8125
8172
|
return task.context.files.map((file) => file.filepath).join(", ");
|
|
8126
8173
|
}
|
|
8127
8174
|
function isEqualRunner(runner, task) {
|
|
8128
8175
|
if (task.isolate) throw new Error("Isolated tasks should not share runners");
|
|
8129
|
-
|
|
8176
|
+
if (runner.worker.name !== task.worker || runner.project !== task.project) return false;
|
|
8177
|
+
// by default, check that the environments are the same
|
|
8178
|
+
// some workers (like vmThreads/vmForks) do not need this check
|
|
8179
|
+
if (!runner.worker.canReuse) return isEnvironmentEqual(task.context.environment, runner.environment);
|
|
8180
|
+
return runner.worker.canReuse(task);
|
|
8181
|
+
}
|
|
8182
|
+
function isEnvironmentEqual(env1, env2) {
|
|
8183
|
+
if (env1.name !== env2.name) return false;
|
|
8184
|
+
return deepEqual(env1.options, env2.options);
|
|
8185
|
+
}
|
|
8186
|
+
function deepEqual(obj1, obj2) {
|
|
8187
|
+
if (obj1 === obj2) return true;
|
|
8188
|
+
if (obj1 == null || obj2 == null) return obj1 === obj2;
|
|
8189
|
+
if (typeof obj1 !== "object" || typeof obj2 !== "object") return false;
|
|
8190
|
+
const keys1 = Object.keys(obj1);
|
|
8191
|
+
const keys2 = Object.keys(obj2);
|
|
8192
|
+
if (keys1.length !== keys2.length) return false;
|
|
8193
|
+
for (const key of keys1) if (!keys2.includes(key) || !deepEqual(obj1[key], obj2[key])) return false;
|
|
8194
|
+
return true;
|
|
8130
8195
|
}
|
|
8131
8196
|
|
|
8132
8197
|
const suppressWarningsPath = resolve(rootDir, "./suppress-warnings.cjs");
|
|
@@ -8195,13 +8260,15 @@ function createPool(ctx) {
|
|
|
8195
8260
|
context: {
|
|
8196
8261
|
files: specs.map((spec) => ({
|
|
8197
8262
|
filepath: spec.moduleId,
|
|
8198
|
-
testLocations: spec.testLines
|
|
8263
|
+
testLocations: spec.testLines,
|
|
8264
|
+
testNamePattern: spec.testNamePattern,
|
|
8265
|
+
testIds: spec.testIds
|
|
8199
8266
|
})),
|
|
8200
8267
|
invalidates,
|
|
8201
8268
|
providedContext: project.getProvidedContext(),
|
|
8202
|
-
workerId: workerId
|
|
8269
|
+
workerId: workerId++,
|
|
8270
|
+
environment
|
|
8203
8271
|
},
|
|
8204
|
-
environment,
|
|
8205
8272
|
project,
|
|
8206
8273
|
env,
|
|
8207
8274
|
execArgv,
|
|
@@ -8468,7 +8535,8 @@ function serializeConfig(project) {
|
|
|
8468
8535
|
serializedDefines: config.browser.enabled ? "" : project._serializedDefines || "",
|
|
8469
8536
|
experimental: {
|
|
8470
8537
|
fsModuleCache: config.experimental.fsModuleCache ?? false,
|
|
8471
|
-
printImportBreakdown: config.experimental.printImportBreakdown
|
|
8538
|
+
printImportBreakdown: config.experimental.printImportBreakdown,
|
|
8539
|
+
openTelemetry: config.experimental.openTelemetry
|
|
8472
8540
|
}
|
|
8473
8541
|
};
|
|
8474
8542
|
}
|
|
@@ -9550,6 +9618,7 @@ function WorkspaceVitestPlugin(project, options) {
|
|
|
9550
9618
|
this.meta.watchMode = false;
|
|
9551
9619
|
},
|
|
9552
9620
|
config(viteConfig) {
|
|
9621
|
+
const originalDefine = { ...viteConfig.define };
|
|
9553
9622
|
const defines = deleteDefineConfig(viteConfig);
|
|
9554
9623
|
const testConfig = viteConfig.test || {};
|
|
9555
9624
|
const root = testConfig.root || viteConfig.root || options.root;
|
|
@@ -9586,6 +9655,7 @@ function WorkspaceVitestPlugin(project, options) {
|
|
|
9586
9655
|
}
|
|
9587
9656
|
};
|
|
9588
9657
|
config.test.defines = defines;
|
|
9658
|
+
config.test.viteDefine = originalDefine;
|
|
9589
9659
|
const classNameStrategy = typeof testConfig.css !== "boolean" && testConfig.css?.modules?.classNameStrategy || "stable";
|
|
9590
9660
|
if (classNameStrategy !== "scoped") {
|
|
9591
9661
|
config.css ??= {};
|
|
@@ -9752,7 +9822,7 @@ function matchPattern(id, moduleDirectories, patterns) {
|
|
|
9752
9822
|
|
|
9753
9823
|
class TestSpecification {
|
|
9754
9824
|
/**
|
|
9755
|
-
* The task
|
|
9825
|
+
* The task id associated with the test module.
|
|
9756
9826
|
*/
|
|
9757
9827
|
taskId;
|
|
9758
9828
|
/**
|
|
@@ -9760,29 +9830,46 @@ class TestSpecification {
|
|
|
9760
9830
|
*/
|
|
9761
9831
|
project;
|
|
9762
9832
|
/**
|
|
9763
|
-
* The
|
|
9833
|
+
* The id of the module in the Vite module graph. It is usually an absolute file path.
|
|
9764
9834
|
*/
|
|
9765
9835
|
moduleId;
|
|
9766
9836
|
/**
|
|
9767
|
-
* The current test pool. It's possible to have multiple pools in a single test project with `
|
|
9768
|
-
* @experimental In
|
|
9837
|
+
* The current test pool. It's possible to have multiple pools in a single test project with `typecheck.enabled`.
|
|
9838
|
+
* @experimental In later versions, the project will only support a single pool.
|
|
9769
9839
|
*/
|
|
9770
9840
|
pool;
|
|
9771
9841
|
/**
|
|
9772
9842
|
* Line numbers of the test locations to run.
|
|
9773
9843
|
*/
|
|
9774
9844
|
testLines;
|
|
9775
|
-
|
|
9776
|
-
|
|
9777
|
-
|
|
9845
|
+
/**
|
|
9846
|
+
* Regular expression pattern to filter test names.
|
|
9847
|
+
*/
|
|
9848
|
+
testNamePattern;
|
|
9849
|
+
/**
|
|
9850
|
+
* The ids of tasks inside of this specification to run.
|
|
9851
|
+
*/
|
|
9852
|
+
testIds;
|
|
9853
|
+
/**
|
|
9854
|
+
* This class represents a test suite for a test module within a single project.
|
|
9855
|
+
* @internal
|
|
9856
|
+
*/
|
|
9857
|
+
constructor(project, moduleId, pool, testLinesOrOptions) {
|
|
9858
|
+
const projectName = project.config.name;
|
|
9859
|
+
const hashName = pool !== "typescript" ? projectName : projectName ? `${projectName}:__typecheck__` : "__typecheck__";
|
|
9778
9860
|
this.taskId = generateFileHash(relative(project.config.root, moduleId), hashName);
|
|
9779
9861
|
this.project = project;
|
|
9780
9862
|
this.moduleId = moduleId;
|
|
9781
9863
|
this.pool = pool;
|
|
9782
|
-
this.testLines =
|
|
9864
|
+
if (Array.isArray(testLinesOrOptions)) this.testLines = testLinesOrOptions;
|
|
9865
|
+
else if (testLinesOrOptions && typeof testLinesOrOptions === "object") {
|
|
9866
|
+
this.testLines = testLinesOrOptions.testLines;
|
|
9867
|
+
this.testNamePattern = testLinesOrOptions.testNamePattern;
|
|
9868
|
+
this.testIds = testLinesOrOptions.testIds;
|
|
9869
|
+
}
|
|
9783
9870
|
}
|
|
9784
9871
|
/**
|
|
9785
|
-
* Test module associated with the specification.
|
|
9872
|
+
* Test module associated with the specification. This will be `undefined` if tests have not been run yet.
|
|
9786
9873
|
*/
|
|
9787
9874
|
get testModule() {
|
|
9788
9875
|
const task = this.project.vitest.state.idMap.get(this.taskId);
|
|
@@ -9798,7 +9885,9 @@ class TestSpecification {
|
|
|
9798
9885
|
this.moduleId,
|
|
9799
9886
|
{
|
|
9800
9887
|
pool: this.pool,
|
|
9801
|
-
testLines: this.testLines
|
|
9888
|
+
testLines: this.testLines,
|
|
9889
|
+
testIds: this.testIds,
|
|
9890
|
+
testNamePattern: this.testNamePattern
|
|
9802
9891
|
}
|
|
9803
9892
|
];
|
|
9804
9893
|
}
|
|
@@ -9907,8 +9996,8 @@ class TestProject {
|
|
|
9907
9996
|
* Creates a new test specification. Specifications describe how to run tests.
|
|
9908
9997
|
* @param moduleId The file path
|
|
9909
9998
|
*/
|
|
9910
|
-
createSpecification(moduleId,
|
|
9911
|
-
return new TestSpecification(this, moduleId, pool || getFilePoolName(this),
|
|
9999
|
+
createSpecification(moduleId, locationsOrOptions, pool) {
|
|
10000
|
+
return new TestSpecification(this, moduleId, pool || getFilePoolName(this), locationsOrOptions);
|
|
9912
10001
|
}
|
|
9913
10002
|
toJSON() {
|
|
9914
10003
|
return {
|
|
@@ -10106,7 +10195,7 @@ class TestProject {
|
|
|
10106
10195
|
_initParentBrowser = deduped(async (childProject) => {
|
|
10107
10196
|
if (!this.isBrowserEnabled() || this._parentBrowser) return;
|
|
10108
10197
|
const provider = this.config.browser.provider || childProject.config.browser.provider;
|
|
10109
|
-
if (provider == null) throw new Error(`
|
|
10198
|
+
if (provider == null) throw new Error(`Provider was not specified in the "browser.provider" setting. Please, pass down playwright(), webdriverio() or preview() from "@vitest/browser-playwright", "@vitest/browser-webdriverio" or "@vitest/browser-preview" package respectively.`);
|
|
10110
10199
|
if (typeof provider.serverFactory !== "function") throw new TypeError(`The browser provider options do not return a "serverFactory" function. Are you using the latest "@vitest/browser-${provider.name}" package?`);
|
|
10111
10200
|
const browser = await provider.serverFactory({
|
|
10112
10201
|
project: this,
|
|
@@ -10133,7 +10222,7 @@ class TestProject {
|
|
|
10133
10222
|
if (!this.closingPromise) this.closingPromise = Promise.all([
|
|
10134
10223
|
this.vite?.close(),
|
|
10135
10224
|
this.typechecker?.stop(),
|
|
10136
|
-
this.browser?.close(),
|
|
10225
|
+
(this.browser || this._parent?._parentBrowser?.vite)?.close(),
|
|
10137
10226
|
this.clearTmpDir()
|
|
10138
10227
|
].filter(Boolean)).then(() => {
|
|
10139
10228
|
if (!this.runner.isClosed()) return this.runner.close();
|
|
@@ -10159,6 +10248,7 @@ class TestProject {
|
|
|
10159
10248
|
...options,
|
|
10160
10249
|
coverage: this.vitest.config.coverage
|
|
10161
10250
|
}, server.config);
|
|
10251
|
+
this._config.api.token = this.vitest.config.api.token;
|
|
10162
10252
|
this._setHash();
|
|
10163
10253
|
for (const _providedKey in this.config.provide) {
|
|
10164
10254
|
const providedKey = _providedKey;
|
|
@@ -10411,7 +10501,7 @@ async function resolveBrowserProjects(vitest, names, resolvedProjects) {
|
|
|
10411
10501
|
return resolvedProjects.filter((project) => !removeProjects.has(project));
|
|
10412
10502
|
}
|
|
10413
10503
|
function cloneConfig(project, { browser, ...config }) {
|
|
10414
|
-
const { locators, viewport, testerHtmlPath, headless, screenshotDirectory, screenshotFailures, browser: _browser, name, provider, ...overrideConfig } = config;
|
|
10504
|
+
const { locators, viewport, testerHtmlPath, headless, screenshotDirectory, screenshotFailures, fileParallelism, browser: _browser, name, provider, ...overrideConfig } = config;
|
|
10415
10505
|
const currentConfig = project.config.browser;
|
|
10416
10506
|
const clonedConfig = deepClone(project.config);
|
|
10417
10507
|
return mergeConfig({
|
|
@@ -10425,6 +10515,7 @@ function cloneConfig(project, { browser, ...config }) {
|
|
|
10425
10515
|
screenshotFailures: screenshotFailures ?? currentConfig.screenshotFailures,
|
|
10426
10516
|
headless: headless ?? currentConfig.headless,
|
|
10427
10517
|
provider: provider ?? currentConfig.provider,
|
|
10518
|
+
fileParallelism: fileParallelism ?? currentConfig.fileParallelism,
|
|
10428
10519
|
name: browser,
|
|
10429
10520
|
instances: []
|
|
10430
10521
|
},
|
|
@@ -11767,6 +11858,12 @@ class TestRun {
|
|
|
11767
11858
|
const task = this.vitest.state.idMap.get(id);
|
|
11768
11859
|
const entity = task && this.vitest.state.getReportedEntity(task);
|
|
11769
11860
|
assert$1(task && entity, `Entity must be found for task ${task?.name || id}`);
|
|
11861
|
+
if (event === "suite-failed-early" && entity.type === "module") {
|
|
11862
|
+
// the file failed during import
|
|
11863
|
+
await this.vitest.report("onTestModuleStart", entity);
|
|
11864
|
+
await this.vitest.report("onTestModuleEnd", entity);
|
|
11865
|
+
return;
|
|
11866
|
+
}
|
|
11770
11867
|
if (event === "suite-prepare" && entity.type === "suite") return await this.vitest.report("onTestSuiteReady", entity);
|
|
11771
11868
|
if (event === "suite-prepare" && entity.type === "module") return await this.vitest.report("onTestModuleStart", entity);
|
|
11772
11869
|
if (event === "suite-finished") {
|
|
@@ -12401,7 +12498,7 @@ class Vitest {
|
|
|
12401
12498
|
* @param filters String filters to match the test files
|
|
12402
12499
|
*/
|
|
12403
12500
|
async start(filters) {
|
|
12404
|
-
return this._traces.$("vitest.start", async (startSpan) => {
|
|
12501
|
+
return this._traces.$("vitest.start", { context: this._traces.getContextFromEnv(process.env) }, async (startSpan) => {
|
|
12405
12502
|
startSpan.setAttributes({ config: this.vite.config.configFile });
|
|
12406
12503
|
try {
|
|
12407
12504
|
await this._traces.$("vitest.coverage.init", async () => {
|
|
@@ -12413,7 +12510,7 @@ class Vitest {
|
|
|
12413
12510
|
}
|
|
12414
12511
|
this.filenamePattern = filters && filters?.length > 0 ? filters : void 0;
|
|
12415
12512
|
startSpan.setAttribute("vitest.start.filters", this.filenamePattern || []);
|
|
12416
|
-
const
|
|
12513
|
+
const specifications = await this._traces.$("vitest.config.resolve_include_glob", async () => {
|
|
12417
12514
|
const specifications = await this.specifications.getRelevantTestSpecifications(filters);
|
|
12418
12515
|
startSpan.setAttribute("vitest.start.specifications", specifications.map((s) => {
|
|
12419
12516
|
const relativeModuleId = relative(s.project.config.root, s.moduleId);
|
|
@@ -12423,7 +12520,7 @@ class Vitest {
|
|
|
12423
12520
|
return specifications;
|
|
12424
12521
|
});
|
|
12425
12522
|
// if run with --changed, don't exit if no tests are found
|
|
12426
|
-
if (!
|
|
12523
|
+
if (!specifications.length) {
|
|
12427
12524
|
await this._traces.$("vitest.test_run", async () => {
|
|
12428
12525
|
await this._testRun.start([]);
|
|
12429
12526
|
const coverage = await this.coverageProvider?.generateCoverage?.({ allTestsRun: true });
|
|
@@ -12437,10 +12534,10 @@ class Vitest {
|
|
|
12437
12534
|
testModules: [],
|
|
12438
12535
|
unhandledErrors: []
|
|
12439
12536
|
};
|
|
12440
|
-
if (
|
|
12537
|
+
if (specifications.length) {
|
|
12441
12538
|
// populate once, update cache on watch
|
|
12442
|
-
await this.cache.stats.populateStats(this.config.root,
|
|
12443
|
-
testModules = await this.runFiles(
|
|
12539
|
+
await this.cache.stats.populateStats(this.config.root, specifications);
|
|
12540
|
+
testModules = await this.runFiles(specifications, true);
|
|
12444
12541
|
}
|
|
12445
12542
|
if (this.config.watch) await this.report("onWatcherStart");
|
|
12446
12543
|
return testModules;
|
|
@@ -12499,6 +12596,19 @@ class Vitest {
|
|
|
12499
12596
|
return this.runFiles(specifications, allTestsRun);
|
|
12500
12597
|
}
|
|
12501
12598
|
/**
|
|
12599
|
+
* Runs tests for the given file paths. This does not trigger `onWatcher*` events.
|
|
12600
|
+
* @param filepaths A list of file paths to run tests for.
|
|
12601
|
+
* @param allTestsRun Indicates whether all tests were run. This only matters for coverage.
|
|
12602
|
+
*/
|
|
12603
|
+
async runTestFiles(filepaths, allTestsRun = false) {
|
|
12604
|
+
const specifications = await this.specifications.getRelevantTestSpecifications(filepaths);
|
|
12605
|
+
if (!specifications.length) return {
|
|
12606
|
+
testModules: [],
|
|
12607
|
+
unhandledErrors: []
|
|
12608
|
+
};
|
|
12609
|
+
return this.runFiles(specifications, allTestsRun);
|
|
12610
|
+
}
|
|
12611
|
+
/**
|
|
12502
12612
|
* Rerun files and trigger `onWatcherRerun`, `onWatcherStart` and `onTestsRerun` events.
|
|
12503
12613
|
* @param specifications A list of specifications to run.
|
|
12504
12614
|
* @param allTestsRun Indicates whether all tests were run. This only matters for coverage.
|
|
@@ -12989,7 +13099,12 @@ async function VitestPlugin(options = {}, vitest = new Vitest("test", deepClone(
|
|
|
12989
13099
|
// this is repeated in configResolved where the config is final
|
|
12990
13100
|
const testConfig = deepMerge({}, configDefaults, removeUndefinedValues(viteConfig.test ?? {}), options);
|
|
12991
13101
|
testConfig.api = resolveApiServerConfig(testConfig, defaultPort);
|
|
12992
|
-
|
|
13102
|
+
// store defines for globalThis to make them
|
|
13103
|
+
// reassignable when running in worker in src/runtime/setup.ts
|
|
13104
|
+
const originalDefine = { ...viteConfig.define };
|
|
13105
|
+
const defines = deleteDefineConfig(viteConfig);
|
|
13106
|
+
options.defines = defines;
|
|
13107
|
+
options.viteDefine = originalDefine;
|
|
12993
13108
|
let open = false;
|
|
12994
13109
|
if (testConfig.ui && testConfig.open) open = testConfig.uiBase ?? "/__vitest__/";
|
|
12995
13110
|
const resolveOptions = getDefaultResolveOptions();
|