@vitest/browser 3.2.4 → 4.0.0-beta.10

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 (43) 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-DFDJV2DF.js +53 -0
  6. package/dist/client/__vitest__/assets/{index-X8b7Z_4p.css → index-KbpJLW--.css} +1 -1
  7. package/dist/client/__vitest__/index.html +2 -2
  8. package/dist/client/__vitest_browser__/orchestrator-BXX6oamz.js +296 -0
  9. package/dist/client/__vitest_browser__/{tester-BYDMHqQ9.js → tester-CMhJ1E1W.js} +301 -580
  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 +34 -24
  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 +20 -15
  21. package/dist/index.js +550 -98
  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 +5 -2
  35. package/dist/types.d.ts +69 -0
  36. package/jest-dom.d.ts +95 -1
  37. package/package.json +22 -30
  38. package/utils.d.ts +1 -1
  39. package/dist/client/__vitest__/assets/index-D_ryMEPs.js +0 -58
  40. package/dist/client/__vitest_browser__/orchestrator-Bo1OwGWc.js +0 -3213
  41. package/dist/index-W1MM53zC.js +0 -1
  42. package/providers/playwright.d.ts +0 -81
  43. package/providers/webdriverio.d.ts +0 -22
@@ -161,9 +161,9 @@ async function importFs(id) {
161
161
  name
162
162
  ));
163
163
  }
164
- const executor = {
164
+ const moduleRunner = {
165
165
  isBrowser: true,
166
- executeId: (id) => {
166
+ import: (id) => {
167
167
  if (id[0] === "/" || id[1] === ":") {
168
168
  return importFs(id);
169
169
  }
@@ -189,7 +189,7 @@ export {
189
189
  getConfig as a,
190
190
  resolve as b,
191
191
  getWorkerState as c,
192
- executor as e,
193
192
  getBrowserState as g,
193
+ moduleRunner as m,
194
194
  relative as r
195
195
  };
@@ -55,10 +55,14 @@ function catchWindowErrors(errorEvent, prop, cb) {
55
55
  }
56
56
 
57
57
  function registerUnexpectedErrors() {
58
- catchWindowErrors('error', 'error', event =>
58
+ const offError = catchWindowErrors('error', 'error', event =>
59
59
  reportUnexpectedError('Error', event.error))
60
- catchWindowErrors('unhandledrejection', 'reason', event =>
60
+ const offRejection = catchWindowErrors('unhandledrejection', 'reason', event =>
61
61
  reportUnexpectedError('Unhandled Rejection', event.reason))
62
+ return () => {
63
+ offError()
64
+ offRejection()
65
+ }
62
66
  }
63
67
 
64
68
  async function reportUnexpectedError(
@@ -71,4 +75,4 @@ async function reportUnexpectedError(
71
75
  }).catch(console.error)
72
76
  }
73
77
 
74
- registerUnexpectedErrors()
78
+ globalThis.__vitest_browser_runner__.disposeExceptionTracker = registerUnexpectedErrors()
@@ -19,6 +19,7 @@
19
19
  window.__vitest_browser_runner__ = {
20
20
  wrapModule,
21
21
  wrapDynamicImport: wrapModule,
22
+ disposeExceptionTracker: () => {},
22
23
  moduleCache,
23
24
  cleanups: [],
24
25
  config: { __VITEST_CONFIG__ },
@@ -26,8 +26,8 @@
26
26
  {__VITEST_INJECTOR__}
27
27
  {__VITEST_ERROR_CATCHER__}
28
28
  {__VITEST_SCRIPTS__}
29
- <script type="module" crossorigin src="/__vitest_browser__/orchestrator-Bo1OwGWc.js"></script>
30
- <link rel="modulepreload" crossorigin href="/__vitest_browser__/utils-Owv5OOOf.js">
29
+ <script type="module" crossorigin src="/__vitest_browser__/orchestrator-BXX6oamz.js"></script>
30
+ <link rel="modulepreload" crossorigin href="/__vitest_browser__/utils-CPmDBIKG.js">
31
31
  </head>
32
32
  <body>
33
33
  <div id="vitest-tester"></div>
@@ -5,8 +5,8 @@
5
5
  <link rel="icon" href="{__VITEST_FAVICON__}" type="image/svg+xml">
6
6
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
7
7
  <title>Vitest Browser Tester</title>
8
- <script type="module" crossorigin src="/__vitest_browser__/tester-BYDMHqQ9.js"></script>
9
- <link rel="modulepreload" crossorigin href="/__vitest_browser__/utils-Owv5OOOf.js">
8
+ <script type="module" crossorigin src="/__vitest_browser__/tester-CMhJ1E1W.js"></script>
9
+ <link rel="modulepreload" crossorigin href="/__vitest_browser__/utils-CPmDBIKG.js">
10
10
  </head>
11
11
  <body>
12
12
  </body>
package/dist/client.js CHANGED
@@ -29,10 +29,13 @@ function createBirpc(functions, options) {
29
29
  return functions;
30
30
  if (method === "$close")
31
31
  return close;
32
+ if (method === "$rejectPendingCalls") {
33
+ return rejectPendingCalls;
34
+ }
32
35
  if (method === "$closed")
33
36
  return closed;
34
37
  if (method === "then" && !eventNames.includes("then") && !("then" in functions))
35
- return undefined;
38
+ return void 0;
36
39
  const sendEvent = (...args) => {
37
40
  post(serialize({ m: method, a: args, t: TYPE_REQUEST }));
38
41
  };
@@ -47,7 +50,7 @@ function createBirpc(functions, options) {
47
50
  try {
48
51
  await _promise;
49
52
  } finally {
50
- _promise = undefined;
53
+ _promise = void 0;
51
54
  }
52
55
  }
53
56
  return new Promise((resolve, reject) => {
@@ -75,14 +78,30 @@ function createBirpc(functions, options) {
75
78
  return sendCall;
76
79
  }
77
80
  });
78
- function close(error) {
81
+ function close(customError) {
79
82
  closed = true;
80
83
  rpcPromiseMap.forEach(({ reject, method }) => {
81
- reject(error || new Error(`[birpc] rpc is closed, cannot call "${method}"`));
84
+ const error = new Error(`[birpc] rpc is closed, cannot call "${method}"`);
85
+ if (customError) {
86
+ customError.cause ??= error;
87
+ return reject(customError);
88
+ }
89
+ reject(error);
82
90
  });
83
91
  rpcPromiseMap.clear();
84
92
  off(onMessage);
85
93
  }
94
+ function rejectPendingCalls(handler) {
95
+ const entries = Array.from(rpcPromiseMap.values());
96
+ const handlerResults = entries.map(({ method, reject }) => {
97
+ if (!handler) {
98
+ return reject(new Error(`[birpc]: rejected pending call "${method}".`));
99
+ }
100
+ return handler({ method, reject });
101
+ });
102
+ rpcPromiseMap.clear();
103
+ return handlerResults;
104
+ }
86
105
  async function onMessage(data, ...extra) {
87
106
  let msg;
88
107
  try {
@@ -348,7 +367,6 @@ function createClient() {
348
367
  }, {
349
368
  post: (msg) => ctx.ws.send(msg),
350
369
  on: (fn) => onMessage = fn,
351
- timeout: -1,
352
370
  serialize: (e) => stringify(e, (_, v) => {
353
371
  if (v instanceof Error) {
354
372
  return {
@@ -360,9 +378,7 @@ function createClient() {
360
378
  return v;
361
379
  }),
362
380
  deserialize: parse,
363
- onTimeoutError(functionName) {
364
- throw new Error(`[vitest-browser]: Timeout calling "${functionName}"`);
365
- }
381
+ timeout: -1
366
382
  });
367
383
  let openPromise;
368
384
  function reconnect(reset = false) {
package/dist/context.js CHANGED
@@ -149,6 +149,18 @@ function processTimeoutOptions(options_) {
149
149
  options_.timeout = remainingTime - 100;
150
150
  return options_;
151
151
  }
152
+ function convertToSelector(elementOrLocator) {
153
+ if (!elementOrLocator) {
154
+ throw new Error("Expected element or locator to be defined.");
155
+ }
156
+ if (elementOrLocator instanceof Element) {
157
+ return convertElementToCssSelector(elementOrLocator);
158
+ }
159
+ if ("selector" in elementOrLocator) {
160
+ return elementOrLocator.selector;
161
+ }
162
+ throw new Error("Expected element or locator to be an instance of Element or Locator.");
163
+ }
152
164
 
153
165
  // this file should not import anything directly, only types and utils
154
166
  // @ts-expect-error not typed global
@@ -374,37 +386,47 @@ const page = {
374
386
  screenshotIds[repeatCount] ??= {};
375
387
  screenshotIds[repeatCount][taskName] = number + 1;
376
388
  const name = options.path || `${taskName.replace(/[^a-z0-9]/gi, "-")}-${number}.png`;
377
- return ensureAwaited((error) => triggerCommand("__vitest_screenshot", [name, processTimeoutOptions({
389
+ const normalizedOptions = "mask" in options ? {
378
390
  ...options,
379
- element: options.element ? convertToSelector(options.element) : undefined
380
- })], error));
391
+ mask: options.mask.map(convertToSelector)
392
+ } : options;
393
+ return ensureAwaited((error) => triggerCommand("__vitest_screenshot", [name, processTimeoutOptions(
394
+ {
395
+ ...normalizedOptions,
396
+ element: options.element ? convertToSelector(options.element) : undefined
397
+ }
398
+ /** TODO */
399
+ )], error));
381
400
  },
382
401
  getByRole() {
383
- throw new Error(`Method "getByRole" is not implemented in the "${provider}" provider.`);
402
+ throw new Error(`Method "getByRole" is not supported by the "${provider}" provider.`);
384
403
  },
385
404
  getByLabelText() {
386
- throw new Error(`Method "getByLabelText" is not implemented in the "${provider}" provider.`);
405
+ throw new Error(`Method "getByLabelText" is not supported by the "${provider}" provider.`);
387
406
  },
388
407
  getByTestId() {
389
- throw new Error(`Method "getByTestId" is not implemented in the "${provider}" provider.`);
408
+ throw new Error(`Method "getByTestId" is not supported by the "${provider}" provider.`);
390
409
  },
391
410
  getByAltText() {
392
- throw new Error(`Method "getByAltText" is not implemented in the "${provider}" provider.`);
411
+ throw new Error(`Method "getByAltText" is not supported by the "${provider}" provider.`);
393
412
  },
394
413
  getByPlaceholder() {
395
- throw new Error(`Method "getByPlaceholder" is not implemented in the "${provider}" provider.`);
414
+ throw new Error(`Method "getByPlaceholder" is not supported by the "${provider}" provider.`);
396
415
  },
397
416
  getByText() {
398
- throw new Error(`Method "getByText" is not implemented in the "${provider}" provider.`);
417
+ throw new Error(`Method "getByText" is not supported by the "${provider}" provider.`);
399
418
  },
400
419
  getByTitle() {
401
- throw new Error(`Method "getByTitle" is not implemented in the "${provider}" provider.`);
420
+ throw new Error(`Method "getByTitle" is not supported by the "${provider}" provider.`);
402
421
  },
403
422
  elementLocator() {
404
- throw new Error(`Method "elementLocator" is not implemented in the "${provider}" provider.`);
423
+ throw new Error(`Method "elementLocator" is not supported by the "${provider}" provider.`);
424
+ },
425
+ frameLocator() {
426
+ throw new Error(`Method "frameLocator" is not supported by the "${provider}" provider.`);
405
427
  },
406
428
  _createLocator() {
407
- throw new Error(`Method "_createLocator" is not implemented in the "${provider}" provider.`);
429
+ throw new Error(`Method "_createLocator" is not supported by the "${provider}" provider.`);
408
430
  },
409
431
  extend(methods) {
410
432
  for (const key in methods) {
@@ -419,18 +441,6 @@ function convertToLocator(element) {
419
441
  }
420
442
  return element;
421
443
  }
422
- function convertToSelector(elementOrLocator) {
423
- if (!elementOrLocator) {
424
- throw new Error("Expected element or locator to be defined.");
425
- }
426
- if (elementOrLocator instanceof Element) {
427
- return convertElementToCssSelector(elementOrLocator);
428
- }
429
- if ("selector" in elementOrLocator) {
430
- return elementOrLocator.selector;
431
- }
432
- throw new Error("Expected element or locator to be an instance of Element or Locator.");
433
- }
434
444
  function getTaskFullName(task) {
435
445
  return task.suite ? `${getTaskFullName(task.suite)} ${task.name}` : task.name;
436
446
  }
@@ -1,25 +1,27 @@
1
- import{expect,chai}from"vitest";import{k as kAriaCheckedRoles,i as getAriaChecked,j as getAriaRole,l as getAriaDisabled,m as beginAriaCaches,n as endAriaCaches,o as isElementVisible$1,p as getElementAccessibleDescription,q as getElementAccessibleErrorMessage,r as getElementAccessibleName,s as cssEscape}from"./public-utils-Kx5DUGWa.js";import{L as Locator,p as processTimeoutOptions}from"./index-W1MM53zC.js";import{server}from"@vitest/browser/context";import"vitest/internal/browser";function getAriaCheckedRoles(){return[...kAriaCheckedRoles]}function getElementFromUserInput(_,K,q){if(_ instanceof Locator&&(_=_.element()),_ instanceof HTMLElement||_ instanceof SVGElement)return _;throw new UserInputElementTypeError(_,K,q)}function getNodeFromUserInput(_,K,q){if(_ instanceof Locator&&(_=_.element()),_ instanceof Node)return _;throw new UserInputNodeTypeError(_,K,q)}function getMessage(_,K,q,J,Y,X){return[`${K}\n`,`${q}:\n${_.utils.EXPECTED_COLOR(redent(display(_,J),2))}`,`${Y}:\n${_.utils.RECEIVED_COLOR(redent(display(_,X),2))}`].join(`
2
- `)}function redent(_,K){return indentString(stripIndent(_),K)}function indentString(_,K){let q=/^(?!\s*$)/gm;return _.replace(q,` `.repeat(K))}function minIndent(_){let K=_.match(/^[ \t]*(?=\S)/gm);return K?K.reduce((_,K)=>Math.min(_,K.length),1/0):0}function stripIndent(_){let K=minIndent(_);if(K===0)return _;let q=RegExp(`^[ \\t]{${K}}`,`gm`);return _.replace(q,``)}function display(_,K){return typeof K==`string`?K:_.utils.stringify(K)}function toSentence(_,{wordConnector:K=`, `,lastWordConnector:q=` and `}={}){return[_.slice(0,-1).join(K),_[_.length-1]].join(_.length>1?q:``)}class GenericTypeError extends Error{constructor(_,K,q,J){super(),Error.captureStackTrace&&Error.captureStackTrace(this,q);let Y=``;try{Y=J.utils.printWithType(`Received`,K,J.utils.printReceived)}catch{}this.message=[J.utils.matcherHint(`${J.isNot?`.not`:``}.${q.name}`,`received`,``),``,`${J.utils.RECEIVED_COLOR(`received`)} value must ${_} or a Locator that returns ${_}.`,Y].join(`
3
- `)}}class UserInputElementTypeError extends GenericTypeError{constructor(_,K,q){super(`an HTMLElement or an SVGElement`,_,K,q)}}class UserInputNodeTypeError extends GenericTypeError{constructor(_,K,q){super(`a Node`,_,K,q)}}function getTag(_){return _ instanceof HTMLFormElement?`FORM`:_.tagName.toUpperCase()}function isInputElement(_){return getTag(_)===`INPUT`}function getSingleElementValue(_){if(_)switch(getTag(_)){case`INPUT`:return getInputValue(_);case`SELECT`:return getSelectValue(_);default:return _.value??getAccessibleValue(_)}}function getSelectValue({multiple:_,options:K}){let q=[...K].filter(_=>_.selected);if(_)return[...q].map(_=>_.value);if(q.length!==0)return q[0].value}function getInputValue(_){switch(_.type){case`number`:return _.value===``?null:Number(_.value);case`checkbox`:return _.checked;default:return _.value}}const rolesSupportingValues=[`meter`,`progressbar`,`slider`,`spinbutton`];function getAccessibleValue(_){if(rolesSupportingValues.includes(_.getAttribute(`role`)||``))return Number(_.getAttribute(`aria-valuenow`))}function normalize(_){return _.replace(/\s+/g,` `).trim()}function matches(_,K){return K instanceof RegExp?K.test(_):_.includes(String(K))}function arrayAsSetComparison(_,K){if(Array.isArray(_)&&Array.isArray(K)){let q=new Set(K);for(let K of new Set(_))if(!q.has(K))return!1;return!0}}const supportedRoles=getAriaCheckedRoles();function toBeChecked(_){let K=getElementFromUserInput(_,toBeChecked,this),q=()=>isInputElement(K)&&[`checkbox`,`radio`].includes(K.type),X=()=>supportedRoles.includes(getAriaRole(K)||``)&&[`true`,`false`].includes(K.getAttribute(`aria-checked`)||``);if(!q()&&!X())return{pass:!1,message:()=>`only inputs with type="checkbox" or type="radio" or elements with ${supportedRolesSentence()} and a valid aria-checked attribute can be used with .toBeChecked(). Use .toHaveValue() instead`};let Z=getAriaChecked(K),Q=Z===!0;return{pass:Q,message:()=>{let _=Q?`is`:`is not`;return[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBeChecked`,`element`,``),``,`Received element ${_} checked:`,` ${this.utils.printReceived(K.cloneNode(!1))}`].join(`
1
+ import{expect,chai}from"vitest";import{getType}from"vitest/internal/browser";import{k as kAriaCheckedRoles,i as getAriaChecked,j as getAriaRole,l as getAriaDisabled,m as beginAriaCaches,n as endAriaCaches,o as isElementVisible$1,p as getElementAccessibleDescription,q as getElementAccessibleErrorMessage,r as getElementAccessibleName,s as cssEscape}from"./public-utils-Kx5DUGWa.js";import{L as Locator,b as getWorkerState,d as convertToSelector,a as getBrowserState,p as processTimeoutOptions}from"./index-DDlvjJVO.js";import{server}from"@vitest/browser/context";function getAriaCheckedRoles(){return[...kAriaCheckedRoles]}function getElementFromUserInput(_,K,q){_ instanceof Locator&&(_=_.element());let J=_?.ownerDocument?.defaultView||window;if(_ instanceof J.HTMLElement||_ instanceof J.SVGElement)return _;throw new UserInputElementTypeError(_,K,q)}function getNodeFromUserInput(_,K,q){_ instanceof Locator&&(_=_.element());let J=_.ownerDocument?.defaultView||window;if(_ instanceof J.Node)return _;throw new UserInputNodeTypeError(_,K,q)}function getMessage(_,K,q,J,Y,X){return[`${K}\n`,`${q}:\n${_.utils.EXPECTED_COLOR(redent(display(_,J),2))}`,`${Y}:\n${_.utils.RECEIVED_COLOR(redent(display(_,X),2))}`].join(`
2
+ `)}function redent(_,K){return indentString(stripIndent(_),K)}function indentString(_,K){let q=/^(?!\s*$)/gm;return _.replace(q,` `.repeat(K))}function minIndent(_){let K=_.match(/^[ \t]*(?=\S)/gm);return K?K.reduce((_,K)=>Math.min(_,K.length),1/0):0}function stripIndent(_){let K=minIndent(_);if(K===0)return _;let q=RegExp(`^[ \\t]{${K}}`,`gm`);return _.replace(q,``)}function display(_,K){return typeof K==`string`?K:_.utils.stringify(K)}function toSentence(_,{wordConnector:K=`, `,lastWordConnector:q=` and `}={}){return[_.slice(0,-1).join(K),_.at(-1)].join(_.length>1?q:``)}class GenericTypeError extends Error{constructor(_,K,q,J){super(),Error.captureStackTrace&&Error.captureStackTrace(this,q);let Y=``;try{Y=J.utils.printWithType(`Received`,K,J.utils.printReceived)}catch{}this.message=[J.utils.matcherHint(`${J.isNot?`.not`:``}.${q.name}`,`received`,``),``,`${J.utils.RECEIVED_COLOR(`received`)} value must ${_} or a Locator that returns ${_}.`,Y].join(`
3
+ `)}}class UserInputElementTypeError extends GenericTypeError{constructor(_,K,q){super(`an HTMLElement or an SVGElement`,_,K,q)}}class UserInputNodeTypeError extends GenericTypeError{constructor(_,K,q){super(`a Node`,_,K,q)}}function getTag(_){return _ instanceof HTMLFormElement?`FORM`:_.tagName.toUpperCase()}function isInputElement(_){return getTag(_)===`INPUT`}function getSingleElementValue(_){if(_)switch(getTag(_)){case`INPUT`:return getInputValue(_);case`SELECT`:return getSelectValue(_);default:return _.value??getAccessibleValue(_)}}function getSelectValue({multiple:_,options:K}){let q=[...K].filter(_=>_.selected);if(_)return[...q].map(_=>_.value);if(q.length!==0)return q[0].value}function getInputValue(_){switch(_.type){case`number`:return _.value===``?null:Number(_.value);case`checkbox`:return _.checked;default:return _.value}}const rolesSupportingValues=[`meter`,`progressbar`,`slider`,`spinbutton`];function getAccessibleValue(_){if(rolesSupportingValues.includes(_.getAttribute(`role`)||``))return Number(_.getAttribute(`aria-valuenow`))}function normalize(_){return _.replace(/\s+/g,` `).trim()}function matches(_,K){return K instanceof RegExp?K.test(_):_.includes(String(K))}function arrayAsSetComparison(_,K){if(Array.isArray(_)&&Array.isArray(K)){let q=new Set(K);for(let K of new Set(_))if(!q.has(K))return!1;return!0}}const supportedRoles=getAriaCheckedRoles();function toBeChecked(_){let K=getElementFromUserInput(_,toBeChecked,this),q=()=>isInputElement(K)&&[`checkbox`,`radio`].includes(K.type),J=()=>supportedRoles.includes(getAriaRole(K)||``)&&[`true`,`false`].includes(K.getAttribute(`aria-checked`)||``);if(!q()&&!J())return{pass:!1,message:()=>`only inputs with type="checkbox" or type="radio" or elements with ${supportedRolesSentence()} and a valid aria-checked attribute can be used with .toBeChecked(). Use .toHaveValue() instead`};let Z=getAriaChecked(K),Q=Z===!0;return{pass:Q,message:()=>{let _=Q?`is`:`is not`;return[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBeChecked`,`element`,``),``,`Received element ${_} checked:`,` ${this.utils.printReceived(K.cloneNode(!1))}`].join(`
4
4
  `)}}}function supportedRolesSentence(){return toSentence(supportedRoles.map(_=>`role="${_}"`),{lastWordConnector:` or `})}function toBeEmptyDOMElement(_){let K=getElementFromUserInput(_,toBeEmptyDOMElement,this);return{pass:isEmptyElement(K),message:()=>[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBeEmptyDOMElement`,`element`,``),``,`Received:`,` ${this.utils.printReceived(K.innerHTML)}`].join(`
5
5
  `)}}function isEmptyElement(_){let K=[..._.childNodes].filter(_=>_.nodeType!==Node.COMMENT_NODE);return K.length===0}function toBeDisabled(_){let K=getElementFromUserInput(_,toBeDisabled,this),q=isElementDisabled(K);return{pass:q,message:()=>{let _=q?`is`:`is not`;return[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBeDisabled`,`element`,``),``,`Received element ${_} disabled:`,` ${this.utils.printReceived(K.cloneNode(!1))}`].join(`
6
6
  `)}}}function toBeEnabled(_){let K=getElementFromUserInput(_,toBeEnabled,this),q=isElementDisabled(K);return{pass:!q,message:()=>{let _=q?`is not`:`is`;return[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBeEnabled`,`element`,``),``,`Received element ${_} enabled:`,` ${this.utils.printReceived(K.cloneNode(!1))}`].join(`
7
7
  `)}}}function isElementDisabled(_){return getTag(_).includes(`-`)?_.hasAttribute(`disabled`):getAriaDisabled(_)}function toBeInTheDocument(_){let K=null;(_!==null||!this.isNot)&&(K=getElementFromUserInput(_,toBeInTheDocument,this));let q=K===null?!1:K.ownerDocument===K.getRootNode({composed:!0}),J=()=>`expected document not to contain element, found ${this.utils.stringify(K?.cloneNode(!0))} instead`,Y=()=>`element could not be found in the document`;return{pass:q,message:()=>[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBeInTheDocument`,`element`,``),``,this.utils.RECEIVED_COLOR(this.isNot?J():Y())].join(`
8
8
  `)}}const FORM_TAGS$1=[`FORM`,`INPUT`,`SELECT`,`TEXTAREA`];function isElementHavingAriaInvalid(_){return _.hasAttribute(`aria-invalid`)&&_.getAttribute(`aria-invalid`)!==`false`}function isSupportsValidityMethod(_){return FORM_TAGS$1.includes(getTag(_))}function isElementInvalid(_){let K=isElementHavingAriaInvalid(_);return isSupportsValidityMethod(_)?K||!_.checkValidity():K}function toBeInvalid(_){let K=getElementFromUserInput(_,toBeInvalid,this),q=isElementInvalid(K);return{pass:q,message:()=>{let _=q?`is`:`is not`;return[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBeInvalid`,`element`,``),``,`Received element ${_} currently invalid:`,` ${this.utils.printReceived(K.cloneNode(!1))}`].join(`
9
9
  `)}}}function toBeValid(_){let K=getElementFromUserInput(_,toBeInvalid,this),q=!isElementInvalid(K);return{pass:q,message:()=>{let _=q?`is`:`is not`;return[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBeValid`,`element`,``),``,`Received element ${_} currently valid:`,` ${this.utils.printReceived(K.cloneNode(!1))}`].join(`
10
- `)}}}function toBePartiallyChecked(_){let K=getElementFromUserInput(_,toBePartiallyChecked,this),q=()=>isInputElement(K)&&K.type===`checkbox`,J=()=>K.getAttribute(`role`)===`checkbox`;if(!q()&&!J())return{pass:!1,message:()=>`only inputs with type="checkbox" or elements with role="checkbox" and a valid aria-checked attribute can be used with .toBePartiallyChecked(). Use .toHaveValue() instead`};let Y=isAriaMixed(K);return{pass:Y,message:()=>{let _=Y?`is`:`is not`;return[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBePartiallyChecked`,`element`,``),``,`Received element ${_} partially checked:`,` ${this.utils.printReceived(K.cloneNode(!1))}`].join(`
10
+ `)}}}function toBeInViewport(_,K){let q=getElementFromUserInput(_,toBeInViewport,this),J=K?.ratio??0;return getViewportIntersection(q,J).then(({pass:_,ratio:K})=>({pass:_,message:()=>{let Y=_?`is`:`is not`,X=J>0?` with ratio ${J}`:``,Z=K===void 0?``:` (actual ratio: ${K.toFixed(3)})`;return[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBeInViewport`,`element`,``),``,`Received element ${Y} in viewport${X}${Z}:`,` ${this.utils.printReceived(q.cloneNode(!1))}`].join(`
11
+ `)}}))}async function getViewportIntersection(_,K){let q=await new Promise(K=>{let q=new IntersectionObserver(_=>{_.length>0?K(_[0].intersectionRatio):K(0),q.disconnect()});q.observe(_),requestAnimationFrame(()=>{})}),J=q>0&&q>K-1e-9;return{pass:J,ratio:q}}function toBePartiallyChecked(_){let K=getElementFromUserInput(_,toBePartiallyChecked,this),q=()=>isInputElement(K)&&K.type===`checkbox`,J=()=>K.getAttribute(`role`)===`checkbox`;if(!q()&&!J())return{pass:!1,message:()=>`only inputs with type="checkbox" or elements with role="checkbox" and a valid aria-checked attribute can be used with .toBePartiallyChecked(). Use .toHaveValue() instead`};let Y=isAriaMixed(K);return{pass:Y,message:()=>{let _=Y?`is`:`is not`;return[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBePartiallyChecked`,`element`,``),``,`Received element ${_} partially checked:`,` ${this.utils.printReceived(K.cloneNode(!1))}`].join(`
11
12
  `)}}}function isAriaMixed(_){let K=getAriaChecked(_)===`mixed`;if(!K&&isInputElement(_)&&[`checkbox`,`radio`].includes(_.type)){let K=_.getAttribute(`aria-checked`);if(K===`mixed`)return!0}return K}const FORM_TAGS=[`SELECT`,`TEXTAREA`],ARIA_FORM_TAGS=[`INPUT`,`SELECT`,`TEXTAREA`],UNSUPPORTED_INPUT_TYPES=[`color`,`hidden`,`range`,`submit`,`image`,`reset`],SUPPORTED_ARIA_ROLES=[`checkbox`,`combobox`,`gridcell`,`listbox`,`radiogroup`,`spinbutton`,`textbox`,`tree`];function isRequiredOnFormTagsExceptInput(_){return FORM_TAGS.includes(getTag(_))&&_.hasAttribute(`required`)}function isRequiredOnSupportedInput(_){return getTag(_)===`INPUT`&&_.hasAttribute(`required`)&&(_.hasAttribute(`type`)&&!UNSUPPORTED_INPUT_TYPES.includes(_.getAttribute(`type`)||``)||!_.hasAttribute(`type`))}function isElementRequiredByARIA(_){return _.hasAttribute(`aria-required`)&&_.getAttribute(`aria-required`)===`true`&&(ARIA_FORM_TAGS.includes(getTag(_))||_.hasAttribute(`role`)&&SUPPORTED_ARIA_ROLES.includes(_.getAttribute(`role`)||``))}function toBeRequired(_){let K=getElementFromUserInput(_,toBeRequired,this),q=isRequiredOnFormTagsExceptInput(K)||isRequiredOnSupportedInput(K)||isElementRequiredByARIA(K);return{pass:q,message:()=>{let _=q?`is`:`is not`;return[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBeRequired`,`element`,``),``,`Received element ${_} required:`,` ${this.utils.printReceived(K.cloneNode(!1))}`].join(`
12
13
  `)}}}function toBeVisible(_){let K=getElementFromUserInput(_,toBeVisible,this),q=K.ownerDocument===K.getRootNode({composed:!0});beginAriaCaches();let J=q&&isElementVisible(K);return endAriaCaches(),{pass:J,message:()=>{let _=J?`is`:`is not`;return[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBeVisible`,`element`,``),``,`Received element ${_} visible${q?``:` (element is not in the document)`}:`,` ${this.utils.printReceived(K.cloneNode(!1))}`].join(`
13
14
  `)}}}function isElementVisible(_){let K=isElementVisible$1(_);if(server.browser!==`webkit`)return K;let q=_.closest(`details`);return!q||_===q?K:isElementVisibleInDetails(_)}function isElementVisibleInDetails(_){let K=_;for(;K;){if(K.tagName===`DETAILS`){let q=K.querySelector(`summary`)===_;if(!K.open&&!q)return!1}K=K.parentElement}return _.offsetParent!==null}function toContainElement(_,K){let q=getElementFromUserInput(_,toContainElement,this),J=K===null?null:getElementFromUserInput(K,toContainElement,this);return{pass:q.contains(J),message:()=>[this.utils.matcherHint(`${this.isNot?`.not`:``}.toContainElement`,`element`,`element`),``,this.utils.RECEIVED_COLOR(`${this.utils.stringify(q.cloneNode(!1))} ${this.isNot?`contains:`:`does not contain:`} ${this.utils.stringify(J?J.cloneNode(!1):null)}
14
15
  `)].join(`
15
16
  `)}}function getNormalizedHtml(_,K){let q=_.ownerDocument.createElement(`div`);return q.innerHTML=K,q.innerHTML}function toContainHTML(_,K){let q=getElementFromUserInput(_,toContainHTML,this);if(typeof K!=`string`)throw TypeError(`.toContainHTML() expects a string value, got ${K}`);return{pass:q.outerHTML.includes(getNormalizedHtml(q,K)),message:()=>[this.utils.matcherHint(`${this.isNot?`.not`:``}.toContainHTML`,`element`,``),`Expected:`,` ${this.utils.EXPECTED_COLOR(K)}`,`Received:`,` ${this.utils.printReceived(q.cloneNode(!0))}`].join(`
16
- `)}}function toHaveAccessibleDescription(_,K){let q=getElementFromUserInput(_,toHaveAccessibleDescription,this),J=getElementAccessibleDescription(q,!1),Y=arguments.length===1,X=!1;return X=Y?J!==``:K instanceof RegExp?K.test(J):this.equals(J,K,this.customTesters),{pass:X,message:()=>{let _=this.isNot?`not to`:`to`;return getMessage(this,this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveAccessibleDescription`,`element`,``),`Expected element ${_} have accessible description`,K,`Received`,J)}}}function toHaveAccessibleErrorMessage(_,K){let q=getElementFromUserInput(_,toHaveAccessibleErrorMessage,this),J=getElementAccessibleErrorMessage(q)??``,Y=arguments.length===1,X=!1;return X=Y?J!==``:K instanceof RegExp?K.test(J):this.equals(J,K,this.customTesters),{pass:X,message:()=>{let _=this.isNot?`not to`:`to`;return K==null?[this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveAccessibleErrorMessage`,`element`,``),`Expected element ${_} have accessible error message, but got${this.isNot?``:` nothing`}`,this.isNot?this.utils.RECEIVED_COLOR(redent(J,2)):``].filter(Boolean).join(`
17
+ `)}}function toHaveAccessibleDescription(_,K){let q=getElementFromUserInput(_,toHaveAccessibleDescription,this),J=getElementAccessibleDescription(q,!1),Y=q.ownerDocument.defaultView||window,X=arguments.length===1,Z=!1;return Z=X?J!==``:K instanceof Y.RegExp?K.test(J):this.equals(J,K,this.customTesters),{pass:Z,message:()=>{let _=this.isNot?`not to`:`to`;return getMessage(this,this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveAccessibleDescription`,`element`,``),`Expected element ${_} have accessible description`,K,`Received`,J)}}}function toHaveAccessibleErrorMessage(_,K){let q=getElementFromUserInput(_,toHaveAccessibleErrorMessage,this),J=getElementAccessibleErrorMessage(q)??``,Y=q.ownerDocument.defaultView||window,X=arguments.length===1,Z=!1;return Z=X?J!==``:K instanceof Y.RegExp?K.test(J):this.equals(J,K,this.customTesters),{pass:Z,message:()=>{let _=this.isNot?`not to`:`to`;return K==null?[this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveAccessibleErrorMessage`,`element`,``),`Expected element ${_} have accessible error message, but got${this.isNot?``:` nothing`}`,this.isNot?this.utils.RECEIVED_COLOR(redent(J,2)):``].filter(Boolean).join(`
17
18
 
18
- `):getMessage(this,this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveAccessibleErrorMessage`,`element`,``),`Expected element ${_} have accessible error message`,K,`Received`,J)}}}function toHaveAccessibleName(_,K){let q=getElementFromUserInput(_,toHaveAccessibleName,this),J=getElementAccessibleName(q,!1),Y=arguments.length===1,X=!1;return X=Y?J!==``:K instanceof RegExp?K.test(J):this.equals(J,K,this.customTesters),{pass:X,message:()=>{let _=this.isNot?`not to`:`to`;return getMessage(this,this.utils.matcherHint(`${this.isNot?`.not`:``}.${toHaveAccessibleName.name}`,`element`,``),`Expected element ${_} have accessible name`,K,`Received`,J)}}}function toHaveAttribute(_,K,q){let J=getElementFromUserInput(_,toHaveAttribute,this),Y=q!==void 0,X=J.hasAttribute(K),Z=J.getAttribute(K);return{pass:Y?X&&this.equals(Z,q,this.customTesters):X,message:()=>{let _=this.isNot?`not to`:`to`,J=X?printAttribute(this.utils.stringify,K,Z):null,Q=this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveAttribute`,`element`,this.utils.printExpected(K),{secondArgument:Y?this.utils.printExpected(q):void 0,comment:getAttributeComment(this.utils.stringify,K,q)});return getMessage(this,Q,`Expected the element ${_} have attribute`,printAttribute(this.utils.stringify,K,q),`Received`,J)}}}function printAttribute(_,K,q){return q===void 0?K:`${K}=${_(q)}`}function getAttributeComment(_,K,q){return q===void 0?`element.hasAttribute(${_(K)})`:`element.getAttribute(${_(K)}) === ${_(q)}`}function toHaveClass(_,...K){let q=getElementFromUserInput(_,toHaveClass,this),{expectedClassNames:J,options:Y}=getExpectedClassNamesAndOptions(K),X=splitClassNames(q.getAttribute(`class`)),Z=J.reduce((_,K)=>_.concat(typeof K==`string`||!K?splitClassNames(K):K),[]),Q=Z.some(_=>_ instanceof RegExp);if(Y.exact&&Q)throw Error(`Exact option does not support RegExp expected class names`);return Y.exact?{pass:isSubset$1(Z,X)&&Z.length===X.length,message:()=>{let _=this.isNot?`not to`:`to`;return getMessage(this,this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveClass`,`element`,this.utils.printExpected(Z.join(` `))),`Expected the element ${_} have EXACTLY defined classes`,Z.join(` `),`Received`,X.join(` `))}}:Z.length>0?{pass:isSubset$1(Z,X),message:()=>{let _=this.isNot?`not to`:`to`;return getMessage(this,this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveClass`,`element`,this.utils.printExpected(Z.join(` `))),`Expected the element ${_} have class`,Z.join(` `),`Received`,X.join(` `))}}:{pass:this.isNot?X.length>0:!1,message:()=>this.isNot?getMessage(this,this.utils.matcherHint(`.not.toHaveClass`,`element`,``),`Expected the element to have classes`,`(none)`,`Received`,X.join(` `)):[this.utils.matcherHint(`.toHaveClass`,`element`),`At least one expected class must be provided.`].join(`
19
+ `):getMessage(this,this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveAccessibleErrorMessage`,`element`,``),`Expected element ${_} have accessible error message`,K,`Received`,J)}}}function toHaveAccessibleName(_,K){let q=getElementFromUserInput(_,toHaveAccessibleName,this),J=getElementAccessibleName(q,!1),Y=arguments.length===1,X=q.ownerDocument.defaultView||window,Z=!1;return Z=Y?J!==``:K instanceof X.RegExp?K.test(J):this.equals(J,K,this.customTesters),{pass:Z,message:()=>{let _=this.isNot?`not to`:`to`;return getMessage(this,this.utils.matcherHint(`${this.isNot?`.not`:``}.${toHaveAccessibleName.name}`,`element`,``),`Expected element ${_} have accessible name`,K,`Received`,J)}}}function toHaveAttribute(_,K,q){let J=getElementFromUserInput(_,toHaveAttribute,this),Y=q!==void 0,X=J.hasAttribute(K),Z=J.getAttribute(K);return{pass:Y?X&&this.equals(Z,q,this.customTesters):X,message:()=>{let _=this.isNot?`not to`:`to`,J=X?printAttribute(this.utils.stringify,K,Z):null,Q=this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveAttribute`,`element`,this.utils.printExpected(K),{secondArgument:Y?this.utils.printExpected(q):void 0,comment:getAttributeComment(this.utils.stringify,K,q)});return getMessage(this,Q,`Expected the element ${_} have attribute`,printAttribute(this.utils.stringify,K,q),`Received`,J)}}}function printAttribute(_,K,q){return q===void 0?K:`${K}=${_(q)}`}function getAttributeComment(_,K,q){return q===void 0?`element.hasAttribute(${_(K)})`:`element.getAttribute(${_(K)}) === ${_(q)}`}function toHaveClass(_,...K){let q=getElementFromUserInput(_,toHaveClass,this),{expectedClassNames:J,options:Y}=getExpectedClassNamesAndOptions(K),X=splitClassNames(q.getAttribute(`class`)),Z=J.reduce((_,K)=>_.concat(typeof K==`string`||!K?splitClassNames(K):K),[]),Q=Z.some(_=>_ instanceof RegExp);if(Y.exact&&Q)throw Error(`Exact option does not support RegExp expected class names`);return Y.exact?{pass:isSubset$1(Z,X)&&Z.length===X.length,message:()=>{let _=this.isNot?`not to`:`to`;return getMessage(this,this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveClass`,`element`,this.utils.printExpected(Z.join(` `))),`Expected the element ${_} have EXACTLY defined classes`,Z.join(` `),`Received`,X.join(` `))}}:Z.length>0?{pass:isSubset$1(Z,X),message:()=>{let _=this.isNot?`not to`:`to`;return getMessage(this,this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveClass`,`element`,this.utils.printExpected(Z.join(` `))),`Expected the element ${_} have class`,Z.join(` `),`Received`,X.join(` `))}}:{pass:this.isNot?X.length>0:!1,message:()=>this.isNot?getMessage(this,this.utils.matcherHint(`.not.toHaveClass`,`element`,``),`Expected the element to have classes`,`(none)`,`Received`,X.join(` `)):[this.utils.matcherHint(`.toHaveClass`,`element`),`At least one expected class must be provided.`].join(`
19
20
  `)}}function getExpectedClassNamesAndOptions(_){let K=_.pop(),q,J;return typeof K==`object`&&!(K instanceof RegExp)?(q=_,J=K):(q=_.concat(K),J={exact:!1}),{expectedClassNames:q,options:J}}function splitClassNames(_){return _?_.split(/\s+/).filter(_=>_.length>0):[]}function isSubset$1(_,K){return _.every(_=>typeof _==`string`?K.includes(_):K.some(K=>_.test(K)))}function toHaveDisplayValue(_,K){let q=getElementFromUserInput(_,toHaveDisplayValue,this),J=getTag(q);if(![`SELECT`,`INPUT`,`TEXTAREA`].includes(J))throw Error(`.toHaveDisplayValue() currently supports only input, textarea or select elements, try with another matcher instead.`);if(isInputElement(q)&&[`radio`,`checkbox`].includes(q.type))throw Error(`.toHaveDisplayValue() currently does not support input[type="${q.type}"], try with another matcher instead.`);let Y=getValues(J,q),X=getExpectedValues(K),Z=X.filter(_=>Y.some(K=>_ instanceof RegExp?_.test(K):this.equals(K,String(_),this.customTesters))).length,Q=Z===Y.length,$=Z===X.length;return{pass:Q&&$,message:()=>getMessage(this,this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveDisplayValue`,`element`,``),`Expected element ${this.isNot?`not `:``}to have display value`,K,`Received`,Y)}}function getValues(_,K){return _===`SELECT`?Array.from(K).filter(_=>_.selected).map(_=>_.textContent||``):[K.value]}function getExpectedValues(_){return Array.isArray(_)?_:[_]}function toHaveFocus(_){let K=getElementFromUserInput(_,toHaveFocus,this);return{pass:K.ownerDocument.activeElement===K,message:()=>[this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveFocus`,`element`,``),``,...this.isNot?[`Received element is focused:`,` ${this.utils.printReceived(K)}`]:[`Expected element with focus:`,` ${this.utils.printExpected(K)}`,`Received element with focus:`,` ${this.utils.printReceived(K.ownerDocument.activeElement)}`]].join(`
20
- `)}}function toHaveFormValues(_,K){let q=getElementFromUserInput(_,toHaveFormValues,this);if(!(q instanceof HTMLFieldSetElement)&&!(q instanceof HTMLFormElement))throw TypeError(`toHaveFormValues must be called on a form or a fieldset, instead got ${getTag(q)}`);if(!K||typeof K!=`object`)throw TypeError(`toHaveFormValues must be called with an object of expected form values. Got ${K}`);let J=getAllFormValues(q);return{pass:Object.entries(K).every(([_,K])=>this.equals(J[_],K,[arrayAsSetComparison,...this.customTesters])),message:()=>{let _=this.isNot?`not to`:`to`,q=`${this.isNot?`.not`:``}.toHaveFormValues`,Y={};for(let _ in J){if(!Object.hasOwn(K,_))continue;Y[_]=J[_]}return[this.utils.matcherHint(q,`element`,``),`Expected the element ${_} have form values`,this.utils.diff(K,Y)].join(`
21
+ `)}}function toHaveFormValues(_,K){let q=getElementFromUserInput(_,toHaveFormValues,this),J=q.ownerDocument.defaultView||window;if(!(q instanceof J.HTMLFieldSetElement)&&!(q instanceof J.HTMLFormElement))throw TypeError(`toHaveFormValues must be called on a form or a fieldset, instead got ${getTag(q)}`);if(!K||typeof K!=`object`)throw TypeError(`toHaveFormValues must be called with an object of expected form values. Got ${K}`);let Y=getAllFormValues(q);return{pass:Object.entries(K).every(([_,K])=>this.equals(Y[_],K,[arrayAsSetComparison,...this.customTesters])),message:()=>{let _=this.isNot?`not to`:`to`,q=`${this.isNot?`.not`:``}.toHaveFormValues`,J={};for(let _ in Y){if(!Object.hasOwn(K,_))continue;J[_]=Y[_]}return[this.utils.matcherHint(q,`element`,``),`Expected the element ${_} have form values`,this.utils.diff(K,J)].join(`
21
22
 
22
23
  `)}}}function getMultiElementValue(_){let K=[...new Set(_.map(_=>_.type))];if(K.length!==1)throw Error(`Multiple form elements with the same name must be of the same type`);switch(K[0]){case`radio`:{let K=_.find(_=>_.checked);return K?K.value:void 0}case`checkbox`:return _.filter(_=>_.checked).map(_=>_.value);default:return _.map(_=>_.value)}}function getFormValue(_,K){let q=[..._.querySelectorAll(`[name="${cssEscape(K)}"]`)];if(q.length!==0)switch(q.length){case 1:return getSingleElementValue(q[0]);default:return getMultiElementValue(q)}}function getPureName(_){return/\[\]$/.test(_)?_.slice(0,-2):_}function getAllFormValues(_){let K={};for(let q of _.elements){if(!(`name`in q))continue;let J=q.name;K[getPureName(J)]=getFormValue(_,J)}return K}function toHaveRole(_,K){let q=getElementFromUserInput(_,toHaveRole,this);beginAriaCaches();let J=getAriaRole(q);return endAriaCaches(),{pass:J===K,message:()=>{let _=this.isNot?`not to`:`to`;return getMessage(this,this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveRole`,`element`,``),`Expected element ${_} have role`,K,`Received`,J)}}}function toHaveSelection(_,K){let q=getElementFromUserInput(_,toHaveSelection,this),J=K!==void 0;if(J&&typeof K!=`string`)throw Error(`expected selection must be a string or undefined`);let Y=getSelection(q);return{pass:J?this.equals(Y,K,[arrayAsSetComparison,...this.customTesters]):!!Y,message:()=>{let _=this.isNot?`not to`:`to`,q=this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveSelection`,`element`,K);return getMessage(this,q,`Expected the element ${_} have selection`,J?K:`(any)`,`Received`,Y)}}}function getSelection(_){let K=_.ownerDocument.getSelection();if(!K)return``;if([`INPUT`,`TEXTAREA`].includes(getTag(_))){let K=_;return[`radio`,`checkbox`].includes(K.type)||K.selectionStart==null||K.selectionEnd==null?``:K.value.toString().substring(K.selectionStart,K.selectionEnd)}if(K.anchorNode===null||K.focusNode===null)return``;let q=K.getRangeAt(0),J=_.ownerDocument.createRange();if(K.containsNode(_,!1))J.selectNodeContents(_),K.removeAllRanges(),K.addRange(J);else if(!(_.contains(K.anchorNode)&&_.contains(K.focusNode))){let Y=_===q.startContainer||_.contains(q.startContainer),X=_===q.endContainer||_.contains(q.endContainer);K.removeAllRanges(),(Y||X)&&(J.selectNodeContents(_),Y&&J.setStart(q.startContainer,q.startOffset),X&&J.setEnd(q.endContainer,q.endOffset),K.addRange(J))}let Y=K.toString();return K.removeAllRanges(),K.addRange(q),Y}const browser=server.config.browser.name,usedValuesProps=new Set(`backgroundPosition.background-position.bottom.left.right.top.height.width.margin-bottom.marginBottom.margin-left.marginLeft.margin-right.marginRight.margin-top.marginTop.min-height.minHeight.min-width.minWidth.padding-bottom.padding-left.padding-right.padding-top.text-indent.paddingBottom.paddingLeft.paddingRight.paddingTop.textIndent`.split(`.`));function toHaveStyle(_,K){let q=getElementFromUserInput(_,toHaveStyle,this),{getComputedStyle:J}=q.ownerDocument.defaultView,Y=typeof K==`object`?getStyleFromObjectCSS(K):computeCSSStyleDeclaration(K),X=J(q),Z=new Set(Array.from(q.style));return{pass:isSubset(Y,q,X,Z),message:()=>{let _=`${this.isNot?`.not`:``}.toHaveStyle`,K=new Set(Object.keys(Y)),J=Array.from(X).filter(_=>K.has(_)).reduce((_,K)=>{let J=Z.has(K)&&usedValuesProps.has(K)?q.style:X;return _[K]=J[K],_},{}),Q=printoutObjectStyles(J),$=Q===``?`Expected styles could not be parsed by the browser. Did you make a typo?`:this.utils.diff(printoutObjectStyles(Y),Q);return[this.utils.matcherHint(_,`element`,``),$].join(`
23
24
 
24
25
  `)}}}function getStyleFromObjectCSS(_){let K=browser===`chrome`||browser===`chromium`?document:document.implementation.createHTMLDocument(``),q=K.createElement(`div`);K.body.appendChild(q);let J=Object.keys(_);J.forEach(K=>{q.style[K]=_[K]});let Y={},X=window.getComputedStyle(q);return J.forEach(_=>{let K=usedValuesProps.has(_)?q.style:X,J=K[_];J!=null&&(Y[_]=J)}),q.remove(),Y}function computeCSSStyleDeclaration(_){let K=browser===`chrome`||browser===`chromium`||browser===`webkit`?document:document.implementation.createHTMLDocument(``),q=K.createElement(`div`);q.setAttribute(`style`,_.replace(/\n/g,``)),K.body.appendChild(q);let J=window.getComputedStyle(q),Y=Array.from(q.style).reduce((_,K)=>(_[K]=usedValuesProps.has(K)?q.style.getPropertyValue(K):J.getPropertyValue(K),_),{});return q.remove(),Y}function printoutObjectStyles(_){return Object.keys(_).sort().map(K=>`${K}: ${_[K]};`).join(`
25
- `)}function isSubset(_,K,q,J){let Y=Object.keys(_);return Y.length?Y.every(Y=>{let X=_[Y],Z=Y.startsWith(`--`),Q=[Y];Z||Q.push(Y.toLowerCase());let $=Q.some(_=>{let Z=J.has(Y)&&usedValuesProps.has(Y)?K.style:q;return Z[_]===X||Z.getPropertyValue(_)===X});return $}):!1}function toHaveTextContent(_,K,q={normalizeWhitespace:!0}){let J=getNodeFromUserInput(_,toHaveTextContent,this),Y=q.normalizeWhitespace?normalize(J.textContent||``):(J.textContent||``).replace(/\u00A0/g,` `),X=Y!==``&&K===``;return{pass:!X&&matches(Y,K),message:()=>{let _=this.isNot?`not to`:`to`;return getMessage(this,this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveTextContent`,`element`,``),X?`Checking with empty string will always match, use .toBeEmptyDOMElement() instead`:`Expected element ${_} have text content`,K,`Received`,Y)}}}function toHaveValue(_,K){let q=getElementFromUserInput(_,toHaveValue,this);if(isInputElement(q)&&[`checkbox`,`radio`].includes(q.type))throw Error(`input with type=checkbox or type=radio cannot be used with .toHaveValue(). Use .toBeChecked() for type=checkbox or .toHaveFormValues() instead`);let J=getSingleElementValue(q),Y=K!==void 0,X=K,Z=J;return K==J&&K!==J&&(X=`${K} (${typeof K})`,Z=`${J} (${typeof J})`),{pass:Y?this.equals(J,K,[arrayAsSetComparison,...this.customTesters]):!!J,message:()=>{let _=this.isNot?`not to`:`to`,q=this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveValue`,`element`,K);return getMessage(this,q,`Expected the element ${_} have value`,Y?X:`(any)`,`Received`,Z)}}}const matchers={toBeDisabled,toBeEnabled,toBeEmptyDOMElement,toBeInTheDocument,toBeInvalid,toBeRequired,toBeValid,toBeVisible,toContainElement,toContainHTML,toHaveAccessibleDescription,toHaveAccessibleErrorMessage,toHaveAccessibleName,toHaveAttribute,toHaveClass,toHaveFocus,toHaveFormValues,toHaveStyle,toHaveTextContent,toHaveValue,toHaveDisplayValue,toBeChecked,toBePartiallyChecked,toHaveRole,toHaveSelection};function element(q,J){if(q!=null&&!(q instanceof Element)&&!(`element`in q))throw Error(`Invalid element or locator: ${q}. Expected an instance of Element or Locator, received ${typeof q}`);return expect.poll(function(){if(q instanceof Element||q==null)return q;chai.util.flag(this,`_poll.element`,!0);let _=chai.util.flag(this,`negate`),J=chai.util.flag(this,`_name`),Y=chai.util.flag(this,`_isLastPollAttempt`);if(_&&J===`toBeInTheDocument`)return q.query();if(Y)return q.element();let X=q.query();if(!X)throw Error(`Cannot find element with locator: ${JSON.stringify(q)}`);return X},processTimeoutOptions(J))}expect.extend(matchers),Object.assign(expect,{element});
26
+ `)}function isSubset(_,K,q,J){let Y=Object.keys(_);return Y.length?Y.every(Y=>{let X=_[Y],Z=Y.startsWith(`--`),Q=[Y];Z||Q.push(Y.toLowerCase());let $=Q.some(_=>{let Z=J.has(Y)&&usedValuesProps.has(Y)?K.style:q;return Z[_]===X||Z.getPropertyValue(_)===X});return $}):!1}function toHaveTextContent(_,K,q={normalizeWhitespace:!0}){let J=getNodeFromUserInput(_,toHaveTextContent,this),Y=q.normalizeWhitespace?normalize(J.textContent||``):(J.textContent||``).replace(/\u00A0/g,` `),X=Y!==``&&K===``;return{pass:!X&&matches(Y,K),message:()=>{let _=this.isNot?`not to`:`to`;return getMessage(this,this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveTextContent`,`element`,``),X?`Checking with empty string will always match, use .toBeEmptyDOMElement() instead`:`Expected element ${_} have text content`,K,`Received`,Y)}}}function toHaveValue(_,K){let q=getElementFromUserInput(_,toHaveValue,this);if(isInputElement(q)&&[`checkbox`,`radio`].includes(q.type))throw Error(`input with type=checkbox or type=radio cannot be used with .toHaveValue(). Use .toBeChecked() for type=checkbox or .toHaveFormValues() instead`);let J=getSingleElementValue(q),Y=K!==void 0,X=K,Z=J;return K==J&&K!==J&&(X=`${K} (${typeof K})`,Z=`${J} (${typeof J})`),{pass:Y?this.equals(J,K,[arrayAsSetComparison,...this.customTesters]):!!J,message:()=>{let _=this.isNot?`not to`:`to`,q=this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveValue`,`element`,K);return getMessage(this,q,`Expected the element ${_} have value`,Y?X:`(any)`,`Received`,Z)}}}const counters=new Map([]);async function toMatchScreenshot(_,K,q=typeof K==`object`?K:{}){if(this.isNot)throw Error(`'toMatchScreenshot' cannot be used with "not"`);let J=getWorkerState().current;if(J===void 0||this.currentTestName===void 0)throw Error(`'toMatchScreenshot' cannot be used without test context`);let Y=`${J.result?.repeatCount??0}${this.testPath}${this.currentTestName}`,X=counters.get(Y);X===void 0&&(X={current:0},counters.set(Y,X)),X.current+=1;let Z=typeof K==`string`?K:`${this.currentTestName} ${X.current}`,Q=q.screenshotOptions&&`mask`in q.screenshotOptions?{...q,screenshotOptions:{...q.screenshotOptions,mask:q.screenshotOptions.mask.map(convertToSelector)}}:q,$=await getBrowserState().commands.triggerCommand(`__vitest_screenshotMatcher`,[Z,this.currentTestName,{element:convertToSelector(_),...Q}]);if($.pass===!1&&`context`in J){let{annotate:_}=J.context,K=[];$.reference&&K.push(_(`Reference screenshot`,{path:$.reference})),$.actual&&K.push(_(`Actual screenshot`,{path:$.actual})),$.diff&&K.push(_(`Diff`,{path:$.diff})),await Promise.all(K)}return{pass:$.pass,message:()=>$.pass?``:[this.utils.matcherHint(`toMatchScreenshot`,`element`,``),``,$.message,$.reference?`\nReference screenshot:\n ${this.utils.EXPECTED_COLOR($.reference)}`:null,$.actual?`\nActual screenshot:\n ${this.utils.RECEIVED_COLOR($.actual)}`:null,$.diff?this.utils.DIM_COLOR(`\nDiff image:\n ${$.diff}`):null].filter(_=>_!==null).join(`
27
+ `)}}const matchers={toBeDisabled,toBeEnabled,toBeEmptyDOMElement,toBeInTheDocument,toBeInViewport,toBeInvalid,toBeRequired,toBeValid,toBeVisible,toContainElement,toContainHTML,toHaveAccessibleDescription,toHaveAccessibleErrorMessage,toHaveAccessibleName,toHaveAttribute,toHaveClass,toHaveFocus,toHaveFormValues,toHaveStyle,toHaveTextContent,toHaveValue,toHaveDisplayValue,toBeChecked,toBePartiallyChecked,toHaveRole,toHaveSelection,toMatchScreenshot},kLocator=Symbol.for(`$$vitest:locator`);function element(J,Y){if(J!=null&&!(J instanceof HTMLElement)&&!(J instanceof SVGElement)&&!(kLocator in J))throw Error(`Invalid element or locator: ${J}. Expected an instance of HTMLElement, SVGElement or Locator, received ${getType(J)}`);return expect.poll(function(){if(J instanceof Element||J==null)return J;chai.util.flag(this,`_poll.element`,!0);let _=chai.util.flag(this,`negate`),q=chai.util.flag(this,`_name`);if(_&&q===`toBeInTheDocument`)return J.query();if(q===`toHaveLength`)return J.elements();let Y=chai.util.flag(this,`_isLastPollAttempt`);if(Y)return J.element();let X=J.query();if(!X)throw Error(`Cannot find element with locator: ${JSON.stringify(J)}`);return X},processTimeoutOptions(Y))}expect.extend(matchers),Object.assign(expect,{element});
@@ -0,0 +1,6 @@
1
+ export { playwright } from './providers/playwright.js';
2
+ export { preview } from './providers/preview.js';
3
+ export { webdriverio } from './providers/webdriverio.js';
4
+ import '@vitest/mocker/node';
5
+ import 'tinyrainbow';
6
+ import 'vitest/node';
@@ -0,0 +1 @@
1
+ import{server,page}from"@vitest/browser/context";import{I as Ivya,e as getByRoleSelector,c as getByAltTextSelector,f as getByLabelSelector,b as getByPlaceholderSelector,d as getByTestIdSelector,a as getByTextSelector,g as getByTitleSelector,h as getElementError}from"./public-utils-Kx5DUGWa.js";function ensureAwaited(e){let S=getWorkerState().current;if(!S||S.type!==`test`)return e();let C=!1,w=Error(`STACK_TRACE_ERROR`);S.onFinished??=[],S.onFinished.push(()=>{if(!C){let e=Error(`The call was not awaited. This method is asynchronous and must be awaited; otherwise, the call will not start to avoid unhandled rejections.`);throw e.stack=w.stack?.replace(w.message,e.message),e}});let T;return{then(S,E){return C=!0,(T||=e(w)).then(S,E)},catch(S){return(T||=e(w)).catch(S)},finally(S){return(T||=e(w)).finally(S)},[Symbol.toStringTag]:`Promise`}}function getBrowserState(){return window.__vitest_browser_runner__}function getWorkerState(){let e=window.__vitest_worker__;if(!e)throw Error(`Worker state is not found. This is an issue with Vitest. Please, open an issue.`);return e}const provider=getBrowserState().provider;function convertElementToCssSelector(e){if(!e||!(e instanceof Element))throw Error(`Expected DOM element to be an instance of Element, received ${typeof e}`);return getUniqueCssSelector(e)}function escapeIdForCSSSelector(e){return e.split(``).map(e=>{let S=e.charCodeAt(0);return e===` `||e===`#`||e===`.`||e===`:`||e===`[`||e===`]`||e===`>`||e===`+`||e===`~`||e===`\\`?`\\${e}`:S>=65536?`\\${S.toString(16).toUpperCase().padStart(6,`0`)} `:S<32||S===127||S>=128?`\\${S.toString(16).toUpperCase().padStart(2,`0`)} `:e}).join(``)}function getUniqueCssSelector(e){let S=[],C,w=!1;for(;C=getParent(e);){C.shadowRoot&&(w=!0);let T=e.tagName;if(e.id)S.push(`#${escapeIdForCSSSelector(e.id)}`);else if(!e.nextElementSibling&&!e.previousElementSibling)S.push(T.toLowerCase());else{let w=0,E=0,D=0;for(let S of C.children)w++,S.tagName===T&&E++,S===e&&(D=w);E>1?S.push(`${T.toLowerCase()}:nth-child(${D})`):S.push(T.toLowerCase())}e=C}return`${getBrowserState().provider===`webdriverio`&&w?`>>>`:``}${S.reverse().join(` > `)}`}function getParent(e){let S=e.parentNode;return S instanceof ShadowRoot?S.host:S}const now=Date.now;function processTimeoutOptions(e){if(e&&e.timeout!=null||provider!==`playwright`||getWorkerState().config.browser.providerOptions.actionTimeout!=null)return e;let S=getBrowserState().runner,C=S._currentTaskStartTime;if(!C)return e;let w=S._currentTaskTimeout;if(w===0||w==null||w===1/0)return e;e||={};let T=now(),E=C+w,D=E-T;return D<=0||(e.timeout=D-100),e}function getIframeScale(){let e=window.parent.document.querySelector(`iframe[data-vitest]`)?.parentElement;if(!e)throw Error(`Cannot find Tester element. This is a bug in Vitest. Please, open a new issue with reproduction.`);let S=e.getAttribute(`data-scale`),C=Number(S);if(Number.isNaN(C))throw TypeError(`Cannot parse scale value from Tester element (${S}). This is a bug in Vitest. Please, open a new issue with reproduction.`);return C}function escapeRegexForSelector(e){return e.unicode||e.unicodeSets?String(e):String(e).replace(/(^|[^\\])(\\\\)*(["'`])/g,`$1$2\\$3`).replace(/>>/g,`\\>\\>`)}function escapeForTextSelector(e,S){return typeof e==`string`?`${JSON.stringify(e)}i`:escapeRegexForSelector(e)}function convertToSelector(e){if(!e)throw Error(`Expected element or locator to be defined.`);if(e instanceof Element)return convertElementToCssSelector(e);if(`selector`in e)return e.selector;throw Error(`Expected element or locator to be an instance of Element or Locator.`)}const selectorEngine=Ivya.create({browser:(e=>{switch(e){case`edge`:case`chrome`:return`chromium`;case`safari`:return`webkit`;default:return e}})(server.config.browser.name),testIdAttribute:server.config.browser.locators.testIdAttribute}),kLocator=Symbol.for(`$$vitest:locator`);class Locator{_parsedSelector;_container;_pwSelector;constructor(){Object.defineProperty(this,kLocator,{enumerable:!1,writable:!1,configurable:!1,value:kLocator})}click(e={}){return this.triggerCommand(`__vitest_click`,this.selector,e)}dblClick(e={}){return this.triggerCommand(`__vitest_dblClick`,this.selector,e)}tripleClick(e={}){return this.triggerCommand(`__vitest_tripleClick`,this.selector,e)}clear(e){return this.triggerCommand(`__vitest_clear`,this.selector,e)}hover(e){return this.triggerCommand(`__vitest_hover`,this.selector,e)}unhover(e){return this.triggerCommand(`__vitest_hover`,`html > body`,e)}fill(e,S){return this.triggerCommand(`__vitest_fill`,this.selector,e,S)}async upload(e,S){let C=(Array.isArray(e)?e:[e]).map(async e=>{if(typeof e==`string`)return e;let S=await new Promise((S,C)=>{let w=new FileReader;w.onload=()=>S(w.result),w.onerror=()=>C(Error(`Failed to read file: ${e.name}`)),w.readAsDataURL(e)});return{name:e.name,mimeType:e.type,base64:S}});return this.triggerCommand(`__vitest_upload`,this.selector,await Promise.all(C),S)}dropTo(e,S={}){return this.triggerCommand(`__vitest_dragAndDrop`,this.selector,e.selector,S)}selectOptions(e,S){let C=(Array.isArray(e)?e:[e]).map(e=>{if(typeof e!=`string`){let S=`element`in e?e.selector:selectorEngine.generateSelectorSimple(e);return{element:S}}return e});return this.triggerCommand(`__vitest_selectOptions`,this.selector,C,S)}screenshot(e){return page.screenshot({...e,element:this})}getByRole(e,S){return this.locator(getByRoleSelector(e,S))}getByAltText(e,S){return this.locator(getByAltTextSelector(e,S))}getByLabelText(e,S){return this.locator(getByLabelSelector(e,S))}getByPlaceholder(e,S){return this.locator(getByPlaceholderSelector(e,S))}getByTestId(S){return this.locator(getByTestIdSelector(server.config.browser.locators.testIdAttribute,S))}getByText(e,S){return this.locator(getByTextSelector(e,S))}getByTitle(e,S){return this.locator(getByTitleSelector(e,S))}filter(e){let S=[];if(e?.hasText&&S.push(`internal:has-text=${escapeForTextSelector(e.hasText)}`),e?.hasNotText&&S.push(`internal:has-not-text=${escapeForTextSelector(e.hasNotText)}`),e?.has){let C=e.has;S.push(`internal:has=${JSON.stringify(C._pwSelector||C.selector)}`)}if(e?.hasNot){let C=e.hasNot;S.push(`internal:has-not=${JSON.stringify(C._pwSelector||C.selector)}`)}if(!S.length)throw Error(`Locator.filter expects at least one filter. None provided.`);return this.locator(S.join(` >> `))}and(e){return this.locator(`internal:and=${JSON.stringify(e._pwSelector||e.selector)}`)}or(e){return this.locator(`internal:or=${JSON.stringify(e._pwSelector||e.selector)}`)}query(){let e=this._parsedSelector||=selectorEngine.parseSelector(this._pwSelector||this.selector);return selectorEngine.querySelector(e,document.documentElement,!0)}element(){let e=this.query();if(!e)throw getElementError(this._pwSelector||this.selector,this._container||document.body);return e}elements(){let e=this._parsedSelector||=selectorEngine.parseSelector(this._pwSelector||this.selector);return selectorEngine.querySelectorAll(e,document.documentElement)}get length(){return this.elements().length}all(){return this.elements().map(e=>this.elementLocator(e))}nth(e){return this.locator(`nth=${e}`)}first(){return this.nth(0)}last(){return this.nth(-1)}toString(){return this.selector}toJSON(){return this.selector}triggerCommand(e,...S){let C=getBrowserState().commands;return ensureAwaited(w=>C.triggerCommand(e,S,w))}}export{Locator as L,getBrowserState as a,getWorkerState as b,convertElementToCssSelector as c,convertToSelector as d,getIframeScale as g,processTimeoutOptions as p,selectorEngine as s};
package/dist/index.d.ts CHANGED
@@ -2,9 +2,8 @@ import { Plugin } from 'vitest/config';
2
2
  import { CDPSession, BrowserServerState as BrowserServerState$1, ProjectBrowser as ProjectBrowser$1, TestProject, BrowserProvider, Vitest, ResolvedConfig, Vite, BrowserCommand, BrowserScript, ProcessPool } from 'vitest/node';
3
3
  import { StackTraceParserOptions } from '@vitest/utils/source-map';
4
4
  import { ViteDevServer, HtmlTagDescriptor } from 'vite';
5
- import { CancelReason, BrowserTesterOptions, TestExecutionMethod, RunnerTestFile, AfterSuiteRunMeta, UserConsoleLog, SnapshotResult, SerializedConfig, ErrorWithDiff, ParsedStack } from 'vitest';
6
- import { MockedModuleSerialized } from '@vitest/mocker';
7
- import { ServerIdResolution, ServerMockResolution } from '@vitest/mocker/node';
5
+ import { CancelReason, BrowserTesterOptions, TestExecutionMethod, RunnerTestFile, AfterSuiteRunMeta, UserConsoleLog, SnapshotResult, SerializedConfig, TestError, ParsedStack } from 'vitest';
6
+ import { ServerIdResolution, ServerMockResolution, MockedModuleSerialized } from '@vitest/mocker';
8
7
  import { TestAnnotation, TaskResultPack, TaskEventPack } from '@vitest/runner';
9
8
 
10
9
  type ArgumentsType<T> = T extends (...args: infer A) => any ? A : never;
@@ -22,7 +21,16 @@ type BirpcReturn<RemoteFunctions, LocalFunctions = Record<string, never>> = {
22
21
  $functions: LocalFunctions;
23
22
  $close: (error?: Error) => void;
24
23
  $closed: boolean;
24
+ $rejectPendingCalls: (handler?: PendingCallHandler) => Promise<void>[];
25
25
  };
26
+ type PendingCallHandler = (options: Pick<PromiseEntry, 'method' | 'reject'>) => void | Promise<void>;
27
+ interface PromiseEntry {
28
+ resolve: (arg: any) => void;
29
+ reject: (error: any) => void;
30
+ method: string;
31
+ timeoutId?: ReturnType<typeof setTimeout>;
32
+ }
33
+ declare const setTimeout: typeof globalThis.setTimeout;
26
34
 
27
35
  interface WebSocketBrowserHandlers {
28
36
  resolveSnapshotPath: (testPath: string) => string;
@@ -44,17 +52,16 @@ interface WebSocketBrowserHandlers {
44
52
  resolveId: (id: string, importer?: string) => Promise<ServerIdResolution | null>;
45
53
  triggerCommand: <T>(sessionId: string, command: string, testPath: string | undefined, payload: unknown[]) => Promise<T>;
46
54
  resolveMock: (id: string, importer: string, options: {
47
- mock: "spy" | "factory" | "auto"
55
+ mock: "spy" | "factory" | "auto";
48
56
  }) => Promise<ServerMockResolution>;
49
57
  invalidate: (ids: string[]) => void;
50
58
  getBrowserFileSourceMap: (id: string) => SourceMap | null | {
51
- mappings: ""
59
+ mappings: "";
52
60
  } | undefined;
53
61
  wdioSwitchContext: (direction: "iframe" | "parent") => void;
54
62
  registerMock: (sessionId: string, mock: MockedModuleSerialized) => void;
55
63
  unregisterMock: (sessionId: string, id: string) => void;
56
64
  clearMocks: (sessionId: string) => void;
57
- // cdp
58
65
  sendCdpEvent: (sessionId: string, event: string, payload?: Record<string, unknown>) => unknown;
59
66
  trackCdpEvent: (sessionId: string, type: "on" | "once" | "off", event: string, listenerId: string) => void;
60
67
  }
@@ -64,9 +71,9 @@ interface WebSocketBrowserEvents {
64
71
  cleanupTesters: () => Promise<void>;
65
72
  cdpEvent: (event: string, payload: unknown) => void;
66
73
  resolveManualMock: (url: string) => Promise<{
67
- url: string
68
- keys: string[]
69
- responseId: string
74
+ url: string;
75
+ keys: string[];
76
+ responseId: string;
70
77
  }>;
71
78
  }
72
79
  type WebSocketBrowserRPC = BirpcReturn<WebSocketBrowserEvents, WebSocketBrowserHandlers>;
@@ -113,7 +120,7 @@ declare class ProjectBrowser implements ProjectBrowser$1 {
113
120
  get vite(): ViteDevServer;
114
121
  wrapSerializedConfig(): SerializedConfig;
115
122
  initBrowserProvider(project: TestProject): Promise<void>;
116
- parseErrorStacktrace(e: ErrorWithDiff, options?: StackTraceParserOptions): ParsedStack[];
123
+ parseErrorStacktrace(e: TestError, options?: StackTraceParserOptions): ParsedStack[];
117
124
  parseStacktrace(trace: string, options?: StackTraceParserOptions): ParsedStack[];
118
125
  close(): Promise<void>;
119
126
  }
@@ -122,7 +129,6 @@ declare class ParentBrowserProject {
122
129
  project: TestProject;
123
130
  base: string;
124
131
  orchestratorScripts: string | undefined;
125
- testerScripts: HtmlTagDescriptor[] | undefined;
126
132
  faviconUrl: string;
127
133
  prefixOrchestratorUrl: string;
128
134
  prefixTesterUrl: string;
@@ -139,12 +145,11 @@ declare class ParentBrowserProject {
139
145
  children: Set<ProjectBrowser>;
140
146
  vitest: Vitest;
141
147
  config: ResolvedConfig;
142
- // cache for non-vite source maps
143
148
  private sourceMapCache;
144
149
  constructor(project: TestProject, base: string);
145
150
  setServer(vite: Vite.ViteDevServer): void;
146
151
  spawn(project: TestProject): ProjectBrowser;
147
- parseErrorStacktrace(e: ErrorWithDiff, options?: StackTraceParserOptions): ParsedStack[];
152
+ parseErrorStacktrace(e: TestError, options?: StackTraceParserOptions): ParsedStack[];
148
153
  parseStacktrace(trace: string, options?: StackTraceParserOptions): ParsedStack[];
149
154
  readonly cdps: Map<string, BrowserServerCDPHandler>;
150
155
  private cdpSessionsPromises;
@@ -152,8 +157,8 @@ declare class ParentBrowserProject {
152
157
  removeCDPHandler(sessionId: string): void;
153
158
  formatScripts(scripts: BrowserScript[] | undefined): Promise<HtmlTagDescriptor[]>;
154
159
  resolveTesterUrl(pathname: string): {
155
- sessionId: string
156
- testFile: string
160
+ sessionId: string;
161
+ testFile: string;
157
162
  };
158
163
  private retrieveSourceMapURL;
159
164
  }