@vitest/browser 5.0.0-beta.5 → 5.0.0-beta.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.
@@ -642,7 +642,7 @@ function parseStacktrace(stack, options = {}) {
642
642
  if (!position) return stack;
643
643
  const { line, column, source, name } = position;
644
644
  let file = source || stack.file;
645
- if (file.match(/\/\w:\//)) file = file.slice(1);
645
+ if (/\/\w:\//.test(file)) file = file.slice(1);
646
646
  if (shouldFilter(ignoreStackEntries, file)) return null;
647
647
  if (line != null && column != null) return {
648
648
  line,
@@ -968,7 +968,7 @@ function createBrowserRunner(mocker, state, coverageModule) {
968
968
  artifact.location = {
969
969
  line,
970
970
  column: column + 1,
971
- file: file.match(/\/\w:\//) ? file.slice(1) : file
971
+ file: /\/\w:\//.test(file) ? file.slice(1) : file
972
972
  };
973
973
  if (artifact.type === "internal:annotation") artifact.annotation.location = artifact.location;
974
974
  }
@@ -1022,7 +1022,7 @@ function createBrowserRunner(mocker, state, coverageModule) {
1022
1022
  return;
1023
1023
  }
1024
1024
  if (shouldTraceView) {
1025
- (/* @__PURE__ */ getBrowserState()).browserTraceDomSnapshot = await __vitePreload(() => import("./rrweb-snapshot-iZCFA2to.js"), []);
1025
+ (/* @__PURE__ */ getBrowserState()).browserTraceDomSnapshot = await __vitePreload(() => import("./rrweb-snapshot-DkFyu2W8.js"), []);
1026
1026
  (/* @__PURE__ */ getBrowserState()).browserTraceAttempts.set(test.id, {
1027
1027
  retry,
1028
1028
  repeats,
@@ -1933,52 +1933,64 @@ var traces = new Traces({
1933
1933
  var rootTesterSpan;
1934
1934
  (/* @__PURE__ */ getBrowserState()).traces = traces;
1935
1935
  channel.addEventListener("message", async (e) => {
1936
- await client.waitForConnection();
1937
1936
  const data = e.data;
1938
- debug === null || debug === void 0 || debug("event from orchestrator", JSON.stringify(e.data));
1939
1937
  if (!isEvent(data)) {
1938
+ await client.waitForConnection();
1940
1939
  unhandledError(/* @__PURE__ */ new Error(`Unknown message: ${JSON.stringify(e.data)}`), "Unknown Iframe Message");
1941
1940
  return;
1942
1941
  }
1943
1942
  if (!("iframeId" in data) || data.iframeId !== (/* @__PURE__ */ getBrowserState()).iframeId) return;
1944
- switch (data.event) {
1945
- case "execute": {
1946
- const { method, files, context, concurrencyId, workerId } = data;
1947
- const state = /* @__PURE__ */ getWorkerState();
1948
- const parsedContext = parse(context);
1949
- state.ctx.concurrencyId = concurrencyId;
1950
- state.ctx.workerId = workerId;
1951
- state.ctx.providedContext = parsedContext;
1952
- state.providedContext = parsedContext;
1953
- state.metaEnv.VITEST_POOL_ID = String(concurrencyId);
1954
- state.metaEnv.VITEST_WORKER_ID = String(workerId);
1955
- if (method === "collect") await executeTests("collect", files).catch((err) => unhandledError(err, "Collect Error"));
1956
- else await executeTests("run", files).catch((err) => unhandledError(err, "Run Error"));
1957
- break;
1958
- }
1959
- case "cleanup":
1960
- await cleanup().catch((err) => unhandledError(err, "Cleanup Error"));
1961
- rootTesterSpan === null || rootTesterSpan === void 0 || rootTesterSpan.span.end();
1962
- await traces.finish();
1963
- break;
1964
- case "prepare": {
1965
- await traces.waitInit();
1966
- const tracesContext = traces.getContextFromCarrier(data.otelCarrier);
1967
- traces.recordInitSpan(tracesContext);
1968
- rootTesterSpan = traces.startContextSpan(`vitest.browser.tester.run`, tracesContext);
1969
- traces.bind(rootTesterSpan.context);
1970
- await prepare(data).catch((err) => unhandledError(err, "Prepare Error"));
1971
- break;
1972
- }
1973
- case "viewport:done":
1974
- case "viewport:fail":
1975
- case "viewport": break;
1976
- default: unhandledError(/* @__PURE__ */ new Error(`Unknown event: ${data.event}`), "Unknown Event");
1977
- }
1978
1943
  channel.postMessage({
1979
- event: `response:${data.event}`,
1980
- iframeId: (/* @__PURE__ */ getBrowserState()).iframeId
1944
+ event: `ack:${data.event}`,
1945
+ iframeId: data.iframeId,
1946
+ messageId: data.messageId
1981
1947
  });
1948
+ await client.waitForConnection();
1949
+ debug === null || debug === void 0 || debug("event from orchestrator", JSON.stringify(e.data));
1950
+ try {
1951
+ switch (data.event) {
1952
+ case "execute": {
1953
+ const { method, files, context, concurrencyId, workerId } = data;
1954
+ const state = /* @__PURE__ */ getWorkerState();
1955
+ const parsedContext = parse(context);
1956
+ state.ctx.concurrencyId = concurrencyId;
1957
+ state.ctx.workerId = workerId;
1958
+ state.ctx.providedContext = parsedContext;
1959
+ state.providedContext = parsedContext;
1960
+ state.metaEnv.VITEST_POOL_ID = String(concurrencyId);
1961
+ state.metaEnv.VITEST_WORKER_ID = String(workerId);
1962
+ if (method === "collect") await executeTests("collect", files).catch((err) => unhandledError(err, "Collect Error"));
1963
+ else await executeTests("run", files).catch((err) => unhandledError(err, "Run Error"));
1964
+ break;
1965
+ }
1966
+ case "cleanup":
1967
+ await cleanup().catch((err) => unhandledError(err, "Cleanup Error"));
1968
+ rootTesterSpan === null || rootTesterSpan === void 0 || rootTesterSpan.span.end();
1969
+ await traces.finish();
1970
+ break;
1971
+ case "prepare": {
1972
+ await traces.waitInit();
1973
+ const tracesContext = traces.getContextFromCarrier(data.otelCarrier);
1974
+ traces.recordInitSpan(tracesContext);
1975
+ rootTesterSpan = traces.startContextSpan(`vitest.browser.tester.run`, tracesContext);
1976
+ traces.bind(rootTesterSpan.context);
1977
+ await prepare(data).catch((err) => unhandledError(err, "Prepare Error"));
1978
+ break;
1979
+ }
1980
+ case "viewport:done":
1981
+ case "viewport:fail":
1982
+ case "viewport": break;
1983
+ default: unhandledError(/* @__PURE__ */ new Error(`Unknown event: ${data.event}`), "Unknown Event");
1984
+ }
1985
+ } catch (error) {
1986
+ await unhandledError(error, "Tester Error");
1987
+ } finally {
1988
+ channel.postMessage({
1989
+ event: `response:${data.event}`,
1990
+ iframeId: data.iframeId,
1991
+ messageId: data.messageId
1992
+ });
1993
+ }
1982
1994
  });
1983
1995
  var url = new URL(location.href);
1984
1996
  var iframeId = url.searchParams.get("iframeId");
@@ -26,7 +26,7 @@
26
26
  {__VITEST_INJECTOR__}
27
27
  {__VITEST_ERROR_CATCHER__}
28
28
  {__VITEST_SCRIPTS__}
29
- <script type="module" crossorigin src="/__vitest_browser__/orchestrator-bDJB3Bid.js"></script>
29
+ <script type="module" crossorigin src="/__vitest_browser__/orchestrator-pKob2Z-i.js"></script>
30
30
  <link rel="modulepreload" crossorigin href="/__vitest_browser__/defineProperty-WHpdAQXR.js">
31
31
  </head>
32
32
  <body>
@@ -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-C1kIlbPd.js"></script>
8
+ <script type="module" crossorigin src="/__vitest_browser__/tester-DdZeFrjo.js"></script>
9
9
  <link rel="modulepreload" crossorigin href="/__vitest_browser__/defineProperty-WHpdAQXR.js">
10
10
  </head>
11
11
  <body>
package/dist/context.js CHANGED
@@ -245,11 +245,10 @@ function processTimeoutOptions(options_) {
245
245
  const currentTime = now();
246
246
  const endTime = startTime + timeout;
247
247
  const remainingTime = Math.floor(endTime - currentTime);
248
- if (remainingTime <= 0) {
249
- return options_;
250
- }
251
- // give us some time to process the timeout
252
- options_.timeout = remainingTime - 100;
248
+ // keep some buffer to process the timeout, but always hand the provider a
249
+ // positive value so it surfaces a descriptive, source-mapped locator error
250
+ // instead of letting the task timer win the race with a generic timeout
251
+ options_.timeout = Math.max(remainingTime - 100, 1);
253
252
  return options_;
254
253
  }
255
254
  const provider$1 = getBrowserState().provider;
@@ -1,4 +1,4 @@
1
- import{Snapshots as e,recordArtifact as t,expect as n,chai as r}from"vitest";import{getType as i}from"vitest/internal/browser";import{b as a,e as o,i as s,g as c,n as l,a as u,k as d,c as f,d as ee,f as te,h as ne,j as re,l as ie,m as ae,o as oe,p as se,q as ce,r as le,s as ue,t as p,_ as m,u as h,L as g,v as de,w as fe,x as pe,y as me,z as he,A as ge,B as _e,C as ve,D as ye,E as be}from"./locators-CPBpJv8y.js";import{server as xe}from"vitest/browser";var Se=Object.defineProperty,Ce=(e,t)=>{let n={};for(var r in e)Se(n,r,{get:e[r],enumerable:!0});return Se(n,Symbol.toStringTag,{value:`Module`}),n};function we(e,t,n={}){let r=Te(e,t,n);if(r.errors.length)throw Error(r.errors[0].message);return r.fragment}function Te(e,t,n={}){let r=new e.LineCounter,i={keepSourceTokens:!0,lineCounter:r,...n},a=e.parseDocument(t,i),o=[],s=e=>[r.linePos(e[0]),r.linePos(e[1])],c=e=>{o.push({message:e.message,range:[r.linePos(e.pos[0]),r.linePos(e.pos[1])]})},l=(t,n)=>{for(let r of n.items){if(r instanceof e.Scalar&&typeof r.value==`string`){let e=v.parse(r,i,o);e&&(t.children=t.children||[],t.children.push(e));continue}if(r instanceof e.YAMLMap){u(t,r);continue}o.push({message:`Sequence items should be strings or maps`,range:s(r.range||n.range)})}},u=(t,n)=>{for(let r of n.items){if(t.children=t.children||[],!(r.key instanceof e.Scalar&&typeof r.key.value==`string`)){o.push({message:`Only string keys are supported`,range:s(r.key.range||n.range)});continue}let a=r.key,c=r.value;if(a.value===`text`){if(!(c instanceof e.Scalar&&typeof c.value==`string`)){o.push({message:`Text value should be a string`,range:s(r.value.range||n.range)});continue}t.children.push({kind:`text`,text:_(c.value)});continue}if(a.value===`/children`){if(!(c instanceof e.Scalar&&typeof c.value==`string`)||c.value!==`contain`&&c.value!==`equal`&&c.value!==`deep-equal`){o.push({message:`Strict value should be "contain", "equal" or "deep-equal"`,range:s(r.value.range||n.range)});continue}t.containerMode=c.value;continue}if(a.value.startsWith(`/`)){if(!(c instanceof e.Scalar&&typeof c.value==`string`)){o.push({message:`Property value should be a string`,range:s(r.value.range||n.range)});continue}t.props=t.props??{},t.props[a.value.slice(1)]=_(c.value);continue}let u=v.parse(a,i,o);if(u){if(c instanceof e.Scalar){let e=typeof c.value;if(e!==`string`&&e!==`number`&&e!==`boolean`){o.push({message:`Node value should be a string or a sequence`,range:s(r.value.range||n.range)});continue}t.children.push({...u,children:[{kind:`text`,text:_(String(c.value))}]});continue}if(c instanceof e.YAMLSeq){t.children.push(u),l(u,c);continue}o.push({message:`Map values should be strings or sequences`,range:s(r.value.range||n.range)})}}},d={kind:`role`,role:`fragment`};return a.errors.forEach(c),o.length?{errors:o,fragment:d}:a.contents?(a.contents instanceof e.YAMLSeq||o.push({message:`Aria snapshot must be a YAML sequence, elements starting with " -"`,range:s(a.contents.range)}),o.length?{errors:o,fragment:d}:(l(d,a.contents),o.length?{errors:o,fragment:Ee}:d.children?.length===1&&(!d.containerMode||d.containerMode===`contain`)?{fragment:d.children[0],errors:[]}:{fragment:d,errors:[]})):{fragment:d,errors:[]}}const Ee={kind:`role`,role:`fragment`};function De(e){return e.replace(/[\u200b\u00ad]/g,``).replace(/[\r\n\s\t]+/g,` `).trim()}function _(e){return{raw:e,normalized:De(e)}}var v=class e{static parse(t,n,r){try{return new e(t.value)._parse()}catch(e){if(e instanceof y){let i=n.prettyErrors===!1?e.message:`${e.message}:\n\n${t.value}\n${` `.repeat(e.pos)}^\n`;return r.push({message:i,range:[n.lineCounter.linePos(t.range[0]),n.lineCounter.linePos(t.range[0]+e.pos)]}),null}throw e}}constructor(e){m(this,`_input`,void 0),m(this,`_pos`,void 0),m(this,`_length`,void 0),this._input=e,this._pos=0,this._length=e.length}_peek(){return this._input[this._pos]||``}_next(){return this._pos<this._length?this._input[this._pos++]:null}_eof(){return this._pos>=this._length}_isWhitespace(){return!this._eof()&&/\s/.test(this._peek())}_skipWhitespace(){for(;this._isWhitespace();)this._pos++}_readIdentifier(e){this._eof()&&this._throwError(`Unexpected end of input when expecting ${e}`);let t=this._pos;for(;!this._eof()&&/[a-zA-Z]/.test(this._peek());)this._pos++;return this._input.slice(t,this._pos)}_readString(){let e=``,t=!1;for(;!this._eof();){let n=this._next();if(t)e+=n,t=!1;else if(n===`\\`)t=!0;else if(n===`"`)return e;else e+=n}this._throwError(`Unterminated string`)}_throwError(e,t=0){throw new y(e,t||this._pos)}_readRegex(){let e=``,t=!1,n=!1;for(;!this._eof();){let r=this._next();if(t)e+=r,t=!1;else if(r===`\\`)t=!0,e+=r;else if(r===`/`&&!n)return{pattern:e};else r===`[`?(n=!0,e+=r):r===`]`&&n?(e+=r,n=!1):e+=r}this._throwError(`Unterminated regex`)}_readStringOrRegex(){let e=this._peek();return e===`"`?(this._next(),De(this._readString())):e===`/`?(this._next(),this._readRegex()):null}_readAttributes(e){let t=this._pos;for(;this._skipWhitespace(),this._peek()===`[`;){this._next(),this._skipWhitespace(),t=this._pos;let n=this._readIdentifier(`attribute`);this._skipWhitespace();let r=``;if(this._peek()===`=`)for(this._next(),this._skipWhitespace(),t=this._pos;this._peek()!==`]`&&!this._isWhitespace()&&!this._eof();)r+=this._next();this._skipWhitespace(),this._peek()!==`]`&&this._throwError(`Expected ]`),this._next(),this._applyAttribute(e,n,r||`true`,t)}}_parse(){this._skipWhitespace();let e=this._readIdentifier(`role`);e===`fragment`&&this._throwError(`Invalid role "fragment"`),this._skipWhitespace();let t={kind:`role`,role:e,name:this._readStringOrRegex()||void 0};return this._readAttributes(t),this._skipWhitespace(),this._eof()||this._throwError(`Unexpected input`),t}_applyAttribute(e,t,n,r){if(t===`checked`){this._assert(n===`true`||n===`false`||n===`mixed`,`Value of "checked" attribute must be a boolean or "mixed"`,r),e.checked=n===`true`?!0:n===`false`?!1:`mixed`;return}if(t===`disabled`){this._assert(n===`true`||n===`false`,`Value of "disabled" attribute must be a boolean`,r),e.disabled=n===`true`;return}if(t===`expanded`){this._assert(n===`true`||n===`false`,`Value of "expanded" attribute must be a boolean`,r),e.expanded=n===`true`;return}if(t===`active`){this._assert(n===`true`||n===`false`,`Value of "active" attribute must be a boolean`,r),e.active=n===`true`;return}if(t===`level`){this._assert(!Number.isNaN(Number(n)),`Value of "level" attribute must be a number`,r),e.level=Number(n);return}if(t===`pressed`){this._assert(n===`true`||n===`false`||n===`mixed`,`Value of "pressed" attribute must be a boolean or "mixed"`,r),e.pressed=n===`true`?!0:n===`false`?!1:`mixed`;return}if(t===`selected`){this._assert(n===`true`||n===`false`,`Value of "selected" attribute must be a boolean`,r),e.selected=n===`true`;return}this._assert(!1,`Unsupported attribute [${t}]`,r)}_assert(e,t,n){e||this._throwError(t||`Assertion error`,n)}},y=class extends Error{constructor(e,t){super(e),m(this,`pos`,void 0),this.pos=t}};function b(e,t){return t?e?typeof t==`string`?e===t:!!e.match(new RegExp(t.pattern)):!1:!0}function x(e,t){if(!t?.normalized)return!0;if(!e)return!1;if(e===t.normalized||e===t.raw)return!0;let n=C(t);return n?!!e.match(n):!1}const S=Symbol(`cachedRegex`);function C(e){if(e[S]!==void 0)return e[S];let{raw:t}=e,n=t.startsWith(`/`)&&t.endsWith(`/`)&&t.length>1,r;try{r=n?new RegExp(t.slice(1,-1)):null}catch{r=null}return e[S]=r,r}function w(e,t,n){if(typeof e==`string`&&t.kind===`text`)return x(e,t.text);if(typeof e!=`object`||!e||t.kind!==`role`||t.role!==`fragment`&&t.role!==e.role||t.checked!==void 0&&t.checked!==e.checked||t.disabled!==void 0&&t.disabled!==e.disabled||t.expanded!==void 0&&t.expanded!==e.expanded||t.level!==void 0&&t.level!==e.level||t.pressed!==void 0&&t.pressed!==e.pressed||t.selected!==void 0&&t.selected!==e.selected||!b(e.name,t.name))return!1;if(t.props){for(let[n,r]of Object.entries(t.props))if(!x(e.props[n]||``,r))return!1}return t.containerMode===`contain`?E(e.children||[],t.children||[]):t.containerMode===`equal`?T(e.children||[],t.children||[],!1):t.containerMode===`deep-equal`||n?T(e.children||[],t.children||[],!0):E(e.children||[],t.children||[])}function T(e,t,n){if(t.length!==e.length)return!1;for(let r=0;r<t.length;++r)if(!w(e[r],t[r],n))return!1;return!0}function E(e,t){if(t.length>e.length)return!1;let n=e.slice(),r=t.slice();for(let e of r){let t=n.shift();for(;t&&!w(t,e,!1);)t=n.shift();if(!t)return!1}return!0}var Oe=Ce({LineCounter:()=>ke,Scalar:()=>D,YAMLError:()=>A,YAMLMap:()=>O,YAMLSeq:()=>k,parseDocument:()=>Ae}),D=class{constructor(e,t=[0,0,0]){m(this,`value`,void 0),m(this,`range`,void 0),this.value=e,this.range=t}},O=class{constructor(e=[0,0,0]){m(this,`items`,void 0),m(this,`range`,void 0),this.items=[],this.range=e}},k=class{constructor(e=[0,0,0]){m(this,`items`,void 0),m(this,`range`,void 0),this.items=[],this.range=e}},ke=class{constructor(){m(this,`lineStarts`,[0])}addNewLine(e){e>this.lineStarts[this.lineStarts.length-1]&&this.lineStarts.push(e)}linePos(e){let t=0,n=this.lineStarts.length-1;for(;t<n;){let r=t+n+1>>1;this.lineStarts[r]<=e?t=r:n=r-1}return{line:t+1,col:e-this.lineStarts[t]+1}}},A=class extends Error{constructor(e,t){super(e),m(this,`pos`,void 0),this.pos=t}};function Ae(e,t={}){let n=t.lineCounter,r=[];if(n)for(let t=0;t<e.length;t++)e[t]===`
1
+ import{Snapshots as e,recordArtifact as t,expect as n,chai as r}from"vitest";import{getType as i}from"vitest/internal/browser";import{b as a,e as o,i as s,g as c,n as l,a as u,k as d,c as f,d as ee,f as te,h as ne,j as re,l as ie,m as ae,o as oe,p as se,q as ce,r as le,s as ue,t as p,_ as m,u as h,L as g,v as de,w as fe,x as pe,y as me,z as he,A as ge,B as _e,C as ve,D as ye,E as be}from"./locators-CVQtUwrj.js";import{server as xe}from"vitest/browser";var Se=Object.defineProperty,Ce=(e,t)=>{let n={};for(var r in e)Se(n,r,{get:e[r],enumerable:!0});return Se(n,Symbol.toStringTag,{value:`Module`}),n};function we(e,t,n={}){let r=Te(e,t,n);if(r.errors.length)throw Error(r.errors[0].message);return r.fragment}function Te(e,t,n={}){let r=new e.LineCounter,i={keepSourceTokens:!0,lineCounter:r,...n},a=e.parseDocument(t,i),o=[],s=e=>[r.linePos(e[0]),r.linePos(e[1])],c=e=>{o.push({message:e.message,range:[r.linePos(e.pos[0]),r.linePos(e.pos[1])]})},l=(t,n)=>{for(let r of n.items){if(r instanceof e.Scalar&&typeof r.value==`string`){let e=v.parse(r,i,o);e&&(t.children=t.children||[],t.children.push(e));continue}if(r instanceof e.YAMLMap){u(t,r);continue}o.push({message:`Sequence items should be strings or maps`,range:s(r.range||n.range)})}},u=(t,n)=>{for(let r of n.items){if(t.children=t.children||[],!(r.key instanceof e.Scalar&&typeof r.key.value==`string`)){o.push({message:`Only string keys are supported`,range:s(r.key.range||n.range)});continue}let a=r.key,c=r.value;if(a.value===`text`){if(!(c instanceof e.Scalar&&typeof c.value==`string`)){o.push({message:`Text value should be a string`,range:s(r.value.range||n.range)});continue}t.children.push({kind:`text`,text:_(c.value)});continue}if(a.value===`/children`){if(!(c instanceof e.Scalar&&typeof c.value==`string`)||c.value!==`contain`&&c.value!==`equal`&&c.value!==`deep-equal`){o.push({message:`Strict value should be "contain", "equal" or "deep-equal"`,range:s(r.value.range||n.range)});continue}t.containerMode=c.value;continue}if(a.value.startsWith(`/`)){if(!(c instanceof e.Scalar&&typeof c.value==`string`)){o.push({message:`Property value should be a string`,range:s(r.value.range||n.range)});continue}t.props=t.props??{},t.props[a.value.slice(1)]=_(c.value);continue}let u=v.parse(a,i,o);if(u){if(c instanceof e.Scalar){let e=typeof c.value;if(e!==`string`&&e!==`number`&&e!==`boolean`){o.push({message:`Node value should be a string or a sequence`,range:s(r.value.range||n.range)});continue}t.children.push({...u,children:[{kind:`text`,text:_(String(c.value))}]});continue}if(c instanceof e.YAMLSeq){t.children.push(u),l(u,c);continue}o.push({message:`Map values should be strings or sequences`,range:s(r.value.range||n.range)})}}},d={kind:`role`,role:`fragment`};return a.errors.forEach(c),o.length?{errors:o,fragment:d}:a.contents?(a.contents instanceof e.YAMLSeq||o.push({message:`Aria snapshot must be a YAML sequence, elements starting with " -"`,range:s(a.contents.range)}),o.length?{errors:o,fragment:d}:(l(d,a.contents),o.length?{errors:o,fragment:Ee}:d.children?.length===1&&(!d.containerMode||d.containerMode===`contain`)?{fragment:d.children[0],errors:[]}:{fragment:d,errors:[]})):{fragment:d,errors:[]}}const Ee={kind:`role`,role:`fragment`};function De(e){return e.replace(/[\u200b\u00ad]/g,``).replace(/[\r\n\s\t]+/g,` `).trim()}function _(e){return{raw:e,normalized:De(e)}}var v=class e{static parse(t,n,r){try{return new e(t.value)._parse()}catch(e){if(e instanceof y){let i=n.prettyErrors===!1?e.message:`${e.message}:\n\n${t.value}\n${` `.repeat(e.pos)}^\n`;return r.push({message:i,range:[n.lineCounter.linePos(t.range[0]),n.lineCounter.linePos(t.range[0]+e.pos)]}),null}throw e}}constructor(e){m(this,`_input`,void 0),m(this,`_pos`,void 0),m(this,`_length`,void 0),this._input=e,this._pos=0,this._length=e.length}_peek(){return this._input[this._pos]||``}_next(){return this._pos<this._length?this._input[this._pos++]:null}_eof(){return this._pos>=this._length}_isWhitespace(){return!this._eof()&&/\s/.test(this._peek())}_skipWhitespace(){for(;this._isWhitespace();)this._pos++}_readIdentifier(e){this._eof()&&this._throwError(`Unexpected end of input when expecting ${e}`);let t=this._pos;for(;!this._eof()&&/[a-zA-Z]/.test(this._peek());)this._pos++;return this._input.slice(t,this._pos)}_readString(){let e=``,t=!1;for(;!this._eof();){let n=this._next();if(t)e+=n,t=!1;else if(n===`\\`)t=!0;else if(n===`"`)return e;else e+=n}this._throwError(`Unterminated string`)}_throwError(e,t=0){throw new y(e,t||this._pos)}_readRegex(){let e=``,t=!1,n=!1;for(;!this._eof();){let r=this._next();if(t)e+=r,t=!1;else if(r===`\\`)t=!0,e+=r;else if(r===`/`&&!n)return{pattern:e};else r===`[`?(n=!0,e+=r):r===`]`&&n?(e+=r,n=!1):e+=r}this._throwError(`Unterminated regex`)}_readStringOrRegex(){let e=this._peek();return e===`"`?(this._next(),De(this._readString())):e===`/`?(this._next(),this._readRegex()):null}_readAttributes(e){let t=this._pos;for(;this._skipWhitespace(),this._peek()===`[`;){this._next(),this._skipWhitespace(),t=this._pos;let n=this._readIdentifier(`attribute`);this._skipWhitespace();let r=``;if(this._peek()===`=`)for(this._next(),this._skipWhitespace(),t=this._pos;this._peek()!==`]`&&!this._isWhitespace()&&!this._eof();)r+=this._next();this._skipWhitespace(),this._peek()!==`]`&&this._throwError(`Expected ]`),this._next(),this._applyAttribute(e,n,r||`true`,t)}}_parse(){this._skipWhitespace();let e=this._readIdentifier(`role`);e===`fragment`&&this._throwError(`Invalid role "fragment"`),this._skipWhitespace();let t={kind:`role`,role:e,name:this._readStringOrRegex()||void 0};return this._readAttributes(t),this._skipWhitespace(),this._eof()||this._throwError(`Unexpected input`),t}_applyAttribute(e,t,n,r){if(t===`checked`){this._assert(n===`true`||n===`false`||n===`mixed`,`Value of "checked" attribute must be a boolean or "mixed"`,r),e.checked=n===`true`?!0:n===`false`?!1:`mixed`;return}if(t===`disabled`){this._assert(n===`true`||n===`false`,`Value of "disabled" attribute must be a boolean`,r),e.disabled=n===`true`;return}if(t===`expanded`){this._assert(n===`true`||n===`false`,`Value of "expanded" attribute must be a boolean`,r),e.expanded=n===`true`;return}if(t===`active`){this._assert(n===`true`||n===`false`,`Value of "active" attribute must be a boolean`,r),e.active=n===`true`;return}if(t===`level`){this._assert(!Number.isNaN(Number(n)),`Value of "level" attribute must be a number`,r),e.level=Number(n);return}if(t===`pressed`){this._assert(n===`true`||n===`false`||n===`mixed`,`Value of "pressed" attribute must be a boolean or "mixed"`,r),e.pressed=n===`true`?!0:n===`false`?!1:`mixed`;return}if(t===`selected`){this._assert(n===`true`||n===`false`,`Value of "selected" attribute must be a boolean`,r),e.selected=n===`true`;return}this._assert(!1,`Unsupported attribute [${t}]`,r)}_assert(e,t,n){e||this._throwError(t||`Assertion error`,n)}},y=class extends Error{constructor(e,t){super(e),m(this,`pos`,void 0),this.pos=t}};function b(e,t){return t?e?typeof t==`string`?e===t:!!e.match(new RegExp(t.pattern)):!1:!0}function x(e,t){if(!t?.normalized)return!0;if(!e)return!1;if(e===t.normalized||e===t.raw)return!0;let n=C(t);return n?!!e.match(n):!1}const S=Symbol(`cachedRegex`);function C(e){if(e[S]!==void 0)return e[S];let{raw:t}=e,n=t.startsWith(`/`)&&t.endsWith(`/`)&&t.length>1,r;try{r=n?new RegExp(t.slice(1,-1)):null}catch{r=null}return e[S]=r,r}function w(e,t,n){if(typeof e==`string`&&t.kind===`text`)return x(e,t.text);if(typeof e!=`object`||!e||t.kind!==`role`||t.role!==`fragment`&&t.role!==e.role||t.checked!==void 0&&t.checked!==e.checked||t.disabled!==void 0&&t.disabled!==e.disabled||t.expanded!==void 0&&t.expanded!==e.expanded||t.level!==void 0&&t.level!==e.level||t.pressed!==void 0&&t.pressed!==e.pressed||t.selected!==void 0&&t.selected!==e.selected||!b(e.name,t.name))return!1;if(t.props){for(let[n,r]of Object.entries(t.props))if(!x(e.props[n]||``,r))return!1}return t.containerMode===`contain`?E(e.children||[],t.children||[]):t.containerMode===`equal`?T(e.children||[],t.children||[],!1):t.containerMode===`deep-equal`||n?T(e.children||[],t.children||[],!0):E(e.children||[],t.children||[])}function T(e,t,n){if(t.length!==e.length)return!1;for(let r=0;r<t.length;++r)if(!w(e[r],t[r],n))return!1;return!0}function E(e,t){if(t.length>e.length)return!1;let n=e.slice(),r=t.slice();for(let e of r){let t=n.shift();for(;t&&!w(t,e,!1);)t=n.shift();if(!t)return!1}return!0}var Oe=Ce({LineCounter:()=>ke,Scalar:()=>D,YAMLError:()=>A,YAMLMap:()=>O,YAMLSeq:()=>k,parseDocument:()=>Ae}),D=class{constructor(e,t=[0,0,0]){m(this,`value`,void 0),m(this,`range`,void 0),this.value=e,this.range=t}},O=class{constructor(e=[0,0,0]){m(this,`items`,void 0),m(this,`range`,void 0),this.items=[],this.range=e}},k=class{constructor(e=[0,0,0]){m(this,`items`,void 0),m(this,`range`,void 0),this.items=[],this.range=e}},ke=class{constructor(){m(this,`lineStarts`,[0])}addNewLine(e){e>this.lineStarts[this.lineStarts.length-1]&&this.lineStarts.push(e)}linePos(e){let t=0,n=this.lineStarts.length-1;for(;t<n;){let r=t+n+1>>1;this.lineStarts[r]<=e?t=r:n=r-1}return{line:t+1,col:e-this.lineStarts[t]+1}}},A=class extends Error{constructor(e,t){super(e),m(this,`pos`,void 0),this.pos=t}};function Ae(e,t={}){let n=t.lineCounter,r=[];if(n)for(let t=0;t<e.length;t++)e[t]===`
2
2
  `&&n.addNewLine(t+1);try{return{contents:new je(e,r).parseRoot(),errors:r}}catch(e){if(e instanceof A)return r.push(e),{contents:null,errors:r};throw e}}var je=class{constructor(e,t){m(this,`lines`,void 0),m(this,`pos`,void 0),m(this,`text`,void 0),m(this,`errors`,void 0),this.text=e,this.errors=t,this.lines=[],this.pos=0;let n=0,r=e.split(`
3
3
  `);for(let e of r){let t=e.replace(/\r$/,``),r=t.replace(/^\s+/,``),i=t.length-r.length;this.lines.push({indent:i,content:r,offset:n+i,lineOffset:n,raw:t}),n+=e.length+1}for(;this.lines.length>0&&this.lines[this.lines.length-1].content===``;)this.lines.pop()}parseRoot(){if(this.lines.length===0)return null;let e=this.parseNode(0);if(this.skipEmpty(),this.pos<this.lines.length){let e=this.currentLine();this.addError(`Unexpected scalar at node end`,e.offset)}return e}currentLine(){return this.lines[this.pos]}parseNode(e){this.skipEmpty();let t=this.currentLine();return!t||t.indent<e?null:t.content.startsWith(`- `)||t.content===`-`?this.parseSequence(t.indent):this.isMapEntry(t.content)?this.parseMap(t.indent):(this.pos++,this.parseScalarValue(t.content,t.offset,t))}parseSequence(e){let t=this.currentLine(),n=new k([t.offset-t.indent,0,0]),r=t.offset;for(;this.pos<this.lines.length;){this.skipEmpty();let t=this.currentLine();if(!t||t.indent<e)break;if(t.indent>e){this.addError(`Bad indentation of a sequence entry`,t.offset);break}if(!t.content.startsWith(`- `)&&t.content!==`-`)break;let i=t.content===`-`?1:2,a=t.content.slice(i),o=t.offset+i;if(this.pos++,a===``||a.trim()===``){let t=this.parseNode(e+1);t&&(n.items.push(t),r=this.peekLastOffset())}else if(this.isMapEntry(a)){let s=this.parseInlineMap(a,o,e+i,t);n.items.push(s),r=s.range[2]}else{let e=this.parseScalarValue(a,o,t);n.items.push(e),r=e.range[2]}}return n.range[1]=r,n.range[2]=r,n}parseMap(e){let t=this.currentLine(),n=new O([t.offset-t.indent,0,0]),r=t.offset;for(;this.pos<this.lines.length;){this.skipEmpty();let t=this.currentLine();if(!t||t.indent<e)break;if(t.indent>e){this.addError(`Bad indentation of a mapping entry`,t.offset);break}if(!this.isMapEntry(t.content))break;let{key:i,valueStr:a,colonOffset:o,valueOffset:s}=this.splitMapEntry(t.content,t.offset),c=new D(i,[t.offset,t.offset+i.length,o]);this.pos++;let l;l=a===``?this.parseMapValue(e,o):this.parseScalarValue(a.trim(),s,t),n.items.push({key:c,value:l}),r=l?this.getNodeEnd(l):o+1}return n.range[1]=r,n.range[2]=r,n}parseInlineMap(e,t,n,r){let i=new O([t,0,0]),a=t,{key:o,valueStr:s,colonOffset:c,valueOffset:l}=this.splitMapEntry(e,t),u=new D(o,[t,t+o.length,c]),d;for(d=s===``?this.parseMapValue(n,c):this.parseScalarValue(s.trim(),l,r),i.items.push({key:u,value:d}),a=d?this.getNodeEnd(d):c+1;this.pos<this.lines.length;){this.skipEmpty();let e=this.currentLine();if(!e||e.indent<n||e.indent>n||!this.isMapEntry(e.content)||e.content.startsWith(`- `))break;let t=this.splitMapEntry(e.content,e.offset),r=new D(t.key,[e.offset,e.offset+t.key.length,t.colonOffset]);this.pos++;let o;o=t.valueStr===``?this.parseMapValue(n,t.colonOffset):this.parseScalarValue(t.valueStr.trim(),t.valueOffset,e),i.items.push({key:r,value:o}),a=o?this.getNodeEnd(o):t.colonOffset+1}return i.range[1]=a,i.range[2]=a,i}parseMapValue(e,t){this.skipEmpty();let n=this.currentLine();return!n||n.indent<e?new D(null,[t+1,t+1,t+1]):n.indent===e&&(n.content.startsWith(`- `)||n.content===`-`)?this.parseNode(e):n.indent>e?this.parseNode(e+1):new D(null,[t+1,t+1,t+1])}getNodeEnd(e){return e.range[2]}peekLastOffset(){if(this.pos>0&&this.pos<=this.lines.length){let e=this.lines[this.pos-1];return e.lineOffset+e.raw.length}return this.text.length}parseScalarValue(e,t,n){let r=e.trim(),i=t+e.indexOf(r),a=i+r.length,o=n.lineOffset+n.raw.length;return r.startsWith(`"`)?this.parseQuotedScalar(r,i,o):r===`true`||r===`false`?new D(r===`true`,[i,a,o]):r===`null`||r===`~`?new D(null,[i,a,o]):r!==``&&Me(r)?new D(Number(r),[i,a,o]):new D(r,[i,a,o])}parseQuotedScalar(e,t,n){let r=``,i=1;for(;i<e.length;){let a=e[i];if(a===`\\`){if(i++,i>=e.length){this.addError(`Unterminated double-quoted string`,t+i);break}let n=e[i];switch(n){case`n`:r+=`
4
4
  `;break;case`t`:r+=` `;break;case`r`:r+=`\r`;break;case`"`:r+=`"`;break;case`\\`:r+=`\\`;break;case`/`:r+=`/`;break;default:r+=n}}else if(a===`"`){let e=t+i+1;return new D(r,[t,e,n])}else r+=a;i++}return this.addError(`Unterminated double-quoted string`,t),new D(r,[t,t+e.length,n])}skipEmpty(){for(;this.pos<this.lines.length&&this.lines[this.pos].content===``;)this.pos++}isMapEntry(e){return this.findMapColon(e)>=0}findMapColon(e){let t=!1,n=!1;for(let r=0;r<e.length;r++){let i=e[r];if(n){n=!1;continue}if(i===`\\`&&t){n=!0;continue}if(i===`"`){t=!t;continue}if(!t&&i===`:`&&(r+1>=e.length||e[r+1]===` `))return r}return-1}splitMapEntry(e,t){let n=this.findMapColon(e),r=e.slice(0,n).trim(),i=t+n,a=e.slice(n+1),o=a.trimStart(),s=i+1+(a.length-a.trimStart().length);return r.startsWith(`"`)&&r.endsWith(`"`)?{key:r.slice(1,-1),valueStr:o,colonOffset:i,valueOffset:s}:{key:r,valueStr:o,colonOffset:i,valueOffset:s}}addError(e,t){this.errors.push(new A(e,[t,t+1]))}};function Me(e){return e===``||e===`-`||e===`+`?!1:/^[+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?$/.test(e)}function j(e){return Ne(e)?`"`+e.replace(/[\\"\x00-\x1f\x7f-\x9f]/g,e=>{switch(e){case`\\`:return`\\\\`;case`"`:return`\\"`;case`\b`:return`\\b`;case`\f`:return`\\f`;case`
@@ -7,7 +7,7 @@ import{Snapshots as e,recordArtifact as t,expect as n,chai as r}from"vitest";imp
7
7
  `)}function Ve(e){let t=e.role;return e.name!==void 0&&(t+=` ${ze(e.name)}`),t+=N(e),t}function I(e,t,n){if(e.kind===`text`){n.push(`${t}- text: ${F(e.text)}`);return}let r=Ve(e),i=e.children||[],a=[];if(e.containerMode&&e.containerMode!==`contain`&&a.push(`${t} - /children: ${e.containerMode}`),e.props)for(let[n,r]of Object.entries(e.props))a.push(`${t} - /${n}: ${F(r)}`);if(i.length===0&&a.length===0){n.push(`${t}- ${r}`);return}if(i.length===1&&i[0].kind===`text`&&a.length===0){n.push(`${t}- ${r}: ${F(i[0].text)}`);return}n.push(`${t}- ${r}:`),n.push(...a);for(let e of i)I(e,`${t} `,n)}function He(e,t){let n=e.role===`fragment`?e.children:[e],r=L(t)?t.children??[]:[t],i=L(t)?t.containerMode:void 0,a=qe(n,r,``,i);return a.pass&&i&&i!==`contain`&&a.resolved.unshift(`- /children: ${i}`),{pass:a.pass,resolved:a.resolved.join(`
8
8
  `)}}function L(e){return e.kind===`role`&&e.role===`fragment`}function Ue(e){return typeof e==`object`&&!!e&&`pattern`in e}function We(e,t){let n=e.role;return t.name===void 0||(Ue(t.name)&&b(e.name,t.name)?n+=` ${ze(t.name)}`:e.name&&(n+=` ${JSON.stringify(e.name)}`)),t.level!==void 0&&(n+=` [level=${e.level}]`),t.checked!==void 0&&(e.checked===!0?n+=` [checked]`:e.checked===`mixed`&&(n+=` [checked=mixed]`)),t.disabled!==void 0&&e.disabled&&(n+=` [disabled]`),t.expanded!==void 0&&(e.expanded===!0?n+=` [expanded]`:e.expanded===!1&&(n+=` [expanded=false]`)),t.pressed!==void 0&&(e.pressed===!0?n+=` [pressed]`:e.pressed===`mixed`&&(n+=` [pressed=mixed]`)),t.selected!==void 0&&e.selected&&(n+=` [selected]`),n}function Ge(e,t){let n=new Map,r=0;for(let i=0;i<e.length&&r<t.length;i++)w(e[i],t[r],!1)&&(n.set(i,r),r++);return n}function Ke(e,t){let n=new Map,r=new Set;for(let i=0;i<t.length;i++)for(let a=0;a<e.length;a++)if(!r.has(a)&&w(e[a],t[i],!1)){n.set(a,i),r.add(a);break}return n}function R(e,t){let n=[];return typeof e==`string`?n.push(`${t}- text: ${e}`):P(e,t,n),n}function qe(e,t,n,r){if(e.some(e=>typeof e!=`string`&&e.role===`fragment`)||t.some(e=>L(e)))throw Error(`Internal error: fragment wrappers must be unwrapped at matchAriaTree root`);if(r===`equal`||r===`deep-equal`)return Je(e,t,n,r===`deep-equal`);let i=[],a=Ge(e,t);if(t.length!==a.size){let r=Ke(e,t);for(let a=0;a<e.length;a++){let o=r.get(a);o===void 0?i.push(...R(e[a],n)):i.push(...z(e[a],t[o],n))}return{resolved:i,pass:!1}}for(let r=0;r<e.length;r++){let o=a.get(r);o!==void 0&&i.push(...z(e[r],t[o],n))}return{resolved:i,pass:!0}}function Je(e,t,n,r){let i=[],a=e.length===t.length&&e.every((e,n)=>w(e,t[n],r));for(let a=0;a<e.length;a++)a<t.length?i.push(...z(e[a],t[a],n,r)):i.push(...R(e[a],n));return{resolved:i,pass:a}}function z(e,t,n,r=!1){if(typeof e==`string`&&t.kind===`text`)return[`${n}- text: ${x(e,t.text)&&C(t.text)?F(t.text):e}`];if(typeof e==`string`||t.kind===`text`)return R(e,n);let i=We(e,t),a=qe(e.children,t.children||[],`${n} `,t.containerMode??(r?`equal`:`contain`)),o=[];t.containerMode&&t.containerMode!==`contain`&&o.push(`${n} - /children: ${t.containerMode}`);let s=new Set([...Object.keys(e.props),...Object.keys(t.props||{})]);for(let r of s){let i=e.props[r],a=t.props?.[r];if(i!==void 0){let e=(a===void 0||x(i,a))&&a&&C(a)?F(a):i;o.push(`${n} - /${r}: ${e}`)}}let c=[];if(!a.resolved.length&&!o.length)c.push(`${n}- ${i}`);else if(a.resolved.length===1&&a.resolved[0].trimStart().startsWith(`- text: `)&&!o.length){let e=a.resolved[0].trimStart().slice(8);c.push(`${n}- ${i}: ${e}`)}else c.push(`${n}- ${i}:`),c.push(...o),c.push(...a.resolved);return c}function Ye(e){return we(Oe,e)}var Xe=Object.freeze({__proto__:null,generateAriaTree:Pe,matchAriaTree:He,parseAriaTemplate:Ye,renderAriaTemplate:Be,renderAriaTree:Re});h().aria=Xe;const{generateAriaTree:Ze,matchAriaTree:Qe,parseAriaTemplate:$e,renderAriaTemplate:et,renderAriaTree:tt}=Xe,B={name:`aria`,capture(e){if(e instanceof Element)return Ze(e);throw TypeError(`aria adapter expects an Element`)},render(e){return V(tt(e))},parseExpected(e){let t=Error.stackTraceLimit;Error.stackTraceLimit=t+20;try{return $e(e.trim())}finally{Error.stackTraceLimit=t}},match(e,t){let n=Qe(e,t);return n.pass?{pass:!0}:{pass:!1,message:`Accessibility tree does not match expected template`,resolved:V(n.resolved),expected:V(et(t))}}};function V(e){return`\n${e}\n`}const nt={toMatchAriaSnapshot(t){return e.toMatchDomainSnapshot.call(this,B,t)},toMatchAriaInlineSnapshot(t,n){return e.toMatchDomainInlineSnapshot.call(this,B,t,n)}};for(let e of Object.values(nt))Object.assign(e,{__vitest_poll_takeover__:!0});function rt(){return[...d]}function it(e,t,n){return e instanceof g&&(e=e.query()),e==null?null:H(e,t,n)}function H(e,t,n){e instanceof g&&(e=e.element());let r=e?.ownerDocument?.defaultView||window;if(e instanceof r.HTMLElement||e instanceof r.SVGElement)return e;throw new ft(e,t,n)}function at(e,t,n){e instanceof g&&(e=e.element());let r=e.ownerDocument?.defaultView||window;if(e instanceof r.Node)return e;throw new pt(e,t,n)}function U(e,t,n,r,i,a){return[`${t}\n`,`${n}:\n${e.utils.EXPECTED_COLOR(W(lt(e,r),2))}`,`${i}:\n${e.utils.RECEIVED_COLOR(W(lt(e,a),2))}`].join(`
9
9
  `)}function W(e,t){return ot(ct(e),t)}function ot(e,t){return e.replace(/^(?!\s*$)/gm,` `.repeat(t))}function st(e){let t=e.match(/^[ \t]*(?=\S)/gm);return t?t.reduce((e,t)=>Math.min(e,t.length),1/0):0}function ct(e){let t=st(e);if(t===0)return e;let n=RegExp(`^[ \\t]{${t}}`,`gm`);return e.replace(n,``)}function lt(e,t){return typeof t==`string`?t:e.utils.stringify(t)}function ut(e,{wordConnector:t=`, `,lastWordConnector:n=` and `}={}){return[e.slice(0,-1).join(t),e.at(-1)].join(e.length>1?n:``)}class dt extends Error{constructor(e,t,n,r){super(),Error.captureStackTrace&&Error.captureStackTrace(this,n);let i=``;try{i=r.utils.printWithType(`Received`,t,r.utils.printReceived)}catch{}this.message=[r.utils.matcherHint(`${r.isNot?`.not`:``}.${n.name}`,`received`,``),``,`${r.utils.RECEIVED_COLOR(`received`)} value must ${e} or a Locator that returns ${e}.`,i].join(`
10
- `)}}class ft extends dt{constructor(e,t,n){super(`an HTMLElement or an SVGElement`,e,t,n)}}class pt extends dt{constructor(e,t,n){super(`a Node`,e,t,n)}}function G(e){return e instanceof HTMLFormElement?`FORM`:e.tagName.toUpperCase()}function K(e){return G(e)===`INPUT`}function mt(e){if(e)switch(G(e)){case`INPUT`:return gt(e);case`SELECT`:return ht(e);default:return e.value??vt(e)}}function ht({multiple:e,options:t}){let n=[...t].filter(e=>e.selected);if(e)return[...n].map(e=>e.value);if(n.length!==0)return n[0].value}function gt(e){switch(e.type){case`number`:return e.value===``?null:Number(e.value);case`checkbox`:return e.checked;default:return e.value}}const _t=[`meter`,`progressbar`,`slider`,`spinbutton`];function vt(e){if(_t.includes(e.getAttribute(`role`)||``))return Number(e.getAttribute(`aria-valuenow`))}function yt(e){return e.replace(/\s+/g,` `).trim()}function bt(e,t){return t instanceof RegExp?t.test(e):e.includes(String(t))}function q(e,t){if(Array.isArray(e)&&Array.isArray(t)){let n=new Set(t);for(let t of new Set(e))if(!n.has(t))return!1;return!0}}const xt=rt();function St(e){let t=H(e,St,this);if(!(K(t)&&[`checkbox`,`radio`].includes(t.type))&&!(xt.includes(c(t)||``)&&[`true`,`false`].includes(t.getAttribute(`aria-checked`)||``)))return{pass:!1,message:()=>`only inputs with type="checkbox" or type="radio" or elements with ${Ct()} and a valid aria-checked attribute can be used with .toBeChecked(). Use .toHaveValue() instead`};let n=f(t)===!0;return{pass:n,message:()=>{let e=n?`is`:`is not`;return[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBeChecked`,`element`,``),``,`Received element ${e} checked:`,` ${this.utils.printReceived(t.cloneNode(!1))}`].join(`
10
+ `)}}class ft extends dt{constructor(e,t,n){super(`an HTMLElement or an SVGElement`,e,t,n)}}class pt extends dt{constructor(e,t,n){super(`a Node`,e,t,n)}}function G(e){return e instanceof HTMLFormElement?`FORM`:e.tagName.toUpperCase()}function K(e){return G(e)===`INPUT`}function mt(e){if(e)switch(G(e)){case`INPUT`:return gt(e);case`SELECT`:return ht(e);default:return e.value??vt(e)}}function ht({multiple:e,options:t}){let n=[...t].filter(e=>e.selected);if(e)return Array.from(n,e=>e.value);if(n.length!==0)return n[0].value}function gt(e){switch(e.type){case`number`:return e.value===``?null:Number(e.value);case`checkbox`:return e.checked;default:return e.value}}const _t=[`meter`,`progressbar`,`slider`,`spinbutton`];function vt(e){if(_t.includes(e.getAttribute(`role`)||``))return Number(e.getAttribute(`aria-valuenow`))}function yt(e){return e.replace(/\s+/g,` `).trim()}function bt(e,t){return t instanceof RegExp?t.test(e):e.includes(String(t))}function q(e,t){if(Array.isArray(e)&&Array.isArray(t)){let n=new Set(t);for(let t of new Set(e))if(!n.has(t))return!1;return!0}}const xt=rt();function St(e){let t=H(e,St,this);if(!(K(t)&&[`checkbox`,`radio`].includes(t.type))&&!(xt.includes(c(t)||``)&&[`true`,`false`].includes(t.getAttribute(`aria-checked`)||``)))return{pass:!1,message:()=>`only inputs with type="checkbox" or type="radio" or elements with ${Ct()} and a valid aria-checked attribute can be used with .toBeChecked(). Use .toHaveValue() instead`};let n=f(t)===!0;return{pass:n,message:()=>{let e=n?`is`:`is not`;return[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBeChecked`,`element`,``),``,`Received element ${e} checked:`,` ${this.utils.printReceived(t.cloneNode(!1))}`].join(`
11
11
  `)}}}function Ct(){return ut(xt.map(e=>`role="${e}"`),{lastWordConnector:` or `})}function wt(e){let t=H(e,wt,this);return{pass:Tt(t),message:()=>[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBeEmptyDOMElement`,`element`,``),``,`Received:`,` ${this.utils.printReceived(t.innerHTML)}`].join(`
12
12
  `)}}function Tt(e){return[...e.childNodes].filter(e=>e.nodeType!==Node.COMMENT_NODE).length===0}function Et(e){let t=H(e,Et,this),n=Ot(t);return{pass:n,message:()=>{let e=n?`is`:`is not`;return[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBeDisabled`,`element`,``),``,`Received element ${e} disabled:`,` ${this.utils.printReceived(t.cloneNode(!1))}`].join(`
13
13
  `)}}}function Dt(e){let t=H(e,Dt,this),n=Ot(t);return{pass:!n,message:()=>{let e=n?`is not`:`is`;return[this.utils.matcherHint(`${this.isNot?`.not`:``}.toBeEnabled`,`element`,``),``,`Received element ${e} enabled:`,` ${this.utils.printReceived(t.cloneNode(!1))}`].join(`
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { ResolvedConfig, BrowserServerFactory, BrowserCommand, BrowserProviderOption } from 'vitest/node';
1
+ import { TestProject, ResolvedConfig, BrowserServerFactory, BrowserCommand, BrowserProviderOption } from 'vitest/node';
2
2
  import { ScreenshotMatcherOptions, NonStandardScreenshotComparators, ScreenshotComparatorRegistry } from '@vitest/browser/context';
3
3
 
4
4
  interface BaseMetadata {
@@ -61,6 +61,8 @@ declare function parseKeyDef(text: string): {
61
61
  repeat: number;
62
62
  }[];
63
63
  declare function resolveScreenshotPath(testPath: string, name: string, config: ResolvedConfig, customPath: string | undefined): string;
64
+ declare function assertBrowserFileAccess(project: TestProject, path: string): void;
65
+ declare function assertBrowserApiWrite(project: TestProject, path: string): void;
64
66
 
65
67
  interface SerializedLocator {
66
68
  selector: string;
@@ -73,5 +75,5 @@ declare function defineBrowserProvider<T extends object = object>(options: Omit<
73
75
  options?: T;
74
76
  }): BrowserProviderOption;
75
77
 
76
- export { createBrowserServer, defineBrowserCommand, defineBrowserProvider, parseKeyDef, resolveScreenshotPath };
78
+ export { assertBrowserApiWrite, assertBrowserFileAccess, createBrowserServer, defineBrowserCommand, defineBrowserProvider, parseKeyDef, resolveScreenshotPath };
77
79
  export type { CustomComparatorsRegistry, SerializedLocator };
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 { isValidApiRequest, isFileServingAllowed, distDir, rolldownVersion, resolveApiServerConfig, resolveFsAllow, isFileLoadingAllowed, createDebugger, createViteLogger, createViteServer } from 'vitest/node';
4
+ import { isFileLoadingAllowed, isValidApiRequest, isFileServingAllowed, distDir, rolldownVersion, resolveApiServerConfig, resolveFsAllow, createDebugger, createViteLogger, createViteServer } from 'vitest/node';
5
5
  import { fileURLToPath } from 'node:url';
6
6
  import fs, { readFileSync, createReadStream, promises, existsSync } from 'node:fs';
7
7
  import { createRequire } from 'node:module';
@@ -10,16 +10,17 @@ import { slash as slash$1, toArray, deepMerge } from '@vitest/utils/helpers';
10
10
  import MagicString from 'magic-string';
11
11
  import sirv from 'sirv';
12
12
  import crypto from 'node:crypto';
13
+ import { platform } from 'node:os';
14
+ import 'vite';
13
15
  import { readFile as readFile$1, mkdir, writeFile as writeFile$1 } from 'node:fs/promises';
14
16
  import { parseErrorStacktrace, parseStacktrace } from '@vitest/utils/source-map';
15
17
  import { extractSourcemapFromFile } from '@vitest/utils/source-map/node';
16
18
  import { resolve as resolve$1, basename as basename$1, dirname as dirname$1 } from 'node:path';
17
- import { platform } from 'node:os';
18
19
  import { PNG } from 'pngjs';
19
20
  import { diff } from '@blazediff/core';
20
21
  import { WebSocketServer } from 'ws';
21
22
 
22
- var version = "5.0.0-beta.5";
23
+ var version = "5.0.0-beta.6";
23
24
 
24
25
  const _DRIVE_LETTER_START_RE = /^[A-Za-z]:\//;
25
26
  function normalizeWindowsPath(input = "") {
@@ -214,6 +215,8 @@ const basename = function(p, extension) {
214
215
  const pkgRoot = resolve(fileURLToPath(import.meta.url), "../..");
215
216
  const distRoot = resolve(pkgRoot, "dist");
216
217
 
218
+ const API_TOKEN_FILE = ".vitest-secret-token";
219
+
217
220
  /// <reference types="../types/index.d.ts" />
218
221
 
219
222
  // (c) 2020-present Andrea Giammarchi
@@ -675,6 +678,17 @@ async function getBrowserProvider(options, project) {
675
678
  function slash(path) {
676
679
  return path.replace(/\\/g, "/").replace(/\/+/g, "/");
677
680
  }
681
+ function assertBrowserFileAccess(project, path) {
682
+ const normalized = slash(path);
683
+ if (!isFileLoadingAllowed(project.vite.config, normalized) && !isFileLoadingAllowed(project.vitest.vite.config, normalized)) {
684
+ throw new Error(`Access denied to "${path}". See Vite config documentation for "server.fs": https://vitejs.dev/config/server-options.html#server-fs-strict.`);
685
+ }
686
+ }
687
+ function assertBrowserApiWrite(project, path) {
688
+ if (!project.config.browser.api.allowWrite || !project.vitest.config.api.allowWrite) {
689
+ throw new Error(`Cannot modify file "${path}". File writing is disabled because the server is exposed to the internet, see https://vitest.dev/config/browser/api.`);
690
+ }
691
+ }
678
692
 
679
693
  async function resolveOrchestrator(globalServer, url, res) {
680
694
  const sessionId = url.searchParams.get("sessionId");
@@ -1207,6 +1221,8 @@ var BrowserPlugin = (parentServer, base = "/") => {
1207
1221
  };
1208
1222
  viteConfig.server.fs ??= {};
1209
1223
  viteConfig.server.fs.allow = viteConfig.server.fs.allow || [];
1224
+ viteConfig.server.fs.deny ??= [];
1225
+ viteConfig.server.fs.deny.push(API_TOKEN_FILE);
1210
1226
  viteConfig.server.fs.allow.push(...resolveFsAllow(parentServer.vitest.config.root, parentServer.vitest.vite.config.configFile), distRoot);
1211
1227
  return { resolve: { alias: viteConfig.test?.alias } };
1212
1228
  }
@@ -1904,19 +1920,9 @@ _Mime_extensionToType = new WeakMap(), _Mime_typeToExtension = new WeakMap(), _M
1904
1920
 
1905
1921
  var mime = new Mime(types)._freeze();
1906
1922
 
1907
- function assertFileAccess(path, project) {
1908
- if (!isFileLoadingAllowed(project.vite.config, path) && !isFileLoadingAllowed(project.vitest.vite.config, path)) {
1909
- throw new Error(`Access denied to "${path}". See Vite config documentation for "server.fs": https://vitejs.dev/config/server-options.html#server-fs-strict.`);
1910
- }
1911
- }
1912
- function assertWrite(path, project) {
1913
- if (!project.config.browser.api.allowWrite || !project.vitest.config.api.allowWrite) {
1914
- throw new Error(`Cannot modify file "${path}". File writing is disabled because server is exposed to the internet, see https://vitest.dev/config/browser/api.`);
1915
- }
1916
- }
1917
1923
  const readFile = async ({ project }, path, options = {}) => {
1918
1924
  const filepath = resolve$1(project.config.root, path);
1919
- assertFileAccess(slash(filepath), project);
1925
+ assertBrowserFileAccess(project, filepath);
1920
1926
  // never return a Buffer
1921
1927
  if (typeof options === "object" && !options.encoding) {
1922
1928
  options.encoding = "utf-8";
@@ -1924,9 +1930,9 @@ const readFile = async ({ project }, path, options = {}) => {
1924
1930
  return promises.readFile(filepath, options);
1925
1931
  };
1926
1932
  const writeFile = async ({ project }, path, data, options) => {
1927
- assertWrite(path, project);
1933
+ assertBrowserApiWrite(project, path);
1928
1934
  const filepath = resolve$1(project.config.root, path);
1929
- assertFileAccess(slash(filepath), project);
1935
+ assertBrowserFileAccess(project, filepath);
1930
1936
  const dir = dirname$1(filepath);
1931
1937
  if (!fs.existsSync(dir)) {
1932
1938
  await promises.mkdir(dir, { recursive: true });
@@ -1934,14 +1940,14 @@ const writeFile = async ({ project }, path, data, options) => {
1934
1940
  await promises.writeFile(filepath, data, options);
1935
1941
  };
1936
1942
  const removeFile = async ({ project }, path) => {
1937
- assertWrite(path, project);
1943
+ assertBrowserApiWrite(project, path);
1938
1944
  const filepath = resolve$1(project.config.root, path);
1939
- assertFileAccess(slash(filepath), project);
1945
+ assertBrowserFileAccess(project, filepath);
1940
1946
  await promises.rm(filepath);
1941
1947
  };
1942
1948
  const _fileInfo = async ({ project }, path, encoding) => {
1943
1949
  const filepath = resolve$1(project.config.root, path);
1944
- assertFileAccess(slash(filepath), project);
1950
+ assertBrowserFileAccess(project, filepath);
1945
1951
  const content = await promises.readFile(filepath, encoding || "base64");
1946
1952
  return {
1947
1953
  content,
@@ -2106,7 +2112,7 @@ function resolveOptions({ context, name, options, testName }) {
2106
2112
  ext: `.${extension}`,
2107
2113
  platform: platform(),
2108
2114
  root,
2109
- screenshotDirectory: relative(root, join(root, context.project.config.browser.screenshotDirectory ?? "__screenshots__")),
2115
+ screenshotDirectory: context.project.config.browser.expect?.toMatchScreenshot?.screenshotDirectory ?? "__screenshots__",
2110
2116
  attachmentsDir: relative(root, context.project.config.attachmentsDir),
2111
2117
  testFileDirectory: relative(root, dirname(context.testPath)),
2112
2118
  testFileName: basename(context.testPath),
@@ -2213,7 +2219,7 @@ function asyncTimeout(timeout) {
2213
2219
  if (timeout === 0) {
2214
2220
  resolve(null);
2215
2221
  } else {
2216
- setTimeout(() => resolve(null), timeout);
2222
+ setTimeout(resolve, timeout, null);
2217
2223
  }
2218
2224
  });
2219
2225
  }
@@ -2287,7 +2293,7 @@ const screenshotMatcher = async (context, name, testName, options) => {
2287
2293
  comparator,
2288
2294
  comparatorOptions
2289
2295
  });
2290
- await performSideEffects(outcome, codec);
2296
+ await performSideEffects(outcome, codec, context.project);
2291
2297
  return buildOutput(outcome, timeout);
2292
2298
  };
2293
2299
  /**
@@ -2377,17 +2383,17 @@ async function determineOutcome({ comparator, comparatorOptions, paths, referenc
2377
2383
  *
2378
2384
  * Only `missing-reference`, `update-reference`, and `mismatch` write files. Successful matches produce no side effects.
2379
2385
  */
2380
- async function performSideEffects(outcome, codec) {
2386
+ async function performSideEffects(outcome, codec, project) {
2381
2387
  switch (outcome.type) {
2382
2388
  case "missing-reference":
2383
2389
  case "update-reference": {
2384
- await writeScreenshot(outcome.reference.path, await encodeScreenshot(outcome.reference, codec));
2390
+ await writeScreenshot(outcome.reference.path, await encodeScreenshot(outcome.reference, codec), project);
2385
2391
  break;
2386
2392
  }
2387
2393
  case "mismatch": {
2388
- await writeScreenshot(outcome.actual.path, await encodeScreenshot(outcome.actual, codec));
2394
+ await writeScreenshot(outcome.actual.path, await encodeScreenshot(outcome.actual, codec), project);
2389
2395
  if (outcome.diff) {
2390
- await writeScreenshot(outcome.diff.path, await codec.encode(outcome.diff.image, {}));
2396
+ await writeScreenshot(outcome.diff.path, await codec.encode(outcome.diff.image, {}), project);
2391
2397
  }
2392
2398
  break;
2393
2399
  }
@@ -2549,8 +2555,10 @@ async function takeScreenshotData({ buffer, codec, context, element, name, scree
2549
2555
  };
2550
2556
  }
2551
2557
  /** Writes encoded images to disk, creating parent directories as needed. */
2552
- async function writeScreenshot(path, image) {
2558
+ async function writeScreenshot(path, image, project) {
2553
2559
  try {
2560
+ assertBrowserApiWrite(project, path);
2561
+ assertBrowserFileAccess(project, path);
2554
2562
  await mkdir(dirname(path), { recursive: true });
2555
2563
  await writeFile$1(path, image);
2556
2564
  } catch (cause) {
@@ -3204,6 +3212,16 @@ function setupBrowserRpc(globalServer, defaultMockerRegistry) {
3204
3212
  artifact.attachments = [];
3205
3213
  vitest.logger.error(`[vitest] Cannot record attachments ("${attachments}") because file writing is disabled, removing attachments from artifact "${artifact.type}". See https://vitest.dev/config/browser/api.`);
3206
3214
  }
3215
+ } else {
3216
+ // attachment files are copied into `attachmentsDir`, so confine
3217
+ // client-supplied paths to Vite's `server.fs` boundary
3218
+ const attachments = artifact.type === "internal:annotation" ? artifact.annotation.attachment ? [artifact.annotation.attachment] : [] : artifact.attachments ?? [];
3219
+ for (const attachment of attachments) {
3220
+ const path = attachment.path;
3221
+ if (path && !path.startsWith("http://") && !path.startsWith("https://")) {
3222
+ checkFileAccess(resolve(project.config.root, path));
3223
+ }
3224
+ }
3207
3225
  }
3208
3226
  return vitest._testRun.recordArtifact(id, artifact);
3209
3227
  },
@@ -3516,4 +3534,4 @@ function defineBrowserProvider(options) {
3516
3534
  };
3517
3535
  }
3518
3536
 
3519
- export { createBrowserServer, defineBrowserCommand, defineBrowserProvider, parseKeyDef, resolveScreenshotPath };
3537
+ export { assertBrowserApiWrite, assertBrowserFileAccess, createBrowserServer, defineBrowserCommand, defineBrowserProvider, parseKeyDef, resolveScreenshotPath };