@vitest/browser 5.0.0-beta.2 → 5.0.0-beta.4
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/context.d.ts +8 -0
- package/dist/client/.vite/manifest.json +8 -8
- package/dist/client/__vitest__/assets/index-B2jbgabi.js +139 -0
- package/dist/client/__vitest__/assets/index-CEyXAB_I.css +1 -0
- package/dist/client/__vitest__/index.html +2 -2
- package/dist/client/__vitest_browser__/defineProperty-C3k2g8Sk.js +267 -0
- package/dist/client/__vitest_browser__/orchestrator-B44yH1M4.js +343 -0
- package/dist/client/__vitest_browser__/rrweb-snapshot-iZCFA2to.js +4388 -0
- package/dist/client/__vitest_browser__/tester-kAU8uxhk.js +5086 -0
- package/dist/client/orchestrator.html +2 -2
- package/dist/client/tester/tester.html +2 -2
- package/dist/client/tester/trace.d.ts +9 -6
- package/dist/client.js +10 -1
- package/dist/context.js +53 -23
- package/dist/expect-element.js +30 -30
- package/dist/index.js +153 -33
- package/dist/locators-CPBpJv8y.js +5 -0
- package/dist/locators.js +1 -1
- package/dist/shared/screenshotMatcher/types.d.ts +2 -1
- package/dist/state.js +64 -14
- package/dist/types.d.ts +7 -2
- package/jest-dom.d.ts +26 -6
- package/matchers.d.ts +2 -1
- package/package.json +7 -7
- package/dist/client/__vitest__/assets/index-Cd6On2Pm.js +0 -136
- package/dist/client/__vitest__/assets/index-Dw9P28Qt.css +0 -1
- package/dist/client/__vitest_browser__/orchestrator-BfoS0x4w.js +0 -411
- package/dist/client/__vitest_browser__/rrweb-snapshot-xhvrgOHx.js +0 -5476
- package/dist/client/__vitest_browser__/tester-BJtW9QqZ.js +0 -5588
- package/dist/client/__vitest_browser__/utils-Nd8hqrhP.js +0 -189
- package/dist/locators-CesZ2RSY.js +0 -5
package/dist/state.js
CHANGED
|
@@ -3,7 +3,12 @@
|
|
|
3
3
|
|
|
4
4
|
let SOURCEMAPPING_URL = "sourceMa";
|
|
5
5
|
SOURCEMAPPING_URL += "ppingURL";
|
|
6
|
+
//#endregion
|
|
7
|
+
//#region src/shared/utils.ts
|
|
6
8
|
const isWindows = typeof process < "u" && process.platform === "win32";
|
|
9
|
+
/**
|
|
10
|
+
* Undo {@link wrapId}'s `/@id/` and null byte replacements.
|
|
11
|
+
*/
|
|
7
12
|
function unwrapId(id) {
|
|
8
13
|
return id.startsWith("/@id/") ? id.slice(5).replace("__x00__", "\0") : id;
|
|
9
14
|
}
|
|
@@ -15,11 +20,13 @@
|
|
|
15
20
|
function cleanUrl(url) {
|
|
16
21
|
return url.replace(postfixRE, "");
|
|
17
22
|
}
|
|
23
|
+
//#endregion
|
|
24
|
+
//#region ../../node_modules/.pnpm/pathe@2.0.3/node_modules/pathe/dist/shared/pathe.M-eThtNZ.mjs
|
|
18
25
|
const _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
|
|
19
26
|
function normalizeWindowsPath(input = "") {
|
|
20
27
|
return input && input.replace(/\\/g, "/").replace(_DRIVE_LETTER_START_RE, (r) => r.toUpperCase());
|
|
21
28
|
}
|
|
22
|
-
const _IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]
|
|
29
|
+
const _IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/, _DRIVE_LETTER_RE = /^[A-Za-z]:$/;
|
|
23
30
|
function cwd() {
|
|
24
31
|
return typeof process < "u" && typeof process.cwd == "function" ? process.cwd().replace(/\\/g, "/") : "/";
|
|
25
32
|
}
|
|
@@ -59,25 +66,35 @@
|
|
|
59
66
|
}
|
|
60
67
|
const isAbsolute = function(p) {
|
|
61
68
|
return _IS_ABSOLUTE_RE.test(p);
|
|
62
|
-
},
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
69
|
+
}, dirname = function(p) {
|
|
70
|
+
let segments = normalizeWindowsPath(p).replace(/\/$/, "").split("/").slice(0, -1);
|
|
71
|
+
return segments.length === 1 && _DRIVE_LETTER_RE.test(segments[0]) && (segments[0] += "/"), segments.join("/") || (isAbsolute(p) ? "/" : ".");
|
|
72
|
+
}, textDecoder = new TextDecoder(), decodeBase64 = typeof Buffer == "function" && typeof Buffer.from == "function" ? (base64) => Buffer.from(base64, "base64").toString("utf-8") : (base64) => textDecoder.decode(Uint8Array.from(atob(base64), (c) => c.charCodeAt(0)));
|
|
73
|
+
const posixDirname = dirname, posixResolve = resolve;
|
|
74
|
+
//#endregion
|
|
75
|
+
//#region ../../node_modules/.pnpm/@jridgewell+sourcemap-codec@1.5.5/node_modules/@jridgewell/sourcemap-codec/dist/sourcemap-codec.mjs
|
|
76
|
+
var chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", intToChar = new Uint8Array(64), charToInt = new Uint8Array(128);
|
|
77
|
+
for (let i = 0; i < chars.length; i++) {
|
|
78
|
+
let c = chars.charCodeAt(i);
|
|
67
79
|
intToChar[i] = c, charToInt[c] = i;
|
|
68
80
|
}
|
|
81
|
+
//#endregion
|
|
82
|
+
//#region src/module-runner/sourcemap/decoder.ts
|
|
69
83
|
var DecodedMap = class {
|
|
70
84
|
_encoded;
|
|
71
85
|
_decoded;
|
|
72
86
|
_decodedMemo;
|
|
73
87
|
url;
|
|
88
|
+
file;
|
|
74
89
|
version;
|
|
75
90
|
names = [];
|
|
76
91
|
resolvedSources;
|
|
77
92
|
constructor(map, from) {
|
|
78
93
|
this.map = map;
|
|
79
94
|
let { mappings, names, sources } = map;
|
|
80
|
-
this.version = map.version, this.names = names || [], this._encoded = mappings || "", this._decodedMemo = memoizedState(), this.url = from, this.
|
|
95
|
+
this.version = map.version, this.names = names || [], this._encoded = mappings || "", this._decodedMemo = memoizedState(), this.url = from, this.file = from;
|
|
96
|
+
let originDir = posixDirname(from);
|
|
97
|
+
this.resolvedSources = (sources || []).map((s) => posixResolve(originDir, s || ""));
|
|
81
98
|
}
|
|
82
99
|
};
|
|
83
100
|
function memoizedState() {
|
|
@@ -87,7 +104,9 @@
|
|
|
87
104
|
lastIndex: -1
|
|
88
105
|
};
|
|
89
106
|
}
|
|
90
|
-
|
|
107
|
+
//#endregion
|
|
108
|
+
//#region src/module-runner/evaluatedModules.ts
|
|
109
|
+
const MODULE_RUNNER_SOURCEMAPPING_REGEXP = RegExp(`//# ${SOURCEMAPPING_URL}=data:application/json;base64,(.+)`);
|
|
91
110
|
var EvaluatedModuleNode = class {
|
|
92
111
|
importers = /* @__PURE__ */ new Set();
|
|
93
112
|
imports = /* @__PURE__ */ new Set();
|
|
@@ -104,19 +123,44 @@
|
|
|
104
123
|
idToModuleMap = /* @__PURE__ */ new Map();
|
|
105
124
|
fileToModulesMap = /* @__PURE__ */ new Map();
|
|
106
125
|
urlToIdModuleMap = /* @__PURE__ */ new Map();
|
|
126
|
+
/**
|
|
127
|
+
* Returns the module node by the resolved module ID. Usually, module ID is
|
|
128
|
+
* the file system path with query and/or hash. It can also be a virtual module.
|
|
129
|
+
*
|
|
130
|
+
* Module runner graph will have 1 to 1 mapping with the server module graph.
|
|
131
|
+
* @param id Resolved module ID
|
|
132
|
+
*/
|
|
107
133
|
getModuleById(id) {
|
|
108
134
|
return this.idToModuleMap.get(id);
|
|
109
135
|
}
|
|
136
|
+
/**
|
|
137
|
+
* Returns all modules related to the file system path. Different modules
|
|
138
|
+
* might have different query parameters or hash, so it's possible to have
|
|
139
|
+
* multiple modules for the same file.
|
|
140
|
+
* @param file The file system path of the module
|
|
141
|
+
*/
|
|
110
142
|
getModulesByFile(file) {
|
|
111
143
|
return this.fileToModulesMap.get(file);
|
|
112
144
|
}
|
|
145
|
+
/**
|
|
146
|
+
* Returns the module node by the URL that was used in the import statement.
|
|
147
|
+
* Unlike module graph on the server, the URL is not resolved and is used as is.
|
|
148
|
+
* @param url Server URL that was used in the import statement
|
|
149
|
+
*/
|
|
113
150
|
getModuleByUrl(url) {
|
|
114
151
|
return this.urlToIdModuleMap.get(unwrapId(url));
|
|
115
152
|
}
|
|
153
|
+
/**
|
|
154
|
+
* Ensure that module is in the graph. If the module is already in the graph,
|
|
155
|
+
* it will return the existing module node. Otherwise, it will create a new
|
|
156
|
+
* module node and add it to the graph.
|
|
157
|
+
* @param id Resolved module ID
|
|
158
|
+
* @param url URL that was used in the import statement
|
|
159
|
+
*/
|
|
116
160
|
ensureModule(id, url) {
|
|
117
161
|
if (id = normalizeModuleId(id), this.idToModuleMap.has(id)) {
|
|
118
|
-
let moduleNode
|
|
119
|
-
return this.urlToIdModuleMap.set(url, moduleNode
|
|
162
|
+
let moduleNode = this.idToModuleMap.get(id);
|
|
163
|
+
return this.urlToIdModuleMap.set(url, moduleNode), moduleNode;
|
|
120
164
|
}
|
|
121
165
|
let moduleNode = new EvaluatedModuleNode(id, url);
|
|
122
166
|
this.idToModuleMap.set(id, moduleNode), this.urlToIdModuleMap.set(url, moduleNode);
|
|
@@ -126,6 +170,11 @@
|
|
|
126
170
|
invalidateModule(node) {
|
|
127
171
|
node.evaluated = false, node.meta = void 0, node.map = void 0, node.promise = void 0, node.exports = void 0, node.imports.clear();
|
|
128
172
|
}
|
|
173
|
+
/**
|
|
174
|
+
* Extracts the inlined source map from the module code and returns the decoded
|
|
175
|
+
* source map. If the source map is not inlined, it will return null.
|
|
176
|
+
* @param id Resolved module ID
|
|
177
|
+
*/
|
|
129
178
|
getModuleSourceMapById(id) {
|
|
130
179
|
let mod = this.getModuleById(id);
|
|
131
180
|
if (!mod) return null;
|
|
@@ -147,10 +196,10 @@
|
|
|
147
196
|
"node:test/reporters"
|
|
148
197
|
]);
|
|
149
198
|
function normalizeModuleId(file) {
|
|
150
|
-
|
|
151
|
-
let unixFile = slash(file).replace(/^\/@fs\//, isWindows ? "" : "/").replace(/^node:/, "").replace(/^\/+/, "/");
|
|
152
|
-
return unixFile.replace(/^file:\/+/, isWindows ? "" : "/");
|
|
199
|
+
return prefixedBuiltins.has(file) ? file : slash(file).replace(/^\/@fs\//, isWindows ? "" : "/").replace(/^node:/, "").replace(/^\/+/, "/").replace(/^file:\/+/, isWindows ? "" : "/");
|
|
153
200
|
}
|
|
201
|
+
//#endregion
|
|
202
|
+
//#region src/module-runner/importMetaResolver.ts
|
|
154
203
|
const customizationHookNamespace = "vite-module-runner:import-meta-resolve/v1/"; `
|
|
155
204
|
|
|
156
205
|
export async function resolve(specifier, context, nextResolve) {
|
|
@@ -160,11 +209,12 @@ export async function resolve(specifier, context, nextResolve) {
|
|
|
160
209
|
specifier = parsedSpecifier
|
|
161
210
|
context.parentURL = parsedImporter
|
|
162
211
|
}
|
|
163
|
-
|
|
164
212
|
return nextResolve(specifier, context)
|
|
165
213
|
}
|
|
166
214
|
|
|
167
215
|
`;
|
|
216
|
+
//#endregion
|
|
217
|
+
//#region src/module-runner/createImportMeta.ts
|
|
168
218
|
new Proxy({}, { get(_, p) {
|
|
169
219
|
throw Error(`[module runner] Dynamic access of "import.meta.env" is not supported. Please, use "import.meta.env.${String(p)}" instead.`);
|
|
170
220
|
} });
|
package/dist/types.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import type { MockedModuleSerialized, ServerIdResolution, ServerMockResolution } from "@vitest/mocker";
|
|
2
|
-
import type { TaskEventPack, TaskResultPack, TestArtifact } from "@vitest/runner";
|
|
2
|
+
import type { BaselineData, TaskEventPack, TaskResultPack, TestArtifact } from "@vitest/runner";
|
|
3
3
|
import type { BirpcReturn } from "birpc";
|
|
4
|
-
import type { AfterSuiteRunMeta, BrowserTesterOptions, CancelReason, RunnerTestFile, SerializedTestSpecification, SnapshotResult, TestExecutionMethod, UserConsoleLog } from "vitest";
|
|
4
|
+
import type { AfterSuiteRunMeta, BrowserTesterOptions, CancelReason, RunnerTestFile, SerializedTestSpecification, SnapshotResult, TestBenchmark, TestExecutionMethod, UserConsoleLog } from "vitest";
|
|
5
|
+
import type { MarkOptions } from "vitest/browser";
|
|
5
6
|
export interface WebSocketBrowserHandlers {
|
|
6
7
|
resolveSnapshotPath: (testPath: string) => string;
|
|
7
8
|
resolveSnapshotRawPath: (testPath: string, rawPath: string) => string;
|
|
@@ -10,6 +11,9 @@ export interface WebSocketBrowserHandlers {
|
|
|
10
11
|
onCollected: (method: TestExecutionMethod, files: RunnerTestFile[]) => Promise<void>;
|
|
11
12
|
onTaskArtifactRecord: <Artifact extends TestArtifact>(testId: string, artifact: Artifact) => Promise<Artifact>;
|
|
12
13
|
onTaskUpdate: (method: TestExecutionMethod, packs: TaskResultPack[], events: TaskEventPack[]) => void;
|
|
14
|
+
onTestBenchmark: (testId: string, benchmark: TestBenchmark) => void;
|
|
15
|
+
readBenchmarkResult: (relativePath: string) => Promise<BaselineData | null>;
|
|
16
|
+
writeBenchmarkResult: (relativePath: string, data: BaselineData) => Promise<void>;
|
|
13
17
|
onAfterSuiteRun: (meta: AfterSuiteRunMeta) => void;
|
|
14
18
|
cancelCurrentRun: (reason: CancelReason) => void;
|
|
15
19
|
getCountOfFailedTests: () => number;
|
|
@@ -49,6 +53,7 @@ export interface WebSocketBrowserEvents {
|
|
|
49
53
|
createTesters: (options: BrowserTesterOptions) => Promise<void>;
|
|
50
54
|
cleanupTesters: () => Promise<void>;
|
|
51
55
|
cdpEvent: (event: string, payload: unknown) => void;
|
|
56
|
+
pageMark: (name: string, options?: MarkOptions) => Promise<void>;
|
|
52
57
|
resolveManualMock: (url: string) => Promise<{
|
|
53
58
|
url: string;
|
|
54
59
|
keys: string[];
|
package/jest-dom.d.ts
CHANGED
|
@@ -377,6 +377,25 @@ export interface TestingLibraryMatchers<E, R> {
|
|
|
377
377
|
* @see https://vitest.dev/api/browser/assertions#tohavestyle
|
|
378
378
|
*/
|
|
379
379
|
toHaveStyle(css: string | Partial<CSSStyleDeclaration>): R
|
|
380
|
+
/**
|
|
381
|
+
* @description
|
|
382
|
+
* Validate that the given element's text content matches the provided string exactly.
|
|
383
|
+
*
|
|
384
|
+
* Supports elements, but also text nodes and fragments.
|
|
385
|
+
*
|
|
386
|
+
* If you wish to perform a partial check or use a RegExp, use `toMatchTextContent` instead.
|
|
387
|
+
* @example
|
|
388
|
+
* <span data-testid="text-content">Text Content</span>
|
|
389
|
+
*
|
|
390
|
+
* const element = page.getByTestId('text-content')
|
|
391
|
+
* await expect.element(element).toHaveTextContent('Text Content')
|
|
392
|
+
* await expect.element(element).not.toHaveTextContent('Content')
|
|
393
|
+
* @see https://vitest.dev/api/browser/assertions#tohavetextcontent
|
|
394
|
+
*/
|
|
395
|
+
toHaveTextContent(
|
|
396
|
+
text: string | number,
|
|
397
|
+
options?: {normalizeWhitespace: boolean},
|
|
398
|
+
): R
|
|
380
399
|
/**
|
|
381
400
|
* @description
|
|
382
401
|
* Check whether the given element has a text content or not.
|
|
@@ -391,15 +410,15 @@ export interface TestingLibraryMatchers<E, R> {
|
|
|
391
410
|
* <span data-testid="text-content">Text Content</span>
|
|
392
411
|
*
|
|
393
412
|
* const element = page.getByTestId('text-content')
|
|
394
|
-
* await expect.element(element).
|
|
413
|
+
* await expect.element(element).toMatchTextContent('Content')
|
|
395
414
|
* // to match the whole content
|
|
396
|
-
* await expect.element(element).
|
|
415
|
+
* await expect.element(element).toMatchTextContent(/^Text Content$/)
|
|
397
416
|
* // to use case-insensitive match
|
|
398
|
-
* await expect.element(element).
|
|
399
|
-
* await expect.element(element).not.
|
|
400
|
-
* @see https://vitest.dev/api/browser/assertions#
|
|
417
|
+
* await expect.element(element).toMatchTextContent(/content$/i)
|
|
418
|
+
* await expect.element(element).not.toMatchTextContent('content')
|
|
419
|
+
* @see https://vitest.dev/api/browser/assertions#tomatchtextcontent
|
|
401
420
|
*/
|
|
402
|
-
|
|
421
|
+
toMatchTextContent(
|
|
403
422
|
text: string | number | RegExp,
|
|
404
423
|
options?: {normalizeWhitespace: boolean},
|
|
405
424
|
): R
|
|
@@ -692,6 +711,7 @@ export interface TestingLibraryMatchers<E, R> {
|
|
|
692
711
|
*
|
|
693
712
|
* // basic usage, auto-generates screenshot name
|
|
694
713
|
* await expect.element(getByTestId('button')).toMatchScreenshot()
|
|
714
|
+
* await expect(page).toMatchScreenshot()
|
|
695
715
|
*
|
|
696
716
|
* // with custom name
|
|
697
717
|
* await expect.element(getByTestId('button')).toMatchScreenshot('fancy-button')
|
package/matchers.d.ts
CHANGED
|
@@ -18,7 +18,8 @@ declare module 'vitest' {
|
|
|
18
18
|
|
|
19
19
|
interface ExpectStatic {
|
|
20
20
|
/**
|
|
21
|
-
* `expect.element(locator)`
|
|
21
|
+
* `expect.element(locator)` retries locator resolution and DOM assertions
|
|
22
|
+
* using the `expect.poll` timeout options.
|
|
22
23
|
* You can set default timeout via `expect.poll.timeout` option in the config.
|
|
23
24
|
* @see {@link https://vitest.dev/api/expect#poll}
|
|
24
25
|
*/
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vitest/browser",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "5.0.0-beta.
|
|
4
|
+
"version": "5.0.0-beta.4",
|
|
5
5
|
"description": "Browser running for Vitest",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"funding": "https://opencollective.com/vitest",
|
|
@@ -63,7 +63,7 @@
|
|
|
63
63
|
"providers"
|
|
64
64
|
],
|
|
65
65
|
"peerDependencies": {
|
|
66
|
-
"vitest": "5.0.0-beta.
|
|
66
|
+
"vitest": "5.0.0-beta.4"
|
|
67
67
|
},
|
|
68
68
|
"dependencies": {
|
|
69
69
|
"@blazediff/core": "1.9.1",
|
|
@@ -72,8 +72,8 @@
|
|
|
72
72
|
"sirv": "^3.0.2",
|
|
73
73
|
"tinyrainbow": "^3.1.0",
|
|
74
74
|
"ws": "^8.19.0",
|
|
75
|
-
"@vitest/mocker": "5.0.0-beta.
|
|
76
|
-
"@vitest/utils": "5.0.0-beta.
|
|
75
|
+
"@vitest/mocker": "5.0.0-beta.4",
|
|
76
|
+
"@vitest/utils": "5.0.0-beta.4"
|
|
77
77
|
},
|
|
78
78
|
"devDependencies": {
|
|
79
79
|
"@opentelemetry/api": "^1.9.0",
|
|
@@ -83,12 +83,12 @@
|
|
|
83
83
|
"@types/ws": "^8.18.1",
|
|
84
84
|
"birpc": "^4.0.0",
|
|
85
85
|
"flatted": "^3.4.2",
|
|
86
|
-
"ivya": "^1.8.
|
|
86
|
+
"ivya": "^1.8.2",
|
|
87
87
|
"mime": "^4.1.0",
|
|
88
88
|
"pathe": "^2.0.3",
|
|
89
89
|
"rrweb-snapshot": "2.0.0-alpha.20",
|
|
90
|
-
"@vitest/runner": "5.0.0-beta.
|
|
91
|
-
"vitest": "5.0.0-beta.
|
|
90
|
+
"@vitest/runner": "5.0.0-beta.4",
|
|
91
|
+
"vitest": "5.0.0-beta.4"
|
|
92
92
|
},
|
|
93
93
|
"scripts": {
|
|
94
94
|
"typecheck": "tsc -p ./src/client/tsconfig.json --noEmit",
|