@vitest/browser 3.1.0-beta.2 → 3.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/context.d.ts +2 -1
- package/dist/client/.vite/manifest.json +1 -1
- package/dist/client/__vitest__/assets/index-B0KEk_KY.css +1 -0
- package/dist/client/__vitest__/assets/index-BLZJq7cG.js +52 -0
- package/dist/client/__vitest__/index.html +2 -2
- package/dist/client/__vitest_browser__/tester-DiLSqOx4.js +3431 -0
- package/dist/client/tester/tester.html +1 -1
- package/dist/client.js +18 -0
- package/dist/context.js +5 -5
- package/dist/expect-element.js +25 -0
- package/dist/index-DjDyxzt8.js +1 -0
- package/dist/index.d.ts +10 -1
- package/dist/index.js +83 -8
- package/dist/locators/index.d.ts +61 -0
- package/dist/locators/index.js +1 -4
- package/dist/locators/playwright.js +1 -114
- package/dist/locators/preview.js +1 -78
- package/dist/locators/webdriverio.js +1 -154
- package/dist/providers.js +2 -1
- package/dist/public-utils-xf4CCUzp.js +6 -0
- package/dist/utils.js +1 -3
- package/dist/{webdriver-BP2w_ajA.js → webdriver-2iYWIzBv.js} +135 -3
- package/jest-dom.d.ts +623 -712
- package/matchers.d.ts +4 -4
- package/package.json +14 -16
- package/dist/client/__vitest__/assets/index-Bne9c1R6.css +0 -1
- package/dist/client/__vitest__/assets/index-C3wX9Cb1.js +0 -52
- package/dist/client/__vitest_browser__/tester-DRF-LncV.js +0 -16365
- package/dist/index-VvsEiykv.js +0 -327
- package/dist/public-utils-4WiYB3_6.js +0 -5559
|
@@ -5,7 +5,7 @@
|
|
|
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-
|
|
8
|
+
<script type="module" crossorigin src="/__vitest_browser__/tester-DiLSqOx4.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/__vitest_browser__/utils-CNTxSNQV.js">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
package/dist/client.js
CHANGED
|
@@ -281,6 +281,24 @@ function createClient() {
|
|
|
281
281
|
return;
|
|
282
282
|
}
|
|
283
283
|
cdp.emit(event, payload);
|
|
284
|
+
},
|
|
285
|
+
async resolveManualMock(url) {
|
|
286
|
+
const mocker = globalThis.__vitest_mocker__;
|
|
287
|
+
const responseId = getBrowserState().sessionId;
|
|
288
|
+
if (!mocker) {
|
|
289
|
+
return {
|
|
290
|
+
url,
|
|
291
|
+
keys: [],
|
|
292
|
+
responseId
|
|
293
|
+
};
|
|
294
|
+
}
|
|
295
|
+
const exports = await mocker.resolveFactoryModule(url);
|
|
296
|
+
const keys = Object.keys(exports);
|
|
297
|
+
return {
|
|
298
|
+
url,
|
|
299
|
+
keys,
|
|
300
|
+
responseId
|
|
301
|
+
};
|
|
284
302
|
}
|
|
285
303
|
}, {
|
|
286
304
|
post: (msg) => ctx.ws.send(msg),
|
package/dist/context.js
CHANGED
|
@@ -116,13 +116,13 @@ function processTimeoutOptions(options_) {
|
|
|
116
116
|
if (getWorkerState().config.browser.providerOptions.actionTimeout != null) {
|
|
117
117
|
return options_;
|
|
118
118
|
}
|
|
119
|
-
const
|
|
120
|
-
const startTime =
|
|
121
|
-
if (!
|
|
119
|
+
const runner = getBrowserState().runner;
|
|
120
|
+
const startTime = runner._currentTaskStartTime;
|
|
121
|
+
if (!startTime) {
|
|
122
122
|
return options_;
|
|
123
123
|
}
|
|
124
|
-
const timeout =
|
|
125
|
-
if (timeout === 0 || timeout === Number.POSITIVE_INFINITY) {
|
|
124
|
+
const timeout = runner._currentTaskTimeout;
|
|
125
|
+
if (timeout === 0 || timeout == null || timeout === Number.POSITIVE_INFINITY) {
|
|
126
126
|
return options_;
|
|
127
127
|
}
|
|
128
128
|
options_ = options_ || {};
|
|
@@ -0,0 +1,25 @@
|
|
|
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(`
|
|
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(`
|
|
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
|
+
`)}}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
|
+
`)}}}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
|
+
`)}}}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
|
+
`)}}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
|
+
`)}}}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(`
|
|
11
|
+
`)}}}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
|
+
`)}}}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
|
+
`)}}}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
|
+
`)].join(`
|
|
15
|
+
`)}}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
|
+
|
|
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
|
+
`)}}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
|
+
|
|
22
|
+
`)}}}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
|
+
`)}}}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});
|
|
@@ -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(`#tester-ui`);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,getIframeScale as a,convertElementToCssSelector as c,getBrowserState as g,processTimeoutOptions as p,selectorEngine as s};
|
package/dist/index.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import { CDPSession, BrowserServerState as BrowserServerState$1, ProjectBrowser
|
|
|
3
3
|
import { StackTraceParserOptions } from '@vitest/utils/source-map';
|
|
4
4
|
import { ViteDevServer, HtmlTagDescriptor } from 'vite';
|
|
5
5
|
import { CancelReason, RunnerTestFile, AfterSuiteRunMeta, UserConsoleLog, SnapshotResult, SerializedConfig, ErrorWithDiff, ParsedStack } from 'vitest';
|
|
6
|
+
import { MockedModuleSerialized } from '@vitest/mocker';
|
|
6
7
|
import { ServerIdResolution, ServerMockResolution } from '@vitest/mocker/node';
|
|
7
8
|
import { TaskResultPack, TaskEventPack } from '@vitest/runner';
|
|
8
9
|
|
|
@@ -49,6 +50,9 @@ interface WebSocketBrowserHandlers {
|
|
|
49
50
|
mappings: ""
|
|
50
51
|
} | undefined;
|
|
51
52
|
wdioSwitchContext: (direction: "iframe" | "parent") => void;
|
|
53
|
+
registerMock: (sessionId: string, mock: MockedModuleSerialized) => void;
|
|
54
|
+
unregisterMock: (sessionId: string, id: string) => void;
|
|
55
|
+
clearMocks: (sessionId: string) => void;
|
|
52
56
|
sendCdpEvent: (sessionId: string, event: string, payload?: Record<string, unknown>) => unknown;
|
|
53
57
|
trackCdpEvent: (sessionId: string, type: "on" | "once" | "off", event: string, listenerId: string) => void;
|
|
54
58
|
}
|
|
@@ -56,6 +60,11 @@ interface WebSocketBrowserEvents {
|
|
|
56
60
|
onCancel: (reason: CancelReason) => void;
|
|
57
61
|
createTesters: (files: string[]) => Promise<void>;
|
|
58
62
|
cdpEvent: (event: string, payload: unknown) => void;
|
|
63
|
+
resolveManualMock: (url: string) => Promise<{
|
|
64
|
+
url: string
|
|
65
|
+
keys: string[]
|
|
66
|
+
responseId: string
|
|
67
|
+
}>;
|
|
59
68
|
}
|
|
60
69
|
type WebSocketBrowserRPC = BirpcReturn<WebSocketBrowserEvents, WebSocketBrowserHandlers>;
|
|
61
70
|
interface SourceMap {
|
|
@@ -91,7 +100,6 @@ declare class ProjectBrowser implements ProjectBrowser$1 {
|
|
|
91
100
|
base: string;
|
|
92
101
|
testerHtml: Promise<string> | string;
|
|
93
102
|
testerFilepath: string;
|
|
94
|
-
locatorsUrl: string | undefined;
|
|
95
103
|
provider: BrowserProvider;
|
|
96
104
|
vitest: Vitest;
|
|
97
105
|
config: ResolvedConfig;
|
|
@@ -121,6 +129,7 @@ declare class ParentBrowserProject {
|
|
|
121
129
|
injectorJs: Promise<string> | string;
|
|
122
130
|
errorCatcherUrl: string;
|
|
123
131
|
locatorsUrl: string | undefined;
|
|
132
|
+
matchersUrl: string;
|
|
124
133
|
stateJs: Promise<string> | string;
|
|
125
134
|
commands: Record<string, BrowserCommand<any>>;
|
|
126
135
|
children: Set<ProjectBrowser>;
|
package/dist/index.js
CHANGED
|
@@ -1,22 +1,24 @@
|
|
|
1
|
+
import { ManualMockedModule, RedirectedModule, AutomockedModule, AutospiedModule, MockerRegistry } from '@vitest/mocker';
|
|
2
|
+
import { dynamicImportPlugin, ServerMockResolver, interceptorPlugin } from '@vitest/mocker/node';
|
|
1
3
|
import c from 'tinyrainbow';
|
|
2
4
|
import { getFilePoolName, distDir, resolveApiServerConfig, resolveFsAllow, isFileServingAllowed, createDebugger, isValidApiRequest, createViteLogger, createViteServer } from 'vitest/node';
|
|
3
5
|
import fs, { readFileSync, lstatSync, promises, existsSync } from 'node:fs';
|
|
4
6
|
import { createRequire } from 'node:module';
|
|
5
|
-
import { dynamicImportPlugin, ServerMockResolver } from '@vitest/mocker/node';
|
|
6
7
|
import { slash as slash$1, toArray } from '@vitest/utils';
|
|
7
8
|
import MagicString from 'magic-string';
|
|
8
9
|
import sirv from 'sirv';
|
|
10
|
+
import * as vite from 'vite';
|
|
9
11
|
import { coverageConfigDefaults } from 'vitest/config';
|
|
10
12
|
import { fileURLToPath } from 'node:url';
|
|
11
13
|
import crypto from 'node:crypto';
|
|
12
14
|
import { mkdir, readFile as readFile$1 } from 'node:fs/promises';
|
|
13
15
|
import { parseErrorStacktrace, parseStacktrace } from '@vitest/utils/source-map';
|
|
14
|
-
import { P as PlaywrightBrowserProvider, W as WebdriverBrowserProvider } from './webdriver-
|
|
16
|
+
import { P as PlaywrightBrowserProvider, W as WebdriverBrowserProvider } from './webdriver-2iYWIzBv.js';
|
|
15
17
|
import { resolve as resolve$1, dirname as dirname$1, basename as basename$1, normalize as normalize$1 } from 'node:path';
|
|
16
18
|
import { WebSocketServer } from 'ws';
|
|
17
19
|
import * as nodeos from 'node:os';
|
|
18
20
|
|
|
19
|
-
var version = "3.1.
|
|
21
|
+
var version = "3.1.1";
|
|
20
22
|
|
|
21
23
|
const _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
|
|
22
24
|
function normalizeWindowsPath(input = "") {
|
|
@@ -942,6 +944,14 @@ body {
|
|
|
942
944
|
},
|
|
943
945
|
injectTo: "head"
|
|
944
946
|
},
|
|
947
|
+
{
|
|
948
|
+
tag: "script",
|
|
949
|
+
attrs: {
|
|
950
|
+
type: "module",
|
|
951
|
+
src: parentServer.matchersUrl
|
|
952
|
+
},
|
|
953
|
+
injectTo: "head"
|
|
954
|
+
},
|
|
945
955
|
parentServer.locatorsUrl ? {
|
|
946
956
|
tag: "script",
|
|
947
957
|
attrs: {
|
|
@@ -967,7 +977,17 @@ body {
|
|
|
967
977
|
{
|
|
968
978
|
name: "vitest:browser:support-testing-library",
|
|
969
979
|
config() {
|
|
970
|
-
|
|
980
|
+
const rolldownPlugin = {
|
|
981
|
+
name: "vue-test-utils-rewrite",
|
|
982
|
+
resolveId: {
|
|
983
|
+
filter: { id: /^@vue\/(test-utils|compiler-core)$/ },
|
|
984
|
+
handler(source, importer) {
|
|
985
|
+
const resolved = getRequire().resolve(source, { paths: [importer] });
|
|
986
|
+
return resolved;
|
|
987
|
+
}
|
|
988
|
+
}
|
|
989
|
+
};
|
|
990
|
+
const esbuildPlugin = {
|
|
971
991
|
name: "test-utils-rewrite",
|
|
972
992
|
setup(build) {
|
|
973
993
|
build.onResolve({ filter: /^@vue\/(test-utils|compiler-core)$/ }, (args) => {
|
|
@@ -975,7 +995,8 @@ body {
|
|
|
975
995
|
return { path: resolved };
|
|
976
996
|
});
|
|
977
997
|
}
|
|
978
|
-
}
|
|
998
|
+
};
|
|
999
|
+
return { optimizeDeps: "rolldownVersion" in vite ? { rollupOptions: { plugins: [rolldownPlugin] } } : { esbuildOptions: { plugins: [esbuildPlugin] } } };
|
|
979
1000
|
}
|
|
980
1001
|
}
|
|
981
1002
|
];
|
|
@@ -2497,7 +2518,6 @@ class BrowserServerState {
|
|
|
2497
2518
|
class ProjectBrowser {
|
|
2498
2519
|
testerHtml;
|
|
2499
2520
|
testerFilepath;
|
|
2500
|
-
locatorsUrl;
|
|
2501
2521
|
provider;
|
|
2502
2522
|
vitest;
|
|
2503
2523
|
config;
|
|
@@ -2577,6 +2597,7 @@ class ParentBrowserProject {
|
|
|
2577
2597
|
injectorJs;
|
|
2578
2598
|
errorCatcherUrl;
|
|
2579
2599
|
locatorsUrl;
|
|
2600
|
+
matchersUrl;
|
|
2580
2601
|
stateJs;
|
|
2581
2602
|
commands = {};
|
|
2582
2603
|
children = new Set();
|
|
@@ -2651,6 +2672,7 @@ class ParentBrowserProject {
|
|
|
2651
2672
|
if (builtinProviders.includes(providerName)) {
|
|
2652
2673
|
this.locatorsUrl = join("/@fs/", distRoot, "locators", `${providerName}.js`);
|
|
2653
2674
|
}
|
|
2675
|
+
this.matchersUrl = join("/@fs/", distRoot, "expect-element.js");
|
|
2654
2676
|
this.stateJs = readFile$1(resolve(distRoot, "state.js"), "utf-8").then((js) => this.stateJs = js);
|
|
2655
2677
|
}
|
|
2656
2678
|
setServer(vite) {
|
|
@@ -2886,7 +2908,7 @@ function nanoid(size = 21) {
|
|
|
2886
2908
|
|
|
2887
2909
|
const debug$1 = createDebugger("vitest:browser:api");
|
|
2888
2910
|
const BROWSER_API_PATH = "/__vitest_browser_api__";
|
|
2889
|
-
function setupBrowserRpc(globalServer) {
|
|
2911
|
+
function setupBrowserRpc(globalServer, defaultMockerRegistry) {
|
|
2890
2912
|
const vite = globalServer.vite;
|
|
2891
2913
|
const vitest = globalServer.vitest;
|
|
2892
2914
|
const wss = new WebSocketServer({ noServer: true });
|
|
@@ -2949,6 +2971,7 @@ function setupBrowserRpc(globalServer) {
|
|
|
2949
2971
|
}
|
|
2950
2972
|
function setupClient(project, rpcId, ws, method) {
|
|
2951
2973
|
const mockResolver = new ServerMockResolver(globalServer.vite, { moduleDirectories: project.config.server?.deps?.moduleDirectories });
|
|
2974
|
+
const mocker = project.browser?.provider.mocker;
|
|
2952
2975
|
const rpc = createBirpc({
|
|
2953
2976
|
async onUnhandledError(error, type) {
|
|
2954
2977
|
if (error && typeof error === "object") {
|
|
@@ -3075,6 +3098,55 @@ function setupBrowserRpc(globalServer) {
|
|
|
3075
3098
|
invalidate(ids) {
|
|
3076
3099
|
return mockResolver.invalidate(ids);
|
|
3077
3100
|
},
|
|
3101
|
+
async registerMock(sessionId, module) {
|
|
3102
|
+
if (!mocker) {
|
|
3103
|
+
mockResolver.invalidate([module.id]);
|
|
3104
|
+
if (module.type === "manual") {
|
|
3105
|
+
const mock = ManualMockedModule.fromJSON(module, async () => {
|
|
3106
|
+
try {
|
|
3107
|
+
const { keys } = await rpc.resolveManualMock(module.url);
|
|
3108
|
+
return Object.fromEntries(keys.map((key) => [key, null]));
|
|
3109
|
+
} catch (err) {
|
|
3110
|
+
vitest.state.catchError(err, "Manual Mock Resolver Error");
|
|
3111
|
+
return {};
|
|
3112
|
+
}
|
|
3113
|
+
});
|
|
3114
|
+
defaultMockerRegistry.add(mock);
|
|
3115
|
+
} else {
|
|
3116
|
+
if (module.type === "redirect") {
|
|
3117
|
+
const redirectUrl = new URL(module.redirect);
|
|
3118
|
+
module.redirect = join(vite.config.root, redirectUrl.pathname);
|
|
3119
|
+
}
|
|
3120
|
+
defaultMockerRegistry.register(module);
|
|
3121
|
+
}
|
|
3122
|
+
return;
|
|
3123
|
+
}
|
|
3124
|
+
if (module.type === "manual") {
|
|
3125
|
+
const manualModule = ManualMockedModule.fromJSON(module, async () => {
|
|
3126
|
+
const { keys } = await rpc.resolveManualMock(module.url);
|
|
3127
|
+
return Object.fromEntries(keys.map((key) => [key, null]));
|
|
3128
|
+
});
|
|
3129
|
+
await mocker.register(sessionId, manualModule);
|
|
3130
|
+
} else if (module.type === "redirect") {
|
|
3131
|
+
await mocker.register(sessionId, RedirectedModule.fromJSON(module));
|
|
3132
|
+
} else if (module.type === "automock") {
|
|
3133
|
+
await mocker.register(sessionId, AutomockedModule.fromJSON(module));
|
|
3134
|
+
} else if (module.type === "autospy") {
|
|
3135
|
+
await mocker.register(sessionId, AutospiedModule.fromJSON(module));
|
|
3136
|
+
}
|
|
3137
|
+
},
|
|
3138
|
+
clearMocks(sessionId) {
|
|
3139
|
+
if (!mocker) {
|
|
3140
|
+
return defaultMockerRegistry.clear();
|
|
3141
|
+
}
|
|
3142
|
+
return mocker.clear(sessionId);
|
|
3143
|
+
},
|
|
3144
|
+
unregisterMock(sessionId, id) {
|
|
3145
|
+
if (!mocker) {
|
|
3146
|
+
return defaultMockerRegistry.delete(id);
|
|
3147
|
+
}
|
|
3148
|
+
return mocker.delete(sessionId, id);
|
|
3149
|
+
},
|
|
3078
3150
|
async sendCdpEvent(sessionId, event, payload) {
|
|
3079
3151
|
const cdp = await globalServer.ensureCDPHandler(sessionId, rpcId);
|
|
3080
3152
|
return cdp.send(event, payload);
|
|
@@ -3249,6 +3321,7 @@ async function createBrowserServer(project, configFile, prePlugins = [], postPlu
|
|
|
3249
3321
|
const configPath = typeof configFile === "string" ? configFile : false;
|
|
3250
3322
|
const logLevel = process.env.VITEST_BROWSER_DEBUG ?? "info";
|
|
3251
3323
|
const logger = createViteLogger(project.vitest.logger, logLevel, { allowClearScreen: false });
|
|
3324
|
+
const mockerRegistry = new MockerRegistry();
|
|
3252
3325
|
const vite = await createViteServer({
|
|
3253
3326
|
...project.options,
|
|
3254
3327
|
base: "/",
|
|
@@ -3264,6 +3337,7 @@ async function createBrowserServer(project, configFile, prePlugins = [], postPlu
|
|
|
3264
3337
|
},
|
|
3265
3338
|
mode: project.config.mode,
|
|
3266
3339
|
configFile: configPath,
|
|
3340
|
+
configLoader: project.vite.config.inlineConfig.configLoader,
|
|
3267
3341
|
server: {
|
|
3268
3342
|
hmr: false,
|
|
3269
3343
|
watch: null
|
|
@@ -3272,11 +3346,12 @@ async function createBrowserServer(project, configFile, prePlugins = [], postPlu
|
|
|
3272
3346
|
...prePlugins,
|
|
3273
3347
|
...project.options?.plugins || [],
|
|
3274
3348
|
BrowserPlugin(server),
|
|
3349
|
+
interceptorPlugin({ registry: mockerRegistry }),
|
|
3275
3350
|
...postPlugins
|
|
3276
3351
|
]
|
|
3277
3352
|
});
|
|
3278
3353
|
await vite.listen();
|
|
3279
|
-
setupBrowserRpc(server);
|
|
3354
|
+
setupBrowserRpc(server, mockerRegistry);
|
|
3280
3355
|
return server;
|
|
3281
3356
|
}
|
|
3282
3357
|
|
package/dist/locators/index.d.ts
CHANGED
|
@@ -155,6 +155,33 @@ declare class SelectorEvaluatorImpl implements SelectorEvaluator {
|
|
|
155
155
|
private _getEngine;
|
|
156
156
|
}
|
|
157
157
|
|
|
158
|
+
/**
|
|
159
|
+
* Copyright (c) Microsoft Corporation.
|
|
160
|
+
*
|
|
161
|
+
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
162
|
+
* you may not use this file except in compliance with the License.
|
|
163
|
+
* You may obtain a copy of the License at
|
|
164
|
+
*
|
|
165
|
+
* http://www.apache.org/licenses/LICENSE-2.0
|
|
166
|
+
*
|
|
167
|
+
* Unless required by applicable law or agreed to in writing, software
|
|
168
|
+
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
169
|
+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
170
|
+
* See the License for the specific language governing permissions and
|
|
171
|
+
* limitations under the License.
|
|
172
|
+
*/
|
|
173
|
+
interface ByRoleOptions {
|
|
174
|
+
checked?: boolean;
|
|
175
|
+
disabled?: boolean;
|
|
176
|
+
exact?: boolean;
|
|
177
|
+
expanded?: boolean;
|
|
178
|
+
includeHidden?: boolean;
|
|
179
|
+
level?: number;
|
|
180
|
+
name?: string | RegExp;
|
|
181
|
+
pressed?: boolean;
|
|
182
|
+
selected?: boolean;
|
|
183
|
+
}
|
|
184
|
+
|
|
158
185
|
/**
|
|
159
186
|
* Copyright (c) Microsoft Corporation.
|
|
160
187
|
*
|
|
@@ -191,6 +218,40 @@ declare class Ivya {
|
|
|
191
218
|
queryLocatorSelector(locator: string, root?: Node, strict?: boolean): Element | null;
|
|
192
219
|
queryLocatorSelectorAll(locator: string, root?: Node): Element[];
|
|
193
220
|
querySelector(selector: ParsedSelector, root: Node, strict?: boolean): Element | null;
|
|
221
|
+
queryAllByRole(text: string, options?: ByRoleOptions, container?: Node): Element[];
|
|
222
|
+
queryAllByLabelText(text: string | RegExp, options?: {
|
|
223
|
+
exact?: boolean;
|
|
224
|
+
}, container?: Node): Element[];
|
|
225
|
+
queryAllByTestId(text: string | RegExp, container?: Node): Element[];
|
|
226
|
+
queryAllByText(text: string | RegExp, options?: {
|
|
227
|
+
exact?: boolean;
|
|
228
|
+
}, container?: Node): Element[];
|
|
229
|
+
queryAllByTitle(text: string | RegExp, options?: {
|
|
230
|
+
exact?: boolean;
|
|
231
|
+
}, container?: Node): Element[];
|
|
232
|
+
queryAllByPlaceholder(text: string | RegExp, options?: {
|
|
233
|
+
exact?: boolean;
|
|
234
|
+
}, container?: Node): Element[];
|
|
235
|
+
queryAllByAltText(text: string | RegExp, options?: {
|
|
236
|
+
exact?: boolean;
|
|
237
|
+
}, container?: Node): Element[];
|
|
238
|
+
queryByRole(text: string, options?: ByRoleOptions, container?: Node): Element | null;
|
|
239
|
+
queryByLabelText(text: string | RegExp, options?: {
|
|
240
|
+
exact?: boolean;
|
|
241
|
+
}, container?: Node): Element | null;
|
|
242
|
+
queryByTestId(text: string | RegExp, container?: Node): Element | null;
|
|
243
|
+
queryByText(text: string | RegExp, options?: {
|
|
244
|
+
exact?: boolean;
|
|
245
|
+
}, container?: Node): Element | null;
|
|
246
|
+
queryByTitle(text: string | RegExp, options?: {
|
|
247
|
+
exact?: boolean;
|
|
248
|
+
}, container?: Node): Element | null;
|
|
249
|
+
queryByPlaceholder(text: string | RegExp, options?: {
|
|
250
|
+
exact?: boolean;
|
|
251
|
+
}, container?: Node): Element | null;
|
|
252
|
+
queryByAltText(text: string | RegExp, options?: {
|
|
253
|
+
exact?: boolean;
|
|
254
|
+
}, container?: Node): Element | null;
|
|
194
255
|
private strictModeViolationError;
|
|
195
256
|
generateSelectorSimple(targetElement: Element, options?: GenerateSelectorOptions): string;
|
|
196
257
|
parseSelector(selector: string): ParsedSelector;
|
package/dist/locators/index.js
CHANGED
|
@@ -1,4 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import '../public-utils-4WiYB3_6.js';
|
|
3
|
-
export { L as Locator, s as selectorEngine } from '../index-VvsEiykv.js';
|
|
4
|
-
import 'vitest/utils';
|
|
1
|
+
import"@vitest/browser/context";import"../public-utils-xf4CCUzp.js";export{L as Locator,s as selectorEngine}from"../index-DjDyxzt8.js";import"vitest/utils";
|
|
@@ -1,114 +1 @@
|
|
|
1
|
-
import
|
|
2
|
-
import { g as getByTitleSelector, a as getByTextSelector, b as getByPlaceholderSelector, c as getByAltTextSelector, d as getByTestIdSelector, e as getByRoleSelector, f as getByLabelSelector } from '../public-utils-4WiYB3_6.js';
|
|
3
|
-
import { s as selectorEngine, L as Locator, p as processTimeoutOptions, g as getBrowserState, a as getIframeScale } from '../index-VvsEiykv.js';
|
|
4
|
-
import 'vitest/utils';
|
|
5
|
-
|
|
6
|
-
page.extend({
|
|
7
|
-
getByLabelText(text, options) {
|
|
8
|
-
return new PlaywrightLocator(getByLabelSelector(text, options));
|
|
9
|
-
},
|
|
10
|
-
getByRole(role, options) {
|
|
11
|
-
return new PlaywrightLocator(getByRoleSelector(role, options));
|
|
12
|
-
},
|
|
13
|
-
getByTestId(testId) {
|
|
14
|
-
return new PlaywrightLocator(getByTestIdSelector(server.config.browser.locators.testIdAttribute, testId));
|
|
15
|
-
},
|
|
16
|
-
getByAltText(text, options) {
|
|
17
|
-
return new PlaywrightLocator(getByAltTextSelector(text, options));
|
|
18
|
-
},
|
|
19
|
-
getByPlaceholder(text, options) {
|
|
20
|
-
return new PlaywrightLocator(getByPlaceholderSelector(text, options));
|
|
21
|
-
},
|
|
22
|
-
getByText(text, options) {
|
|
23
|
-
return new PlaywrightLocator(getByTextSelector(text, options));
|
|
24
|
-
},
|
|
25
|
-
getByTitle(title, options) {
|
|
26
|
-
return new PlaywrightLocator(getByTitleSelector(title, options));
|
|
27
|
-
},
|
|
28
|
-
elementLocator(element) {
|
|
29
|
-
return new PlaywrightLocator(selectorEngine.generateSelectorSimple(element), element);
|
|
30
|
-
}
|
|
31
|
-
});
|
|
32
|
-
class PlaywrightLocator extends Locator {
|
|
33
|
-
constructor(selector, _container) {
|
|
34
|
-
super();
|
|
35
|
-
this.selector = selector;
|
|
36
|
-
this._container = _container;
|
|
37
|
-
}
|
|
38
|
-
click(options) {
|
|
39
|
-
return super.click(processTimeoutOptions(processClickOptions(options)));
|
|
40
|
-
}
|
|
41
|
-
dblClick(options) {
|
|
42
|
-
return super.dblClick(processTimeoutOptions(processClickOptions(options)));
|
|
43
|
-
}
|
|
44
|
-
tripleClick(options) {
|
|
45
|
-
return super.tripleClick(processTimeoutOptions(processClickOptions(options)));
|
|
46
|
-
}
|
|
47
|
-
selectOptions(value, options) {
|
|
48
|
-
return super.selectOptions(value, processTimeoutOptions(options));
|
|
49
|
-
}
|
|
50
|
-
clear(options) {
|
|
51
|
-
return super.clear(processTimeoutOptions(options));
|
|
52
|
-
}
|
|
53
|
-
hover(options) {
|
|
54
|
-
return super.hover(processTimeoutOptions(processHoverOptions(options)));
|
|
55
|
-
}
|
|
56
|
-
upload(files, options) {
|
|
57
|
-
return super.upload(files, processTimeoutOptions(options));
|
|
58
|
-
}
|
|
59
|
-
fill(text, options) {
|
|
60
|
-
return super.fill(text, processTimeoutOptions(options));
|
|
61
|
-
}
|
|
62
|
-
dropTo(target, options) {
|
|
63
|
-
return super.dropTo(target, processTimeoutOptions(processDragAndDropOptions(options)));
|
|
64
|
-
}
|
|
65
|
-
locator(selector) {
|
|
66
|
-
return new PlaywrightLocator(`${this.selector} >> ${selector}`, this._container);
|
|
67
|
-
}
|
|
68
|
-
elementLocator(element) {
|
|
69
|
-
return new PlaywrightLocator(selectorEngine.generateSelectorSimple(element), element);
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
function processDragAndDropOptions(options_) {
|
|
73
|
-
if (!options_ || !getBrowserState().config.browser.ui) {
|
|
74
|
-
return options_;
|
|
75
|
-
}
|
|
76
|
-
const options = options_;
|
|
77
|
-
if (options.sourcePosition) {
|
|
78
|
-
options.sourcePosition = processPlaywrightPosition(options.sourcePosition);
|
|
79
|
-
}
|
|
80
|
-
if (options.targetPosition) {
|
|
81
|
-
options.targetPosition = processPlaywrightPosition(options.targetPosition);
|
|
82
|
-
}
|
|
83
|
-
return options_;
|
|
84
|
-
}
|
|
85
|
-
function processHoverOptions(options_) {
|
|
86
|
-
if (!options_ || !getBrowserState().config.browser.ui) {
|
|
87
|
-
return options_;
|
|
88
|
-
}
|
|
89
|
-
const options = options_;
|
|
90
|
-
if (options.position) {
|
|
91
|
-
options.position = processPlaywrightPosition(options.position);
|
|
92
|
-
}
|
|
93
|
-
return options_;
|
|
94
|
-
}
|
|
95
|
-
function processClickOptions(options_) {
|
|
96
|
-
if (!options_ || !getBrowserState().config.browser.ui) {
|
|
97
|
-
return options_;
|
|
98
|
-
}
|
|
99
|
-
const options = options_;
|
|
100
|
-
if (options.position) {
|
|
101
|
-
options.position = processPlaywrightPosition(options.position);
|
|
102
|
-
}
|
|
103
|
-
return options;
|
|
104
|
-
}
|
|
105
|
-
function processPlaywrightPosition(position) {
|
|
106
|
-
const scale = getIframeScale();
|
|
107
|
-
if (position.x != null) {
|
|
108
|
-
position.x *= scale;
|
|
109
|
-
}
|
|
110
|
-
if (position.y != null) {
|
|
111
|
-
position.y *= scale;
|
|
112
|
-
}
|
|
113
|
-
return position;
|
|
114
|
-
}
|
|
1
|
+
import{page,server}from"@vitest/browser/context";import{g as getByTitleSelector,a as getByTextSelector,b as getByPlaceholderSelector,c as getByAltTextSelector,d as getByTestIdSelector,e as getByRoleSelector,f as getByLabelSelector}from"../public-utils-xf4CCUzp.js";import{s as selectorEngine,L as Locator,p as processTimeoutOptions,g as getBrowserState,a as getIframeScale}from"../index-DjDyxzt8.js";import"vitest/utils";page.extend({getByLabelText(e,v){return new PlaywrightLocator(getByLabelSelector(e,v))},getByRole(e,v){return new PlaywrightLocator(getByRoleSelector(e,v))},getByTestId(e){return new PlaywrightLocator(getByTestIdSelector(server.config.browser.locators.testIdAttribute,e))},getByAltText(e,v){return new PlaywrightLocator(getByAltTextSelector(e,v))},getByPlaceholder(e,v){return new PlaywrightLocator(getByPlaceholderSelector(e,v))},getByText(e,v){return new PlaywrightLocator(getByTextSelector(e,v))},getByTitle(e,v){return new PlaywrightLocator(getByTitleSelector(e,v))},elementLocator(e){return new PlaywrightLocator(selectorEngine.generateSelectorSimple(e),e)}});class PlaywrightLocator extends Locator{constructor(e,v){super(),this.selector=e,this._container=v}click(e){return super.click(processTimeoutOptions(processClickOptions(e)))}dblClick(e){return super.dblClick(processTimeoutOptions(processClickOptions(e)))}tripleClick(e){return super.tripleClick(processTimeoutOptions(processClickOptions(e)))}selectOptions(e,v){return super.selectOptions(e,processTimeoutOptions(v))}clear(e){return super.clear(processTimeoutOptions(e))}hover(e){return super.hover(processTimeoutOptions(processHoverOptions(e)))}upload(e,v){return super.upload(e,processTimeoutOptions(v))}fill(e,v){return super.fill(e,processTimeoutOptions(v))}dropTo(e,v){return super.dropTo(e,processTimeoutOptions(processDragAndDropOptions(v)))}locator(e){return new PlaywrightLocator(`${this.selector} >> ${e}`,this._container)}elementLocator(e){return new PlaywrightLocator(selectorEngine.generateSelectorSimple(e),e)}}function processDragAndDropOptions(e){if(!e||!getBrowserState().config.browser.ui)return e;let v=e;return v.sourcePosition&&=processPlaywrightPosition(v.sourcePosition),v.targetPosition&&=processPlaywrightPosition(v.targetPosition),e}function processHoverOptions(e){if(!e||!getBrowserState().config.browser.ui)return e;let v=e;return v.position&&=processPlaywrightPosition(v.position),e}function processClickOptions(e){if(!e||!getBrowserState().config.browser.ui)return e;let v=e;return v.position&&=processPlaywrightPosition(v.position),v}function processPlaywrightPosition(e){let v=getIframeScale();return e.x!=null&&(e.x*=v),e.y!=null&&(e.y*=v),e}
|