@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.
- package/dist/client/.vite/manifest.json +6 -6
- package/dist/client/__vitest__/assets/{index-BjtzXzAw.js → index-DYFYwZ2-.js} +37 -38
- package/dist/client/__vitest__/index.html +1 -1
- package/dist/client/__vitest_browser__/{orchestrator-CQgVbcQq.js → orchestrator-BXzaDpYw.js} +244 -253
- package/dist/client/__vitest_browser__/{tester-BScMoGFI.js → tester-DabNvcOf.js} +200 -493
- package/dist/client/__vitest_browser__/{utils-Owv5OOOf.js → utils-BNwnRrZR.js} +8 -4
- package/dist/client/orchestrator.html +2 -2
- package/dist/client/tester/tester.html +2 -2
- package/dist/expect-element.js +3 -2
- package/dist/index.d.ts +7 -7
- package/dist/index.js +8 -9
- package/dist/locators/index.d.ts +3 -3
- package/dist/types.d.ts +5 -5
- package/jest-dom.d.ts +46 -0
- package/package.json +14 -14
|
@@ -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
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
+
getBrowserState as a,
|
|
193
|
+
getConfig as b,
|
|
194
|
+
resolve as c,
|
|
195
|
+
getWorkerState as d,
|
|
192
196
|
executor as e,
|
|
193
|
-
|
|
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-
|
|
30
|
-
<link rel="modulepreload" crossorigin href="/__vitest_browser__/utils-
|
|
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-
|
|
9
|
-
<link rel="modulepreload" crossorigin href="/__vitest_browser__/utils-
|
|
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>
|
package/dist/expect-element.js
CHANGED
|
@@ -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
|
|
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 {
|
|
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.
|
|
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}
|
|
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}"
|
|
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}
|
|
413
|
-
__VITEST_ERROR_CATCHER__: `<script type="module" src="${globalServer.errorCatcherUrl}"
|
|
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:
|
|
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
|
|
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 })
|
package/dist/locators/index.d.ts
CHANGED
|
@@ -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.
|
|
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.
|
|
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.
|
|
89
|
-
"@vitest/mocker": "4.0.0-beta.
|
|
90
|
-
"@vitest/utils": "4.0.0-beta.
|
|
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.
|
|
95
|
-
"@wdio/types": "^9.
|
|
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.
|
|
103
|
-
"playwright-core": "^1.
|
|
102
|
+
"playwright": "^1.54.1",
|
|
103
|
+
"playwright-core": "^1.54.1",
|
|
104
104
|
"safaridriver": "^1.0.0",
|
|
105
|
-
"webdriverio": "^9.
|
|
106
|
-
"@vitest/ui": "4.0.0-beta.
|
|
107
|
-
"@vitest/runner": "4.0.0-beta.
|
|
108
|
-
"vitest": "4.0.0-beta.
|
|
109
|
-
"@vitest/ws-client": "4.0.0-beta.
|
|
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",
|