@vitest/browser 4.0.4 → 4.0.6
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 +1 -1
- package/dist/client/.vite/manifest.json +1 -1
- package/dist/client/__vitest_browser__/{tester-BNxij3za.js → tester-CQlWpWwO.js} +1 -1
- package/dist/client/esm-client-injector.js +26 -15
- package/dist/client/tester/tester.html +1 -1
- package/dist/context.js +1 -1
- package/dist/expect-element.js +1 -1
- package/dist/index.js +1 -1
- package/dist/state.js +273 -105
- package/package.json +6 -6
package/context.d.ts
CHANGED
|
@@ -227,7 +227,7 @@ export interface UserEvent {
|
|
|
227
227
|
* @see {@link https://testing-library.com/docs/user-event/utility/#-selectoptions-deselectoptions} testing-library API
|
|
228
228
|
*/
|
|
229
229
|
selectOptions: (
|
|
230
|
-
element:
|
|
230
|
+
element: HTMLElement | SVGElement | Locator,
|
|
231
231
|
values: HTMLElement | HTMLElement[] | Locator | Locator[] | string | string[],
|
|
232
232
|
options?: UserEventSelectOptions,
|
|
233
233
|
) => Promise<void>
|
|
@@ -996,7 +996,7 @@ function createBrowserRunner(runnerClass, mocker, state, coverageModule) {
|
|
|
996
996
|
};
|
|
997
997
|
importFile = async (filepath, mode) => {
|
|
998
998
|
let hash = this.hashMap.get(filepath);
|
|
999
|
-
if (!hash) {
|
|
999
|
+
if (mode === "setup" || !hash) {
|
|
1000
1000
|
hash = Date.now().toString();
|
|
1001
1001
|
this.hashMap.set(filepath, hash);
|
|
1002
1002
|
}
|
|
@@ -1,26 +1,37 @@
|
|
|
1
1
|
(() => {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
__vitest_mocker__.prepare().finally(() => {
|
|
10
|
-
module().then(resolve, reject);
|
|
11
|
-
});
|
|
12
|
-
});
|
|
13
|
-
moduleCache.set(promise, { promise, evaluated: false });
|
|
14
|
-
return promise.finally(() => moduleCache.delete(promise));
|
|
2
|
+
function wrapModule(moduleCallback) {
|
|
3
|
+
if (typeof moduleCallback !== "function") {
|
|
4
|
+
return moduleCallback
|
|
5
|
+
}
|
|
6
|
+
|
|
7
|
+
if (typeof __vitest_mocker__ === "undefined" || typeof __vitest_worker__ === 'undefined') {
|
|
8
|
+
return moduleCallback()
|
|
15
9
|
}
|
|
16
|
-
|
|
10
|
+
|
|
11
|
+
const { evaluatedModules } = __vitest_worker__
|
|
12
|
+
const moduleId = crypto.randomUUID()
|
|
13
|
+
const viteModule = evaluatedModules.ensureModule(moduleId, moduleId)
|
|
14
|
+
|
|
15
|
+
viteModule.evaluated = false
|
|
16
|
+
viteModule.promise = new Promise((resolve, reject) => {
|
|
17
|
+
__vitest_mocker__.prepare().finally(() => {
|
|
18
|
+
moduleCallback().then(resolve, reject)
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
return viteModule.promise.finally(() => {
|
|
22
|
+
viteModule.evaluated = true
|
|
23
|
+
viteModule.promise = undefined
|
|
24
|
+
|
|
25
|
+
evaluatedModules.idToModuleMap.delete(viteModule.id)
|
|
26
|
+
evaluatedModules.fileToModulesMap.delete(viteModule.file)
|
|
27
|
+
evaluatedModules.urlToIdModuleMap.delete(viteModule.url)
|
|
28
|
+
});
|
|
17
29
|
}
|
|
18
30
|
|
|
19
31
|
window.__vitest_browser_runner__ = {
|
|
20
32
|
wrapModule,
|
|
21
33
|
wrapDynamicImport: wrapModule,
|
|
22
34
|
disposeExceptionTracker: () => {},
|
|
23
|
-
moduleCache,
|
|
24
35
|
cleanups: [],
|
|
25
36
|
config: { __VITEST_CONFIG__ },
|
|
26
37
|
viteConfig: { __VITEST_VITE_CONFIG__ },
|
|
@@ -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-CQlWpWwO.js"></script>
|
|
9
9
|
<link rel="modulepreload" crossorigin href="/__vitest_browser__/utils-uxqdqUz8.js">
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
package/dist/context.js
CHANGED
|
@@ -292,7 +292,7 @@ function createPreviewUserEvent(userEventBase, options) {
|
|
|
292
292
|
}
|
|
293
293
|
return option;
|
|
294
294
|
});
|
|
295
|
-
await userEvent.selectOptions(element, options);
|
|
295
|
+
await userEvent.selectOptions(toElement(element), options);
|
|
296
296
|
},
|
|
297
297
|
async clear(element) {
|
|
298
298
|
await userEvent.clear(toElement(element));
|
package/dist/expect-element.js
CHANGED
|
@@ -20,7 +20,7 @@ import{expect,chai}from"vitest";import{getType}from"vitest/internal/browser";imp
|
|
|
20
20
|
`)}}function getExpectedClassNamesAndOptions(_){let K=_.pop(),q,J;return typeof K==`object`&&!(K instanceof RegExp)?(q=_,J=K):(q=_.concat(K),J={exact:!1}),{expectedClassNames:q,options:J}}function splitClassNames(_){return _?_.split(/\s+/).filter(_=>_.length>0):[]}function isSubset$1(_,K){return _.every(_=>typeof _==`string`?K.includes(_):K.some(K=>_.test(K)))}function toHaveDisplayValue(_,K){let q=getElementFromUserInput(_,toHaveDisplayValue,this),J=getTag(q);if(![`SELECT`,`INPUT`,`TEXTAREA`].includes(J))throw Error(`.toHaveDisplayValue() currently supports only input, textarea or select elements, try with another matcher instead.`);if(isInputElement(q)&&[`radio`,`checkbox`].includes(q.type))throw Error(`.toHaveDisplayValue() currently does not support input[type="${q.type}"], try with another matcher instead.`);let Y=getValues(J,q),X=getExpectedValues(K),Z=X.filter(_=>Y.some(K=>_ instanceof RegExp?_.test(K):this.equals(K,String(_),this.customTesters))).length,Q=Z===Y.length,$=Z===X.length;return{pass:Q&&$,message:()=>getMessage(this,this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveDisplayValue`,`element`,``),`Expected element ${this.isNot?`not `:``}to have display value`,K,`Received`,Y)}}function getValues(_,K){return _===`SELECT`?Array.from(K).filter(_=>_.selected).map(_=>_.textContent||``):[K.value]}function getExpectedValues(_){return Array.isArray(_)?_:[_]}function toHaveFocus(_){let K=getElementFromUserInput(_,toHaveFocus,this);return{pass:K.ownerDocument.activeElement===K,message:()=>[this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveFocus`,`element`,``),``,...this.isNot?[`Received element is focused:`,` ${this.utils.printReceived(K)}`]:[`Expected element with focus:`,` ${this.utils.printExpected(K)}`,`Received element with focus:`,` ${this.utils.printReceived(K.ownerDocument.activeElement)}`]].join(`
|
|
21
21
|
`)}}function toHaveFormValues(_,K){let q=getElementFromUserInput(_,toHaveFormValues,this),J=q.ownerDocument.defaultView||window;if(!(q instanceof J.HTMLFieldSetElement)&&!(q instanceof J.HTMLFormElement))throw TypeError(`toHaveFormValues must be called on a form or a fieldset, instead got ${getTag(q)}`);if(!K||typeof K!=`object`)throw TypeError(`toHaveFormValues must be called with an object of expected form values. Got ${K}`);let Y=getAllFormValues(q);return{pass:Object.entries(K).every(([_,K])=>this.equals(Y[_],K,[arrayAsSetComparison,...this.customTesters])),message:()=>{let _=this.isNot?`not to`:`to`,q=`${this.isNot?`.not`:``}.toHaveFormValues`,J={};for(let _ in Y){if(!Object.hasOwn(K,_))continue;J[_]=Y[_]}return[this.utils.matcherHint(q,`element`,``),`Expected the element ${_} have form values`,this.utils.diff(K,J)].join(`
|
|
22
22
|
|
|
23
|
-
`)}}}function getMultiElementValue(_){let K
|
|
23
|
+
`)}}}function getMultiElementValue(_){let K=``;for(let q of _){if(K&&K!==q.type)throw Error(`Multiple form elements with the same name must be of the same type`);K=q.type}switch(K){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)=>(_[K]=(Z.has(K)&&usedValuesProps.has(K)?q.style:X)[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(`
|
|
24
24
|
|
|
25
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)[_];K!=null&&(Y[_]=K)}),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(`
|
|
26
26
|
`)}function isSubset(_,K,q,J){let Y=Object.keys(_);return Y.length?Y.every(Y=>{let X=_[Y],Z=Y.startsWith(`--`),Q=[Y];return Z||Q.push(Y.toLowerCase()),Q.some(_=>{let Z=J.has(Y)&&usedValuesProps.has(Y)?K.style:q;return Z[_]===X||Z.getPropertyValue(_)===X})}):!1}function toHaveTextContent(_,K,q={normalizeWhitespace:!0}){let J=getNodeFromUserInput(_,toHaveTextContent,this),Y=q.normalizeWhitespace?normalize(J.textContent||``):(J.textContent||``).replace(/\u00A0/g,` `),X=Y!==``&&K===``;return{pass:!X&&matches(Y,K),message:()=>{let _=this.isNot?`not to`:`to`;return getMessage(this,this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveTextContent`,`element`,``),X?`Checking with empty string will always match, use .toBeEmptyDOMElement() instead`:`Expected element ${_} have text content`,K,`Received`,Y)}}}function toHaveValue(_,K){let q=getElementFromUserInput(_,toHaveValue,this);if(isInputElement(q)&&[`checkbox`,`radio`].includes(q.type))throw Error(`input with type=checkbox or type=radio cannot be used with .toHaveValue(). Use .toBeChecked() for type=checkbox or .toHaveFormValues() instead`);let J=getSingleElementValue(q),Y=K!==void 0,X=K,Z=J;return K==J&&K!==J&&(X=`${K} (${typeof K})`,Z=`${J} (${typeof J})`),{pass:Y?this.equals(J,K,[arrayAsSetComparison,...this.customTesters]):!!J,message:()=>{let _=this.isNot?`not to`:`to`,q=this.utils.matcherHint(`${this.isNot?`.not`:``}.toHaveValue`,`element`,K);return getMessage(this,q,`Expected the element ${_} have value`,Y?X:`(any)`,`Received`,Z)}}}const counters=new Map([]);async function toMatchScreenshot(_,K,q=typeof K==`object`?K:{}){if(this.isNot)throw Error(`'toMatchScreenshot' cannot be used with "not"`);let J=getWorkerState().current;if(J===void 0||this.currentTestName===void 0)throw Error(`'toMatchScreenshot' cannot be used without test context`);let Y=`${J.result?.repeatCount??0}${this.testPath}${this.currentTestName}`,X=counters.get(Y);X===void 0&&(X={current:0},counters.set(Y,X)),X.current+=1;let Z=typeof K==`string`?K:`${this.currentTestName} ${X.current}`,Q=q.screenshotOptions&&`mask`in q.screenshotOptions?{...q,screenshotOptions:{...q.screenshotOptions,mask:q.screenshotOptions.mask.map(convertToSelector)}}:q,$=await getBrowserState().commands.triggerCommand(`__vitest_screenshotMatcher`,[Z,this.currentTestName,{element:convertToSelector(_),...Q}]);if($.pass===!1&&`context`in J){let{annotate:_}=J.context,K=[];$.reference&&K.push(_(`Reference screenshot`,{path:$.reference})),$.actual&&K.push(_(`Actual screenshot`,{path:$.actual})),$.diff&&K.push(_(`Diff`,{path:$.diff})),await Promise.all(K)}return{pass:$.pass,message:()=>$.pass?``:[this.utils.matcherHint(`toMatchScreenshot`,`element`,``),``,$.message,$.reference?`\nReference screenshot:\n ${this.utils.EXPECTED_COLOR($.reference)}`:null,$.actual?`\nActual screenshot:\n ${this.utils.RECEIVED_COLOR($.actual)}`:null,$.diff?this.utils.DIM_COLOR(`\nDiff image:\n ${$.diff}`):null].filter(_=>_!==null).join(`
|
package/dist/index.js
CHANGED
package/dist/state.js
CHANGED
|
@@ -1,111 +1,279 @@
|
|
|
1
1
|
(function () {
|
|
2
|
-
|
|
2
|
+
'use strict';
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
4
|
+
let SOURCEMAPPING_URL = "sourceMa";
|
|
5
|
+
SOURCEMAPPING_URL += "ppingURL";
|
|
6
|
+
const isWindows = typeof process < "u" && process.platform === "win32";
|
|
7
|
+
function unwrapId(id) {
|
|
8
|
+
return id.startsWith("/@id/") ? id.slice(5).replace("__x00__", "\0") : id;
|
|
9
|
+
}
|
|
10
|
+
const windowsSlashRE = /\\/g;
|
|
11
|
+
function slash(p) {
|
|
12
|
+
return p.replace(windowsSlashRE, "/");
|
|
13
|
+
}
|
|
14
|
+
const postfixRE = /[?#].*$/;
|
|
15
|
+
function cleanUrl(url) {
|
|
16
|
+
return url.replace(postfixRE, "");
|
|
17
|
+
}
|
|
18
|
+
const _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
|
|
19
|
+
function normalizeWindowsPath(input = "") {
|
|
20
|
+
return input && input.replace(/\\/g, "/").replace(_DRIVE_LETTER_START_RE, (r) => r.toUpperCase());
|
|
21
|
+
}
|
|
22
|
+
const _IS_ABSOLUTE_RE = /^[/\\](?![/\\])|^[/\\]{2}(?!\.)|^[A-Za-z]:[/\\]/;
|
|
23
|
+
function cwd() {
|
|
24
|
+
return typeof process < "u" && typeof process.cwd == "function" ? process.cwd().replace(/\\/g, "/") : "/";
|
|
25
|
+
}
|
|
26
|
+
const resolve = function(...arguments_) {
|
|
27
|
+
arguments_ = arguments_.map((argument) => normalizeWindowsPath(argument));
|
|
28
|
+
let resolvedPath = "", resolvedAbsolute = false;
|
|
29
|
+
for (let index = arguments_.length - 1; index >= -1 && !resolvedAbsolute; index--) {
|
|
30
|
+
let path = index >= 0 ? arguments_[index] : cwd();
|
|
31
|
+
!path || path.length === 0 || (resolvedPath = `${path}/${resolvedPath}`, resolvedAbsolute = isAbsolute(path));
|
|
32
|
+
}
|
|
33
|
+
return resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute), resolvedAbsolute && !isAbsolute(resolvedPath) ? `/${resolvedPath}` : resolvedPath.length > 0 ? resolvedPath : ".";
|
|
34
|
+
};
|
|
35
|
+
function normalizeString(path, allowAboveRoot) {
|
|
36
|
+
let res = "", lastSegmentLength = 0, lastSlash = -1, dots = 0, char = null;
|
|
37
|
+
for (let index = 0; index <= path.length; ++index) {
|
|
38
|
+
if (index < path.length) char = path[index];
|
|
39
|
+
else if (char === "/") break;
|
|
40
|
+
else char = "/";
|
|
41
|
+
if (char === "/") {
|
|
42
|
+
if (!(lastSlash === index - 1 || dots === 1)) if (dots === 2) {
|
|
43
|
+
if (res.length < 2 || lastSegmentLength !== 2 || res[res.length - 1] !== "." || res[res.length - 2] !== ".") {
|
|
44
|
+
if (res.length > 2) {
|
|
45
|
+
let lastSlashIndex = res.lastIndexOf("/");
|
|
46
|
+
lastSlashIndex === -1 ? (res = "", lastSegmentLength = 0) : (res = res.slice(0, lastSlashIndex), lastSegmentLength = res.length - 1 - res.lastIndexOf("/")), lastSlash = index, dots = 0;
|
|
47
|
+
continue;
|
|
48
|
+
} else if (res.length > 0) {
|
|
49
|
+
res = "", lastSegmentLength = 0, lastSlash = index, dots = 0;
|
|
50
|
+
continue;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
allowAboveRoot && (res += res.length > 0 ? "/.." : "..", lastSegmentLength = 2);
|
|
54
|
+
} else res.length > 0 ? res += `/${path.slice(lastSlash + 1, index)}` : res = path.slice(lastSlash + 1, index), lastSegmentLength = index - lastSlash - 1;
|
|
55
|
+
lastSlash = index, dots = 0;
|
|
56
|
+
} else char === "." && dots !== -1 ? ++dots : dots = -1;
|
|
57
|
+
}
|
|
58
|
+
return res;
|
|
59
|
+
}
|
|
60
|
+
const isAbsolute = function(p) {
|
|
61
|
+
return _IS_ABSOLUTE_RE.test(p);
|
|
62
|
+
}, decodeBase64 = typeof atob < "u" ? atob : (str) => Buffer.from(str, "base64").toString("utf-8");
|
|
63
|
+
const posixResolve = resolve;
|
|
64
|
+
const intToChar = new Uint8Array(64), charToInt = new Uint8Array(128);
|
|
65
|
+
for (let i = 0; i < 64; i++) {
|
|
66
|
+
let c = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/".charCodeAt(i);
|
|
67
|
+
intToChar[i] = c, charToInt[c] = i;
|
|
68
|
+
}
|
|
69
|
+
var DecodedMap = class {
|
|
70
|
+
_encoded;
|
|
71
|
+
_decoded;
|
|
72
|
+
_decodedMemo;
|
|
73
|
+
url;
|
|
74
|
+
version;
|
|
75
|
+
names = [];
|
|
76
|
+
resolvedSources;
|
|
77
|
+
constructor(map, from) {
|
|
78
|
+
this.map = map;
|
|
79
|
+
let { mappings, names, sources } = map;
|
|
80
|
+
this.version = map.version, this.names = names || [], this._encoded = mappings || "", this._decodedMemo = memoizedState(), this.url = from, this.resolvedSources = (sources || []).map((s) => posixResolve(s || "", from));
|
|
81
|
+
}
|
|
82
|
+
};
|
|
83
|
+
function memoizedState() {
|
|
84
|
+
return {
|
|
85
|
+
lastKey: -1,
|
|
86
|
+
lastNeedle: -1,
|
|
87
|
+
lastIndex: -1
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
const MODULE_RUNNER_SOURCEMAPPING_REGEXP = /* @__PURE__ */ RegExp(`//# ${SOURCEMAPPING_URL}=data:application/json;base64,(.+)`);
|
|
91
|
+
var EvaluatedModuleNode = class {
|
|
92
|
+
importers = /* @__PURE__ */ new Set();
|
|
93
|
+
imports = /* @__PURE__ */ new Set();
|
|
94
|
+
evaluated = false;
|
|
95
|
+
meta;
|
|
96
|
+
promise;
|
|
97
|
+
exports;
|
|
98
|
+
file;
|
|
99
|
+
map;
|
|
100
|
+
constructor(id, url) {
|
|
101
|
+
this.id = id, this.url = url, this.file = cleanUrl(id);
|
|
102
|
+
}
|
|
103
|
+
}, EvaluatedModules = class {
|
|
104
|
+
idToModuleMap = /* @__PURE__ */ new Map();
|
|
105
|
+
fileToModulesMap = /* @__PURE__ */ new Map();
|
|
106
|
+
urlToIdModuleMap = /* @__PURE__ */ new Map();
|
|
107
|
+
getModuleById(id) {
|
|
108
|
+
return this.idToModuleMap.get(id);
|
|
109
|
+
}
|
|
110
|
+
getModulesByFile(file) {
|
|
111
|
+
return this.fileToModulesMap.get(file);
|
|
112
|
+
}
|
|
113
|
+
getModuleByUrl(url) {
|
|
114
|
+
return this.urlToIdModuleMap.get(unwrapId(url));
|
|
115
|
+
}
|
|
116
|
+
ensureModule(id, url) {
|
|
117
|
+
if (id = normalizeModuleId(id), this.idToModuleMap.has(id)) {
|
|
118
|
+
let moduleNode$1 = this.idToModuleMap.get(id);
|
|
119
|
+
return this.urlToIdModuleMap.set(url, moduleNode$1), moduleNode$1;
|
|
120
|
+
}
|
|
121
|
+
let moduleNode = new EvaluatedModuleNode(id, url);
|
|
122
|
+
this.idToModuleMap.set(id, moduleNode), this.urlToIdModuleMap.set(url, moduleNode);
|
|
123
|
+
let fileModules = this.fileToModulesMap.get(moduleNode.file) || /* @__PURE__ */ new Set();
|
|
124
|
+
return fileModules.add(moduleNode), this.fileToModulesMap.set(moduleNode.file, fileModules), moduleNode;
|
|
125
|
+
}
|
|
126
|
+
invalidateModule(node) {
|
|
127
|
+
node.evaluated = false, node.meta = void 0, node.map = void 0, node.promise = void 0, node.exports = void 0, node.imports.clear();
|
|
128
|
+
}
|
|
129
|
+
getModuleSourceMapById(id) {
|
|
130
|
+
let mod = this.getModuleById(id);
|
|
131
|
+
if (!mod) return null;
|
|
132
|
+
if (mod.map) return mod.map;
|
|
133
|
+
if (!mod.meta || !("code" in mod.meta)) return null;
|
|
134
|
+
let pattern = `//# ${SOURCEMAPPING_URL}=data:application/json;base64,`, lastIndex = mod.meta.code.lastIndexOf(pattern);
|
|
135
|
+
if (lastIndex === -1) return null;
|
|
136
|
+
let mapString = MODULE_RUNNER_SOURCEMAPPING_REGEXP.exec(mod.meta.code.slice(lastIndex))?.[1];
|
|
137
|
+
return mapString ? (mod.map = new DecodedMap(JSON.parse(decodeBase64(mapString)), mod.file), mod.map) : null;
|
|
138
|
+
}
|
|
139
|
+
clear() {
|
|
140
|
+
this.idToModuleMap.clear(), this.fileToModulesMap.clear(), this.urlToIdModuleMap.clear();
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
const prefixedBuiltins = new Set([
|
|
144
|
+
"node:sea",
|
|
145
|
+
"node:sqlite",
|
|
146
|
+
"node:test",
|
|
147
|
+
"node:test/reporters"
|
|
148
|
+
]);
|
|
149
|
+
function normalizeModuleId(file) {
|
|
150
|
+
if (prefixedBuiltins.has(file)) return file;
|
|
151
|
+
let unixFile = slash(file).replace(/^\/@fs\//, isWindows ? "" : "/").replace(/^node:/, "").replace(/^\/+/, "/");
|
|
152
|
+
return unixFile.replace(/^file:\/+/, isWindows ? "" : "/");
|
|
153
|
+
}
|
|
154
|
+
const customizationHookNamespace = "vite-module-runner:import-meta-resolve/v1/"; `
|
|
9
155
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
config,
|
|
17
|
-
projectName: config.name || "",
|
|
18
|
-
files: [],
|
|
19
|
-
environment: {
|
|
20
|
-
name: "browser",
|
|
21
|
-
options: null
|
|
22
|
-
},
|
|
23
|
-
providedContext: {},
|
|
24
|
-
invalidates: []
|
|
25
|
-
},
|
|
26
|
-
onCancel: null,
|
|
27
|
-
config,
|
|
28
|
-
environment: {
|
|
29
|
-
name: "browser",
|
|
30
|
-
viteEnvironment: "client",
|
|
31
|
-
setup() {
|
|
32
|
-
throw new Error("Not called in the browser");
|
|
33
|
-
}
|
|
34
|
-
},
|
|
35
|
-
onCleanup: (fn) => getBrowserState().cleanups.push(fn),
|
|
36
|
-
evaluatedModules: getBrowserState().evaluatedModules,
|
|
37
|
-
resolvingModules: getBrowserState().resolvingModules,
|
|
38
|
-
moduleExecutionInfo: new Map(),
|
|
39
|
-
metaEnv: null,
|
|
40
|
-
rpc: null,
|
|
41
|
-
durations: {
|
|
42
|
-
environment: 0,
|
|
43
|
-
prepare: performance.now()
|
|
44
|
-
},
|
|
45
|
-
providedContext: {}
|
|
46
|
-
};
|
|
47
|
-
// @ts-expect-error not typed global
|
|
48
|
-
globalThis.__vitest_browser__ = true;
|
|
49
|
-
// @ts-expect-error not typed global
|
|
50
|
-
globalThis.__vitest_worker__ = state;
|
|
51
|
-
getBrowserState().cdp = createCdp();
|
|
52
|
-
function rpc() {
|
|
53
|
-
return state.rpc;
|
|
54
|
-
}
|
|
55
|
-
function createCdp() {
|
|
56
|
-
const listenersMap = new WeakMap();
|
|
57
|
-
function getId(listener) {
|
|
58
|
-
const id = listenersMap.get(listener) || crypto.randomUUID();
|
|
59
|
-
listenersMap.set(listener, id);
|
|
60
|
-
return id;
|
|
61
|
-
}
|
|
62
|
-
const listeners = {};
|
|
63
|
-
const cdp = {
|
|
64
|
-
send(method, params) {
|
|
65
|
-
return rpc().sendCdpEvent(sessionId, method, params);
|
|
66
|
-
},
|
|
67
|
-
on(event, listener) {
|
|
68
|
-
const listenerId = getId(listener);
|
|
69
|
-
listeners[event] = listeners[event] || [];
|
|
70
|
-
listeners[event].push(listener);
|
|
71
|
-
rpc().trackCdpEvent(sessionId, "on", event, listenerId).catch(error);
|
|
72
|
-
return cdp;
|
|
73
|
-
},
|
|
74
|
-
once(event, listener) {
|
|
75
|
-
const listenerId = getId(listener);
|
|
76
|
-
const handler = (data) => {
|
|
77
|
-
listener(data);
|
|
78
|
-
cdp.off(event, listener);
|
|
79
|
-
};
|
|
80
|
-
listeners[event] = listeners[event] || [];
|
|
81
|
-
listeners[event].push(handler);
|
|
82
|
-
rpc().trackCdpEvent(sessionId, "once", event, listenerId).catch(error);
|
|
83
|
-
return cdp;
|
|
84
|
-
},
|
|
85
|
-
off(event, listener) {
|
|
86
|
-
const listenerId = getId(listener);
|
|
87
|
-
if (listeners[event]) {
|
|
88
|
-
listeners[event] = listeners[event].filter((l) => l !== listener);
|
|
89
|
-
}
|
|
90
|
-
rpc().trackCdpEvent(sessionId, "off", event, listenerId).catch(error);
|
|
91
|
-
return cdp;
|
|
92
|
-
},
|
|
93
|
-
emit(event, payload) {
|
|
94
|
-
if (listeners[event]) {
|
|
95
|
-
listeners[event].forEach((l) => {
|
|
96
|
-
try {
|
|
97
|
-
l(payload);
|
|
98
|
-
} catch (err) {
|
|
99
|
-
error(err);
|
|
100
|
-
}
|
|
101
|
-
});
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
};
|
|
105
|
-
return cdp;
|
|
106
|
-
}
|
|
107
|
-
function error(err) {
|
|
108
|
-
window.dispatchEvent(new ErrorEvent("error", { error: err }));
|
|
156
|
+
export async function resolve(specifier, context, nextResolve) {
|
|
157
|
+
if (specifier.startsWith(${JSON.stringify(customizationHookNamespace)})) {
|
|
158
|
+
const data = specifier.slice(${JSON.stringify(customizationHookNamespace)}.length)
|
|
159
|
+
const [parsedSpecifier, parsedImporter] = JSON.parse(data)
|
|
160
|
+
specifier = parsedSpecifier
|
|
161
|
+
context.parentURL = parsedImporter
|
|
109
162
|
}
|
|
110
163
|
|
|
164
|
+
return nextResolve(specifier, context)
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
`;
|
|
168
|
+
new Proxy({}, { get(_, p) {
|
|
169
|
+
throw Error(`[module runner] Dynamic access of "import.meta.env" is not supported. Please, use "import.meta.env.${String(p)}" instead.`);
|
|
170
|
+
} });
|
|
171
|
+
|
|
172
|
+
/* @__NO_SIDE_EFFECTS__ */
|
|
173
|
+
function getBrowserState() {
|
|
174
|
+
// @ts-expect-error not typed global
|
|
175
|
+
return window.__vitest_browser_runner__;
|
|
176
|
+
}
|
|
177
|
+
|
|
178
|
+
const config = getBrowserState().config;
|
|
179
|
+
const sessionId = getBrowserState().sessionId;
|
|
180
|
+
const state = {
|
|
181
|
+
ctx: {
|
|
182
|
+
pool: "browser",
|
|
183
|
+
workerId: 1,
|
|
184
|
+
config,
|
|
185
|
+
projectName: config.name || "",
|
|
186
|
+
files: [],
|
|
187
|
+
environment: {
|
|
188
|
+
name: "browser",
|
|
189
|
+
options: null
|
|
190
|
+
},
|
|
191
|
+
providedContext: {},
|
|
192
|
+
invalidates: []
|
|
193
|
+
},
|
|
194
|
+
onCancel: null,
|
|
195
|
+
config,
|
|
196
|
+
environment: {
|
|
197
|
+
name: "browser",
|
|
198
|
+
viteEnvironment: "client",
|
|
199
|
+
setup() {
|
|
200
|
+
throw new Error("Not called in the browser");
|
|
201
|
+
}
|
|
202
|
+
},
|
|
203
|
+
onCleanup: (fn) => getBrowserState().cleanups.push(fn),
|
|
204
|
+
evaluatedModules: new EvaluatedModules(),
|
|
205
|
+
resolvingModules: new Set(),
|
|
206
|
+
moduleExecutionInfo: new Map(),
|
|
207
|
+
metaEnv: null,
|
|
208
|
+
rpc: null,
|
|
209
|
+
durations: {
|
|
210
|
+
environment: 0,
|
|
211
|
+
prepare: performance.now()
|
|
212
|
+
},
|
|
213
|
+
providedContext: {}
|
|
214
|
+
};
|
|
215
|
+
// @ts-expect-error not typed global
|
|
216
|
+
globalThis.__vitest_browser__ = true;
|
|
217
|
+
// @ts-expect-error not typed global
|
|
218
|
+
globalThis.__vitest_worker__ = state;
|
|
219
|
+
getBrowserState().cdp = createCdp();
|
|
220
|
+
function rpc() {
|
|
221
|
+
return state.rpc;
|
|
222
|
+
}
|
|
223
|
+
function createCdp() {
|
|
224
|
+
const listenersMap = new WeakMap();
|
|
225
|
+
function getId(listener) {
|
|
226
|
+
const id = listenersMap.get(listener) || crypto.randomUUID();
|
|
227
|
+
listenersMap.set(listener, id);
|
|
228
|
+
return id;
|
|
229
|
+
}
|
|
230
|
+
const listeners = {};
|
|
231
|
+
const cdp = {
|
|
232
|
+
send(method, params) {
|
|
233
|
+
return rpc().sendCdpEvent(sessionId, method, params);
|
|
234
|
+
},
|
|
235
|
+
on(event, listener) {
|
|
236
|
+
const listenerId = getId(listener);
|
|
237
|
+
listeners[event] = listeners[event] || [];
|
|
238
|
+
listeners[event].push(listener);
|
|
239
|
+
rpc().trackCdpEvent(sessionId, "on", event, listenerId).catch(error);
|
|
240
|
+
return cdp;
|
|
241
|
+
},
|
|
242
|
+
once(event, listener) {
|
|
243
|
+
const listenerId = getId(listener);
|
|
244
|
+
const handler = (data) => {
|
|
245
|
+
listener(data);
|
|
246
|
+
cdp.off(event, listener);
|
|
247
|
+
};
|
|
248
|
+
listeners[event] = listeners[event] || [];
|
|
249
|
+
listeners[event].push(handler);
|
|
250
|
+
rpc().trackCdpEvent(sessionId, "once", event, listenerId).catch(error);
|
|
251
|
+
return cdp;
|
|
252
|
+
},
|
|
253
|
+
off(event, listener) {
|
|
254
|
+
const listenerId = getId(listener);
|
|
255
|
+
if (listeners[event]) {
|
|
256
|
+
listeners[event] = listeners[event].filter((l) => l !== listener);
|
|
257
|
+
}
|
|
258
|
+
rpc().trackCdpEvent(sessionId, "off", event, listenerId).catch(error);
|
|
259
|
+
return cdp;
|
|
260
|
+
},
|
|
261
|
+
emit(event, payload) {
|
|
262
|
+
if (listeners[event]) {
|
|
263
|
+
listeners[event].forEach((l) => {
|
|
264
|
+
try {
|
|
265
|
+
l(payload);
|
|
266
|
+
} catch (err) {
|
|
267
|
+
error(err);
|
|
268
|
+
}
|
|
269
|
+
});
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
};
|
|
273
|
+
return cdp;
|
|
274
|
+
}
|
|
275
|
+
function error(err) {
|
|
276
|
+
window.dispatchEvent(new ErrorEvent("error", { error: err }));
|
|
277
|
+
}
|
|
278
|
+
|
|
111
279
|
})();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vitest/browser",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "4.0.
|
|
4
|
+
"version": "4.0.6",
|
|
5
5
|
"description": "Browser running for Vitest",
|
|
6
6
|
"license": "MIT",
|
|
7
7
|
"funding": "https://opencollective.com/vitest",
|
|
@@ -51,7 +51,7 @@
|
|
|
51
51
|
"providers"
|
|
52
52
|
],
|
|
53
53
|
"peerDependencies": {
|
|
54
|
-
"vitest": "4.0.
|
|
54
|
+
"vitest": "4.0.6"
|
|
55
55
|
},
|
|
56
56
|
"dependencies": {
|
|
57
57
|
"magic-string": "^0.30.19",
|
|
@@ -60,8 +60,8 @@
|
|
|
60
60
|
"sirv": "^3.0.2",
|
|
61
61
|
"tinyrainbow": "^3.0.3",
|
|
62
62
|
"ws": "^8.18.3",
|
|
63
|
-
"@vitest/mocker": "4.0.
|
|
64
|
-
"@vitest/utils": "4.0.
|
|
63
|
+
"@vitest/mocker": "4.0.6",
|
|
64
|
+
"@vitest/utils": "4.0.6"
|
|
65
65
|
},
|
|
66
66
|
"devDependencies": {
|
|
67
67
|
"@testing-library/user-event": "^14.6.1",
|
|
@@ -72,8 +72,8 @@
|
|
|
72
72
|
"ivya": "^1.7.0",
|
|
73
73
|
"mime": "^4.1.0",
|
|
74
74
|
"pathe": "^2.0.3",
|
|
75
|
-
"vitest": "4.0.
|
|
76
|
-
"
|
|
75
|
+
"@vitest/runner": "4.0.6",
|
|
76
|
+
"vitest": "4.0.6"
|
|
77
77
|
},
|
|
78
78
|
"scripts": {
|
|
79
79
|
"typecheck": "tsc -p ./src/client/tsconfig.json --noEmit",
|