@vitest/browser 5.0.0-beta.4 → 5.0.0-beta.6

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.
@@ -1,33 +1,33 @@
1
1
  {
2
- "../../../../node_modules/.pnpm/rrweb-snapshot@2.0.0-alpha.20_patch_hash=d11ec9bd9b66247ba493ab5fd117fbf0b4cb6e5d0a6a7c600d1d844bfa3d3044/node_modules/rrweb-snapshot/dist/rrweb-snapshot.js": {
3
- "file": "__vitest_browser__/rrweb-snapshot-iZCFA2to.js",
2
+ "../../../../node_modules/.pnpm/rrweb-snapshot@2.0.1_patch_hash=9e976b2c55a5c2ed589c41b8f46cc44b6fe6f528ebb4d3780a44b1ca8cbb17a4/node_modules/rrweb-snapshot/dist/rrweb-snapshot.js": {
3
+ "file": "__vitest_browser__/rrweb-snapshot-DkFyu2W8.js",
4
4
  "name": "rrweb-snapshot",
5
- "src": "../../../../node_modules/.pnpm/rrweb-snapshot@2.0.0-alpha.20_patch_hash=d11ec9bd9b66247ba493ab5fd117fbf0b4cb6e5d0a6a7c600d1d844bfa3d3044/node_modules/rrweb-snapshot/dist/rrweb-snapshot.js",
5
+ "src": "../../../../node_modules/.pnpm/rrweb-snapshot@2.0.1_patch_hash=9e976b2c55a5c2ed589c41b8f46cc44b6fe6f528ebb4d3780a44b1ca8cbb17a4/node_modules/rrweb-snapshot/dist/rrweb-snapshot.js",
6
6
  "isDynamicEntry": true
7
7
  },
8
- "_defineProperty-C3k2g8Sk.js": {
9
- "file": "__vitest_browser__/defineProperty-C3k2g8Sk.js",
8
+ "_defineProperty-WHpdAQXR.js": {
9
+ "file": "__vitest_browser__/defineProperty-WHpdAQXR.js",
10
10
  "name": "defineProperty"
11
11
  },
12
12
  "orchestrator.html": {
13
- "file": "__vitest_browser__/orchestrator-B44yH1M4.js",
13
+ "file": "__vitest_browser__/orchestrator-pKob2Z-i.js",
14
14
  "name": "orchestrator",
15
15
  "src": "orchestrator.html",
16
16
  "isEntry": true,
17
17
  "imports": [
18
- "_defineProperty-C3k2g8Sk.js"
18
+ "_defineProperty-WHpdAQXR.js"
19
19
  ]
20
20
  },
21
21
  "tester/tester.html": {
22
- "file": "__vitest_browser__/tester-kAU8uxhk.js",
22
+ "file": "__vitest_browser__/tester-DdZeFrjo.js",
23
23
  "name": "tester",
24
24
  "src": "tester/tester.html",
25
25
  "isEntry": true,
26
26
  "imports": [
27
- "_defineProperty-C3k2g8Sk.js"
27
+ "_defineProperty-WHpdAQXR.js"
28
28
  ],
29
29
  "dynamicImports": [
30
- "../../../../node_modules/.pnpm/rrweb-snapshot@2.0.0-alpha.20_patch_hash=d11ec9bd9b66247ba493ab5fd117fbf0b4cb6e5d0a6a7c600d1d844bfa3d3044/node_modules/rrweb-snapshot/dist/rrweb-snapshot.js"
30
+ "../../../../node_modules/.pnpm/rrweb-snapshot@2.0.1_patch_hash=9e976b2c55a5c2ed589c41b8f46cc44b6fe6f528ebb4d3780a44b1ca8cbb17a4/node_modules/rrweb-snapshot/dist/rrweb-snapshot.js"
31
31
  ]
32
32
  }
33
33
  }
@@ -122,6 +122,49 @@ var relative = function(from, to) {
122
122
  return [..._from.map(() => ".."), ..._to].join("/");
123
123
  };
124
124
 
125
+ //#endregion
126
+ //#region ../vitest/src/utils/tasks.ts
127
+ /* @__NO_SIDE_EFFECTS__ */
128
+ function getNames(task) {
129
+ const names = [task.name];
130
+ let current = task;
131
+ while (current === null || current === void 0 ? void 0 : current.suite) {
132
+ current = current.suite;
133
+ if (current === null || current === void 0 ? void 0 : current.name) names.unshift(current.name);
134
+ }
135
+ if (current !== task.file) names.unshift(task.file.name);
136
+ return names;
137
+ }
138
+ /* @__NO_SIDE_EFFECTS__ */
139
+ function getTestName(task, separator = " > ") {
140
+ return (/* @__PURE__ */ getNames(task)).slice(1).join(separator);
141
+ }
142
+ /**
143
+ * Generate a unique ID for a file based on its path and project name
144
+ * @param file File relative to the root of the project to keep ID the same between different machines
145
+ * @param projectName The name of the test project
146
+ */
147
+ /* @__NO_SIDE_EFFECTS__ */
148
+ function generateFileHash(file, projectName, meta) {
149
+ return /* @__PURE__ */ generateHash([
150
+ file,
151
+ projectName || "",
152
+ (meta === null || meta === void 0 ? void 0 : meta.typecheck) ? "__typecheck__" : "",
153
+ (meta === null || meta === void 0 ? void 0 : meta.__vitest_label__) || ""
154
+ ].join("\0"));
155
+ }
156
+ /* @__NO_SIDE_EFFECTS__ */
157
+ function generateHash(str) {
158
+ let hash = 0;
159
+ if (str.length === 0) return `${hash}`;
160
+ for (let i = 0; i < str.length; i++) {
161
+ const char = str.charCodeAt(i);
162
+ hash = (hash << 5) - hash + char;
163
+ hash = hash & hash;
164
+ }
165
+ return `${hash}`;
166
+ }
167
+
125
168
  //#endregion
126
169
  //#region \0vite/preload-helper.js
127
170
  var scriptRel = "modulepreload";
@@ -264,4 +307,4 @@ function _defineProperty(e, r, t) {
264
307
  }
265
308
 
266
309
  //#endregion
267
- export { moduleRunner as a, relative as c, getWorkerState as i, resolve as l, getBrowserState as n, now as o, getConfig as r, __vitePreload as s, _defineProperty as t };
310
+ export { moduleRunner as a, generateFileHash as c, resolve as d, getWorkerState as i, getTestName as l, getBrowserState as n, now as o, getConfig as r, __vitePreload as s, _defineProperty as t, relative as u };
@@ -1,4 +1,4 @@
1
- import { c as relative, n as getBrowserState, r as getConfig, t as _defineProperty } from "./defineProperty-C3k2g8Sk.js";
1
+ import { c as generateFileHash, n as getBrowserState, r as getConfig, t as _defineProperty, u as relative } from "./defineProperty-WHpdAQXR.js";
2
2
  import { channel, client, globalChannel } from "@vitest/browser/client";
3
3
  import { Traces } from "vitest/internal/traces";
4
4
 
@@ -16,6 +16,9 @@ var IframeOrchestrator = class {
16
16
  _defineProperty(this, "cancelled", false);
17
17
  _defineProperty(this, "recreateNonIsolatedIframe", false);
18
18
  _defineProperty(this, "iframes", /* @__PURE__ */ new Map());
19
+ _defineProperty(this, "readyIframes", /* @__PURE__ */ new Set());
20
+ _defineProperty(this, "readyWaiters", /* @__PURE__ */ new Map());
21
+ _defineProperty(this, "messageId", 0);
19
22
  _defineProperty(this, "eventTarget", new EventTarget());
20
23
  _defineProperty(this, "traces", void 0);
21
24
  _defineProperty(this, "loggedIframe", /* @__PURE__ */ new WeakSet());
@@ -28,6 +31,9 @@ var IframeOrchestrator = class {
28
31
  });
29
32
  channel.addEventListener("message", (e) => this.onIframeEvent(e));
30
33
  globalChannel.addEventListener("message", (e) => this.onGlobalChannelEvent(e));
34
+ client.waitForConnection().then(() => client.rpc.onOrchestratorReady()).catch((error) => {
35
+ debug("failed to notify orchestrator readiness", error);
36
+ });
31
37
  }
32
38
  async createTesters(options) {
33
39
  await this.traces.waitInit();
@@ -54,6 +60,8 @@ var IframeOrchestrator = class {
54
60
  }
55
61
  this.iframes.forEach((iframe) => iframe.remove());
56
62
  this.iframes.clear();
63
+ this.readyIframes.clear();
64
+ this.readyWaiters.clear();
57
65
  for (let i = 0; i < options.files.length; i++) {
58
66
  if (this.cancelled) {
59
67
  await endSpan();
@@ -85,8 +93,7 @@ var IframeOrchestrator = class {
85
93
  async runNonIsolatedTests(container, options, startTime, otelContext) {
86
94
  if (this.recreateNonIsolatedIframe) {
87
95
  this.recreateNonIsolatedIframe = false;
88
- this.iframes.get(ID_ALL).remove();
89
- this.iframes.delete(ID_ALL);
96
+ this.removeIframe(ID_ALL);
90
97
  debug("recreate non-isolated iframe");
91
98
  }
92
99
  if (!this.iframes.has(ID_ALL)) {
@@ -101,17 +108,16 @@ var IframeOrchestrator = class {
101
108
  iframeId: ID_ALL,
102
109
  files: options.files,
103
110
  method: options.method,
104
- context: options.providedContext
111
+ context: options.providedContext,
112
+ concurrencyId: options.concurrencyId,
113
+ workerId: options.workerId
105
114
  });
106
115
  debug("finished running tests", options.files.join(", "));
107
116
  }
108
117
  async runIsolatedTestInIframe(container, spec, options, startTime, otelContext) {
109
118
  const { width, height } = getConfig().browser.viewport;
110
119
  const file = spec.filepath;
111
- if (this.iframes.has(file)) {
112
- this.iframes.get(file).remove();
113
- this.iframes.delete(file);
114
- }
120
+ if (this.iframes.has(file)) this.removeIframe(file);
115
121
  await this.prepareIframe(container, file, startTime, otelContext);
116
122
  await setIframeViewport(width, height);
117
123
  await this.sendEventToIframe({
@@ -119,7 +125,9 @@ var IframeOrchestrator = class {
119
125
  files: [spec],
120
126
  method: options.method,
121
127
  iframeId: file,
122
- context: options.providedContext
128
+ context: options.providedContext,
129
+ concurrencyId: options.concurrencyId,
130
+ workerId: options.workerId
123
131
  });
124
132
  await this.sendEventToIframe({
125
133
  event: "cleanup",
@@ -147,12 +155,12 @@ Received URL: ${href || "unknown due to CORS"}\nExpected: ${iframe.src}`)));
147
155
  else this.warnReload(iframe, iframeId);
148
156
  } else {
149
157
  this.iframes.set(iframeId, iframe);
150
- this.sendEventToIframe({
158
+ this.waitForReady(iframeId).then(() => this.sendEventToIframe({
151
159
  event: "prepare",
152
160
  iframeId,
153
161
  startTime,
154
162
  otelCarrier: this.traces.getContextCarrier(otelContext)
155
- }).then(resolve, (error) => reject(this.dispatchIframeError(error)));
163
+ })).then(resolve, (error) => reject(this.dispatchIframeError(error)));
156
164
  }
157
165
  };
158
166
  iframe.onerror = (e) => {
@@ -163,6 +171,45 @@ Received URL: ${href || "unknown due to CORS"}\nExpected: ${iframe.src}`)));
163
171
  });
164
172
  return iframe;
165
173
  }
174
+ markReady(iframeId) {
175
+ this.readyIframes.add(iframeId);
176
+ const waiter = this.readyWaiters.get(iframeId);
177
+ if (waiter) {
178
+ this.readyWaiters.delete(iframeId);
179
+ waiter.resolve();
180
+ }
181
+ }
182
+ waitForReady(iframeId) {
183
+ if (this.readyIframes.has(iframeId)) return Promise.resolve();
184
+ return new Promise((resolve, reject) => {
185
+ const timeout = getIframeTimeout();
186
+ const timer = setTimeout(() => {
187
+ this.readyWaiters.delete(iframeId);
188
+ reject(/* @__PURE__ */ new Error(`The iframe "${iframeId}" did not become ready within ${timeout}ms. The tester likely failed to initialize, check the browser console for errors.`));
189
+ }, timeout);
190
+ this.readyWaiters.set(iframeId, {
191
+ resolve: () => {
192
+ clearTimeout(timer);
193
+ resolve();
194
+ },
195
+ reject: (error) => {
196
+ clearTimeout(timer);
197
+ reject(error);
198
+ }
199
+ });
200
+ });
201
+ }
202
+ removeIframe(iframeId) {
203
+ const iframe = this.iframes.get(iframeId);
204
+ this.iframes.delete(iframeId);
205
+ this.readyIframes.delete(iframeId);
206
+ const waiter = this.readyWaiters.get(iframeId);
207
+ if (waiter) {
208
+ this.readyWaiters.delete(iframeId);
209
+ waiter.reject(/* @__PURE__ */ new Error(`The iframe "${iframeId}" was removed before it became ready.`));
210
+ }
211
+ iframe === null || iframe === void 0 || iframe.remove();
212
+ }
166
213
  createWarningMessage(iframeId, location) {
167
214
  return `The iframe${iframeId === ID_ALL ? "" : ` for "${iframeId}"`} was reloaded ${location}. This can lead to unexpected behavior during tests, duplicated test results or tests hanging.\n\nMake sure that your test code does not change window's location, submit forms without preventing default behavior, or imports unoptimized dependencies.\nIf you are using a framework that manipulates browser history (like React Router), consider using memory-based routing for tests. If you think this is a false positive, open an issue with a reproduction: https://github.com/vitest-dev/vitest/issues/new`;
168
215
  }
@@ -188,7 +235,7 @@ Received URL: ${href || "unknown due to CORS"}\nExpected: ${iframe.src}`)));
188
235
  }
189
236
  createTestIframe(iframeId) {
190
237
  const iframe = document.createElement("iframe");
191
- const src = `/?sessionId=${(/* @__PURE__ */ getBrowserState()).sessionId}&iframeId=${iframeId}`;
238
+ const src = `/?sessionId=${(/* @__PURE__ */ getBrowserState()).sessionId}&iframeId=${encodeURIComponent(iframeId)}`;
192
239
  const config = getConfig();
193
240
  iframe.setAttribute("loading", "eager");
194
241
  iframe.setAttribute("src", src);
@@ -222,6 +269,9 @@ Received URL: ${href || "unknown due to CORS"}\nExpected: ${iframe.src}`)));
222
269
  async onIframeEvent(e) {
223
270
  debug("iframe event", JSON.stringify(e.data));
224
271
  switch (e.data.event) {
272
+ case "ready":
273
+ this.markReady(e.data.iframeId);
274
+ break;
225
275
  case "viewport": {
226
276
  const { width, height, iframeId: id } = e.data;
227
277
  if (!this.iframes.get(id)) {
@@ -244,12 +294,14 @@ Received URL: ${href || "unknown due to CORS"}\nExpected: ${iframe.src}`)));
244
294
  });
245
295
  break;
246
296
  }
247
- default:
248
- if (typeof e.data.event === "string" && e.data.event.startsWith("response:")) break;
297
+ default: {
298
+ const event = e.data.event;
299
+ if (typeof event === "string" && (event.startsWith("response:") || event.startsWith("ack:"))) break;
249
300
  await client.rpc.onUnhandledError({
250
301
  name: "Unexpected Event",
251
302
  message: `Unexpected event: ${e.data.event}`
252
303
  }, "Unexpected Event");
304
+ }
253
305
  }
254
306
  }
255
307
  async sendEventToIframe(event) {
@@ -261,23 +313,38 @@ Received URL: ${href || "unknown due to CORS"}\nExpected: ${iframe.src}`)));
261
313
  this.iframeEvents.set(iframe, events);
262
314
  }
263
315
  events.add(event.event);
264
- channel.postMessage(event);
316
+ const messageId = this.messageId++;
317
+ channel.postMessage({
318
+ ...event,
319
+ messageId
320
+ });
265
321
  return new Promise((resolve, reject) => {
322
+ let ackTimer;
266
323
  const cleanupEvents = () => {
324
+ clearTimeout(ackTimer);
267
325
  channel.removeEventListener("message", onReceived);
268
326
  this.eventTarget.removeEventListener("iframeerror", onError);
327
+ events.delete(event.event);
269
328
  };
329
+ const timeout = getIframeTimeout();
330
+ ackTimer = setTimeout(() => {
331
+ cleanupEvents();
332
+ reject(/* @__PURE__ */ new Error(`The iframe "${event.iframeId}" did not acknowledge the "${event.event}" message within ${timeout}ms. The tester might have crashed, been removed, or be blocked by a long synchronous task.`));
333
+ }, timeout);
270
334
  function onReceived(e) {
271
- if (e.data.iframeId === event.iframeId && e.data.event === `response:${event.event}`) {
272
- resolve();
335
+ if (e.data.iframeId !== event.iframeId || e.data.messageId !== messageId) return;
336
+ if (e.data.event === `ack:${event.event}`) {
337
+ clearTimeout(ackTimer);
338
+ return;
339
+ }
340
+ if (e.data.event === `response:${event.event}`) {
273
341
  cleanupEvents();
274
- events.delete(event.event);
342
+ resolve();
275
343
  }
276
344
  }
277
345
  function onError(e) {
278
- reject(e.detail);
279
346
  cleanupEvents();
280
- events.delete(event.event);
347
+ reject(e.detail);
281
348
  }
282
349
  this.eventTarget.addEventListener("iframeerror", onError);
283
350
  channel.addEventListener("message", onReceived);
@@ -300,29 +367,11 @@ async function getContainer(config) {
300
367
  }
301
368
  function generateFileId(file) {
302
369
  const config = getConfig();
303
- return generateFileHash(relative(config.root, file), config.name, {
370
+ return /* @__PURE__ */ generateFileHash(relative(config.root, file), config.name, {
304
371
  typecheck: config.pool === "typescript",
305
372
  __vitest_label__: config.mergeReportsLabel
306
373
  });
307
374
  }
308
- function generateFileHash(file, projectName, meta) {
309
- return generateHash([
310
- file,
311
- projectName || "",
312
- (meta === null || meta === void 0 ? void 0 : meta.typecheck) ? "__typecheck__" : "",
313
- (meta === null || meta === void 0 ? void 0 : meta.__vitest_label__) || ""
314
- ].join("\0"));
315
- }
316
- function generateHash(str) {
317
- let hash = 0;
318
- if (str.length === 0) return `${hash}`;
319
- for (let i = 0; i < str.length; i++) {
320
- const char = str.charCodeAt(i);
321
- hash = (hash << 5) - hash + char;
322
- hash = hash & hash;
323
- }
324
- return `${hash}`;
325
- }
326
375
  async function setIframeViewport(width, height) {
327
376
  const ui = /* @__PURE__ */ getUiAPI();
328
377
  if (ui) await ui.setIframeViewport(width, height);
@@ -339,5 +388,8 @@ function debug(...args) {
339
388
  const debug = getConfig().env.VITEST_BROWSER_DEBUG;
340
389
  if (debug && debug !== "false") client.rpc.debug(...args.map(String));
341
390
  }
391
+ function getIframeTimeout() {
392
+ return Number(getConfig().env.VITEST_BROWSER_IFRAME_TIMEOUT) || 6e4;
393
+ }
342
394
 
343
395
  //#endregion