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

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.
@@ -35,6 +35,9 @@
35
35
  fetch(link.href, fetchOpts);
36
36
  }
37
37
  })();
38
+ function getDefaultExportFromCjs(x) {
39
+ return x && x.__esModule && Object.prototype.hasOwnProperty.call(x, "default") ? x["default"] : x;
40
+ }
38
41
  const _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
39
42
  function normalizeWindowsPath(input = "") {
40
43
  if (!input) {
@@ -186,10 +189,11 @@ function getWorkerState() {
186
189
  return state;
187
190
  }
188
191
  export {
189
- getConfig as a,
190
- resolve as b,
191
- getWorkerState as c,
192
+ getBrowserState as a,
193
+ getConfig as b,
194
+ resolve as c,
195
+ getWorkerState as d,
192
196
  executor as e,
193
- getBrowserState as g,
197
+ getDefaultExportFromCjs as g,
194
198
  relative as r
195
199
  };
@@ -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-CQgVbcQq.js"></script>
30
- <link rel="modulepreload" crossorigin href="/__vitest_browser__/utils-Owv5OOOf.js">
29
+ <script type="module" crossorigin src="/__vitest_browser__/orchestrator-BXzaDpYw.js"></script>
30
+ <link rel="modulepreload" crossorigin href="/__vitest_browser__/utils-BNwnRrZR.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-BScMoGFI.js"></script>
9
- <link rel="modulepreload" crossorigin href="/__vitest_browser__/utils-Owv5OOOf.js">
8
+ <script type="module" crossorigin src="/__vitest_browser__/tester-DabNvcOf.js"></script>
9
+ <link rel="modulepreload" crossorigin href="/__vitest_browser__/utils-BNwnRrZR.js">
10
10
  </head>
11
11
  <body>
12
12
  </body>
@@ -7,7 +7,8 @@ import{expect,chai}from"vitest";import{k as kAriaCheckedRoles,i as getAriaChecke
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)}
@@ -22,4 +23,4 @@ import{expect,chai}from"vitest";import{k as kAriaCheckedRoles,i as getAriaChecke
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 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};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});
package/dist/index.d.ts CHANGED
@@ -43,11 +43,11 @@ interface WebSocketBrowserHandlers {
43
43
  resolveId: (id: string, importer?: string) => Promise<ServerIdResolution | null>;
44
44
  triggerCommand: <T>(sessionId: string, command: string, testPath: string | undefined, payload: unknown[]) => Promise<T>;
45
45
  resolveMock: (id: string, importer: string, options: {
46
- mock: "spy" | "factory" | "auto"
46
+ mock: "spy" | "factory" | "auto";
47
47
  }) => Promise<ServerMockResolution>;
48
48
  invalidate: (ids: string[]) => void;
49
49
  getBrowserFileSourceMap: (id: string) => SourceMap | null | {
50
- mappings: ""
50
+ mappings: "";
51
51
  } | undefined;
52
52
  wdioSwitchContext: (direction: "iframe" | "parent") => void;
53
53
  registerMock: (sessionId: string, mock: MockedModuleSerialized) => void;
@@ -63,9 +63,9 @@ interface WebSocketBrowserEvents {
63
63
  cleanupTesters: () => Promise<void>;
64
64
  cdpEvent: (event: string, payload: unknown) => void;
65
65
  resolveManualMock: (url: string) => Promise<{
66
- url: string
67
- keys: string[]
68
- responseId: string
66
+ url: string;
67
+ keys: string[];
68
+ responseId: string;
69
69
  }>;
70
70
  }
71
71
  type WebSocketBrowserRPC = BirpcReturn<WebSocketBrowserEvents, WebSocketBrowserHandlers>;
@@ -151,8 +151,8 @@ declare class ParentBrowserProject {
151
151
  removeCDPHandler(sessionId: string): void;
152
152
  formatScripts(scripts: BrowserScript[] | undefined): Promise<HtmlTagDescriptor[]>;
153
153
  resolveTesterUrl(pathname: string): {
154
- sessionId: string
155
- testFile: string
154
+ sessionId: string;
155
+ testFile: string;
156
156
  };
157
157
  private retrieveSourceMapURL;
158
158
  }
package/dist/index.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { ManualMockedModule, RedirectedModule, AutomockedModule, AutospiedModule, MockerRegistry } from '@vitest/mocker';
2
2
  import { dynamicImportPlugin, ServerMockResolver, interceptorPlugin } from '@vitest/mocker/node';
3
3
  import c from 'tinyrainbow';
4
- import { getFilePoolName, distDir, resolveApiServerConfig, resolveFsAllow, isFileServingAllowed, createDebugger, isValidApiRequest, createViteLogger, createViteServer } from 'vitest/node';
4
+ import { distDir, resolveApiServerConfig, resolveFsAllow, isFileServingAllowed, createDebugger, isValidApiRequest, createViteLogger, createViteServer } from 'vitest/node';
5
5
  import fs, { readFileSync, lstatSync, promises, existsSync } from 'node:fs';
6
6
  import { createRequire } from 'node:module';
7
7
  import { slash as slash$1, toArray, createDefer } from '@vitest/utils';
@@ -19,7 +19,7 @@ import { WebSocketServer } from 'ws';
19
19
  import * as nodeos from 'node:os';
20
20
  import { performance } from 'node:perf_hooks';
21
21
 
22
- var version = "4.0.0-beta.1";
22
+ var version = "4.0.0-beta.3";
23
23
 
24
24
  const _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
25
25
  function normalizeWindowsPath(input = "") {
@@ -388,7 +388,7 @@ async function resolveOrchestrator(globalServer, url, res) {
388
388
  for (const attr in script.attrs || {}) {
389
389
  html += `${attr}="${script.attrs[attr]}" `;
390
390
  }
391
- html += `>${script.children}</script>`;
391
+ html += `>${script.children}<\/script>`;
392
392
  return html;
393
393
  }).join("\n");
394
394
  }
@@ -402,15 +402,15 @@ async function resolveOrchestrator(globalServer, url, res) {
402
402
  "{__VITEST_INJECTOR__}",
403
403
  "{__VITEST_ERROR_CATCHER__}",
404
404
  "{__VITEST_SCRIPTS__}",
405
- `<script type="module" crossorigin src="${base}${jsEntry}"></script>`
405
+ `<script type="module" crossorigin src="${base}${jsEntry}"><\/script>`
406
406
  ].join("\n"));
407
407
  }
408
408
  return replacer(baseHtml, {
409
409
  __VITEST_FAVICON__: globalServer.faviconUrl,
410
410
  __VITEST_TITLE__: "Vitest Browser Runner",
411
411
  __VITEST_SCRIPTS__: globalServer.orchestratorScripts,
412
- __VITEST_INJECTOR__: `<script type="module">${injector}</script>`,
413
- __VITEST_ERROR_CATCHER__: `<script type="module" src="${globalServer.errorCatcherUrl}"></script>`,
412
+ __VITEST_INJECTOR__: `<script type="module">${injector}<\/script>`,
413
+ __VITEST_ERROR_CATCHER__: `<script type="module" src="${globalServer.errorCatcherUrl}"><\/script>`,
414
414
  __VITEST_SESSION_ID__: JSON.stringify(sessionId)
415
415
  });
416
416
  }
@@ -680,8 +680,7 @@ var BrowserPlugin = (parentServer, base = "/") => {
680
680
  // this plugin can be used in different projects, but all of them
681
681
  // have the same `include` pattern, so it doesn't matter which project we use
682
682
  const project = parentServer.project;
683
- const { testFiles: allTestFiles } = await project.globTestFiles();
684
- const browserTestFiles = allTestFiles.filter((file) => getFilePoolName(project, file) === "browser");
683
+ const { testFiles: browserTestFiles } = await project.globTestFiles();
685
684
  const setupFiles = toArray(project.config.setupFiles);
686
685
  // replace env values - cannot be reassign at runtime
687
686
  const define = {};
@@ -859,7 +858,7 @@ var BrowserPlugin = (parentServer, base = "/") => {
859
858
  return;
860
859
  }
861
860
  const s = new MagicString(code, { filename });
862
- s.prepend(`import.meta.vitest = __vitest_index__;\n`);
861
+ s.prepend(`Object.defineProperty(import.meta, 'vitest', { get() { return typeof __vitest_worker__ !== 'undefined' && __vitest_worker__.filepath === "${filename.replace(/"/g, "\\\"")}" ? __vitest_index__ : undefined } });\n`);
863
862
  return {
864
863
  code: s.toString(),
865
864
  map: s.generateMap({ hires: true })
@@ -297,10 +297,10 @@ declare abstract class Locator {
297
297
  dropTo(target: Locator, options?: UserEventDragAndDropOptions): Promise<void>;
298
298
  selectOptions(value: HTMLElement | HTMLElement[] | Locator | Locator[] | string | string[], options?: UserEventSelectOptions): Promise<void>;
299
299
  screenshot(options: Omit<LocatorScreenshotOptions, "base64"> & {
300
- base64: true
300
+ base64: true;
301
301
  }): Promise<{
302
- path: string
303
- base64: string
302
+ path: string;
303
+ base64: string;
304
304
  }>;
305
305
  screenshot(options?: LocatorScreenshotOptions): Promise<string>;
306
306
  protected abstract locator(selector: string): Locator;
package/dist/types.d.ts CHANGED
@@ -22,11 +22,11 @@ export interface WebSocketBrowserHandlers {
22
22
  resolveId: (id: string, importer?: string) => Promise<ServerIdResolution | null>;
23
23
  triggerCommand: <T>(sessionId: string, command: string, testPath: string | undefined, payload: unknown[]) => Promise<T>;
24
24
  resolveMock: (id: string, importer: string, options: {
25
- mock: "spy" | "factory" | "auto"
25
+ mock: "spy" | "factory" | "auto";
26
26
  }) => Promise<ServerMockResolution>;
27
27
  invalidate: (ids: string[]) => void;
28
28
  getBrowserFileSourceMap: (id: string) => SourceMap | null | {
29
- mappings: ""
29
+ mappings: "";
30
30
  } | undefined;
31
31
  wdioSwitchContext: (direction: "iframe" | "parent") => void;
32
32
  registerMock: (sessionId: string, mock: MockedModuleSerialized) => void;
@@ -52,9 +52,9 @@ export interface WebSocketBrowserEvents {
52
52
  cleanupTesters: () => Promise<void>;
53
53
  cdpEvent: (event: string, payload: unknown) => void;
54
54
  resolveManualMock: (url: string) => Promise<{
55
- url: string
56
- keys: string[]
57
- responseId: string
55
+ url: string;
56
+ keys: string[];
57
+ responseId: string;
58
58
  }>;
59
59
  }
60
60
  export type WebSocketBrowserRPC = BirpcReturn<WebSocketBrowserEvents, WebSocketBrowserHandlers>;
package/jest-dom.d.ts CHANGED
@@ -14,6 +14,52 @@ export interface TestingLibraryMatchers<E, R> {
14
14
  * @see https://vitest.dev/guide/browser/assertion-api#tobeinthedocument
15
15
  */
16
16
  toBeInTheDocument(): R
17
+ /**
18
+ * @description
19
+ * Assert whether an element is within the viewport or not.
20
+ *
21
+ * An element is considered to be in the viewport if any part of it intersects with the current viewport bounds.
22
+ * This matcher calculates the intersection ratio between the element and the viewport, similar to the
23
+ * IntersectionObserver API.
24
+ *
25
+ * The element must be in the document and have visible dimensions. Elements with display: none or
26
+ * visibility: hidden are considered not in viewport.
27
+ * @example
28
+ * <div
29
+ * data-testid="visible-element"
30
+ * style="position: absolute; top: 10px; left: 10px; width: 50px; height: 50px;"
31
+ * >
32
+ * Visible Element
33
+ * </div>
34
+ *
35
+ * <div
36
+ * data-testid="hidden-element"
37
+ * style="position: fixed; top: -100px; left: 10px; width: 50px; height: 50px;"
38
+ * >
39
+ * Hidden Element
40
+ * </div>
41
+ *
42
+ * <div
43
+ * data-testid="large-element"
44
+ * style="height: 400vh;"
45
+ * >
46
+ * Large Element
47
+ * </div>
48
+ *
49
+ * // Check if any part of element is in viewport
50
+ * await expect.element(page.getByTestId('visible-element')).toBeInViewport()
51
+ *
52
+ * // Check if element is outside viewport
53
+ * await expect.element(page.getByTestId('hidden-element')).not.toBeInViewport()
54
+ *
55
+ * // Check if at least 50% of element is visible
56
+ * await expect.element(page.getByTestId('large-element')).toBeInViewport({ ratio: 0.5 })
57
+ *
58
+ * // Check if element is completely visible
59
+ * await expect.element(page.getByTestId('visible-element')).toBeInViewport({ ratio: 1 })
60
+ * @see https://vitest.dev/guide/browser/assertion-api#tobeinviewport
61
+ */
62
+ toBeInViewport(options?: { ratio?: number }): R
17
63
  /**
18
64
  * @description
19
65
  * This allows you to check if an element is currently visible to the user.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vitest/browser",
3
3
  "type": "module",
4
- "version": "4.0.0-beta.1",
4
+ "version": "4.0.0-beta.3",
5
5
  "description": "Browser running for Vitest",
6
6
  "license": "MIT",
7
7
  "funding": "https://opencollective.com/vitest",
@@ -66,7 +66,7 @@
66
66
  "peerDependencies": {
67
67
  "playwright": "*",
68
68
  "webdriverio": "^7.0.0 || ^8.0.0 || ^9.0.0",
69
- "vitest": "4.0.0-beta.1"
69
+ "vitest": "4.0.0-beta.3"
70
70
  },
71
71
  "peerDependenciesMeta": {
72
72
  "playwright": {
@@ -85,28 +85,28 @@
85
85
  "magic-string": "^0.30.17",
86
86
  "sirv": "^3.0.1",
87
87
  "tinyrainbow": "^2.0.0",
88
- "ws": "^8.18.2",
89
- "@vitest/mocker": "4.0.0-beta.1",
90
- "@vitest/utils": "4.0.0-beta.1"
88
+ "ws": "^8.18.3",
89
+ "@vitest/mocker": "4.0.0-beta.3",
90
+ "@vitest/utils": "4.0.0-beta.3"
91
91
  },
92
92
  "devDependencies": {
93
93
  "@types/ws": "^8.18.1",
94
- "@wdio/protocols": "^9.15.0",
95
- "@wdio/types": "^9.15.0",
94
+ "@wdio/protocols": "^9.16.2",
95
+ "@wdio/types": "^9.16.2",
96
96
  "birpc": "2.4.0",
97
97
  "flatted": "^3.3.3",
98
98
  "ivya": "^1.7.0",
99
99
  "mime": "^4.0.7",
100
100
  "pathe": "^2.0.3",
101
101
  "periscopic": "^4.0.2",
102
- "playwright": "^1.53.0",
103
- "playwright-core": "^1.53.0",
102
+ "playwright": "^1.54.1",
103
+ "playwright-core": "^1.54.1",
104
104
  "safaridriver": "^1.0.0",
105
- "webdriverio": "^9.15.0",
106
- "@vitest/ui": "4.0.0-beta.1",
107
- "@vitest/runner": "4.0.0-beta.1",
108
- "vitest": "4.0.0-beta.1",
109
- "@vitest/ws-client": "4.0.0-beta.1"
105
+ "webdriverio": "^9.17.0",
106
+ "@vitest/ui": "4.0.0-beta.3",
107
+ "@vitest/runner": "4.0.0-beta.3",
108
+ "vitest": "4.0.0-beta.3",
109
+ "@vitest/ws-client": "4.0.0-beta.3"
110
110
  },
111
111
  "scripts": {
112
112
  "typecheck": "tsc -p ./src/client/tsconfig.json --noEmit",