@vitest/browser 5.0.0-beta.6 → 5.0.0-beta.7
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/client/.vite/manifest.json +2 -2
- package/dist/client/__vitest_browser__/{orchestrator-pKob2Z-i.js → orchestrator-Bdv4lWwV.js} +9 -2
- package/dist/client/__vitest_browser__/{tester-DdZeFrjo.js → tester-CREI5Ivt.js} +20 -9
- package/dist/client/orchestrator.html +1 -1
- package/dist/client/tester/tester.html +1 -1
- package/dist/context.js +4 -2
- package/dist/expect-element.js +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.js +507 -532
- package/dist/{locators-CVQtUwrj.js → locators-Cxk-0tRh.js} +1 -1
- package/dist/locators.js +1 -1
- package/dist/state.js +1 -0
- package/package.json +7 -7
package/dist/index.js
CHANGED
|
@@ -1,27 +1,24 @@
|
|
|
1
|
+
import fs, { promises, existsSync, readFileSync, createReadStream } from 'node:fs';
|
|
2
|
+
import { createRequire } from 'node:module';
|
|
1
3
|
import { ManualMockedModule, RedirectedModule, AutomockedModule, AutospiedModule, MockerRegistry } from '@vitest/mocker';
|
|
2
4
|
import { dynamicImportPlugin, ServerMockResolver, interceptorPlugin } from '@vitest/mocker/node';
|
|
3
|
-
import c from 'tinyrainbow';
|
|
4
|
-
import { isFileLoadingAllowed, isValidApiRequest, isFileServingAllowed, distDir, rolldownVersion, resolveApiServerConfig, resolveFsAllow, createDebugger, createViteLogger, createViteServer } from 'vitest/node';
|
|
5
|
-
import { fileURLToPath } from 'node:url';
|
|
6
|
-
import fs, { readFileSync, createReadStream, promises, existsSync } from 'node:fs';
|
|
7
|
-
import { createRequire } from 'node:module';
|
|
8
5
|
import { distClientRoot } from '@vitest/ui';
|
|
9
|
-
import { slash as slash$1,
|
|
10
|
-
import MagicString from 'magic-string';
|
|
6
|
+
import { slash as slash$1, deepMerge, cleanUrl as cleanUrl$1, toArray } from '@vitest/utils/helpers';
|
|
11
7
|
import sirv from 'sirv';
|
|
8
|
+
import c from 'tinyrainbow';
|
|
9
|
+
import { isFileLoadingAllowed, createDebugger, isValidApiRequest, isCSSRequest, distDir, rolldownVersion, isFileServingAllowed } from 'vitest/node';
|
|
10
|
+
import { fileURLToPath } from 'node:url';
|
|
12
11
|
import crypto from 'node:crypto';
|
|
13
|
-
import
|
|
14
|
-
import 'vite';
|
|
12
|
+
import MagicString from 'magic-string';
|
|
15
13
|
import { readFile as readFile$1, mkdir, writeFile as writeFile$1 } from 'node:fs/promises';
|
|
16
14
|
import { parseErrorStacktrace, parseStacktrace } from '@vitest/utils/source-map';
|
|
17
15
|
import { extractSourcemapFromFile } from '@vitest/utils/source-map/node';
|
|
18
16
|
import { resolve as resolve$1, basename as basename$1, dirname as dirname$1 } from 'node:path';
|
|
17
|
+
import { platform } from 'node:os';
|
|
19
18
|
import { PNG } from 'pngjs';
|
|
20
19
|
import { diff } from '@blazediff/core';
|
|
21
20
|
import { WebSocketServer } from 'ws';
|
|
22
21
|
|
|
23
|
-
var version = "5.0.0-beta.6";
|
|
24
|
-
|
|
25
22
|
const _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
|
|
26
23
|
function normalizeWindowsPath(input = "") {
|
|
27
24
|
if (!input) {
|
|
@@ -212,11 +209,11 @@ const basename = function(p, extension) {
|
|
|
212
209
|
return extension && lastSegment.endsWith(extension) ? lastSegment.slice(0, -extension.length) : lastSegment;
|
|
213
210
|
};
|
|
214
211
|
|
|
212
|
+
var version = "5.0.0-beta.7";
|
|
213
|
+
|
|
215
214
|
const pkgRoot = resolve(fileURLToPath(import.meta.url), "../..");
|
|
216
215
|
const distRoot = resolve(pkgRoot, "dist");
|
|
217
216
|
|
|
218
|
-
const API_TOKEN_FILE = ".vitest-secret-token";
|
|
219
|
-
|
|
220
217
|
/// <reference types="../types/index.d.ts" />
|
|
221
218
|
|
|
222
219
|
// (c) 2020-present Andrea Giammarchi
|
|
@@ -685,7 +682,7 @@ function assertBrowserFileAccess(project, path) {
|
|
|
685
682
|
}
|
|
686
683
|
}
|
|
687
684
|
function assertBrowserApiWrite(project, path) {
|
|
688
|
-
if (!project.config.
|
|
685
|
+
if (!project.config.api.allowWrite || !project.vitest.config.api.allowWrite) {
|
|
689
686
|
throw new Error(`Cannot modify file "${path}". File writing is disabled because the server is exposed to the internet, see https://vitest.dev/config/browser/api.`);
|
|
690
687
|
}
|
|
691
688
|
}
|
|
@@ -816,16 +813,21 @@ async function resolveTester(globalServer, url, res, next) {
|
|
|
816
813
|
__VITEST_PROVIDED_CONTEXT__: "{}",
|
|
817
814
|
__VITEST_API_TOKEN__: JSON.stringify(globalServer.vitest.config.api.token)
|
|
818
815
|
});
|
|
819
|
-
const testerHtml = typeof browserProject.testerHtml === "string" ? browserProject.testerHtml : await browserProject.testerHtml;
|
|
820
816
|
try {
|
|
821
|
-
|
|
822
|
-
|
|
817
|
+
browserProject.testerHtmlTransformed ??= (async () => {
|
|
818
|
+
const testerHtml = typeof browserProject.testerHtml === "string" ? browserProject.testerHtml : await browserProject.testerHtml;
|
|
819
|
+
const url = join("/@fs/", browserProject.testerFilepath);
|
|
820
|
+
return await browserProject.vite.transformIndexHtml(url, testerHtml);
|
|
821
|
+
})();
|
|
822
|
+
const indexhtml = await browserProject.testerHtmlTransformed;
|
|
823
823
|
const html = replacer(indexhtml, {
|
|
824
824
|
__VITEST_FAVICON__: globalServer.faviconUrl,
|
|
825
825
|
__VITEST_INJECTOR__: injector
|
|
826
826
|
});
|
|
827
827
|
return html;
|
|
828
828
|
} catch (err) {
|
|
829
|
+
// don't cache a rejection — the next request should retry the transform
|
|
830
|
+
browserProject.testerHtmlTransformed = undefined;
|
|
829
831
|
session.fail(err);
|
|
830
832
|
next(err);
|
|
831
833
|
}
|
|
@@ -852,49 +854,41 @@ function createTesterMiddleware(browserServer) {
|
|
|
852
854
|
|
|
853
855
|
const VIRTUAL_ID_CONTEXT = "\0vitest/browser";
|
|
854
856
|
const ID_CONTEXT = "vitest/browser";
|
|
855
|
-
// for libraries that use an older import but are not type checked
|
|
856
|
-
const DEPRECATED_ID_CONTEXT = "@vitest/browser/context";
|
|
857
|
-
const DEPRECATED_VIRTUAL_ID_UTILS = "\0@vitest/browser/utils";
|
|
858
|
-
const DEPRECATED_ID_UTILS = "@vitest/browser/utils";
|
|
859
857
|
const __dirname$1 = dirname(fileURLToPath(import.meta.url));
|
|
860
|
-
function BrowserContext(
|
|
858
|
+
function BrowserContext(contribution) {
|
|
861
859
|
return {
|
|
862
860
|
name: "vitest:browser:virtual-module:context",
|
|
863
861
|
enforce: "pre",
|
|
864
|
-
resolveId
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
if (importer && !importer.includes("/node_modules/")) {
|
|
870
|
-
globalServer.vitest.logger.deprecate(`${importer} tries to load a deprecated "${id}" module. ` + `This import will stop working in the next major version. ` + `Please, use "vitest/browser" instead.`);
|
|
862
|
+
resolveId: {
|
|
863
|
+
order: "pre",
|
|
864
|
+
handler(id) {
|
|
865
|
+
if (id === ID_CONTEXT) {
|
|
866
|
+
return VIRTUAL_ID_CONTEXT;
|
|
871
867
|
}
|
|
872
|
-
return VIRTUAL_ID_CONTEXT;
|
|
873
|
-
}
|
|
874
|
-
if (id === DEPRECATED_ID_UTILS) {
|
|
875
|
-
return DEPRECATED_VIRTUAL_ID_UTILS;
|
|
876
868
|
}
|
|
877
869
|
},
|
|
878
870
|
load(id) {
|
|
871
|
+
const globalServer = contribution.parent;
|
|
879
872
|
if (id === VIRTUAL_ID_CONTEXT) {
|
|
880
873
|
return generateContextFile.call(this, globalServer);
|
|
881
874
|
}
|
|
882
|
-
if (id === DEPRECATED_VIRTUAL_ID_UTILS) {
|
|
883
|
-
return `
|
|
884
|
-
import { utils } from 'vitest/browser'
|
|
885
|
-
export const getElementLocatorSelectors = utils.getElementLocatorSelectors
|
|
886
|
-
export const debug = utils.debug
|
|
887
|
-
export const prettyDOM = utils.prettyDOM
|
|
888
|
-
export const getElementError = utils.getElementError
|
|
889
|
-
`;
|
|
890
|
-
}
|
|
891
875
|
}
|
|
892
876
|
};
|
|
893
877
|
}
|
|
894
878
|
async function generateContextFile(globalServer) {
|
|
895
879
|
const commands = Object.keys(globalServer.commands);
|
|
896
|
-
|
|
897
|
-
|
|
880
|
+
// The provider instance is initialized lazily when a page opens, so reading
|
|
881
|
+
// `child.provider` here races and can be `undefined` before the first page is
|
|
882
|
+
// opened. The provider name is uniform across a project's instances and is
|
|
883
|
+
// already resolved on the config, so read it from there for this shared
|
|
884
|
+
// (cached) context module. The instance is still used below for the
|
|
885
|
+
// preview-only user-event import.
|
|
886
|
+
const child = [...globalServer.children][0];
|
|
887
|
+
const provider = child.provider;
|
|
888
|
+
const providerName = child.config.browser.provider?.name;
|
|
889
|
+
if (!providerName) {
|
|
890
|
+
throw new Error(`Browser provider is not defined for the project "${child.project.name}". This is a bug in Vitest. Please, open a new issue with a reproduction.`);
|
|
891
|
+
}
|
|
898
892
|
const commandsCode = commands.filter((command) => !command.startsWith("__vitest")).map((command) => {
|
|
899
893
|
return ` ["${command}"]: (...args) => __vitest_browser_runner__.commands.triggerCommand("${command}", args),`;
|
|
900
894
|
}).join("\n");
|
|
@@ -929,256 +923,41 @@ async function getUserEventImport(provider, resolve) {
|
|
|
929
923
|
throw new Error(`Failed to resolve user-event package from ${previewDistRoot}`);
|
|
930
924
|
}
|
|
931
925
|
return `\
|
|
932
|
-
import { userEvent as
|
|
933
|
-
const _userEventSetup = __vitest_user_event__
|
|
926
|
+
import { userEvent as _userEventSetup } from '${slash$1(`/@fs/${resolved.id}`)}'
|
|
934
927
|
`;
|
|
935
928
|
}
|
|
936
929
|
|
|
937
|
-
|
|
938
|
-
var BrowserPlugin = (parentServer, base = "/") => {
|
|
939
|
-
function isPackageExists(pkg, root) {
|
|
940
|
-
return parentServer.vitest.packageInstaller.isPackageExists?.(pkg, { paths: [root] });
|
|
941
|
-
}
|
|
930
|
+
var BrowserPlugin = (contribution) => {
|
|
942
931
|
return [
|
|
943
|
-
{
|
|
944
|
-
enforce: "pre",
|
|
945
|
-
name: "vitest:browser",
|
|
946
|
-
async configureServer(server) {
|
|
947
|
-
parentServer.setServer(server);
|
|
948
|
-
// eslint-disable-next-line prefer-arrow-callback
|
|
949
|
-
server.middlewares.use(function vitestHeaders(_req, res, next) {
|
|
950
|
-
const headers = server.config.server.headers;
|
|
951
|
-
if (headers) {
|
|
952
|
-
for (const name in headers) {
|
|
953
|
-
res.setHeader(name, headers[name]);
|
|
954
|
-
}
|
|
955
|
-
}
|
|
956
|
-
next();
|
|
957
|
-
});
|
|
958
|
-
// strip _vitest_original query added by importActual so that
|
|
959
|
-
// the plugin pipeline sees the original import id (e.g. virtual modules's load hook).
|
|
960
|
-
server.middlewares.use((req, _res, next) => {
|
|
961
|
-
if (req.url?.includes("_vitest_original") && parentServer.project.config.browser.provider?.name === "playwright") {
|
|
962
|
-
req.url = req.url.replace(/[?&]_vitest_original(?=[&#]|$)/, "").replace(/[?&]ext\b[^&#]*/, "").replace(/\?$/, "");
|
|
963
|
-
}
|
|
964
|
-
next();
|
|
965
|
-
});
|
|
966
|
-
server.middlewares.use(createOrchestratorMiddleware(parentServer));
|
|
967
|
-
server.middlewares.use(createTesterMiddleware(parentServer));
|
|
968
|
-
server.middlewares.use(`${base}favicon.svg`, (_, res) => {
|
|
969
|
-
const content = readFileSync(resolve(distRoot, "client/favicon.svg"));
|
|
970
|
-
res.write(content, "utf-8");
|
|
971
|
-
res.end();
|
|
972
|
-
});
|
|
973
|
-
// Serve coverage HTML at ./coverage if configured
|
|
974
|
-
const coverageHtmlDir = parentServer.vitest.config.coverage?.htmlDir;
|
|
975
|
-
if (coverageHtmlDir) {
|
|
976
|
-
server.middlewares.use("/__vitest_test__/coverage", sirv(coverageHtmlDir, {
|
|
977
|
-
single: true,
|
|
978
|
-
dev: true,
|
|
979
|
-
setHeaders: (res) => {
|
|
980
|
-
const csp = res.getHeader("Content-Security-Policy");
|
|
981
|
-
if (typeof csp === "string") {
|
|
982
|
-
// add frame-ancestors to allow the iframe to be loaded by Vitest,
|
|
983
|
-
// but keep the rest of the CSP
|
|
984
|
-
res.setHeader("Content-Security-Policy", csp.replace(/frame-ancestors [^;]+/, "frame-ancestors *"));
|
|
985
|
-
}
|
|
986
|
-
res.setHeader("Cache-Control", "public,max-age=0,must-revalidate");
|
|
987
|
-
}
|
|
988
|
-
}));
|
|
989
|
-
}
|
|
990
|
-
server.middlewares.use((req, res, next) => {
|
|
991
|
-
// 9000 mega head move
|
|
992
|
-
// Vite always caches optimized dependencies, but users might mock
|
|
993
|
-
// them in _some_ tests, while keeping original modules in others
|
|
994
|
-
// there is no way to configure that in Vite, so we patch it here
|
|
995
|
-
// to always ignore the cache-control set by Vite in the next middleware
|
|
996
|
-
if (req.url && versionRegexp.test(req.url) && !req.url.includes("chunk-")) {
|
|
997
|
-
res.setHeader("Cache-Control", "no-cache");
|
|
998
|
-
const setHeader = res.setHeader.bind(res);
|
|
999
|
-
res.setHeader = function(name, value) {
|
|
1000
|
-
if (name === "Cache-Control") {
|
|
1001
|
-
return res;
|
|
1002
|
-
}
|
|
1003
|
-
return setHeader(name, value);
|
|
1004
|
-
};
|
|
1005
|
-
}
|
|
1006
|
-
next();
|
|
1007
|
-
});
|
|
1008
|
-
// handle attachments the same way as in packages/ui/node/index.ts
|
|
1009
|
-
server.middlewares.use((req, res, next) => {
|
|
1010
|
-
if (!req.url) {
|
|
1011
|
-
return next();
|
|
1012
|
-
}
|
|
1013
|
-
const url = new URL(req.url, "http://localhost");
|
|
1014
|
-
if (url.pathname !== "/__vitest_attachment__") {
|
|
1015
|
-
return next();
|
|
1016
|
-
}
|
|
1017
|
-
const path = url.searchParams.get("path");
|
|
1018
|
-
const contentType = url.searchParams.get("contentType");
|
|
1019
|
-
if (!isValidApiRequest(parentServer.config, req) || !contentType || !path) {
|
|
1020
|
-
return next();
|
|
1021
|
-
}
|
|
1022
|
-
const fsPath = decodeURIComponent(path);
|
|
1023
|
-
if (!isFileServingAllowed(parentServer.vite.config, fsPath)) {
|
|
1024
|
-
return next();
|
|
1025
|
-
}
|
|
1026
|
-
try {
|
|
1027
|
-
res.setHeader("content-type", contentType);
|
|
1028
|
-
return createReadStream(fsPath).pipe(res).on("close", () => res.end());
|
|
1029
|
-
} catch (err) {
|
|
1030
|
-
return next(err);
|
|
1031
|
-
}
|
|
1032
|
-
});
|
|
1033
|
-
}
|
|
1034
|
-
},
|
|
1035
932
|
{
|
|
1036
933
|
name: "vitest:browser:tests",
|
|
1037
934
|
enforce: "pre",
|
|
1038
|
-
|
|
1039
|
-
|
|
1040
|
-
|
|
1041
|
-
|
|
1042
|
-
|
|
1043
|
-
// the workspace — keeps the optimizeDeps entries symmetrical across
|
|
1044
|
-
// the test/bench project clones so the optimizer doesn't re-scan when
|
|
1045
|
-
// the user switches modes
|
|
1046
|
-
const hasBrowserBenchProject = parentServer.vitest.projects.some((p) => p.config.browser.enabled && p.config.benchmark.enabled);
|
|
1047
|
-
const benchInclude = hasBrowserBenchProject ? project.config.benchmark.include : [];
|
|
1048
|
-
const dir = project.config.dir || project.config.root;
|
|
1049
|
-
const [{ testFiles: browserTestFiles }, browserBenchFiles] = await Promise.all([project.globTestFiles(), benchInclude.length > 0 ? project.globFiles(benchInclude, project.config.benchmark.exclude ?? project.config.exclude, dir) : []]);
|
|
1050
|
-
const setupFiles = toArray(project.config.setupFiles);
|
|
1051
|
-
// replace env values - cannot be reassign at runtime
|
|
1052
|
-
const define = {};
|
|
1053
|
-
for (const env in project.config.env || {}) {
|
|
1054
|
-
const stringValue = JSON.stringify(project.config.env[env]);
|
|
1055
|
-
define[`import.meta.env.${env}`] = stringValue;
|
|
1056
|
-
}
|
|
1057
|
-
const entries = [
|
|
1058
|
-
...new Set([...browserTestFiles, ...browserBenchFiles]),
|
|
1059
|
-
...setupFiles,
|
|
1060
|
-
resolve(distDir, "index.js"),
|
|
1061
|
-
resolve(distDir, "browser.js"),
|
|
1062
|
-
resolve(distDir, "runners.js"),
|
|
1063
|
-
resolve(distDir, "utils.js"),
|
|
1064
|
-
...project.config.snapshotSerializers || []
|
|
1065
|
-
];
|
|
1066
|
-
const exclude = [
|
|
1067
|
-
"vitest",
|
|
1068
|
-
"vitest/browser",
|
|
1069
|
-
"vitest/internal/browser",
|
|
1070
|
-
"vite/module-runner",
|
|
1071
|
-
"@vitest/browser/utils",
|
|
1072
|
-
"@vitest/browser/context",
|
|
1073
|
-
"@vitest/browser/client",
|
|
1074
|
-
"@vitest/utils",
|
|
1075
|
-
"@vitest/utils/source-map",
|
|
1076
|
-
"@vitest/spy",
|
|
1077
|
-
"@vitest/utils/error",
|
|
1078
|
-
"std-env",
|
|
1079
|
-
"tinybench",
|
|
1080
|
-
"tinyspy",
|
|
1081
|
-
"tinyrainbow",
|
|
1082
|
-
"pathe",
|
|
1083
|
-
"msw",
|
|
1084
|
-
"msw/browser"
|
|
1085
|
-
];
|
|
1086
|
-
if (typeof project.config.diff === "string") {
|
|
1087
|
-
entries.push(project.config.diff);
|
|
1088
|
-
}
|
|
1089
|
-
if (parentServer.vitest.coverageProvider) {
|
|
1090
|
-
const coverage = parentServer.vitest._coverageOptions;
|
|
1091
|
-
const provider = coverage.provider;
|
|
1092
|
-
if (provider === "v8") {
|
|
1093
|
-
const path = tryResolve("@vitest/coverage-v8", [parentServer.config.root]);
|
|
1094
|
-
if (path) {
|
|
1095
|
-
entries.push(path);
|
|
1096
|
-
exclude.push("@vitest/coverage-v8/browser");
|
|
1097
|
-
}
|
|
1098
|
-
} else if (provider === "istanbul") {
|
|
1099
|
-
const path = tryResolve("@vitest/coverage-istanbul", [parentServer.config.root]);
|
|
1100
|
-
if (path) {
|
|
1101
|
-
entries.push(path);
|
|
1102
|
-
exclude.push("@vitest/coverage-istanbul");
|
|
1103
|
-
}
|
|
1104
|
-
} else if (provider === "custom" && coverage.customProviderModule) {
|
|
1105
|
-
entries.push(coverage.customProviderModule);
|
|
935
|
+
resolveId: {
|
|
936
|
+
order: "pre",
|
|
937
|
+
handler(id) {
|
|
938
|
+
if (!/\?browserv=\w+$/.test(id)) {
|
|
939
|
+
return;
|
|
1106
940
|
}
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
|
|
1110
|
-
"vitest > magic-string",
|
|
1111
|
-
"vitest > chai"
|
|
1112
|
-
];
|
|
1113
|
-
const provider = parentServer.config.browser.provider || [...parentServer.children][0]?.provider;
|
|
1114
|
-
if (provider?.name === "preview") {
|
|
1115
|
-
include.push("@vitest/browser-preview > @testing-library/user-event", "@vitest/browser-preview > @testing-library/dom");
|
|
1116
|
-
}
|
|
1117
|
-
const fileRoot = browserTestFiles[0] ? dirname(browserTestFiles[0]) : project.config.root;
|
|
1118
|
-
const svelte = isPackageExists("vitest-browser-svelte", fileRoot);
|
|
1119
|
-
if (svelte) {
|
|
1120
|
-
exclude.push("vitest-browser-svelte");
|
|
1121
|
-
}
|
|
1122
|
-
// since we override the resolution in the esbuild plugin, Vite can no longer optimizer it
|
|
1123
|
-
const vue = isPackageExists("vitest-browser-vue", fileRoot);
|
|
1124
|
-
if (vue) {
|
|
1125
|
-
// we override them in the esbuild plugin so optimizer can no longer intercept it
|
|
1126
|
-
include.push("vitest-browser-vue", "vitest-browser-vue > @vue/test-utils", "vitest-browser-vue > @vue/test-utils > @vue/compiler-core");
|
|
1127
|
-
}
|
|
1128
|
-
const vueTestUtils = isPackageExists("@vue/test-utils", fileRoot);
|
|
1129
|
-
if (vueTestUtils) {
|
|
1130
|
-
include.push("@vue/test-utils");
|
|
1131
|
-
}
|
|
1132
|
-
const otelConfig = project.config.experimental.openTelemetry;
|
|
1133
|
-
if (otelConfig?.enabled && otelConfig.browserSdkPath) {
|
|
1134
|
-
entries.push(otelConfig.browserSdkPath);
|
|
1135
|
-
include.push("@opentelemetry/api");
|
|
1136
|
-
} else {
|
|
1137
|
-
exclude.push("@opentelemetry/api");
|
|
1138
|
-
}
|
|
1139
|
-
return {
|
|
1140
|
-
define,
|
|
1141
|
-
resolve: { dedupe: ["vitest"] },
|
|
1142
|
-
optimizeDeps: {
|
|
1143
|
-
entries,
|
|
1144
|
-
exclude,
|
|
1145
|
-
include
|
|
941
|
+
let useId = id.slice(0, id.lastIndexOf("?"));
|
|
942
|
+
if (useId.startsWith("/@fs/")) {
|
|
943
|
+
useId = useId.slice(5);
|
|
1146
944
|
}
|
|
1147
|
-
|
|
1148
|
-
|
|
1149
|
-
|
|
1150
|
-
|
|
1151
|
-
return;
|
|
1152
|
-
}
|
|
1153
|
-
let useId = id.slice(0, id.lastIndexOf("?"));
|
|
1154
|
-
if (useId.startsWith("/@fs/")) {
|
|
1155
|
-
useId = useId.slice(5);
|
|
1156
|
-
}
|
|
1157
|
-
if (/^\w:/.test(useId)) {
|
|
1158
|
-
useId = useId.replace(/\\/g, "/");
|
|
1159
|
-
}
|
|
1160
|
-
return useId;
|
|
1161
|
-
}
|
|
1162
|
-
},
|
|
1163
|
-
{
|
|
1164
|
-
name: "vitest:browser:resolve-virtual",
|
|
1165
|
-
async resolveId(rawId) {
|
|
1166
|
-
if (rawId === "/mockServiceWorker.js") {
|
|
1167
|
-
return this.resolve("msw/mockServiceWorker.js", distRoot, { skipSelf: true });
|
|
945
|
+
if (/^\w:/.test(useId)) {
|
|
946
|
+
useId = useId.replace(/\\/g, "/");
|
|
947
|
+
}
|
|
948
|
+
return useId;
|
|
1168
949
|
}
|
|
1169
950
|
}
|
|
1170
951
|
},
|
|
1171
952
|
{
|
|
1172
953
|
name: "vitest:browser:assets",
|
|
1173
|
-
configureServer(server) {
|
|
1174
|
-
server.middlewares.use("/__vitest__", sirv(distClientRoot));
|
|
1175
|
-
},
|
|
1176
954
|
resolveId(id) {
|
|
1177
955
|
if (id.startsWith("/__vitest_browser__/")) {
|
|
1178
956
|
return resolve(distRoot, "client", id.slice(1));
|
|
1179
957
|
}
|
|
1180
958
|
},
|
|
1181
959
|
transform(code, id) {
|
|
960
|
+
const parentServer = contribution.parent;
|
|
1182
961
|
if (id.includes(parentServer.vite.config.cacheDir) && id.includes("loupe.js")) {
|
|
1183
962
|
// loupe bundle has a nasty require('util') call that leaves a warning in the console
|
|
1184
963
|
const utilRequire = "nodeUtil = require_util();";
|
|
@@ -1186,47 +965,16 @@ var BrowserPlugin = (parentServer, base = "/") => {
|
|
|
1186
965
|
}
|
|
1187
966
|
}
|
|
1188
967
|
},
|
|
1189
|
-
BrowserContext(
|
|
968
|
+
BrowserContext(contribution),
|
|
1190
969
|
dynamicImportPlugin({
|
|
1191
970
|
globalThisAccessor: "\"__vitest_browser_runner__\"",
|
|
1192
|
-
filter(id
|
|
1193
|
-
if (environment.name !== "client") {
|
|
1194
|
-
return false;
|
|
1195
|
-
}
|
|
971
|
+
filter(id) {
|
|
1196
972
|
if (id.includes(distRoot)) {
|
|
1197
973
|
return false;
|
|
1198
974
|
}
|
|
1199
975
|
return true;
|
|
1200
976
|
}
|
|
1201
977
|
}),
|
|
1202
|
-
{
|
|
1203
|
-
name: "vitest:browser:config",
|
|
1204
|
-
enforce: "post",
|
|
1205
|
-
async config(viteConfig) {
|
|
1206
|
-
// Enables using ignore hint for coverage providers with @preserve keyword
|
|
1207
|
-
// Only set esbuild options when not using rolldown-vite (Vite 8+),
|
|
1208
|
-
// which uses oxc for transformation instead of esbuild
|
|
1209
|
-
if (!rolldownVersion && viteConfig.esbuild !== false) {
|
|
1210
|
-
viteConfig.esbuild ||= {};
|
|
1211
|
-
viteConfig.esbuild.legalComments = "inline";
|
|
1212
|
-
}
|
|
1213
|
-
const defaultPort = parentServer.vitest.state._data.browserLastPort++;
|
|
1214
|
-
const api = resolveApiServerConfig(viteConfig.test?.browser || {}, defaultPort);
|
|
1215
|
-
viteConfig.server = {
|
|
1216
|
-
...viteConfig.server,
|
|
1217
|
-
port: defaultPort,
|
|
1218
|
-
...api,
|
|
1219
|
-
middlewareMode: false,
|
|
1220
|
-
open: false
|
|
1221
|
-
};
|
|
1222
|
-
viteConfig.server.fs ??= {};
|
|
1223
|
-
viteConfig.server.fs.allow = viteConfig.server.fs.allow || [];
|
|
1224
|
-
viteConfig.server.fs.deny ??= [];
|
|
1225
|
-
viteConfig.server.fs.deny.push(API_TOKEN_FILE);
|
|
1226
|
-
viteConfig.server.fs.allow.push(...resolveFsAllow(parentServer.vitest.config.root, parentServer.vitest.vite.config.configFile), distRoot);
|
|
1227
|
-
return { resolve: { alias: viteConfig.test?.alias } };
|
|
1228
|
-
}
|
|
1229
|
-
},
|
|
1230
978
|
{
|
|
1231
979
|
name: "vitest:browser:in-source-tests",
|
|
1232
980
|
transform: {
|
|
@@ -1259,130 +1007,6 @@ var BrowserPlugin = (parentServer, base = "/") => {
|
|
|
1259
1007
|
}
|
|
1260
1008
|
}
|
|
1261
1009
|
},
|
|
1262
|
-
{
|
|
1263
|
-
name: "vitest:browser:transform-tester-html",
|
|
1264
|
-
enforce: "pre",
|
|
1265
|
-
async transformIndexHtml(html, ctx) {
|
|
1266
|
-
const projectBrowser = [...parentServer.children].find((server) => {
|
|
1267
|
-
return ctx.filename === server.testerFilepath;
|
|
1268
|
-
});
|
|
1269
|
-
if (!projectBrowser) {
|
|
1270
|
-
return;
|
|
1271
|
-
}
|
|
1272
|
-
const stateJs = typeof parentServer.stateJs === "string" ? parentServer.stateJs : await parentServer.stateJs;
|
|
1273
|
-
const testerTags = [];
|
|
1274
|
-
const isDefaultTemplate = resolve(distRoot, "client/tester/tester.html") === projectBrowser.testerFilepath;
|
|
1275
|
-
if (!isDefaultTemplate) {
|
|
1276
|
-
const manifestContent = parentServer.manifest instanceof Promise ? await parentServer.manifest : parentServer.manifest;
|
|
1277
|
-
const testerEntry = manifestContent["tester/tester.html"];
|
|
1278
|
-
testerTags.push({
|
|
1279
|
-
tag: "script",
|
|
1280
|
-
attrs: {
|
|
1281
|
-
type: "module",
|
|
1282
|
-
crossorigin: "",
|
|
1283
|
-
src: `${parentServer.base}${testerEntry.file}`
|
|
1284
|
-
},
|
|
1285
|
-
injectTo: "head"
|
|
1286
|
-
});
|
|
1287
|
-
for (const importName of testerEntry.imports || []) {
|
|
1288
|
-
const entryManifest = manifestContent[importName];
|
|
1289
|
-
if (entryManifest) {
|
|
1290
|
-
testerTags.push({
|
|
1291
|
-
tag: "link",
|
|
1292
|
-
attrs: {
|
|
1293
|
-
href: `${parentServer.base}${entryManifest.file}`,
|
|
1294
|
-
rel: "modulepreload",
|
|
1295
|
-
crossorigin: ""
|
|
1296
|
-
},
|
|
1297
|
-
injectTo: "head"
|
|
1298
|
-
});
|
|
1299
|
-
}
|
|
1300
|
-
}
|
|
1301
|
-
} else {
|
|
1302
|
-
// inject the reset style only in the default template,
|
|
1303
|
-
// allowing users to customize the style in their own template
|
|
1304
|
-
testerTags.push({
|
|
1305
|
-
tag: "style",
|
|
1306
|
-
children: `
|
|
1307
|
-
html {
|
|
1308
|
-
padding: 0;
|
|
1309
|
-
margin: 0;
|
|
1310
|
-
}
|
|
1311
|
-
body {
|
|
1312
|
-
padding: 0;
|
|
1313
|
-
margin: 0;
|
|
1314
|
-
min-height: 100vh;
|
|
1315
|
-
}`,
|
|
1316
|
-
injectTo: "head"
|
|
1317
|
-
});
|
|
1318
|
-
}
|
|
1319
|
-
return [
|
|
1320
|
-
{
|
|
1321
|
-
tag: "script",
|
|
1322
|
-
children: "{__VITEST_INJECTOR__}",
|
|
1323
|
-
injectTo: "head-prepend"
|
|
1324
|
-
},
|
|
1325
|
-
{
|
|
1326
|
-
tag: "script",
|
|
1327
|
-
children: stateJs,
|
|
1328
|
-
injectTo: "head-prepend"
|
|
1329
|
-
},
|
|
1330
|
-
{
|
|
1331
|
-
tag: "script",
|
|
1332
|
-
attrs: {
|
|
1333
|
-
type: "module",
|
|
1334
|
-
src: parentServer.errorCatcherUrl
|
|
1335
|
-
},
|
|
1336
|
-
injectTo: "head"
|
|
1337
|
-
},
|
|
1338
|
-
{
|
|
1339
|
-
tag: "script",
|
|
1340
|
-
attrs: {
|
|
1341
|
-
type: "module",
|
|
1342
|
-
src: parentServer.matchersUrl
|
|
1343
|
-
},
|
|
1344
|
-
injectTo: "head"
|
|
1345
|
-
},
|
|
1346
|
-
...parentServer.initScripts.map((script) => ({
|
|
1347
|
-
tag: "script",
|
|
1348
|
-
attrs: {
|
|
1349
|
-
type: "module",
|
|
1350
|
-
src: join("/@fs/", script)
|
|
1351
|
-
},
|
|
1352
|
-
injectTo: "head"
|
|
1353
|
-
})),
|
|
1354
|
-
...testerTags
|
|
1355
|
-
].filter((s) => s != null);
|
|
1356
|
-
}
|
|
1357
|
-
},
|
|
1358
|
-
{
|
|
1359
|
-
name: "vitest:browser:support-testing-library",
|
|
1360
|
-
enforce: "pre",
|
|
1361
|
-
config() {
|
|
1362
|
-
const rolldownPlugin = {
|
|
1363
|
-
name: "vue-test-utils-rewrite",
|
|
1364
|
-
resolveId: {
|
|
1365
|
-
filter: { id: /^@vue\/(test-utils|compiler-core)$/ },
|
|
1366
|
-
handler(source, importer) {
|
|
1367
|
-
const resolved = getRequire().resolve(source, { paths: [importer] });
|
|
1368
|
-
return resolved;
|
|
1369
|
-
}
|
|
1370
|
-
}
|
|
1371
|
-
};
|
|
1372
|
-
const esbuildPlugin = {
|
|
1373
|
-
name: "test-utils-rewrite",
|
|
1374
|
-
setup(build) {
|
|
1375
|
-
// test-utils: resolve to CJS instead of the browser because the browser version expects a global Vue object
|
|
1376
|
-
// compiler-core: only CJS version allows slots as strings
|
|
1377
|
-
build.onResolve({ filter: /^@vue\/(test-utils|compiler-core)$/ }, (args) => {
|
|
1378
|
-
const resolved = getRequire().resolve(args.path, { paths: [args.importer] });
|
|
1379
|
-
return { path: resolved };
|
|
1380
|
-
});
|
|
1381
|
-
}
|
|
1382
|
-
};
|
|
1383
|
-
return { optimizeDeps: rolldownVersion ? { rolldownOptions: { plugins: [rolldownPlugin] } } : { esbuildOptions: { plugins: [esbuildPlugin] } } };
|
|
1384
|
-
}
|
|
1385
|
-
},
|
|
1386
1010
|
{
|
|
1387
1011
|
name: "vitest:browser:__vitest_browser_import_meta_env_init__",
|
|
1388
1012
|
transform: { handler(code) {
|
|
@@ -1395,21 +1019,6 @@ body {
|
|
|
1395
1019
|
}
|
|
1396
1020
|
];
|
|
1397
1021
|
};
|
|
1398
|
-
function tryResolve(path, paths) {
|
|
1399
|
-
try {
|
|
1400
|
-
const _require = getRequire();
|
|
1401
|
-
return _require.resolve(path, { paths });
|
|
1402
|
-
} catch {
|
|
1403
|
-
return undefined;
|
|
1404
|
-
}
|
|
1405
|
-
}
|
|
1406
|
-
let _require;
|
|
1407
|
-
function getRequire() {
|
|
1408
|
-
if (!_require) {
|
|
1409
|
-
_require = createRequire(import.meta.url);
|
|
1410
|
-
}
|
|
1411
|
-
return _require;
|
|
1412
|
-
}
|
|
1413
1022
|
const postfixRE = /[?#].*$/;
|
|
1414
1023
|
function cleanUrl(url) {
|
|
1415
1024
|
return url.replace(postfixRE, "");
|
|
@@ -1455,19 +1064,6 @@ class BrowserServerCDPHandler {
|
|
|
1455
1064
|
}
|
|
1456
1065
|
}
|
|
1457
1066
|
|
|
1458
|
-
const _startV8Coverage = async (context) => {
|
|
1459
|
-
const session = await context.__ensureCDPHandler();
|
|
1460
|
-
await session.send("Profiler.enable");
|
|
1461
|
-
await session.send("Profiler.startPreciseCoverage", {
|
|
1462
|
-
callCount: true,
|
|
1463
|
-
detailed: true
|
|
1464
|
-
});
|
|
1465
|
-
};
|
|
1466
|
-
const _takeV8Coverage = async (context) => {
|
|
1467
|
-
const session = await context.__ensureCDPHandler();
|
|
1468
|
-
return session.send("Profiler.takePreciseCoverage");
|
|
1469
|
-
};
|
|
1470
|
-
|
|
1471
1067
|
const types = {
|
|
1472
1068
|
'application/andrew-inset': ['ez'],
|
|
1473
1069
|
'application/appinstaller': ['appinstaller'],
|
|
@@ -2606,8 +2202,6 @@ var builtinCommands = {
|
|
|
2606
2202
|
readFile,
|
|
2607
2203
|
removeFile,
|
|
2608
2204
|
writeFile,
|
|
2609
|
-
__vitest_startV8Coverage: _startV8Coverage,
|
|
2610
|
-
__vitest_takeV8Coverage: _takeV8Coverage,
|
|
2611
2205
|
__vitest_markTrace: _markTrace,
|
|
2612
2206
|
__vitest_groupTraceStart: _groupTraceStart,
|
|
2613
2207
|
__vitest_groupTraceEnd: _groupTraceEnd,
|
|
@@ -2625,6 +2219,10 @@ class BrowserServerState {
|
|
|
2625
2219
|
class ProjectBrowser {
|
|
2626
2220
|
testerHtml;
|
|
2627
2221
|
testerFilepath;
|
|
2222
|
+
// the tester template is read once per server, so the transformed HTML
|
|
2223
|
+
// is stable too — computing it for every iframe request pays the whole
|
|
2224
|
+
// transformIndexHtml plugin pipeline each time
|
|
2225
|
+
testerHtmlTransformed;
|
|
2628
2226
|
provider;
|
|
2629
2227
|
vitest;
|
|
2630
2228
|
vite;
|
|
@@ -2726,21 +2324,27 @@ class ParentBrowserProject {
|
|
|
2726
2324
|
config;
|
|
2727
2325
|
// cache for non-vite source maps
|
|
2728
2326
|
sourceMapCache = new Map();
|
|
2729
|
-
constructor(
|
|
2730
|
-
this.project = project;
|
|
2327
|
+
constructor(ctx, base) {
|
|
2731
2328
|
this.base = base;
|
|
2732
|
-
this.vitest =
|
|
2733
|
-
this.config =
|
|
2329
|
+
this.vitest = ctx.vitest;
|
|
2330
|
+
this.config = ctx.config;
|
|
2734
2331
|
this.stackTraceOptions = {
|
|
2735
|
-
frameFilter:
|
|
2332
|
+
frameFilter: this.config.onStackTrace,
|
|
2736
2333
|
getSourceMap: (id) => {
|
|
2737
2334
|
if (this.sourceMapCache.has(id)) {
|
|
2738
2335
|
return this.sourceMapCache.get(id);
|
|
2739
2336
|
}
|
|
2740
2337
|
const result = this.vite.moduleGraph.getModuleById(id)?.transformResult;
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
2338
|
+
const filePath = id.split("?")[0];
|
|
2339
|
+
// prefer the map stored on disk when the transform pipeline can't
|
|
2340
|
+
// provide a usable one:
|
|
2341
|
+
// - pre-bundled deps: the pipeline map resolves back into the
|
|
2342
|
+
// optimizer cache, while the map esbuild wrote next to the file
|
|
2343
|
+
// points at the real package sources
|
|
2344
|
+
// - an empty `mappings` means the map was intentionally not served
|
|
2345
|
+
// to the browser (`vitest:browser:framework-sourcemaps`), but disk
|
|
2346
|
+
// is still the source of truth for error stack traces
|
|
2347
|
+
if (result && (!result.map || result.map.mappings === "" || filePath.startsWith(this.vite.config.cacheDir))) {
|
|
2744
2348
|
const extracted = extractSourcemapFromFile(result.code, filePath);
|
|
2745
2349
|
this.sourceMapCache.set(id, extracted?.map);
|
|
2746
2350
|
return extracted?.map;
|
|
@@ -2771,11 +2375,11 @@ class ParentBrowserProject {
|
|
|
2771
2375
|
this.commands[name] ??= command;
|
|
2772
2376
|
}
|
|
2773
2377
|
// validate names because they can't be used as identifiers
|
|
2774
|
-
for (const command in
|
|
2378
|
+
for (const command in this.config.browser.commands) {
|
|
2775
2379
|
if (!/^[a-z_$][\w$]*$/i.test(command)) {
|
|
2776
2380
|
throw new Error(`Invalid command name "${command}". Only alphanumeric characters, $ and _ are allowed.`);
|
|
2777
2381
|
}
|
|
2778
|
-
this.commands[command] =
|
|
2382
|
+
this.commands[command] = this.config.browser.commands[command];
|
|
2779
2383
|
}
|
|
2780
2384
|
this.prefixTesterUrl = `${base || "/"}`;
|
|
2781
2385
|
this.prefixOrchestratorUrl = `${base}__vitest_test__/`;
|
|
@@ -2783,7 +2387,7 @@ class ParentBrowserProject {
|
|
|
2783
2387
|
this.manifest = (async () => {
|
|
2784
2388
|
return JSON.parse(await readFile$1(`${distRoot}/client/.vite/manifest.json`, "utf8"));
|
|
2785
2389
|
})().then((manifest) => this.manifest = manifest);
|
|
2786
|
-
this.orchestratorHtml = (
|
|
2390
|
+
this.orchestratorHtml = (this.config.browser.ui ? readFile$1(resolve(distClientRoot, "index.html"), "utf8") : readFile$1(resolve(distRoot, "client/orchestrator.html"), "utf8")).then((html) => this.orchestratorHtml = html);
|
|
2787
2391
|
this.injectorJs = readFile$1(resolve(distRoot, "client/esm-client-injector.js"), "utf8").then((js) => this.injectorJs = js);
|
|
2788
2392
|
this.errorCatcherUrl = join("/@fs/", resolve(distRoot, "client/error-catcher.js"));
|
|
2789
2393
|
this.matchersUrl = join("/@fs/", distRoot, "expect-element.js");
|
|
@@ -3161,14 +2765,14 @@ function setupBrowserRpc(globalServer, defaultMockerRegistry) {
|
|
|
3161
2765
|
}
|
|
3162
2766
|
}
|
|
3163
2767
|
function canWrite(project) {
|
|
3164
|
-
return project.config.
|
|
2768
|
+
return project.config.api.allowWrite && project.vitest.config.api.allowWrite;
|
|
3165
2769
|
}
|
|
3166
2770
|
function isCdpAllowed(project) {
|
|
3167
|
-
return project.config.api.allowExec && project.
|
|
2771
|
+
return project.config.api.allowExec && project.vitest.config.api.allowExec && project.config.api.allowWrite && project.vitest.config.api.allowWrite;
|
|
3168
2772
|
}
|
|
3169
2773
|
function assertCdpAllowed(project) {
|
|
3170
2774
|
if (!isCdpAllowed(project)) {
|
|
3171
|
-
throw new Error(`Cannot use CDP because browser API write or exec operations are disabled. See https://vitest.dev/config/
|
|
2775
|
+
throw new Error(`Cannot use CDP because browser API write or exec operations are disabled. See https://vitest.dev/config/api.`);
|
|
3172
2776
|
}
|
|
3173
2777
|
}
|
|
3174
2778
|
function setupClient(project, rpcId, ws, options) {
|
|
@@ -3204,13 +2808,13 @@ function setupBrowserRpc(globalServer, defaultMockerRegistry) {
|
|
|
3204
2808
|
if (!canWrite(project)) {
|
|
3205
2809
|
if (artifact.type === "internal:annotation" && artifact.annotation.attachment) {
|
|
3206
2810
|
artifact.annotation.attachment = undefined;
|
|
3207
|
-
vitest.logger.error(`[vitest] Cannot record annotation attachment because file writing is disabled. See https://vitest.dev/config/
|
|
2811
|
+
vitest.logger.error(`[vitest] Cannot record annotation attachment because file writing is disabled. See https://vitest.dev/config/api.`);
|
|
3208
2812
|
}
|
|
3209
2813
|
// remove attachments if cannot write
|
|
3210
2814
|
if (artifact.attachments?.length) {
|
|
3211
2815
|
const attachments = artifact.attachments.map((n) => n.path).filter((r) => !!r).join("\", \"");
|
|
3212
2816
|
artifact.attachments = [];
|
|
3213
|
-
vitest.logger.error(`[vitest] Cannot record attachments ("${attachments}") because file writing is disabled, removing attachments from artifact "${artifact.type}". See https://vitest.dev/config/
|
|
2817
|
+
vitest.logger.error(`[vitest] Cannot record attachments ("${attachments}") because file writing is disabled, removing attachments from artifact "${artifact.type}". See https://vitest.dev/config/api.`);
|
|
3214
2818
|
}
|
|
3215
2819
|
} else {
|
|
3216
2820
|
// attachment files are copied into `attachmentsDir`, so confine
|
|
@@ -3234,7 +2838,7 @@ function setupBrowserRpc(globalServer, defaultMockerRegistry) {
|
|
|
3234
2838
|
},
|
|
3235
2839
|
async writeBenchmarkResult(relativePath, data) {
|
|
3236
2840
|
if (!canWrite(project)) {
|
|
3237
|
-
vitest.logger.error(`[vitest] Cannot write benchmark artifact "${relativePath}" because file writing is disabled. See https://vitest.dev/config/
|
|
2841
|
+
vitest.logger.error(`[vitest] Cannot write benchmark artifact "${relativePath}" because file writing is disabled. See https://vitest.dev/config/api.`);
|
|
3238
2842
|
return;
|
|
3239
2843
|
}
|
|
3240
2844
|
checkFileAccess(project.benchmark.resolve(relativePath));
|
|
@@ -3276,7 +2880,7 @@ function setupBrowserRpc(globalServer, defaultMockerRegistry) {
|
|
|
3276
2880
|
async saveSnapshotFile(id, content) {
|
|
3277
2881
|
checkFileAccess(id);
|
|
3278
2882
|
if (!canWrite(project)) {
|
|
3279
|
-
vitest.logger.error(`[vitest] Cannot save snapshot file "${id}". File writing is disabled because server is exposed to the internet, see https://vitest.dev/config/
|
|
2883
|
+
vitest.logger.error(`[vitest] Cannot save snapshot file "${id}". File writing is disabled because server is exposed to the internet, see https://vitest.dev/config/api.`);
|
|
3280
2884
|
return;
|
|
3281
2885
|
}
|
|
3282
2886
|
await promises.mkdir(dirname(id), { recursive: true });
|
|
@@ -3285,7 +2889,7 @@ function setupBrowserRpc(globalServer, defaultMockerRegistry) {
|
|
|
3285
2889
|
async removeSnapshotFile(id) {
|
|
3286
2890
|
checkFileAccess(id);
|
|
3287
2891
|
if (!canWrite(project)) {
|
|
3288
|
-
vitest.logger.error(`[vitest] Cannot remove snapshot file "${id}". File writing is disabled because server is exposed to the internet, see https://vitest.dev/config/
|
|
2892
|
+
vitest.logger.error(`[vitest] Cannot remove snapshot file "${id}". File writing is disabled because server is exposed to the internet, see https://vitest.dev/config/api.`);
|
|
3289
2893
|
return;
|
|
3290
2894
|
}
|
|
3291
2895
|
if (!existsSync(id)) {
|
|
@@ -3466,66 +3070,437 @@ function stringifyReplace(key, value) {
|
|
|
3466
3070
|
function defineBrowserCommand(fn) {
|
|
3467
3071
|
return fn;
|
|
3468
3072
|
}
|
|
3469
|
-
const
|
|
3470
|
-
|
|
3471
|
-
|
|
3472
|
-
|
|
3473
|
-
|
|
3474
|
-
|
|
3475
|
-
|
|
3476
|
-
|
|
3477
|
-
const logLevel = process.env.VITEST_BROWSER_DEBUG ?? "info";
|
|
3478
|
-
const logger = createViteLogger(project.vitest.logger, logLevel, { allowClearScreen: false });
|
|
3073
|
+
const versionRegexp = /(?:\?|&)v=\w{8}/;
|
|
3074
|
+
/**
|
|
3075
|
+
* The browser provider's `serverFactory`. Returns a `BrowserServerContribution`
|
|
3076
|
+
* that Vitest core uses to build the SINGLE Vite server shared by `project.vite`
|
|
3077
|
+
* and `project.browser.vite`. This factory does NOT create a server (core does);
|
|
3078
|
+
* it only contributes config, plugins, the parent factory, and the RPC setup.
|
|
3079
|
+
*/
|
|
3080
|
+
const createBrowserServer = async () => {
|
|
3479
3081
|
const mockerRegistry = new MockerRegistry();
|
|
3480
|
-
|
|
3481
|
-
|
|
3482
|
-
|
|
3483
|
-
|
|
3484
|
-
|
|
3485
|
-
|
|
3486
|
-
|
|
3487
|
-
|
|
3488
|
-
|
|
3489
|
-
|
|
3490
|
-
|
|
3491
|
-
|
|
3492
|
-
|
|
3082
|
+
const contribution = {
|
|
3083
|
+
async transformIndexHtml(ctx) {
|
|
3084
|
+
const parentServer = contribution.parent;
|
|
3085
|
+
const projectBrowser = [...parentServer.children].find((server) => {
|
|
3086
|
+
return ctx.filename === server.testerFilepath;
|
|
3087
|
+
});
|
|
3088
|
+
if (!projectBrowser) {
|
|
3089
|
+
return;
|
|
3090
|
+
}
|
|
3091
|
+
const stateJs = typeof parentServer.stateJs === "string" ? parentServer.stateJs : await parentServer.stateJs;
|
|
3092
|
+
const testerTags = [];
|
|
3093
|
+
const isDefaultTemplate = resolve(distRoot, "client/tester/tester.html") === projectBrowser.testerFilepath;
|
|
3094
|
+
if (!isDefaultTemplate) {
|
|
3095
|
+
const manifestContent = parentServer.manifest instanceof Promise ? await parentServer.manifest : parentServer.manifest;
|
|
3096
|
+
const testerEntry = manifestContent["tester/tester.html"];
|
|
3097
|
+
testerTags.push({
|
|
3098
|
+
tag: "script",
|
|
3099
|
+
attrs: {
|
|
3100
|
+
type: "module",
|
|
3101
|
+
crossorigin: "",
|
|
3102
|
+
src: `${parentServer.base}${testerEntry.file}`
|
|
3103
|
+
},
|
|
3104
|
+
injectTo: "head"
|
|
3105
|
+
});
|
|
3106
|
+
for (const importName of testerEntry.imports || []) {
|
|
3107
|
+
const entryManifest = manifestContent[importName];
|
|
3108
|
+
if (entryManifest) {
|
|
3109
|
+
testerTags.push({
|
|
3110
|
+
tag: "link",
|
|
3111
|
+
attrs: {
|
|
3112
|
+
href: `${parentServer.base}${entryManifest.file}`,
|
|
3113
|
+
rel: "modulepreload",
|
|
3114
|
+
crossorigin: ""
|
|
3115
|
+
},
|
|
3116
|
+
injectTo: "head"
|
|
3117
|
+
});
|
|
3118
|
+
}
|
|
3493
3119
|
}
|
|
3120
|
+
} else {
|
|
3121
|
+
// inject the reset style only in the default template,
|
|
3122
|
+
// allowing users to customize the style in their own template
|
|
3123
|
+
testerTags.push({
|
|
3124
|
+
tag: "style",
|
|
3125
|
+
children: `
|
|
3126
|
+
html {
|
|
3127
|
+
padding: 0;
|
|
3128
|
+
margin: 0;
|
|
3129
|
+
}
|
|
3130
|
+
body {
|
|
3131
|
+
padding: 0;
|
|
3132
|
+
margin: 0;
|
|
3133
|
+
min-height: 100vh;
|
|
3134
|
+
}`,
|
|
3135
|
+
injectTo: "head"
|
|
3136
|
+
});
|
|
3494
3137
|
}
|
|
3138
|
+
return [
|
|
3139
|
+
{
|
|
3140
|
+
tag: "script",
|
|
3141
|
+
children: "{__VITEST_INJECTOR__}",
|
|
3142
|
+
injectTo: "head-prepend"
|
|
3143
|
+
},
|
|
3144
|
+
{
|
|
3145
|
+
tag: "script",
|
|
3146
|
+
children: stateJs,
|
|
3147
|
+
injectTo: "head-prepend"
|
|
3148
|
+
},
|
|
3149
|
+
{
|
|
3150
|
+
tag: "script",
|
|
3151
|
+
attrs: {
|
|
3152
|
+
type: "module",
|
|
3153
|
+
src: parentServer.errorCatcherUrl
|
|
3154
|
+
},
|
|
3155
|
+
injectTo: "head"
|
|
3156
|
+
},
|
|
3157
|
+
{
|
|
3158
|
+
tag: "script",
|
|
3159
|
+
attrs: {
|
|
3160
|
+
type: "module",
|
|
3161
|
+
src: parentServer.matchersUrl
|
|
3162
|
+
},
|
|
3163
|
+
injectTo: "head"
|
|
3164
|
+
},
|
|
3165
|
+
...parentServer.initScripts.map((script) => ({
|
|
3166
|
+
tag: "script",
|
|
3167
|
+
attrs: {
|
|
3168
|
+
type: "module",
|
|
3169
|
+
src: join("/@fs/", script)
|
|
3170
|
+
},
|
|
3171
|
+
injectTo: "head"
|
|
3172
|
+
})),
|
|
3173
|
+
...testerTags
|
|
3174
|
+
].filter((s) => s != null);
|
|
3495
3175
|
},
|
|
3496
|
-
|
|
3497
|
-
|
|
3498
|
-
|
|
3499
|
-
|
|
3500
|
-
|
|
3501
|
-
|
|
3502
|
-
|
|
3176
|
+
configureServer(server) {
|
|
3177
|
+
const parentServer = contribution.parent;
|
|
3178
|
+
parentServer.setServer(server);
|
|
3179
|
+
// eslint-disable-next-line prefer-arrow-callback
|
|
3180
|
+
server.middlewares.use(function vitestHeaders(_req, res, next) {
|
|
3181
|
+
const headers = server.config.server.headers;
|
|
3182
|
+
if (headers) {
|
|
3183
|
+
for (const name in headers) {
|
|
3184
|
+
res.setHeader(name, headers[name]);
|
|
3185
|
+
}
|
|
3186
|
+
}
|
|
3187
|
+
next();
|
|
3188
|
+
});
|
|
3189
|
+
// strip _vitest_original query added by importActual so that
|
|
3190
|
+
// the plugin pipeline sees the original import id (e.g. virtual modules's load hook).
|
|
3191
|
+
server.middlewares.use((req, _res, next) => {
|
|
3192
|
+
if (req.url?.includes("_vitest_original") && parentServer.config.browser.provider?.name === "playwright") {
|
|
3193
|
+
req.url = req.url.replace(/[?&]_vitest_original(?=[&#]|$)/, "").replace(/[?&]ext\b[^&#]*/, "").replace(/\?$/, "");
|
|
3194
|
+
}
|
|
3195
|
+
next();
|
|
3196
|
+
});
|
|
3197
|
+
server.middlewares.use(createOrchestratorMiddleware(parentServer));
|
|
3198
|
+
server.middlewares.use(createTesterMiddleware(parentServer));
|
|
3199
|
+
server.middlewares.use(`/favicon.svg`, (_, res) => {
|
|
3200
|
+
const content = readFileSync(resolve(distRoot, "client/favicon.svg"));
|
|
3201
|
+
res.write(content, "utf-8");
|
|
3202
|
+
res.end();
|
|
3203
|
+
});
|
|
3204
|
+
// Serve coverage HTML at ./coverage if configured
|
|
3205
|
+
const coverageHtmlDir = parentServer.vitest.config.coverage?.htmlDir;
|
|
3206
|
+
if (coverageHtmlDir) {
|
|
3207
|
+
server.middlewares.use("/__vitest_test__/coverage", sirv(coverageHtmlDir, {
|
|
3208
|
+
single: true,
|
|
3209
|
+
dev: true,
|
|
3210
|
+
setHeaders: (res) => {
|
|
3211
|
+
const csp = res.getHeader("Content-Security-Policy");
|
|
3212
|
+
if (typeof csp === "string") {
|
|
3213
|
+
// add frame-ancestors to allow the iframe to be loaded by Vitest,
|
|
3214
|
+
// but keep the rest of the CSP
|
|
3215
|
+
res.setHeader("Content-Security-Policy", csp.replace(/frame-ancestors [^;]+/, "frame-ancestors *"));
|
|
3216
|
+
}
|
|
3217
|
+
res.setHeader("Cache-Control", "public,max-age=0,must-revalidate");
|
|
3218
|
+
}
|
|
3219
|
+
}));
|
|
3220
|
+
}
|
|
3221
|
+
server.middlewares.use((req, res, next) => {
|
|
3222
|
+
// 9000 mega head move
|
|
3223
|
+
// Vite always caches optimized dependencies, but users might mock
|
|
3224
|
+
// them in _some_ tests, while keeping original modules in others
|
|
3225
|
+
// there is no way to configure that in Vite, so we patch it here
|
|
3226
|
+
// to always ignore the cache-control set by Vite in the next middleware
|
|
3227
|
+
if (req.url && versionRegexp.test(req.url) && !req.url.includes("chunk-")) {
|
|
3228
|
+
res.setHeader("Cache-Control", "no-cache");
|
|
3229
|
+
const setHeader = res.setHeader.bind(res);
|
|
3230
|
+
res.setHeader = function(name, value) {
|
|
3231
|
+
if (name === "Cache-Control") {
|
|
3232
|
+
return res;
|
|
3233
|
+
}
|
|
3234
|
+
return setHeader(name, value);
|
|
3235
|
+
};
|
|
3236
|
+
}
|
|
3237
|
+
next();
|
|
3238
|
+
});
|
|
3239
|
+
// handle attachments the same way as in packages/ui/node/index.ts
|
|
3240
|
+
server.middlewares.use((req, res, next) => {
|
|
3241
|
+
if (!req.url) {
|
|
3242
|
+
return next();
|
|
3243
|
+
}
|
|
3244
|
+
const url = new URL(req.url, "http://localhost");
|
|
3245
|
+
if (url.pathname !== "/__vitest_attachment__") {
|
|
3246
|
+
return next();
|
|
3247
|
+
}
|
|
3248
|
+
const path = url.searchParams.get("path");
|
|
3249
|
+
const contentType = url.searchParams.get("contentType");
|
|
3250
|
+
if (!isValidApiRequest(parentServer.config, req) || !contentType || !path) {
|
|
3251
|
+
return next();
|
|
3252
|
+
}
|
|
3253
|
+
const fsPath = decodeURIComponent(path);
|
|
3254
|
+
if (!isFileServingAllowed(parentServer.vite.config, fsPath)) {
|
|
3255
|
+
return next();
|
|
3256
|
+
}
|
|
3257
|
+
try {
|
|
3258
|
+
res.setHeader("content-type", contentType);
|
|
3259
|
+
return createReadStream(fsPath).pipe(res).on("close", () => res.end());
|
|
3260
|
+
} catch (err) {
|
|
3261
|
+
return next(err);
|
|
3262
|
+
}
|
|
3263
|
+
});
|
|
3264
|
+
// When the Vitest UI (`test.ui`) is enabled, the `vitest:ui` plugin owns
|
|
3265
|
+
// `/__vitest__` (including the token-injected index.html and its assets),
|
|
3266
|
+
// so registering sirv here would shadow it and serve the page without a token.
|
|
3267
|
+
if (!parentServer.vitest.config.ui) {
|
|
3268
|
+
server.middlewares.use("/__vitest__", sirv(distClientRoot));
|
|
3269
|
+
}
|
|
3503
3270
|
},
|
|
3504
|
-
|
|
3505
|
-
|
|
3506
|
-
{
|
|
3507
|
-
|
|
3508
|
-
|
|
3509
|
-
|
|
3271
|
+
async config(viteConfig) {
|
|
3272
|
+
const testConfig = viteConfig.test || {};
|
|
3273
|
+
const config = {
|
|
3274
|
+
resolve: {
|
|
3275
|
+
alias: testConfig.alias,
|
|
3276
|
+
dedupe: ["vitest"]
|
|
3277
|
+
},
|
|
3278
|
+
server: {
|
|
3279
|
+
fs: { allow: [distRoot] },
|
|
3280
|
+
middlewareMode: false,
|
|
3281
|
+
watch: null,
|
|
3282
|
+
forwardConsole: false
|
|
3510
3283
|
}
|
|
3511
|
-
}
|
|
3512
|
-
|
|
3513
|
-
|
|
3514
|
-
|
|
3284
|
+
};
|
|
3285
|
+
// Enables using the @preserve ignore hint for coverage providers. Only for
|
|
3286
|
+
// esbuild (rolldown-vite uses oxc instead).
|
|
3287
|
+
if (!rolldownVersion && viteConfig.esbuild !== false) {
|
|
3288
|
+
config.esbuild = { legalComments: "inline" };
|
|
3289
|
+
}
|
|
3290
|
+
const define = {};
|
|
3291
|
+
const envVars = testConfig.env || {};
|
|
3292
|
+
for (const env in envVars) {
|
|
3293
|
+
define[`import.meta.env.${env}`] = JSON.stringify(envVars[env]);
|
|
3294
|
+
}
|
|
3295
|
+
config.define = define;
|
|
3296
|
+
return config;
|
|
3297
|
+
},
|
|
3298
|
+
resolveOptimizeDeps(projectConfigs, testFiles, harness) {
|
|
3299
|
+
return resolveBrowserOptimizeDeps(projectConfigs, testFiles, harness);
|
|
3300
|
+
},
|
|
3301
|
+
plugins: [],
|
|
3302
|
+
createParent({ config, vitest }) {
|
|
3303
|
+
if (vitest.version !== version) {
|
|
3304
|
+
vitest.logger.warn(c.yellow(`Loaded ${c.inverse(c.yellow(` vitest@${vitest.version} `))} and ${c.inverse(c.yellow(` @vitest/browser@${version} `))}.` + "\nRunning mixed versions is not supported and may lead into bugs" + "\nUpdate your dependencies and make sure the versions match."));
|
|
3305
|
+
}
|
|
3306
|
+
return new ParentBrowserProject({
|
|
3307
|
+
config,
|
|
3308
|
+
vitest
|
|
3309
|
+
}, "/");
|
|
3310
|
+
},
|
|
3311
|
+
setupRpc(parent) {
|
|
3312
|
+
setupBrowserRpc(parent, mockerRegistry);
|
|
3313
|
+
}
|
|
3314
|
+
};
|
|
3315
|
+
contribution.plugins = [
|
|
3316
|
+
...BrowserPlugin(contribution),
|
|
3317
|
+
interceptorPlugin({ registry: mockerRegistry }),
|
|
3318
|
+
{
|
|
3319
|
+
name: "vitest:browser:framework-sourcemaps",
|
|
3320
|
+
enforce: "post",
|
|
3321
|
+
transform(code, id) {
|
|
3322
|
+
const parentServer = contribution.parent;
|
|
3323
|
+
// In a headless run nothing can open devtools, so sourcemaps of
|
|
3324
|
+
// Vitest's own pre-built modules are never consumed: their stack
|
|
3325
|
+
// frames are filtered by stackIgnorePatterns. Generating and
|
|
3326
|
+
// inlining these maps costs server CPU and multiplies the bytes
|
|
3327
|
+
// the browser downloads by ~5 for every fresh browser context.
|
|
3328
|
+
// Sourcemaps of user files and (by default) their dependencies are
|
|
3329
|
+
// kept — they point error stacks and devtools at original sources.
|
|
3330
|
+
if (!parentServer || !isHeadlessServer(parentServer) || parentServer.vitest.config.inspector.enabled) {
|
|
3331
|
+
return null;
|
|
3515
3332
|
}
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3524
|
-
|
|
3525
|
-
|
|
3526
|
-
|
|
3527
|
-
|
|
3333
|
+
if (isCSSRequest(id)) {
|
|
3334
|
+
return null;
|
|
3335
|
+
}
|
|
3336
|
+
const path = cleanUrl$1(id);
|
|
3337
|
+
if (path.startsWith(distRoot) || path.startsWith(distDir)) {
|
|
3338
|
+
return {
|
|
3339
|
+
code,
|
|
3340
|
+
map: { mappings: "" }
|
|
3341
|
+
};
|
|
3342
|
+
}
|
|
3343
|
+
// users that never debug into node_modules can drop dependency
|
|
3344
|
+
// sourcemaps entirely; `server.sourcemapIgnoreList` (default:
|
|
3345
|
+
// node_modules) can opt paths back in even then, e.g. with
|
|
3346
|
+
// `preserveSymlinks` where workspace code keeps its node_modules
|
|
3347
|
+
// path and would be wrongly treated as a dependency
|
|
3348
|
+
if (parentServer.config.browser.dependencySourcemaps === false && path.includes("/node_modules/") && (parentServer.vite.config.server.sourcemapIgnoreList(path, path) ?? true)) {
|
|
3349
|
+
return {
|
|
3350
|
+
code,
|
|
3351
|
+
map: { mappings: "" }
|
|
3352
|
+
};
|
|
3353
|
+
}
|
|
3354
|
+
return null;
|
|
3355
|
+
}
|
|
3356
|
+
}
|
|
3357
|
+
];
|
|
3358
|
+
return contribution;
|
|
3528
3359
|
};
|
|
3360
|
+
function isHeadlessServer(parentServer) {
|
|
3361
|
+
if (!parentServer.config.browser.headless) {
|
|
3362
|
+
return false;
|
|
3363
|
+
}
|
|
3364
|
+
// sibling instances share this server (and its module graph cache, so a
|
|
3365
|
+
// late-spawned instance would receive already-cached transforms) and can
|
|
3366
|
+
// override `headless` — check the static instance options instead of the
|
|
3367
|
+
// lazily populated `children` to stay deterministic across runs
|
|
3368
|
+
const instances = parentServer.config.browser.instances ?? [];
|
|
3369
|
+
return instances.every((instance) => instance.headless !== false);
|
|
3370
|
+
}
|
|
3371
|
+
function resolveBrowserOptimizeDeps(projectConfigs, testFiles, harness) {
|
|
3372
|
+
// `testFiles` are globbed by the core package and aggregated across every
|
|
3373
|
+
// project that shares this browser Vite server (instance and benchmark
|
|
3374
|
+
// variants). The remaining options are shared by those projects, so the first
|
|
3375
|
+
// config is representative.
|
|
3376
|
+
const testConfig = projectConfigs[0];
|
|
3377
|
+
const root = testConfig.root || process.cwd();
|
|
3378
|
+
const setupFiles = new Set(projectConfigs.flatMap((config) => toArray(config.setupFiles || [])));
|
|
3379
|
+
const entries = [
|
|
3380
|
+
...testFiles,
|
|
3381
|
+
...setupFiles,
|
|
3382
|
+
resolve(distDir, "index.js"),
|
|
3383
|
+
resolve(distDir, "browser.js"),
|
|
3384
|
+
resolve(distDir, "runners.js"),
|
|
3385
|
+
resolve(distDir, "utils.js"),
|
|
3386
|
+
...testConfig.snapshotSerializers || []
|
|
3387
|
+
];
|
|
3388
|
+
// Keep these external (never pre-bundle by optimizer):
|
|
3389
|
+
// - vitest/browser, @vitest/browser/context, @vitest/browser/utils are
|
|
3390
|
+
// VIRTUAL modules generated per-server (see pluginContext.ts) — optimizer
|
|
3391
|
+
// cannot resolve/run their `load`, it would freeze stale/empty content.
|
|
3392
|
+
// - vite/module-runner is small enough to not need pre-bundling.
|
|
3393
|
+
// - msw is a large, side-effectful service-worker library.
|
|
3394
|
+
const exclude = [
|
|
3395
|
+
"vitest/browser",
|
|
3396
|
+
"vite/module-runner",
|
|
3397
|
+
"@vitest/browser/utils",
|
|
3398
|
+
"@vitest/browser/context",
|
|
3399
|
+
"msw",
|
|
3400
|
+
"msw/browser"
|
|
3401
|
+
];
|
|
3402
|
+
if (typeof testConfig.diff === "string") {
|
|
3403
|
+
entries.push(testConfig.diff);
|
|
3404
|
+
}
|
|
3405
|
+
if (testConfig.coverage?.enabled) {
|
|
3406
|
+
const provider = testConfig.coverage.provider ?? "v8";
|
|
3407
|
+
if (provider === "v8") {
|
|
3408
|
+
const path = tryResolve("@vitest/coverage-v8", [root]);
|
|
3409
|
+
if (path) {
|
|
3410
|
+
entries.push(path);
|
|
3411
|
+
exclude.push("@vitest/coverage-v8/browser");
|
|
3412
|
+
}
|
|
3413
|
+
} else if (provider === "istanbul") {
|
|
3414
|
+
const path = tryResolve("@vitest/coverage-istanbul", [root]);
|
|
3415
|
+
if (path) {
|
|
3416
|
+
entries.push(path);
|
|
3417
|
+
exclude.push("@vitest/coverage-istanbul");
|
|
3418
|
+
}
|
|
3419
|
+
} else if (provider === "custom" && testConfig.coverage.customProviderModule) {
|
|
3420
|
+
entries.push(testConfig.coverage.customProviderModule);
|
|
3421
|
+
}
|
|
3422
|
+
}
|
|
3423
|
+
// Pre-bundle the vitest runtime so the browser fetches a few optimized
|
|
3424
|
+
// chunks instead of ~20 separately-served dist chunks (faster startup).
|
|
3425
|
+
// `vitest`, `vitest/internal/browser` and `@vitest/browser/client` are
|
|
3426
|
+
// optimized together in a single pass, so esbuild dedupes their shared
|
|
3427
|
+
// stateful chunks (the test collector, the runner, the RPC client) to a
|
|
3428
|
+
// single instance — preserving module identity between the test files'
|
|
3429
|
+
// `import 'vitest'` and the tester. Their transitive deps (@vitest/utils,
|
|
3430
|
+
// @vitest/spy, pathe, tinyrainbow, …) are inlined into these bundles.
|
|
3431
|
+
const include = [
|
|
3432
|
+
"vitest > expect-type",
|
|
3433
|
+
"vitest > magic-string",
|
|
3434
|
+
"vitest > chai",
|
|
3435
|
+
"vitest",
|
|
3436
|
+
"vitest/internal/browser",
|
|
3437
|
+
"@vitest/browser/client"
|
|
3438
|
+
];
|
|
3439
|
+
const provider = testConfig.browser?.provider;
|
|
3440
|
+
if (provider?.name === "preview") {
|
|
3441
|
+
include.push("@vitest/browser-preview > @testing-library/user-event", "@vitest/browser-preview > @testing-library/dom");
|
|
3442
|
+
}
|
|
3443
|
+
const isPackageExists = (pkg) => {
|
|
3444
|
+
return harness.packageInstaller.isPackageExists(pkg, { paths: [root] });
|
|
3445
|
+
};
|
|
3446
|
+
if (isPackageExists("vitest-browser-svelte")) {
|
|
3447
|
+
exclude.push("vitest-browser-svelte");
|
|
3448
|
+
}
|
|
3449
|
+
// since we override the resolution in the esbuild plugin, Vite can no longer optimize it
|
|
3450
|
+
if (isPackageExists("vitest-browser-vue")) {
|
|
3451
|
+
include.push("vitest-browser-vue", "vitest-browser-vue > @vue/test-utils", "vitest-browser-vue > @vue/test-utils > @vue/compiler-core");
|
|
3452
|
+
}
|
|
3453
|
+
if (isPackageExists("@vue/test-utils")) {
|
|
3454
|
+
include.push("@vue/test-utils");
|
|
3455
|
+
}
|
|
3456
|
+
const otelConfig = testConfig.experimental?.openTelemetry;
|
|
3457
|
+
if (otelConfig?.enabled && otelConfig.browserSdkPath) {
|
|
3458
|
+
entries.push(otelConfig.browserSdkPath);
|
|
3459
|
+
include.push("@opentelemetry/api");
|
|
3460
|
+
} else {
|
|
3461
|
+
exclude.push("@opentelemetry/api");
|
|
3462
|
+
}
|
|
3463
|
+
// resolve @vue/(test-utils|compiler-core) to CJS instead of the browser build:
|
|
3464
|
+
// test-utils' browser build expects a global Vue; compiler-core's CJS build is
|
|
3465
|
+
// the only one that allows slots as strings.
|
|
3466
|
+
const rolldownPlugin = {
|
|
3467
|
+
name: "vue-test-utils-rewrite",
|
|
3468
|
+
resolveId: {
|
|
3469
|
+
filter: { id: /^@vue\/(test-utils|compiler-core)$/ },
|
|
3470
|
+
handler(source, importer) {
|
|
3471
|
+
return getRequire().resolve(source, { paths: [importer] });
|
|
3472
|
+
}
|
|
3473
|
+
}
|
|
3474
|
+
};
|
|
3475
|
+
const esbuildPlugin = {
|
|
3476
|
+
name: "test-utils-rewrite",
|
|
3477
|
+
setup(build) {
|
|
3478
|
+
build.onResolve({ filter: /^@vue\/(test-utils|compiler-core)$/ }, (args) => {
|
|
3479
|
+
return { path: getRequire().resolve(args.path, { paths: [args.importer] }) };
|
|
3480
|
+
});
|
|
3481
|
+
}
|
|
3482
|
+
};
|
|
3483
|
+
return {
|
|
3484
|
+
entries,
|
|
3485
|
+
exclude,
|
|
3486
|
+
include,
|
|
3487
|
+
...rolldownVersion ? { rolldownOptions: { plugins: [rolldownPlugin] } } : { esbuildOptions: { plugins: [esbuildPlugin] } }
|
|
3488
|
+
};
|
|
3489
|
+
}
|
|
3490
|
+
function tryResolve(path, paths) {
|
|
3491
|
+
try {
|
|
3492
|
+
return getRequire().resolve(path, { paths });
|
|
3493
|
+
} catch {
|
|
3494
|
+
return undefined;
|
|
3495
|
+
}
|
|
3496
|
+
}
|
|
3497
|
+
let _require;
|
|
3498
|
+
function getRequire() {
|
|
3499
|
+
if (!_require) {
|
|
3500
|
+
_require = createRequire(import.meta.url);
|
|
3501
|
+
}
|
|
3502
|
+
return _require;
|
|
3503
|
+
}
|
|
3529
3504
|
function defineBrowserProvider(options) {
|
|
3530
3505
|
return {
|
|
3531
3506
|
...options,
|