@vitest/browser 4.0.0-beta.1 → 4.0.0-beta.11

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