@vitest/browser 2.0.4 → 2.1.0-beta.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.
@@ -2,7 +2,8 @@
2
2
  <html lang="en">
3
3
  <head>
4
4
  <meta charset="UTF-8" />
5
- <link rel="icon" href="./favicon.svg" type="image/svg+xml" />
5
+ <link rel="icon" href="./favicon.ico" sizes="48x48">
6
+ <link rel="icon" href="./favicon.svg" sizes="any" type="image/svg+xml">
6
7
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
8
  <title>Vitest</title>
8
9
  <link rel="preconnect" href="https://fonts.googleapis.com" />
@@ -22,8 +23,8 @@
22
23
  })();
23
24
  </script>
24
25
  <!-- !LOAD_METADATA! -->
25
- <script type="module" crossorigin src="./assets/index--tE7Z8jQ.js"></script>
26
- <link rel="stylesheet" crossorigin href="./assets/index-C0SwoDYm.css">
26
+ <script type="module" crossorigin src="./assets/index-uh8h5Yzr.js"></script>
27
+ <link rel="stylesheet" crossorigin href="./assets/index-JTfsnJeu.css">
27
28
  </head>
28
29
  <body>
29
30
  <div id="app"></div>
@@ -186,7 +186,8 @@ class IframeOrchestrator {
186
186
  const config = getConfig();
187
187
  const container = await getContainer(config);
188
188
  if (config.browser.ui) {
189
- container.className = "scrolls";
189
+ container.className = "absolute origin-top mt-[8px]";
190
+ container.parentElement.setAttribute("data-ready", "true");
190
191
  container.textContent = "";
191
192
  }
192
193
  const { width, height } = config.browser.viewport;
@@ -229,10 +230,9 @@ class IframeOrchestrator {
229
230
  `${url.pathname}__vitest_test__/__test__/${getBrowserState().contextId}/${encodeURIComponent(file)}`
230
231
  );
231
232
  iframe.setAttribute("data-vitest", "true");
232
- iframe.style.display = "block";
233
233
  iframe.style.border = "none";
234
- iframe.style.zIndex = "1";
235
- iframe.style.position = "relative";
234
+ iframe.style.width = "100%";
235
+ iframe.style.height = "100%";
236
236
  iframe.setAttribute("allowfullscreen", "true");
237
237
  iframe.setAttribute("allow", "clipboard-write;");
238
238
  iframe.setAttribute("name", "vitest-iframe");
@@ -436,13 +436,19 @@ class VitestBrowserClientMocker {
436
436
  );
437
437
  }
438
438
  const ext = extname(resolved.id);
439
- const url2 = new URL(`/@id/${resolved.id}`, location.href);
440
- const query = `_vitest_original&ext.${ext}`;
439
+ const url2 = new URL(resolved.url, location.href);
440
+ const query = `_vitest_original&ext${ext}`;
441
441
  const actualUrl = `${url2.pathname}${url2.search ? `${url2.search}&${query}` : `?${query}`}${url2.hash}`;
442
442
  return getBrowserState().wrapModule(() => import(
443
443
  /* @vite-ignore */
444
444
  actualUrl
445
- ));
445
+ )).then((mod) => {
446
+ if (!resolved.optimized || typeof mod.default === "undefined") {
447
+ return mod;
448
+ }
449
+ const m = mod.default;
450
+ return (m == null ? void 0 : m.__esModule) ? m : { ...typeof m === "object" && !Array.isArray(m) || typeof m === "function" ? m : {}, default: m };
451
+ });
446
452
  }
447
453
  async importMock(rawId, importer) {
448
454
  await this.prepare();
@@ -11874,8 +11880,16 @@ const matchers = /* @__PURE__ */ Object.freeze(/* @__PURE__ */ Object.defineProp
11874
11880
  }, Symbol.toStringTag, { value: "Module" }));
11875
11881
  async function setupExpectDom() {
11876
11882
  expect.extend(matchers);
11877
- expect.element = (element, options) => {
11878
- return expect.poll(() => element, options);
11883
+ expect.element = (elementOrLocator, options) => {
11884
+ if (!(elementOrLocator instanceof Element) && !("element" in elementOrLocator)) {
11885
+ throw new Error(`Invalid element or locator: ${elementOrLocator}. Expected an instance of Element or Locator, received ${typeof elementOrLocator}`);
11886
+ }
11887
+ return expect.poll(() => {
11888
+ if (elementOrLocator instanceof Element) {
11889
+ return elementOrLocator;
11890
+ }
11891
+ return elementOrLocator.element();
11892
+ }, options);
11879
11893
  };
11880
11894
  }
11881
11895
  const url = new URL(location.href);
@@ -1,10 +1,5 @@
1
1
  import { channel, client } from '@vitest/browser/client'
2
2
 
3
- function on(event, listener) {
4
- window.addEventListener(event, listener)
5
- return () => window.removeEventListener(event, listener)
6
- }
7
-
8
3
  function serializeError(unhandledError) {
9
4
  if (typeof unhandledError !== 'object' || !unhandledError) {
10
5
  return {
@@ -19,41 +14,40 @@ function serializeError(unhandledError) {
19
14
  }
20
15
  }
21
16
 
22
- function catchWindowErrors(cb) {
17
+ function catchWindowErrors(errorEvent, prop, cb) {
23
18
  let userErrorListenerCount = 0
24
19
  function throwUnhandlerError(e) {
25
- if (userErrorListenerCount === 0 && e.error != null) {
20
+ if (userErrorListenerCount === 0 && e[prop] != null) {
26
21
  cb(e)
27
22
  }
28
23
  else {
29
- console.error(e.error)
24
+ console.error(e[prop])
30
25
  }
31
26
  }
32
27
  const addEventListener = window.addEventListener.bind(window)
33
28
  const removeEventListener = window.removeEventListener.bind(window)
34
- window.addEventListener('error', throwUnhandlerError)
29
+ window.addEventListener(errorEvent, throwUnhandlerError)
35
30
  window.addEventListener = function (...args) {
36
- if (args[0] === 'error') {
31
+ if (args[0] === errorEvent) {
37
32
  userErrorListenerCount++
38
33
  }
39
34
  return addEventListener.apply(this, args)
40
35
  }
41
36
  window.removeEventListener = function (...args) {
42
- if (args[0] === 'error' && userErrorListenerCount) {
37
+ if (args[0] === errorEvent && userErrorListenerCount) {
43
38
  userErrorListenerCount--
44
39
  }
45
40
  return removeEventListener.apply(this, args)
46
41
  }
47
42
  return function clearErrorHandlers() {
48
- window.removeEventListener('error', throwUnhandlerError)
43
+ window.removeEventListener(errorEvent, throwUnhandlerError)
49
44
  }
50
45
  }
51
46
 
52
47
  function registerUnexpectedErrors() {
53
- catchWindowErrors(event =>
54
- reportUnexpectedError('Error', event.error),
55
- )
56
- on('unhandledrejection', event =>
48
+ catchWindowErrors('error', 'error', event =>
49
+ reportUnexpectedError('Error', event.error))
50
+ catchWindowErrors('unhandledrejection', 'reason', event =>
57
51
  reportUnexpectedError('Unhandled Rejection', event.reason))
58
52
  }
59
53
 
@@ -26,7 +26,7 @@
26
26
  {__VITEST_INJECTOR__}
27
27
  {__VITEST_ERROR_CATCHER__}
28
28
  {__VITEST_SCRIPTS__}
29
- <script type="module" crossorigin src="/__vitest_browser__/orchestrator-CNOAigTE.js"></script>
29
+ <script type="module" crossorigin src="/__vitest_browser__/orchestrator-BObhEEvc.js"></script>
30
30
  <link rel="modulepreload" crossorigin href="/__vitest_browser__/preload-helper-Btt6SgIy.js">
31
31
  </head>
32
32
  <body>
@@ -18,20 +18,12 @@
18
18
  </style>
19
19
  {__VITEST_INJECTOR__}
20
20
  <script>{__VITEST_STATE__}</script>
21
- {__VITEST_ERROR_CATCHER__}
21
+ {__VITEST_INTERNAL_SCRIPTS__}
22
22
  {__VITEST_SCRIPTS__}
23
- <script type="module" crossorigin src="/__vitest_browser__/tester-BSSDPE9E.js"></script>
23
+ <script type="module" crossorigin src="/__vitest_browser__/tester-CRcWWhrn.js"></script>
24
24
  <link rel="modulepreload" crossorigin href="/__vitest_browser__/preload-helper-Btt6SgIy.js">
25
25
  </head>
26
- <body
27
- data-vitest-body
28
- style="
29
- width: 100%;
30
- height: 100%;
31
- transform: scale(1);
32
- transform-origin: left top;
33
- "
34
- >
26
+ <body data-vitest-body>
35
27
  {__VITEST_APPEND__}
36
28
  </body>
37
29
  </html>
package/dist/context.js CHANGED
@@ -1,15 +1,16 @@
1
- const state = () => __vitest_worker__;
2
- const runner = () => __vitest_browser_runner__;
3
- function filepath() {
4
- return state().filepath || state().current?.file?.filepath || void 0;
1
+ // @__NO_SIDE_EFFECTS__
2
+ function getBrowserState() {
3
+ return window.__vitest_browser_runner__;
5
4
  }
6
- const rpc = () => state().rpc;
7
- const contextId = runner().contextId;
8
- const channel = new BroadcastChannel(`vitest:${contextId}`);
9
- function triggerCommand(command, ...args) {
10
- return rpc().triggerCommand(contextId, command, filepath(), args);
5
+ // @__NO_SIDE_EFFECTS__
6
+ function getWorkerState() {
7
+ const state = window.__vitest_worker__;
8
+ if (!state) {
9
+ throw new Error("Worker state is not found. This is an issue with Vitest. Please, open an issue.");
10
+ }
11
+ return state;
11
12
  }
12
- const provider = runner().provider;
13
+ // @__NO_SIDE_EFFECTS__
13
14
  function convertElementToCssSelector(element) {
14
15
  if (!element || !(element instanceof Element)) {
15
16
  throw new Error(
@@ -18,6 +19,22 @@ function convertElementToCssSelector(element) {
18
19
  }
19
20
  return getUniqueCssSelector(element);
20
21
  }
22
+ function escapeIdForCSSSelector(id) {
23
+ return id.split("").map((char) => {
24
+ const code = char.charCodeAt(0);
25
+ if (char === " " || char === "#" || char === "." || char === ":" || char === "[" || char === "]" || char === ">" || char === "+" || char === "~" || char === "\\") {
26
+ return `\\${char}`;
27
+ } else if (code >= 65536) {
28
+ return `\\${code.toString(16).toUpperCase().padStart(6, "0")} `;
29
+ } else if (code < 32 || code === 127) {
30
+ return `\\${code.toString(16).toUpperCase().padStart(2, "0")} `;
31
+ } else if (code >= 128) {
32
+ return `\\${code.toString(16).toUpperCase().padStart(2, "0")} `;
33
+ } else {
34
+ return char;
35
+ }
36
+ }).join("");
37
+ }
21
38
  function getUniqueCssSelector(el) {
22
39
  const path = [];
23
40
  let parent;
@@ -28,9 +45,9 @@ function getUniqueCssSelector(el) {
28
45
  }
29
46
  const tag = el.tagName;
30
47
  if (el.id) {
31
- path.push(`#${el.id}`);
48
+ path.push(`#${escapeIdForCSSSelector(el.id)}`);
32
49
  } else if (!el.nextElementSibling && !el.previousElementSibling) {
33
- path.push(tag);
50
+ path.push(tag.toLowerCase());
34
51
  } else {
35
52
  let index = 0;
36
53
  let sameTagSiblings = 0;
@@ -45,14 +62,14 @@ function getUniqueCssSelector(el) {
45
62
  }
46
63
  }
47
64
  if (sameTagSiblings > 1) {
48
- path.push(`${tag}:nth-child(${elementIndex})`);
65
+ path.push(`${tag.toLowerCase()}:nth-child(${elementIndex})`);
49
66
  } else {
50
- path.push(tag);
67
+ path.push(tag.toLowerCase());
51
68
  }
52
69
  }
53
70
  el = parent;
54
71
  }
55
- return `${provider === "webdriverio" && hasShadowRoot ? ">>>" : ""}${path.reverse().join(" > ")}`.toLowerCase();
72
+ return `${(/* @__PURE__ */ getBrowserState()).provider === "webdriverio" && hasShadowRoot ? ">>>" : ""}${path.reverse().join(" > ")}`;
56
73
  }
57
74
  function getParent(el) {
58
75
  const parent = el.parentNode;
@@ -61,108 +78,87 @@ function getParent(el) {
61
78
  }
62
79
  return parent;
63
80
  }
64
- const userEvent = {
65
- // TODO: actually setup userEvent with config options
66
- setup() {
67
- return userEvent;
68
- },
69
- click(element, options = {}) {
70
- const css = convertElementToCssSelector(element);
71
- return triggerCommand("__vitest_click", css, options);
72
- },
73
- dblClick(element, options = {}) {
74
- const css = convertElementToCssSelector(element);
75
- return triggerCommand("__vitest_dblClick", css, options);
76
- },
77
- tripleClick(element, options = {}) {
78
- const css = convertElementToCssSelector(element);
79
- return triggerCommand("__vitest_tripleClick", css, options);
80
- },
81
- selectOptions(element, value) {
82
- const values = provider === "webdriverio" ? getWebdriverioSelectOptions(element, value) : getSimpleSelectOptions(element, value);
83
- const css = convertElementToCssSelector(element);
84
- return triggerCommand("__vitest_selectOptions", css, values);
85
- },
86
- type(element, text, options = {}) {
87
- const css = convertElementToCssSelector(element);
88
- return triggerCommand("__vitest_type", css, text, options);
89
- },
90
- clear(element) {
91
- const css = convertElementToCssSelector(element);
92
- return triggerCommand("__vitest_clear", css);
93
- },
94
- tab(options = {}) {
95
- return triggerCommand("__vitest_tab", options);
96
- },
97
- keyboard(text) {
98
- return triggerCommand("__vitest_keyboard", text);
99
- },
100
- hover(element) {
101
- const css = convertElementToCssSelector(element);
102
- return triggerCommand("__vitest_hover", css);
103
- },
104
- unhover(element) {
105
- const css = convertElementToCssSelector(element.ownerDocument.body);
106
- return triggerCommand("__vitest_hover", css);
107
- },
108
- // non userEvent events, but still useful
109
- fill(element, text, options) {
110
- const css = convertElementToCssSelector(element);
111
- return triggerCommand("__vitest_fill", css, text, options);
112
- },
113
- dragAndDrop(source, target, options = {}) {
114
- const sourceCss = convertElementToCssSelector(source);
115
- const targetCss = convertElementToCssSelector(target);
116
- return triggerCommand("__vitest_dragAndDrop", sourceCss, targetCss, options);
117
- }
118
- };
119
- function getWebdriverioSelectOptions(element, value) {
120
- const options = [...element.querySelectorAll("option")];
121
- const arrayValues = Array.isArray(value) ? value : [value];
122
- if (!arrayValues.length) {
123
- return [];
124
- }
125
- if (arrayValues.length > 1) {
126
- throw new Error(`Provider "webdriverio" doesn't support selecting multiple values at once`);
127
- }
128
- const optionValue = arrayValues[0];
129
- if (typeof optionValue !== "string") {
130
- const index = options.indexOf(optionValue);
131
- if (index === -1) {
132
- throw new Error(`The element ${convertElementToCssSelector(optionValue)} was not found in the "select" options.`);
133
- }
134
- return [{ index }];
135
- }
136
- const valueIndex = options.findIndex((option) => option.value === optionValue);
137
- if (valueIndex !== -1) {
138
- return [{ index: valueIndex }];
139
- }
140
- const labelIndex = options.findIndex(
141
- (option) => option.textContent?.trim() === optionValue || option.ariaLabel === optionValue
142
- );
143
- if (labelIndex === -1) {
144
- throw new Error(`The option "${optionValue}" was not found in the "select" options.`);
145
- }
146
- return [{ index: labelIndex }];
81
+
82
+ const state = () => getWorkerState();
83
+ const provider = __vitest_browser_runner__.provider;
84
+ function filepath() {
85
+ return getWorkerState().filepath || getWorkerState().current?.file?.filepath || void 0;
147
86
  }
148
- function getSimpleSelectOptions(element, value) {
149
- return (Array.isArray(value) ? value : [value]).map((v) => {
150
- if (typeof v !== "string") {
151
- return { element: convertElementToCssSelector(v) };
87
+ const rpc = () => getWorkerState().rpc;
88
+ const contextId = getBrowserState().contextId;
89
+ const channel = new BroadcastChannel(`vitest:${contextId}`);
90
+ function triggerCommand(command, ...args) {
91
+ return rpc().triggerCommand(contextId, command, filepath(), args);
92
+ }
93
+ function createUserEvent() {
94
+ const keyboard = {
95
+ unreleased: []
96
+ };
97
+ return {
98
+ setup() {
99
+ return createUserEvent();
100
+ },
101
+ click(element, options = {}) {
102
+ return convertToLocator(element).click(processClickOptions(options));
103
+ },
104
+ dblClick(element, options = {}) {
105
+ return convertToLocator(element).dblClick(processClickOptions(options));
106
+ },
107
+ tripleClick(element, options = {}) {
108
+ return convertToLocator(element).tripleClick(processClickOptions(options));
109
+ },
110
+ selectOptions(element, value) {
111
+ return convertToLocator(element).selectOptions(value);
112
+ },
113
+ async type(element, text, options = {}) {
114
+ const selector = convertToSelector(element);
115
+ const { unreleased } = await triggerCommand(
116
+ "__vitest_type",
117
+ selector,
118
+ text,
119
+ { ...options, unreleased: keyboard.unreleased }
120
+ );
121
+ keyboard.unreleased = unreleased;
122
+ },
123
+ clear(element) {
124
+ return convertToLocator(element).clear();
125
+ },
126
+ tab(options = {}) {
127
+ return triggerCommand("__vitest_tab", options);
128
+ },
129
+ async keyboard(text) {
130
+ const { unreleased } = await triggerCommand(
131
+ "__vitest_keyboard",
132
+ text,
133
+ keyboard
134
+ );
135
+ keyboard.unreleased = unreleased;
136
+ },
137
+ hover(element, options = {}) {
138
+ return convertToLocator(element).hover(processHoverOptions(options));
139
+ },
140
+ unhover(element, options = {}) {
141
+ return convertToLocator(element).unhover(options);
142
+ },
143
+ // non userEvent events, but still useful
144
+ fill(element, text, options) {
145
+ return convertToLocator(element).fill(text, options);
146
+ },
147
+ dragAndDrop(source, target, options = {}) {
148
+ const sourceLocator = convertToLocator(source);
149
+ const targetLocator = convertToLocator(target);
150
+ return sourceLocator.dropTo(targetLocator, processDragAndDropOptions(options));
152
151
  }
153
- return v;
154
- });
152
+ };
155
153
  }
154
+ const userEvent = createUserEvent();
156
155
  function cdp() {
157
- return runner().cdp;
156
+ return getBrowserState().cdp;
158
157
  }
159
158
  const screenshotIds = {};
160
159
  const page = {
161
- get config() {
162
- return runner().config;
163
- },
164
160
  viewport(width, height) {
165
- const id = runner().iframeId;
161
+ const id = getBrowserState().iframeId;
166
162
  channel.postMessage({ type: "viewport", width, height, id });
167
163
  return new Promise((resolve, reject) => {
168
164
  channel.addEventListener("message", function handler(e) {
@@ -178,7 +174,7 @@ const page = {
178
174
  });
179
175
  },
180
176
  async screenshot(options = {}) {
181
- const currentTest = state().current;
177
+ const currentTest = getWorkerState().current;
182
178
  if (!currentTest) {
183
179
  throw new Error("Cannot take a screenshot outside of a test.");
184
180
  }
@@ -195,12 +191,165 @@ const page = {
195
191
  const name = options.path || `${taskName.replace(/[^a-z0-9]/gi, "-")}-${number}.png`;
196
192
  return triggerCommand("__vitest_screenshot", name, {
197
193
  ...options,
198
- element: options.element ? convertElementToCssSelector(options.element) : void 0
194
+ element: options.element ? convertToSelector(options.element) : void 0
199
195
  });
196
+ },
197
+ getByRole() {
198
+ throw new Error('Method "getByRole" is not implemented in the current provider.');
199
+ },
200
+ getByLabelText() {
201
+ throw new Error('Method "getByLabelText" is not implemented in the current provider.');
202
+ },
203
+ getByTestId() {
204
+ throw new Error('Method "getByTestId" is not implemented in the current provider.');
205
+ },
206
+ getByAltText() {
207
+ throw new Error('Method "getByAltText" is not implemented in the current provider.');
208
+ },
209
+ getByPlaceholder() {
210
+ throw new Error('Method "getByPlaceholder" is not implemented in the current provider.');
211
+ },
212
+ getByText() {
213
+ throw new Error('Method "getByText" is not implemented in the current provider.');
214
+ },
215
+ getByTitle() {
216
+ throw new Error('Method "getByTitle" is not implemented in the current provider.');
217
+ },
218
+ elementLocator() {
219
+ throw new Error('Method "elementLocator" is not implemented in the current provider.');
220
+ },
221
+ extend(methods) {
222
+ for (const key in methods) {
223
+ page[key] = methods[key];
224
+ }
225
+ return page;
200
226
  }
201
227
  };
228
+ function convertToLocator(element) {
229
+ if (element instanceof Element) {
230
+ return page.elementLocator(element);
231
+ }
232
+ return element;
233
+ }
234
+ function convertToSelector(elementOrLocator) {
235
+ if (!elementOrLocator) {
236
+ throw new Error("Expected element or locator to be defined.");
237
+ }
238
+ if (elementOrLocator instanceof Element) {
239
+ return convertElementToCssSelector(elementOrLocator);
240
+ }
241
+ if ("selector" in elementOrLocator) {
242
+ return elementOrLocator.selector;
243
+ }
244
+ throw new Error("Expected element or locator to be an instance of Element or Locator.");
245
+ }
202
246
  function getTaskFullName(task) {
203
247
  return task.suite ? `${getTaskFullName(task.suite)} ${task.name}` : task.name;
204
248
  }
249
+ function processClickOptions(options_) {
250
+ if (!options_ || !state().config.browser.ui) {
251
+ return options_;
252
+ }
253
+ if (provider === "playwright") {
254
+ const options = options_;
255
+ if (options.position) {
256
+ options.position = processPlaywrightPosition(options.position);
257
+ }
258
+ }
259
+ if (provider === "webdriverio") {
260
+ const options = options_;
261
+ if (options.x != null || options.y != null) {
262
+ const cache = {};
263
+ if (options.x != null) {
264
+ options.x = scaleCoordinate(options.x, cache);
265
+ }
266
+ if (options.y != null) {
267
+ options.y = scaleCoordinate(options.y, cache);
268
+ }
269
+ }
270
+ }
271
+ return options_;
272
+ }
273
+ function processHoverOptions(options_) {
274
+ if (!options_ || !state().config.browser.ui) {
275
+ return options_;
276
+ }
277
+ if (provider === "playwright") {
278
+ const options = options_;
279
+ if (options.position) {
280
+ options.position = processPlaywrightPosition(options.position);
281
+ }
282
+ }
283
+ if (provider === "webdriverio") {
284
+ const options = options_;
285
+ const cache = {};
286
+ if (options.xOffset != null) {
287
+ options.xOffset = scaleCoordinate(options.xOffset, cache);
288
+ }
289
+ if (options.yOffset != null) {
290
+ options.yOffset = scaleCoordinate(options.yOffset, cache);
291
+ }
292
+ }
293
+ return options_;
294
+ }
295
+ function processDragAndDropOptions(options_) {
296
+ if (!options_ || !state().config.browser.ui) {
297
+ return options_;
298
+ }
299
+ if (provider === "playwright") {
300
+ const options = options_;
301
+ if (options.sourcePosition) {
302
+ options.sourcePosition = processPlaywrightPosition(options.sourcePosition);
303
+ }
304
+ if (options.targetPosition) {
305
+ options.targetPosition = processPlaywrightPosition(options.targetPosition);
306
+ }
307
+ }
308
+ if (provider === "webdriverio") {
309
+ const cache = {};
310
+ const options = options_;
311
+ if (options.sourceX != null) {
312
+ options.sourceX = scaleCoordinate(options.sourceX, cache);
313
+ }
314
+ if (options.sourceY != null) {
315
+ options.sourceY = scaleCoordinate(options.sourceY, cache);
316
+ }
317
+ if (options.targetX != null) {
318
+ options.targetX = scaleCoordinate(options.targetX, cache);
319
+ }
320
+ if (options.targetY != null) {
321
+ options.targetY = scaleCoordinate(options.targetY, cache);
322
+ }
323
+ }
324
+ return options_;
325
+ }
326
+ function scaleCoordinate(coordinate, cache) {
327
+ return Math.round(coordinate * getCachedScale(cache));
328
+ }
329
+ function getCachedScale(cache) {
330
+ return cache.scale ??= getIframeScale();
331
+ }
332
+ function processPlaywrightPosition(position) {
333
+ const scale = getIframeScale();
334
+ if (position.x != null) {
335
+ position.x *= scale;
336
+ }
337
+ if (position.y != null) {
338
+ position.y *= scale;
339
+ }
340
+ return position;
341
+ }
342
+ function getIframeScale() {
343
+ const testerUi = window.parent.document.querySelector("#tester-ui");
344
+ if (!testerUi) {
345
+ throw new Error(`Cannot find Tester element. This is a bug in Vitest. Please, open a new issue with reproduction.`);
346
+ }
347
+ const scaleAttribute = testerUi.getAttribute("data-scale");
348
+ const scale = Number(scaleAttribute);
349
+ if (Number.isNaN(scale)) {
350
+ throw new TypeError(`Cannot parse scale value from Tester element (${scaleAttribute}). This is a bug in Vitest. Please, open a new issue with reproduction.`);
351
+ }
352
+ return scale;
353
+ }
205
354
 
206
355
  export { cdp, page, userEvent };