@vitest/browser 3.1.0 → 3.1.2

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.
@@ -187,8 +187,8 @@ function getWorkerState() {
187
187
  }
188
188
  export {
189
189
  getConfig as a,
190
- getWorkerState as b,
191
- resolve as c,
190
+ resolve as b,
191
+ getWorkerState as c,
192
192
  executor as e,
193
193
  getBrowserState as g,
194
194
  relative as r
@@ -77,9 +77,9 @@ async function reportUnexpectedError(
77
77
 
78
78
  if (!state.runTests || !__vitest_worker__.current) {
79
79
  channel.postMessage({
80
- type: 'done',
81
- filenames: state.files,
82
- id: state.iframeId,
80
+ // TODO: what to do in this case now?
81
+ event: 'response:???',
82
+ iframeId: state.iframeId,
83
83
  })
84
84
  }
85
85
  }
@@ -22,7 +22,6 @@
22
22
  moduleCache,
23
23
  config: { __VITEST_CONFIG__ },
24
24
  viteConfig: { __VITEST_VITE_CONFIG__ },
25
- files: { __VITEST_FILES__ },
26
25
  type: { __VITEST_TYPE__ },
27
26
  sessionId: { __VITEST_SESSION_ID__ },
28
27
  testerId: { __VITEST_TESTER_ID__ },
@@ -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-CqPXjvQE.js"></script>
30
- <link rel="modulepreload" crossorigin href="/__vitest_browser__/utils-CNTxSNQV.js">
29
+ <script type="module" crossorigin src="/__vitest_browser__/orchestrator-CuTjqoE1.js"></script>
30
+ <link rel="modulepreload" crossorigin href="/__vitest_browser__/utils-Owv5OOOf.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-DiLSqOx4.js"></script>
9
- <link rel="modulepreload" crossorigin href="/__vitest_browser__/utils-CNTxSNQV.js">
8
+ <script type="module" crossorigin src="/__vitest_browser__/tester-D8qCxA_3.js"></script>
9
+ <link rel="modulepreload" crossorigin href="/__vitest_browser__/utils-Owv5OOOf.js">
10
10
  </head>
11
11
  <body>
12
12
  </body>
package/dist/client.js CHANGED
@@ -1,3 +1,5 @@
1
+ const TYPE_REQUEST = "q";
2
+ const TYPE_RESPONSE = "s";
1
3
  const DEFAULT_TIMEOUT = 6e4;
2
4
  function defaultSerialize(i) {
3
5
  return i;
@@ -30,7 +32,7 @@ function createBirpc(functions, options) {
30
32
  if (method === "then" && !eventNames.includes("then") && !("then" in functions))
31
33
  return void 0;
32
34
  const sendEvent = (...args) => {
33
- post(serialize({ m: method, a: args, t: "q" }));
35
+ post(serialize({ m: method, a: args, t: TYPE_REQUEST }));
34
36
  };
35
37
  if (eventNames.includes(method)) {
36
38
  sendEvent.asEvent = sendEvent;
@@ -52,8 +54,9 @@ function createBirpc(functions, options) {
52
54
  if (timeout >= 0) {
53
55
  timeoutId = setTimeout$1(() => {
54
56
  try {
55
- options.onTimeoutError?.(method, args);
56
- throw new Error(`[birpc] timeout on calling "${method}"`);
57
+ const handleResult = options.onTimeoutError?.(method, args);
58
+ if (handleResult !== true)
59
+ throw new Error(`[birpc] timeout on calling "${method}"`);
57
60
  } catch (e) {
58
61
  reject(e);
59
62
  }
@@ -70,17 +73,24 @@ function createBirpc(functions, options) {
70
73
  return sendCall;
71
74
  }
72
75
  });
73
- function close() {
76
+ function close(error) {
74
77
  closed = true;
75
78
  rpcPromiseMap.forEach(({ reject, method }) => {
76
- reject(new Error(`[birpc] rpc is closed, cannot call "${method}"`));
79
+ reject(error || new Error(`[birpc] rpc is closed, cannot call "${method}"`));
77
80
  });
78
81
  rpcPromiseMap.clear();
79
82
  off(onMessage);
80
83
  }
81
84
  async function onMessage(data, ...extra) {
82
- const msg = deserialize(data);
83
- if (msg.t === "q") {
85
+ let msg;
86
+ try {
87
+ msg = deserialize(data);
88
+ } catch (e) {
89
+ if (options.onGeneralError?.(e) !== true)
90
+ throw e;
91
+ return;
92
+ }
93
+ if (msg.t === TYPE_REQUEST) {
84
94
  const { m: method, a: args } = msg;
85
95
  let result, error;
86
96
  const fn = resolver ? resolver(method, functions[method]) : functions[method];
@@ -96,7 +106,26 @@ function createBirpc(functions, options) {
96
106
  if (msg.i) {
97
107
  if (error && options.onError)
98
108
  options.onError(error, method, args);
99
- post(serialize({ t: "s", i: msg.i, r: result, e: error }), ...extra);
109
+ if (error && options.onFunctionError) {
110
+ if (options.onFunctionError(error, method, args) === true)
111
+ return;
112
+ }
113
+ if (!error) {
114
+ try {
115
+ post(serialize({ t: TYPE_RESPONSE, i: msg.i, r: result }), ...extra);
116
+ return;
117
+ } catch (e) {
118
+ error = e;
119
+ if (options.onGeneralError?.(e, method, args) !== true)
120
+ throw e;
121
+ }
122
+ }
123
+ try {
124
+ post(serialize({ t: TYPE_RESPONSE, i: msg.i, e: error }), ...extra);
125
+ } catch (e) {
126
+ if (options.onGeneralError?.(e, method, args) !== true)
127
+ throw e;
128
+ }
100
129
  }
101
130
  } else {
102
131
  const { i: ack, r: result, e: error } = msg;
@@ -237,15 +266,6 @@ function getBrowserState() {
237
266
 
238
267
  const channel = new BroadcastChannel(`vitest:${getBrowserState().sessionId}`);
239
268
  const globalChannel = new BroadcastChannel("vitest:global");
240
- function waitForChannel(event) {
241
- return new Promise((resolve) => {
242
- channel.addEventListener("message", (e) => {
243
- if (e.data?.type === event) {
244
- resolve();
245
- }
246
- }, { once: true });
247
- });
248
- }
249
269
 
250
270
  const PAGE_TYPE = getBrowserState().type;
251
271
  const PORT = location.port;
@@ -269,11 +289,19 @@ function createClient() {
269
289
  let onMessage;
270
290
  ctx.rpc = createBirpc({
271
291
  onCancel: setCancel,
272
- async createTesters(files) {
273
- if (PAGE_TYPE !== "orchestrator") {
274
- return;
292
+ async createTesters(options) {
293
+ const orchestrator = getBrowserState().orchestrator;
294
+ if (!orchestrator) {
295
+ throw new TypeError("Only orchestrator can create testers.");
296
+ }
297
+ return orchestrator.createTesters(options);
298
+ },
299
+ async cleanupTesters() {
300
+ const orchestrator = getBrowserState().orchestrator;
301
+ if (!orchestrator) {
302
+ throw new TypeError("Only orchestrator can cleanup testers.");
275
303
  }
276
- getBrowserState().createTesters?.(files);
304
+ return orchestrator.cleanupTesters();
277
305
  },
278
306
  cdpEvent(event, payload) {
279
307
  const cdp = getBrowserState().cdp;
@@ -303,6 +331,7 @@ function createClient() {
303
331
  }, {
304
332
  post: (msg) => ctx.ws.send(msg),
305
333
  on: (fn) => onMessage = fn,
334
+ timeout: -1,
306
335
  serialize: (e) => stringify(e, (_, v) => {
307
336
  if (v instanceof Error) {
308
337
  return {
@@ -358,4 +387,4 @@ function createClient() {
358
387
  }
359
388
  const client = createClient();
360
389
 
361
- export { ENTRY_URL, HOST, PORT, RPC_ID, channel, client, globalChannel, onCancel, waitForChannel };
390
+ export { ENTRY_URL, HOST, PORT, RPC_ID, channel, client, globalChannel, onCancel };
package/dist/context.js CHANGED
@@ -323,18 +323,18 @@ const page = {
323
323
  viewport(width, height) {
324
324
  const id = getBrowserState().iframeId;
325
325
  channel.postMessage({
326
- type: "viewport",
326
+ event: "viewport",
327
327
  width,
328
328
  height,
329
- id
329
+ iframeId: id
330
330
  });
331
331
  return new Promise((resolve, reject) => {
332
332
  channel.addEventListener("message", function handler(e) {
333
- if (e.data.type === "viewport:done" && e.data.id === id) {
333
+ if (e.data.event === "viewport:done" && e.data.iframeId === id) {
334
334
  channel.removeEventListener("message", handler);
335
335
  resolve();
336
336
  }
337
- if (e.data.type === "viewport:fail" && e.data.id === id) {
337
+ if (e.data.event === "viewport:fail" && e.data.iframeId === id) {
338
338
  channel.removeEventListener("message", handler);
339
339
  reject(new Error(e.data.error));
340
340
  }
@@ -1,4 +1,4 @@
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-xf4CCUzp.js";import{L as Locator,p as processTimeoutOptions}from"./index-DjDyxzt8.js";import{server}from"@vitest/browser/context";import"vitest/utils";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(`
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-xf4CCUzp.js";import{L as Locator,p as processTimeoutOptions}from"./index-C34csx3Z.js";import{server}from"@vitest/browser/context";import"vitest/utils";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
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
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(`
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(`
@@ -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-xf4CCUzp.js";function ensureAwaited(e){let b=getWorkerState().current;if(!b||b.type!==`test`)return e();let x=!1,S=Error(`STACK_TRACE_ERROR`);b.onFinished??=[],b.onFinished.push(()=>{if(!x){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=S.stack?.replace(S.message,e.message),e}});let C;return{then(b,w){return x=!0,(C||=e(S)).then(b,w)},catch(b){return(C||=e(S)).catch(b)},finally(b){return(C||=e(S)).finally(b)},[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 b=e.charCodeAt(0);return e===` `||e===`#`||e===`.`||e===`:`||e===`[`||e===`]`||e===`>`||e===`+`||e===`~`||e===`\\`?`\\${e}`:b>=65536?`\\${b.toString(16).toUpperCase().padStart(6,`0`)} `:b<32||b===127||b>=128?`\\${b.toString(16).toUpperCase().padStart(2,`0`)} `:e}).join(``)}function getUniqueCssSelector(e){let b=[],x,S=!1;for(;x=getParent(e);){x.shadowRoot&&(S=!0);let C=e.tagName;if(e.id)b.push(`#${escapeIdForCSSSelector(e.id)}`);else if(!e.nextElementSibling&&!e.previousElementSibling)b.push(C.toLowerCase());else{let S=0,w=0,T=0;for(let b of x.children)S++,b.tagName===C&&w++,b===e&&(T=S);w>1?b.push(`${C.toLowerCase()}:nth-child(${T})`):b.push(C.toLowerCase())}e=x}return`${getBrowserState().provider===`webdriverio`&&S?`>>>`:``}${b.reverse().join(` > `)}`}function getParent(e){let b=e.parentNode;return b instanceof ShadowRoot?b.host:b}const now=Date.now;function processTimeoutOptions(e){if(e&&e.timeout!=null||provider!==`playwright`||getWorkerState().config.browser.providerOptions.actionTimeout!=null)return e;let b=getBrowserState().runner,x=b._currentTaskStartTime;if(!x)return e;let S=b._currentTaskTimeout;if(S===0||S==null||S===1/0)return e;e||={};let C=now(),w=x+S,T=w-C;return T<=0||(e.timeout=T-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 b=e.getAttribute(`data-scale`),x=Number(b);if(Number.isNaN(x))throw TypeError(`Cannot parse scale value from Tester element (${b}). This is a bug in Vitest. Please, open a new issue with reproduction.`);return x}function escapeRegexForSelector(e){return e.unicode||e.unicodeSets?String(e):String(e).replace(/(^|[^\\])(\\\\)*(["'`])/g,`$1$2\\$3`).replace(/>>/g,`\\>\\>`)}function escapeForTextSelector(e,b){return typeof e==`string`?`${JSON.stringify(e)}i`:escapeRegexForSelector(e)}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});class Locator{_parsedSelector;_container;_pwSelector;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,b){return this.triggerCommand(`__vitest_fill`,this.selector,e,b)}async upload(e,b){let x=(Array.isArray(e)?e:[e]).map(async e=>{if(typeof e==`string`)return e;let b=await new Promise((b,x)=>{let S=new FileReader;S.onload=()=>b(S.result),S.onerror=()=>x(Error(`Failed to read file: ${e.name}`)),S.readAsDataURL(e)});return{name:e.name,mimeType:e.type,base64:b}});return this.triggerCommand(`__vitest_upload`,this.selector,await Promise.all(x),b)}dropTo(e,b={}){return this.triggerCommand(`__vitest_dragAndDrop`,this.selector,e.selector,b)}selectOptions(e,b){let x=(Array.isArray(e)?e:[e]).map(e=>{if(typeof e!=`string`){let b=`element`in e?e.selector:selectorEngine.generateSelectorSimple(e);return{element:b}}return e});return this.triggerCommand(`__vitest_selectOptions`,this.selector,x,b)}screenshot(e){return page.screenshot({...e,element:this})}getByRole(e,b){return this.locator(getByRoleSelector(e,b))}getByAltText(e,b){return this.locator(getByAltTextSelector(e,b))}getByLabelText(e,b){return this.locator(getByLabelSelector(e,b))}getByPlaceholder(e,b){return this.locator(getByPlaceholderSelector(e,b))}getByTestId(b){return this.locator(getByTestIdSelector(server.config.browser.locators.testIdAttribute,b))}getByText(e,b){return this.locator(getByTextSelector(e,b))}getByTitle(e,b){return this.locator(getByTitleSelector(e,b))}filter(e){let b=[];if(e?.hasText&&b.push(`internal:has-text=${escapeForTextSelector(e.hasText)}`),e?.hasNotText&&b.push(`internal:has-not-text=${escapeForTextSelector(e.hasNotText)}`),e?.has){let x=e.has;b.push(`internal:has=${JSON.stringify(x._pwSelector||x.selector)}`)}if(e?.hasNot){let x=e.hasNot;b.push(`internal:has-not=${JSON.stringify(x._pwSelector||x.selector)}`)}if(!b.length)throw Error(`Locator.filter expects at least one filter. None provided.`);return this.locator(b.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)}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,...b){let x=getBrowserState().commands;return ensureAwaited(S=>x.triggerCommand(e,b,S))}}export{Locator as L,getBrowserState as a,convertElementToCssSelector as c,getIframeScale as g,processTimeoutOptions as p,selectorEngine as s};
package/dist/index.d.ts CHANGED
@@ -2,7 +2,7 @@ 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, RunnerTestFile, AfterSuiteRunMeta, UserConsoleLog, SnapshotResult, SerializedConfig, ErrorWithDiff, ParsedStack } from 'vitest';
5
+ import { CancelReason, BrowserTesterOptions, TestExecutionMethod, RunnerTestFile, AfterSuiteRunMeta, UserConsoleLog, SnapshotResult, SerializedConfig, ErrorWithDiff, ParsedStack } from 'vitest';
6
6
  import { MockedModuleSerialized } from '@vitest/mocker';
7
7
  import { ServerIdResolution, ServerMockResolution } from '@vitest/mocker/node';
8
8
  import { TaskResultPack, TaskEventPack } from '@vitest/runner';
@@ -20,24 +20,23 @@ type BirpcReturn<RemoteFunctions, LocalFunctions = Record<string, never>> = {
20
20
  [K in keyof RemoteFunctions]: BirpcFn<RemoteFunctions[K]>;
21
21
  } & {
22
22
  $functions: LocalFunctions;
23
- $close: () => void;
23
+ $close: (error?: Error) => void;
24
24
  };
25
25
 
26
26
  interface WebSocketBrowserHandlers {
27
27
  resolveSnapshotPath: (testPath: string) => string;
28
28
  resolveSnapshotRawPath: (testPath: string, rawPath: string) => string;
29
29
  onUnhandledError: (error: unknown, type: string) => Promise<void>;
30
- onQueued: (file: RunnerTestFile) => void;
31
- onCollected: (files: RunnerTestFile[]) => Promise<void>;
32
- onTaskUpdate: (packs: TaskResultPack[], events: TaskEventPack[]) => void;
30
+ onQueued: (method: TestExecutionMethod, file: RunnerTestFile) => void;
31
+ onCollected: (method: TestExecutionMethod, files: RunnerTestFile[]) => Promise<void>;
32
+ onTaskUpdate: (method: TestExecutionMethod, packs: TaskResultPack[], events: TaskEventPack[]) => void;
33
33
  onAfterSuiteRun: (meta: AfterSuiteRunMeta) => void;
34
34
  onCancel: (reason: CancelReason) => void;
35
35
  getCountOfFailedTests: () => number;
36
36
  readSnapshotFile: (id: string) => Promise<string | null>;
37
37
  saveSnapshotFile: (id: string, content: string) => Promise<void>;
38
38
  removeSnapshotFile: (id: string) => Promise<void>;
39
- sendLog: (log: UserConsoleLog) => void;
40
- finishBrowserTests: (sessionId: string) => void;
39
+ sendLog: (method: TestExecutionMethod, log: UserConsoleLog) => void;
41
40
  snapshotSaved: (snapshot: SnapshotResult) => void;
42
41
  debug: (...args: string[]) => void;
43
42
  resolveId: (id: string, importer?: string) => Promise<ServerIdResolution | null>;
@@ -58,7 +57,8 @@ interface WebSocketBrowserHandlers {
58
57
  }
59
58
  interface WebSocketBrowserEvents {
60
59
  onCancel: (reason: CancelReason) => void;
61
- createTesters: (files: string[]) => Promise<void>;
60
+ createTesters: (options: BrowserTesterOptions) => Promise<void>;
61
+ cleanupTesters: () => Promise<void>;
62
62
  cdpEvent: (event: string, payload: unknown) => void;
63
63
  resolveManualMock: (url: string) => Promise<{
64
64
  url: string