@vitest/browser 4.0.0-beta.9 → 4.0.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/README.md +6 -14
- package/context.d.ts +86 -29
- package/context.js +3 -2
- package/dist/client/.vite/manifest.json +6 -6
- package/dist/client/__vitest__/assets/index-COTh6lXR.css +1 -0
- package/dist/client/__vitest__/assets/index-DOkKC3NI.js +53 -0
- package/dist/client/__vitest__/index.html +2 -2
- package/dist/client/__vitest_browser__/orchestrator-CFVVvVT1.js +313 -0
- package/dist/client/__vitest_browser__/tester-BNxij3za.js +2133 -0
- package/dist/client/__vitest_browser__/{utils-FY_Qin7d.js → utils-uxqdqUz8.js} +48 -24
- package/dist/client/orchestrator.html +2 -2
- package/dist/client/tester/tester.html +2 -2
- package/dist/client.js +1 -1
- package/dist/context.js +80 -19
- package/dist/expect-element.js +14 -14
- package/dist/index-BnLTaCRv.js +6 -0
- package/dist/index.d.ts +64 -165
- package/dist/index.js +572 -1431
- package/dist/{locators/index.d.ts → locators.d.ts} +27 -3
- package/dist/locators.js +1 -0
- package/dist/state.js +0 -1
- package/dist/types.d.ts +0 -1
- package/jest-dom.d.ts +5 -5
- package/matchers.d.ts +2 -2
- package/package.json +18 -54
- package/utils.d.ts +5 -5
- package/dist/client/__vitest__/assets/index-CBcuRGkf.js +0 -57
- package/dist/client/__vitest__/assets/index-KbpJLW--.css +0 -1
- package/dist/client/__vitest_browser__/orchestrator-C2rrmv36.js +0 -3198
- package/dist/client/__vitest_browser__/tester-mSVktQ7a.js +0 -3282
- package/dist/index-B7Hfmz-h.js +0 -1
- package/dist/locators/index.js +0 -1
- package/dist/locators/playwright.js +0 -1
- package/dist/locators/preview.js +0 -1
- package/dist/locators/webdriverio.js +0 -1
- package/dist/providers.js +0 -47
- package/dist/public-utils-Kx5DUGWa.js +0 -6
- package/dist/utils.js +0 -1
- package/dist/webdriver-AHRa6U3j.js +0 -517
- package/providers/playwright.d.ts +0 -97
- package/providers/webdriverio.d.ts +0 -35
- package/providers.d.ts +0 -7
|
@@ -23,8 +23,8 @@
|
|
|
23
23
|
})();
|
|
24
24
|
</script>
|
|
25
25
|
<!-- !LOAD_METADATA! -->
|
|
26
|
-
<script type="module" src="./assets/index-
|
|
27
|
-
<link rel="stylesheet" href="./assets/index-
|
|
26
|
+
<script type="module" src="./assets/index-DOkKC3NI.js"></script>
|
|
27
|
+
<link rel="stylesheet" href="./assets/index-COTh6lXR.css">
|
|
28
28
|
</head>
|
|
29
29
|
<body>
|
|
30
30
|
<div id="app"></div>
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
import { g as getBrowserState, a as getConfig, r as relative, b as generateFileHash } from "./utils-uxqdqUz8.js";
|
|
2
|
+
import { channel, globalChannel, client } from "@vitest/browser/client";
|
|
3
|
+
// @__NO_SIDE_EFFECTS__
|
|
4
|
+
function getUiAPI() {
|
|
5
|
+
return window.__vitest_ui_api__;
|
|
6
|
+
}
|
|
7
|
+
const ID_ALL = "__vitest_all__";
|
|
8
|
+
class IframeOrchestrator {
|
|
9
|
+
cancelled = false;
|
|
10
|
+
recreateNonIsolatedIframe = false;
|
|
11
|
+
iframes = /* @__PURE__ */ new Map();
|
|
12
|
+
eventTarget = new EventTarget();
|
|
13
|
+
constructor() {
|
|
14
|
+
debug("init orchestrator", getBrowserState().sessionId);
|
|
15
|
+
channel.addEventListener(
|
|
16
|
+
"message",
|
|
17
|
+
(e) => this.onIframeEvent(e)
|
|
18
|
+
);
|
|
19
|
+
globalChannel.addEventListener(
|
|
20
|
+
"message",
|
|
21
|
+
(e) => this.onGlobalChannelEvent(e)
|
|
22
|
+
);
|
|
23
|
+
}
|
|
24
|
+
async createTesters(options) {
|
|
25
|
+
const startTime = performance.now();
|
|
26
|
+
this.cancelled = false;
|
|
27
|
+
const config = getConfig();
|
|
28
|
+
debug("create testers", options.files.join(", "));
|
|
29
|
+
const container = await getContainer(config);
|
|
30
|
+
if (config.browser.ui) {
|
|
31
|
+
container.className = "absolute origin-top mt-[8px]";
|
|
32
|
+
container.parentElement.setAttribute("data-ready", "true");
|
|
33
|
+
if (container.textContent) {
|
|
34
|
+
container.textContent = "";
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (config.browser.isolate === false) {
|
|
38
|
+
await this.runNonIsolatedTests(container, options, startTime);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
this.iframes.forEach((iframe) => iframe.remove());
|
|
42
|
+
this.iframes.clear();
|
|
43
|
+
for (let i = 0; i < options.files.length; i++) {
|
|
44
|
+
if (this.cancelled) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const file = options.files[i];
|
|
48
|
+
debug("create iframe", file);
|
|
49
|
+
await this.runIsolatedTestInIframe(
|
|
50
|
+
container,
|
|
51
|
+
file,
|
|
52
|
+
options,
|
|
53
|
+
startTime
|
|
54
|
+
);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
async cleanupTesters() {
|
|
58
|
+
const config = getConfig();
|
|
59
|
+
if (config.browser.isolate) {
|
|
60
|
+
const files = Array.from(this.iframes.keys());
|
|
61
|
+
const ui = /* @__PURE__ */ getUiAPI();
|
|
62
|
+
if (ui && files[0]) {
|
|
63
|
+
const id = generateFileId(files[0]);
|
|
64
|
+
ui.setCurrentFileId(id);
|
|
65
|
+
}
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
const iframe = this.iframes.get(ID_ALL);
|
|
69
|
+
if (!iframe) {
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
await sendEventToIframe({
|
|
73
|
+
event: "cleanup",
|
|
74
|
+
iframeId: ID_ALL
|
|
75
|
+
});
|
|
76
|
+
this.recreateNonIsolatedIframe = true;
|
|
77
|
+
}
|
|
78
|
+
async runNonIsolatedTests(container, options, startTime) {
|
|
79
|
+
if (this.recreateNonIsolatedIframe) {
|
|
80
|
+
this.recreateNonIsolatedIframe = false;
|
|
81
|
+
this.iframes.get(ID_ALL).remove();
|
|
82
|
+
this.iframes.delete(ID_ALL);
|
|
83
|
+
debug("recreate non-isolated iframe");
|
|
84
|
+
}
|
|
85
|
+
if (!this.iframes.has(ID_ALL)) {
|
|
86
|
+
debug("preparing non-isolated iframe");
|
|
87
|
+
await this.prepareIframe(container, ID_ALL, startTime);
|
|
88
|
+
}
|
|
89
|
+
const config = getConfig();
|
|
90
|
+
const { width, height } = config.browser.viewport;
|
|
91
|
+
const iframe = this.iframes.get(ID_ALL);
|
|
92
|
+
await setIframeViewport(iframe, width, height);
|
|
93
|
+
debug("run non-isolated tests", options.files.join(", "));
|
|
94
|
+
await sendEventToIframe({
|
|
95
|
+
event: "execute",
|
|
96
|
+
iframeId: ID_ALL,
|
|
97
|
+
files: options.files,
|
|
98
|
+
method: options.method,
|
|
99
|
+
context: options.providedContext
|
|
100
|
+
});
|
|
101
|
+
debug("finished running tests", options.files.join(", "));
|
|
102
|
+
}
|
|
103
|
+
async runIsolatedTestInIframe(container, spec, options, startTime) {
|
|
104
|
+
const config = getConfig();
|
|
105
|
+
const { width, height } = config.browser.viewport;
|
|
106
|
+
const file = spec.filepath;
|
|
107
|
+
if (this.iframes.has(file)) {
|
|
108
|
+
this.iframes.get(file).remove();
|
|
109
|
+
this.iframes.delete(file);
|
|
110
|
+
}
|
|
111
|
+
const iframe = await this.prepareIframe(container, file, startTime);
|
|
112
|
+
await setIframeViewport(iframe, width, height);
|
|
113
|
+
await sendEventToIframe({
|
|
114
|
+
event: "execute",
|
|
115
|
+
files: [spec],
|
|
116
|
+
method: options.method,
|
|
117
|
+
iframeId: file,
|
|
118
|
+
context: options.providedContext
|
|
119
|
+
});
|
|
120
|
+
await sendEventToIframe({
|
|
121
|
+
event: "cleanup",
|
|
122
|
+
iframeId: file
|
|
123
|
+
});
|
|
124
|
+
}
|
|
125
|
+
dispatchIframeError(error) {
|
|
126
|
+
const event = new CustomEvent("iframeerror", { detail: error });
|
|
127
|
+
this.eventTarget.dispatchEvent(event);
|
|
128
|
+
return error;
|
|
129
|
+
}
|
|
130
|
+
async prepareIframe(container, iframeId, startTime) {
|
|
131
|
+
const iframe = this.createTestIframe(iframeId);
|
|
132
|
+
container.appendChild(iframe);
|
|
133
|
+
await new Promise((resolve, reject) => {
|
|
134
|
+
iframe.onload = () => {
|
|
135
|
+
const href = this.getIframeHref(iframe);
|
|
136
|
+
debug("iframe loaded with href", href);
|
|
137
|
+
if (href !== iframe.src) {
|
|
138
|
+
reject(this.dispatchIframeError(new Error(
|
|
139
|
+
`Cannot connect to the iframe. Did you change the location or submitted a form? If so, don't forget to call \`event.preventDefault()\` to avoid reloading the page.
|
|
140
|
+
|
|
141
|
+
Received URL: ${href || "unknown"}
|
|
142
|
+
Expected: ${iframe.src}`
|
|
143
|
+
)));
|
|
144
|
+
} else {
|
|
145
|
+
this.iframes.set(iframeId, iframe);
|
|
146
|
+
sendEventToIframe({
|
|
147
|
+
event: "prepare",
|
|
148
|
+
iframeId,
|
|
149
|
+
startTime
|
|
150
|
+
}).then(resolve, (error) => reject(this.dispatchIframeError(error)));
|
|
151
|
+
}
|
|
152
|
+
};
|
|
153
|
+
iframe.onerror = (e) => {
|
|
154
|
+
if (typeof e === "string") {
|
|
155
|
+
reject(this.dispatchIframeError(new Error(e)));
|
|
156
|
+
} else if (e instanceof ErrorEvent) {
|
|
157
|
+
reject(this.dispatchIframeError(e.error));
|
|
158
|
+
} else {
|
|
159
|
+
reject(this.dispatchIframeError(new Error(`Cannot load the iframe ${iframeId}.`)));
|
|
160
|
+
}
|
|
161
|
+
};
|
|
162
|
+
});
|
|
163
|
+
return iframe;
|
|
164
|
+
}
|
|
165
|
+
getIframeHref(iframe) {
|
|
166
|
+
var _a;
|
|
167
|
+
try {
|
|
168
|
+
return (_a = iframe.contentWindow) == null ? void 0 : _a.location.href;
|
|
169
|
+
} catch {
|
|
170
|
+
return void 0;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
createTestIframe(iframeId) {
|
|
174
|
+
const iframe = document.createElement("iframe");
|
|
175
|
+
const src = `/?sessionId=${getBrowserState().sessionId}&iframeId=${iframeId}`;
|
|
176
|
+
iframe.setAttribute("loading", "eager");
|
|
177
|
+
iframe.setAttribute("src", src);
|
|
178
|
+
iframe.setAttribute("data-vitest", "true");
|
|
179
|
+
iframe.style.border = "none";
|
|
180
|
+
iframe.style.width = "100%";
|
|
181
|
+
iframe.style.height = "100%";
|
|
182
|
+
iframe.setAttribute("allowfullscreen", "true");
|
|
183
|
+
iframe.setAttribute("allow", "clipboard-write;");
|
|
184
|
+
iframe.setAttribute("name", "vitest-iframe");
|
|
185
|
+
return iframe;
|
|
186
|
+
}
|
|
187
|
+
async onGlobalChannelEvent(e) {
|
|
188
|
+
debug("global channel event", JSON.stringify(e.data));
|
|
189
|
+
switch (e.data.type) {
|
|
190
|
+
case "cancel": {
|
|
191
|
+
this.cancelled = true;
|
|
192
|
+
break;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
async onIframeEvent(e) {
|
|
197
|
+
debug("iframe event", JSON.stringify(e.data));
|
|
198
|
+
switch (e.data.event) {
|
|
199
|
+
case "viewport": {
|
|
200
|
+
const { width, height, iframeId: id } = e.data;
|
|
201
|
+
const iframe = this.iframes.get(id);
|
|
202
|
+
if (!iframe) {
|
|
203
|
+
const error = `Cannot find iframe with id ${id}`;
|
|
204
|
+
channel.postMessage({
|
|
205
|
+
event: "viewport:fail",
|
|
206
|
+
iframeId: id,
|
|
207
|
+
error
|
|
208
|
+
});
|
|
209
|
+
await client.rpc.onUnhandledError(
|
|
210
|
+
{
|
|
211
|
+
name: "Teardown Error",
|
|
212
|
+
message: error
|
|
213
|
+
},
|
|
214
|
+
"Teardown Error"
|
|
215
|
+
);
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
await setIframeViewport(iframe, width, height);
|
|
219
|
+
channel.postMessage({ event: "viewport:done", iframeId: id });
|
|
220
|
+
break;
|
|
221
|
+
}
|
|
222
|
+
default: {
|
|
223
|
+
if (typeof e.data.event === "string" && e.data.event.startsWith("response:")) {
|
|
224
|
+
break;
|
|
225
|
+
}
|
|
226
|
+
await client.rpc.onUnhandledError(
|
|
227
|
+
{
|
|
228
|
+
name: "Unexpected Event",
|
|
229
|
+
message: `Unexpected event: ${e.data.event}`
|
|
230
|
+
},
|
|
231
|
+
"Unexpected Event"
|
|
232
|
+
);
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
const orchestrator = new IframeOrchestrator();
|
|
238
|
+
getBrowserState().orchestrator = orchestrator;
|
|
239
|
+
async function getContainer(config) {
|
|
240
|
+
if (config.browser.ui) {
|
|
241
|
+
const element = document.querySelector("#tester-ui");
|
|
242
|
+
if (!element) {
|
|
243
|
+
return new Promise((resolve) => {
|
|
244
|
+
queueMicrotask(() => {
|
|
245
|
+
resolve(getContainer(config));
|
|
246
|
+
});
|
|
247
|
+
});
|
|
248
|
+
}
|
|
249
|
+
return element;
|
|
250
|
+
}
|
|
251
|
+
return document.querySelector("#vitest-tester");
|
|
252
|
+
}
|
|
253
|
+
async function sendEventToIframe(event) {
|
|
254
|
+
channel.postMessage(event);
|
|
255
|
+
return new Promise((resolve, reject) => {
|
|
256
|
+
function cleanupEvents() {
|
|
257
|
+
channel.removeEventListener("message", onReceived);
|
|
258
|
+
orchestrator.eventTarget.removeEventListener("iframeerror", onError);
|
|
259
|
+
}
|
|
260
|
+
function onReceived(e) {
|
|
261
|
+
if (e.data.iframeId === event.iframeId && e.data.event === `response:${event.event}`) {
|
|
262
|
+
resolve();
|
|
263
|
+
cleanupEvents();
|
|
264
|
+
}
|
|
265
|
+
}
|
|
266
|
+
function onError(e) {
|
|
267
|
+
reject(e.detail);
|
|
268
|
+
cleanupEvents();
|
|
269
|
+
}
|
|
270
|
+
orchestrator.eventTarget.addEventListener("iframeerror", onError);
|
|
271
|
+
channel.addEventListener("message", onReceived);
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
function generateFileId(file) {
|
|
275
|
+
const config = getConfig();
|
|
276
|
+
const path = relative(config.root, file);
|
|
277
|
+
return generateFileHash(path, config.name);
|
|
278
|
+
}
|
|
279
|
+
async function setIframeViewport(iframe, width, height) {
|
|
280
|
+
var _a, _b;
|
|
281
|
+
const ui = /* @__PURE__ */ getUiAPI();
|
|
282
|
+
if (ui) {
|
|
283
|
+
await ui.setIframeViewport(width, height);
|
|
284
|
+
} else if (getBrowserState().provider === "webdriverio") {
|
|
285
|
+
(_a = iframe.parentElement) == null ? void 0 : _a.setAttribute("data-scale", "1");
|
|
286
|
+
await client.rpc.triggerCommand(
|
|
287
|
+
getBrowserState().sessionId,
|
|
288
|
+
"__vitest_viewport",
|
|
289
|
+
void 0,
|
|
290
|
+
[{ width, height }]
|
|
291
|
+
);
|
|
292
|
+
} else {
|
|
293
|
+
const scale = Math.min(
|
|
294
|
+
1,
|
|
295
|
+
iframe.parentElement.parentElement.clientWidth / width,
|
|
296
|
+
iframe.parentElement.parentElement.clientHeight / height
|
|
297
|
+
);
|
|
298
|
+
iframe.parentElement.style.cssText = `
|
|
299
|
+
width: ${width}px;
|
|
300
|
+
height: ${height}px;
|
|
301
|
+
transform: scale(${scale});
|
|
302
|
+
transform-origin: left top;
|
|
303
|
+
`;
|
|
304
|
+
(_b = iframe.parentElement) == null ? void 0 : _b.setAttribute("data-scale", String(scale));
|
|
305
|
+
await new Promise((r) => requestAnimationFrame(r));
|
|
306
|
+
}
|
|
307
|
+
}
|
|
308
|
+
function debug(...args) {
|
|
309
|
+
const debug2 = getConfig().env.VITEST_BROWSER_DEBUG;
|
|
310
|
+
if (debug2 && debug2 !== "false") {
|
|
311
|
+
client.rpc.debug(...args.map(String));
|
|
312
|
+
}
|
|
313
|
+
}
|