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

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.
@@ -1 +1 @@
1
- import"@vitest/browser/context";import"../public-utils-Kx5DUGWa.js";export{L as Locator,s as selectorEngine}from"../index-W1MM53zC.js";import"vitest/internal/browser";
1
+ import"@vitest/browser/context";import"../public-utils-Kx5DUGWa.js";export{L as Locator,s as selectorEngine}from"../index-D_g_FMM5.js";import"vitest/internal/browser";
@@ -1 +1 @@
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-Kx5DUGWa.js";import{s as selectorEngine,L as Locator,p as processTimeoutOptions,g as getIframeScale}from"../index-W1MM53zC.js";import"vitest/internal/browser";page.extend({getByLabelText(e,_){return new PlaywrightLocator(getByLabelSelector(e,_))},getByRole(e,_){return new PlaywrightLocator(getByRoleSelector(e,_))},getByTestId(e){return new PlaywrightLocator(getByTestIdSelector(server.config.browser.locators.testIdAttribute,e))},getByAltText(e,_){return new PlaywrightLocator(getByAltTextSelector(e,_))},getByPlaceholder(e,_){return new PlaywrightLocator(getByPlaceholderSelector(e,_))},getByText(e,_){return new PlaywrightLocator(getByTextSelector(e,_))},getByTitle(e,_){return new PlaywrightLocator(getByTitleSelector(e,_))},_createLocator(e){return new PlaywrightLocator(e)},elementLocator(e){return new PlaywrightLocator(selectorEngine.generateSelectorSimple(e),e)}});class PlaywrightLocator extends Locator{constructor(e,_){super(),this.selector=e,this._container=_}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,_){return super.selectOptions(e,processTimeoutOptions(_))}clear(e){return super.clear(processTimeoutOptions(e))}hover(e){return super.hover(processTimeoutOptions(processHoverOptions(e)))}upload(e,_){return super.upload(e,processTimeoutOptions(_))}fill(e,_){return super.fill(e,processTimeoutOptions(_))}dropTo(e,_){return super.dropTo(e,processTimeoutOptions(processDragAndDropOptions(_)))}locator(e){return new PlaywrightLocator(`${this.selector} >> ${e}`,this._container)}elementLocator(e){return new PlaywrightLocator(selectorEngine.generateSelectorSimple(e),e)}}function processDragAndDropOptions(e){if(!e)return e;let _=e;return _.sourcePosition&&=processPlaywrightPosition(_.sourcePosition),_.targetPosition&&=processPlaywrightPosition(_.targetPosition),e}function processHoverOptions(e){if(!e)return e;let _=e;return _.position&&=processPlaywrightPosition(_.position),e}function processClickOptions(e){if(!e)return e;let _=e;return _.position&&=processPlaywrightPosition(_.position),_}function processPlaywrightPosition(e){let _=getIframeScale();return e.x!=null&&(e.x*=_),e.y!=null&&(e.y*=_),e}
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-Kx5DUGWa.js";import{s as selectorEngine,L as Locator,p as processTimeoutOptions,g as getIframeScale}from"../index-D_g_FMM5.js";import"vitest/internal/browser";page.extend({getByLabelText(e,_){return new PlaywrightLocator(getByLabelSelector(e,_))},getByRole(e,_){return new PlaywrightLocator(getByRoleSelector(e,_))},getByTestId(e){return new PlaywrightLocator(getByTestIdSelector(server.config.browser.locators.testIdAttribute,e))},getByAltText(e,_){return new PlaywrightLocator(getByAltTextSelector(e,_))},getByPlaceholder(e,_){return new PlaywrightLocator(getByPlaceholderSelector(e,_))},getByText(e,_){return new PlaywrightLocator(getByTextSelector(e,_))},getByTitle(e,_){return new PlaywrightLocator(getByTitleSelector(e,_))},_createLocator(e){return new PlaywrightLocator(e)},elementLocator(e){return new PlaywrightLocator(selectorEngine.generateSelectorSimple(e),e)}});class PlaywrightLocator extends Locator{constructor(e,_){super(),this.selector=e,this._container=_}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,_){return super.selectOptions(e,processTimeoutOptions(_))}clear(e){return super.clear(processTimeoutOptions(e))}hover(e){return super.hover(processTimeoutOptions(processHoverOptions(e)))}upload(e,_){return super.upload(e,processTimeoutOptions(_))}fill(e,_){return super.fill(e,processTimeoutOptions(_))}dropTo(e,_){return super.dropTo(e,processTimeoutOptions(processDragAndDropOptions(_)))}locator(e){return new PlaywrightLocator(`${this.selector} >> ${e}`,this._container)}elementLocator(e){return new PlaywrightLocator(selectorEngine.generateSelectorSimple(e),e)}}function processDragAndDropOptions(e){if(!e)return e;let _=e;return _.sourcePosition&&=processPlaywrightPosition(_.sourcePosition),_.targetPosition&&=processPlaywrightPosition(_.targetPosition),e}function processHoverOptions(e){if(!e)return e;let _=e;return _.position&&=processPlaywrightPosition(_.position),e}function processClickOptions(e){if(!e)return e;let _=e;return _.position&&=processPlaywrightPosition(_.position),_}function processPlaywrightPosition(e){let _=getIframeScale();return e.x!=null&&(e.x*=_),e.y!=null&&(e.y*=_),e}
@@ -1 +1 @@
1
- import{page,server,userEvent}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,h as getElementError}from"../public-utils-Kx5DUGWa.js";import{s as selectorEngine,L as Locator,c as convertElementToCssSelector}from"../index-W1MM53zC.js";import"vitest/internal/browser";page.extend({getByLabelText(e,m){return new PreviewLocator(getByLabelSelector(e,m))},getByRole(e,m){return new PreviewLocator(getByRoleSelector(e,m))},getByTestId(e){return new PreviewLocator(getByTestIdSelector(server.config.browser.locators.testIdAttribute,e))},getByAltText(e,m){return new PreviewLocator(getByAltTextSelector(e,m))},getByPlaceholder(e,m){return new PreviewLocator(getByPlaceholderSelector(e,m))},getByText(e,m){return new PreviewLocator(getByTextSelector(e,m))},getByTitle(e,m){return new PreviewLocator(getByTitleSelector(e,m))},_createLocator(e){return new PreviewLocator(e)},elementLocator(e){return new PreviewLocator(selectorEngine.generateSelectorSimple(e),e)}});class PreviewLocator extends Locator{constructor(e,m){super(),this._pwSelector=e,this._container=m}get selector(){let e=this.elements().map(e=>convertElementToCssSelector(e));if(!e.length)throw getElementError(this._pwSelector,this._container||document.body);return e.join(`, `)}click(){return userEvent.click(this.element())}dblClick(){return userEvent.dblClick(this.element())}tripleClick(){return userEvent.tripleClick(this.element())}hover(){return userEvent.hover(this.element())}unhover(){return userEvent.unhover(this.element())}async fill(e){return userEvent.fill(this.element(),e)}async upload(e){return userEvent.upload(this.element(),e)}selectOptions(e){return userEvent.selectOptions(this.element(),e)}clear(){return userEvent.clear(this.element())}locator(e){return new PreviewLocator(`${this._pwSelector} >> ${e}`,this._container)}elementLocator(e){return new PreviewLocator(selectorEngine.generateSelectorSimple(e),e)}}
1
+ import{page,server,userEvent}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,h as getElementError}from"../public-utils-Kx5DUGWa.js";import{s as selectorEngine,L as Locator,c as convertElementToCssSelector}from"../index-D_g_FMM5.js";import"vitest/internal/browser";page.extend({getByLabelText(e,m){return new PreviewLocator(getByLabelSelector(e,m))},getByRole(e,m){return new PreviewLocator(getByRoleSelector(e,m))},getByTestId(e){return new PreviewLocator(getByTestIdSelector(server.config.browser.locators.testIdAttribute,e))},getByAltText(e,m){return new PreviewLocator(getByAltTextSelector(e,m))},getByPlaceholder(e,m){return new PreviewLocator(getByPlaceholderSelector(e,m))},getByText(e,m){return new PreviewLocator(getByTextSelector(e,m))},getByTitle(e,m){return new PreviewLocator(getByTitleSelector(e,m))},_createLocator(e){return new PreviewLocator(e)},elementLocator(e){return new PreviewLocator(selectorEngine.generateSelectorSimple(e),e)}});class PreviewLocator extends Locator{constructor(e,m){super(),this._pwSelector=e,this._container=m}get selector(){let e=this.elements().map(e=>convertElementToCssSelector(e));if(!e.length)throw getElementError(this._pwSelector,this._container||document.body);return e.join(`, `)}click(){return userEvent.click(this.element())}dblClick(){return userEvent.dblClick(this.element())}tripleClick(){return userEvent.tripleClick(this.element())}hover(){return userEvent.hover(this.element())}unhover(){return userEvent.unhover(this.element())}async fill(e){return userEvent.fill(this.element(),e)}async upload(e){return userEvent.upload(this.element(),e)}selectOptions(e){return userEvent.selectOptions(this.element(),e)}clear(){return userEvent.clear(this.element())}locator(e){return new PreviewLocator(`${this._pwSelector} >> ${e}`,this._container)}elementLocator(e){return new PreviewLocator(selectorEngine.generateSelectorSimple(e),e)}}
@@ -1 +1 @@
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,h as getElementError}from"../public-utils-Kx5DUGWa.js";import{s as selectorEngine,L as Locator,c as convertElementToCssSelector,a as getBrowserState,g as getIframeScale}from"../index-W1MM53zC.js";import"vitest/internal/browser";page.extend({getByLabelText(e,g){return new WebdriverIOLocator(getByLabelSelector(e,g))},getByRole(e,g){return new WebdriverIOLocator(getByRoleSelector(e,g))},getByTestId(e){return new WebdriverIOLocator(getByTestIdSelector(server.config.browser.locators.testIdAttribute,e))},getByAltText(e,g){return new WebdriverIOLocator(getByAltTextSelector(e,g))},getByPlaceholder(e,g){return new WebdriverIOLocator(getByPlaceholderSelector(e,g))},getByText(e,g){return new WebdriverIOLocator(getByTextSelector(e,g))},getByTitle(e,g){return new WebdriverIOLocator(getByTitleSelector(e,g))},_createLocator(e){return new WebdriverIOLocator(e)},elementLocator(e){return new WebdriverIOLocator(selectorEngine.generateSelectorSimple(e))}});class WebdriverIOLocator extends Locator{constructor(e,g){super(),this._pwSelector=e,this._container=g}get selector(){let e=this.elements().map(e=>convertElementToCssSelector(e));if(!e.length)throw getElementError(this._pwSelector,this._container||document.body);return e.join(`, `)}click(e){return super.click(processClickOptions(e))}dblClick(e){return super.dblClick(processClickOptions(e))}tripleClick(e){return super.tripleClick(processClickOptions(e))}selectOptions(e,g){let _=getWebdriverioSelectOptions(this.element(),e);return this.triggerCommand(`__vitest_selectOptions`,this.selector,_,g)}hover(e){return super.hover(processHoverOptions(e))}dropTo(e,g){return super.dropTo(e,processDragAndDropOptions(g))}locator(e){return new WebdriverIOLocator(`${this._pwSelector} >> ${e}`,this._container)}elementLocator(e){return new WebdriverIOLocator(selectorEngine.generateSelectorSimple(e),e)}}function getWebdriverioSelectOptions(e,g){let _=[...e.querySelectorAll(`option`)],v=Array.isArray(g)?g:[g];if(!v.length)return[];if(v.length>1)throw Error(`Provider "webdriverio" doesn't support selecting multiple values at once`);let y=v[0];if(typeof y!=`string`){let e=`element`in y?y.element():y,g=_.indexOf(e);if(g===-1)throw Error(`The element ${selectorEngine.previewNode(e)} was not found in the "select" options.`);return[{index:g}]}let b=_.findIndex(e=>e.value===y);if(b!==-1)return[{index:b}];let x=_.findIndex(e=>e.textContent?.trim()===y||e.ariaLabel===y);if(x===-1)throw Error(`The option "${y}" was not found in the "select" options.`);return[{index:x}]}function processClickOptions(e){if(!e||!getBrowserState().config.browser.ui)return e;let g=e;if(g.x!=null||g.y!=null){let e={};g.x!=null&&(g.x=scaleCoordinate(g.x,e)),g.y!=null&&(g.y=scaleCoordinate(g.y,e))}return e}function processHoverOptions(e){if(!e||!getBrowserState().config.browser.ui)return e;let g=e,_={};return g.xOffset!=null&&(g.xOffset=scaleCoordinate(g.xOffset,_)),g.yOffset!=null&&(g.yOffset=scaleCoordinate(g.yOffset,_)),e}function processDragAndDropOptions(e){if(!e||!getBrowserState().config.browser.ui)return e;let g={},_=e;return _.sourceX!=null&&(_.sourceX=scaleCoordinate(_.sourceX,g)),_.sourceY!=null&&(_.sourceY=scaleCoordinate(_.sourceY,g)),_.targetX!=null&&(_.targetX=scaleCoordinate(_.targetX,g)),_.targetY!=null&&(_.targetY=scaleCoordinate(_.targetY,g)),e}function scaleCoordinate(e,g){return Math.round(e*getCachedScale(g))}function getCachedScale(e){return e.scale??=getIframeScale()}
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,h as getElementError}from"../public-utils-Kx5DUGWa.js";import{s as selectorEngine,L as Locator,c as convertElementToCssSelector,a as getBrowserState,g as getIframeScale}from"../index-D_g_FMM5.js";import"vitest/internal/browser";page.extend({getByLabelText(e,g){return new WebdriverIOLocator(getByLabelSelector(e,g))},getByRole(e,g){return new WebdriverIOLocator(getByRoleSelector(e,g))},getByTestId(e){return new WebdriverIOLocator(getByTestIdSelector(server.config.browser.locators.testIdAttribute,e))},getByAltText(e,g){return new WebdriverIOLocator(getByAltTextSelector(e,g))},getByPlaceholder(e,g){return new WebdriverIOLocator(getByPlaceholderSelector(e,g))},getByText(e,g){return new WebdriverIOLocator(getByTextSelector(e,g))},getByTitle(e,g){return new WebdriverIOLocator(getByTitleSelector(e,g))},_createLocator(e){return new WebdriverIOLocator(e)},elementLocator(e){return new WebdriverIOLocator(selectorEngine.generateSelectorSimple(e))}});class WebdriverIOLocator extends Locator{constructor(e,g){super(),this._pwSelector=e,this._container=g}get selector(){let e=this.elements().map(e=>convertElementToCssSelector(e));if(!e.length)throw getElementError(this._pwSelector,this._container||document.body);let g=!1,_=e.map(e=>e.startsWith(`>>>`)?(g=!0,e.slice(3)):e);return(g?`>>>`:``)+_.join(`, `)}click(e){return super.click(processClickOptions(e))}dblClick(e){return super.dblClick(processClickOptions(e))}tripleClick(e){return super.tripleClick(processClickOptions(e))}selectOptions(e,g){let _=getWebdriverioSelectOptions(this.element(),e);return this.triggerCommand(`__vitest_selectOptions`,this.selector,_,g)}hover(e){return super.hover(processHoverOptions(e))}dropTo(e,g){return super.dropTo(e,processDragAndDropOptions(g))}locator(e){return new WebdriverIOLocator(`${this._pwSelector} >> ${e}`,this._container)}elementLocator(e){return new WebdriverIOLocator(selectorEngine.generateSelectorSimple(e),e)}}function getWebdriverioSelectOptions(e,g){let _=[...e.querySelectorAll(`option`)],v=Array.isArray(g)?g:[g];if(!v.length)return[];if(v.length>1)throw Error(`Provider "webdriverio" doesn't support selecting multiple values at once`);let y=v[0];if(typeof y!=`string`){let e=`element`in y?y.element():y,g=_.indexOf(e);if(g===-1)throw Error(`The element ${selectorEngine.previewNode(e)} was not found in the "select" options.`);return[{index:g}]}let b=_.findIndex(e=>e.value===y);if(b!==-1)return[{index:b}];let x=_.findIndex(e=>e.textContent?.trim()===y||e.ariaLabel===y);if(x===-1)throw Error(`The option "${y}" was not found in the "select" options.`);return[{index:x}]}function processClickOptions(e){if(!e||!getBrowserState().config.browser.ui)return e;let g=e;if(g.x!=null||g.y!=null){let e={};g.x!=null&&(g.x=scaleCoordinate(g.x,e)),g.y!=null&&(g.y=scaleCoordinate(g.y,e))}return e}function processHoverOptions(e){if(!e||!getBrowserState().config.browser.ui)return e;let g=e,_={};return g.xOffset!=null&&(g.xOffset=scaleCoordinate(g.xOffset,_)),g.yOffset!=null&&(g.yOffset=scaleCoordinate(g.yOffset,_)),e}function processDragAndDropOptions(e){if(!e||!getBrowserState().config.browser.ui)return e;let g={},_=e;return _.sourceX!=null&&(_.sourceX=scaleCoordinate(_.sourceX,g)),_.sourceY!=null&&(_.sourceY=scaleCoordinate(_.sourceY,g)),_.targetX!=null&&(_.targetX=scaleCoordinate(_.targetX,g)),_.targetY!=null&&(_.targetY=scaleCoordinate(_.targetY,g)),e}function scaleCoordinate(e,g){return Math.round(e*getCachedScale(g))}function getCachedScale(e){return e.scale??=getIframeScale()}
package/dist/providers.js CHANGED
@@ -1,4 +1,4 @@
1
- import { W as WebdriverBrowserProvider, P as PlaywrightBrowserProvider } from './webdriver-KA1WiV0q.js';
1
+ import { W as WebdriverBrowserProvider, P as PlaywrightBrowserProvider } from './webdriver-AHRa6U3j.js';
2
2
  import '@vitest/mocker/node';
3
3
  import 'tinyrainbow';
4
4
  import 'vitest/node';
@@ -0,0 +1,13 @@
1
+ import type { ScreenshotComparatorRegistry, ScreenshotMatcherOptions } from "../../../context.js";
2
+ export type ScreenshotMatcherArguments<ComparatorName extends keyof ScreenshotComparatorRegistry = keyof ScreenshotComparatorRegistry> = [name: string, testName: string, options: ScreenshotMatcherOptions<ComparatorName> & {
3
+ element: string;
4
+ }];
5
+ export type ScreenshotMatcherOutput = Promise<{
6
+ pass: false;
7
+ reference: string | null;
8
+ actual: string | null;
9
+ diff: string | null;
10
+ message: string;
11
+ } | {
12
+ pass: true;
13
+ }>;
package/dist/state.js CHANGED
@@ -28,14 +28,16 @@
28
28
  config,
29
29
  environment: {
30
30
  name: "browser",
31
- transformMode: "web",
31
+ viteEnvironment: "client",
32
32
  setup() {
33
33
  throw new Error("Not called in the browser");
34
34
  }
35
35
  },
36
36
  onCleanup: (fn) => getBrowserState().cleanups.push(fn),
37
- moduleCache: getBrowserState().moduleCache,
37
+ evaluatedModules: getBrowserState().evaluatedModules,
38
+ resolvingModules: getBrowserState().resolvingModules,
38
39
  moduleExecutionInfo: new Map(),
40
+ metaEnv: null,
39
41
  rpc: null,
40
42
  durations: {
41
43
  environment: 0,
@@ -376,9 +376,14 @@ class WebdriverBrowserProvider {
376
376
  getSupportedBrowsers() {
377
377
  return webdriverBrowsers;
378
378
  }
379
- async initialize(ctx, { browser, options }) {
379
+ async initialize(project, { browser, options }) {
380
+ // increase shutdown timeout because WDIO takes some extra time to kill the driver
381
+ if (!project.vitest.state._data.timeoutIncreased) {
382
+ project.vitest.state._data.timeoutIncreased = true;
383
+ project.vitest.config.teardownTimeout += 1e4;
384
+ }
380
385
  this.closing = false;
381
- this.project = ctx;
386
+ this.project = project;
382
387
  this.browserName = browser;
383
388
  this.options = options;
384
389
  }
@@ -386,13 +391,13 @@ class WebdriverBrowserProvider {
386
391
  return this.iframeSwitched;
387
392
  }
388
393
  async switchToTestFrame() {
389
- const page = this.browser;
394
+ const browser = this.browser;
390
395
  // support wdio@9
391
- if (page.switchFrame) {
392
- await page.switchFrame(page.$("iframe[data-vitest]"));
396
+ if (browser.switchFrame) {
397
+ await browser.switchFrame(browser.$("iframe[data-vitest]"));
393
398
  } else {
394
- const iframe = await page.findElement("css selector", "iframe[data-vitest]");
395
- await page.switchToFrame(iframe);
399
+ const iframe = await browser.findElement("css selector", "iframe[data-vitest]");
400
+ await browser.switchToFrame(iframe);
396
401
  }
397
402
  this.iframeSwitched = true;
398
403
  }
@@ -497,10 +502,15 @@ class WebdriverBrowserProvider {
497
502
  async close() {
498
503
  debug?.("[%s] closing provider", this.browserName);
499
504
  this.closing = true;
500
- await Promise.all([this.browser?.sessionId ? this.browser?.deleteSession?.() : null]);
501
- // TODO: right now process can only exit with timeout, if we use browser
502
- // needs investigating
503
- process.exit();
505
+ const browser = this.browser;
506
+ const sessionId = browser?.sessionId;
507
+ if (!browser || !sessionId) {
508
+ return;
509
+ }
510
+ // https://github.com/webdriverio/webdriverio/blob/ab1a2e82b13a9c7d0e275ae87e7357e1b047d8d3/packages/wdio-runner/src/index.ts#L486
511
+ await browser.deleteSession();
512
+ browser.sessionId = undefined;
513
+ this.browser = null;
504
514
  }
505
515
  }
506
516
 
package/jest-dom.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  // Disable automatic exports.
2
2
 
3
3
  import { ARIARole } from './aria-role.ts'
4
+ import { ScreenshotComparatorRegistry, ScreenshotMatcherOptions } from './context.js'
4
5
 
5
6
  export interface TestingLibraryMatchers<E, R> {
6
7
  /**
@@ -626,7 +627,7 @@ export interface TestingLibraryMatchers<E, R> {
626
627
  * other element that contains text, such as a paragraph, span, div etc.
627
628
  *
628
629
  * NOTE: the expected selection is a string, it does not allow to check for
629
- * selection range indeces.
630
+ * selection range indices.
630
631
  *
631
632
  * @example
632
633
  * <div>
@@ -673,4 +674,51 @@ export interface TestingLibraryMatchers<E, R> {
673
674
  * @see https://vitest.dev/guide/browser/assertion-api#tohaveselection
674
675
  */
675
676
  toHaveSelection(selection?: string): R
677
+
678
+ /**
679
+ * @description
680
+ * This assertion allows you to perform visual regression testing by comparing
681
+ * screenshots of elements or pages against stored reference images.
682
+ *
683
+ * When differences are detected beyond the configured threshold, the test fails.
684
+ * To help identify the changes, the assertion generates:
685
+ *
686
+ * - The actual screenshot captured during the test
687
+ * - The expected reference screenshot
688
+ * - A diff image highlighting the differences (when possible)
689
+ *
690
+ * @example
691
+ * <button data-testid="button">Fancy Button</button>
692
+ *
693
+ * // basic usage, auto-generates screenshot name
694
+ * await expect.element(getByTestId('button')).toMatchScreenshot()
695
+ *
696
+ * // with custom name
697
+ * await expect.element(getByTestId('button')).toMatchScreenshot('fancy-button')
698
+ *
699
+ * // with options
700
+ * await expect.element(getByTestId('button')).toMatchScreenshot({
701
+ * comparatorName: 'pixelmatch',
702
+ * comparatorOptions: {
703
+ * allowedMismatchedPixelRatio: 0.01,
704
+ * },
705
+ * })
706
+ *
707
+ * // with both name and options
708
+ * await expect.element(getByTestId('button')).toMatchScreenshot('fancy-button', {
709
+ * comparatorName: 'pixelmatch',
710
+ * comparatorOptions: {
711
+ * allowedMismatchedPixelRatio: 0.01,
712
+ * },
713
+ * })
714
+ *
715
+ * @see https://vitest.dev/guide/browser/assertion-api#tomatchscreenshot
716
+ */
717
+ toMatchScreenshot<ComparatorName extends keyof ScreenshotComparatorRegistry>(
718
+ options?: ScreenshotMatcherOptions<ComparatorName>,
719
+ ): Promise<R>
720
+ toMatchScreenshot<ComparatorName extends keyof ScreenshotComparatorRegistry>(
721
+ name?: string,
722
+ options?: ScreenshotMatcherOptions<ComparatorName>,
723
+ ): Promise<R>
676
724
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vitest/browser",
3
3
  "type": "module",
4
- "version": "4.0.0-beta.3",
4
+ "version": "4.0.0-beta.5",
5
5
  "description": "Browser running for Vitest",
6
6
  "license": "MIT",
7
7
  "funding": "https://opencollective.com/vitest",
@@ -66,7 +66,7 @@
66
66
  "peerDependencies": {
67
67
  "playwright": "*",
68
68
  "webdriverio": "^7.0.0 || ^8.0.0 || ^9.0.0",
69
- "vitest": "4.0.0-beta.3"
69
+ "vitest": "4.0.0-beta.5"
70
70
  },
71
71
  "peerDependenciesMeta": {
72
72
  "playwright": {
@@ -83,17 +83,20 @@
83
83
  "@testing-library/dom": "^10.4.0",
84
84
  "@testing-library/user-event": "^14.6.1",
85
85
  "magic-string": "^0.30.17",
86
+ "pixelmatch": "7.1.0",
87
+ "pngjs": "^7.0.0",
86
88
  "sirv": "^3.0.1",
87
89
  "tinyrainbow": "^2.0.0",
88
90
  "ws": "^8.18.3",
89
- "@vitest/mocker": "4.0.0-beta.3",
90
- "@vitest/utils": "4.0.0-beta.3"
91
+ "@vitest/mocker": "4.0.0-beta.5",
92
+ "@vitest/utils": "4.0.0-beta.5"
91
93
  },
92
94
  "devDependencies": {
95
+ "@types/pngjs": "^6.0.5",
93
96
  "@types/ws": "^8.18.1",
94
97
  "@wdio/protocols": "^9.16.2",
95
98
  "@wdio/types": "^9.16.2",
96
- "birpc": "2.4.0",
99
+ "birpc": "^2.5.0",
97
100
  "flatted": "^3.3.3",
98
101
  "ivya": "^1.7.0",
99
102
  "mime": "^4.0.7",
@@ -102,11 +105,11 @@
102
105
  "playwright": "^1.54.1",
103
106
  "playwright-core": "^1.54.1",
104
107
  "safaridriver": "^1.0.0",
105
- "webdriverio": "^9.17.0",
106
- "@vitest/ui": "4.0.0-beta.3",
107
- "@vitest/runner": "4.0.0-beta.3",
108
- "vitest": "4.0.0-beta.3",
109
- "@vitest/ws-client": "4.0.0-beta.3"
108
+ "webdriverio": "^9.18.1",
109
+ "@vitest/runner": "4.0.0-beta.5",
110
+ "@vitest/ui": "4.0.0-beta.5",
111
+ "@vitest/ws-client": "4.0.0-beta.5",
112
+ "vitest": "4.0.0-beta.5"
110
113
  },
111
114
  "scripts": {
112
115
  "typecheck": "tsc -p ./src/client/tsconfig.json --noEmit",
@@ -11,6 +11,10 @@ import type {
11
11
  import { Protocol } from 'playwright-core/types/protocol'
12
12
  import '../matchers.js'
13
13
  import type {} from "vitest/node"
14
+ import type {
15
+ ScreenshotComparatorRegistry,
16
+ ScreenshotMatcherOptions,
17
+ } from "@vitest/browser/context"
14
18
 
15
19
  declare module 'vitest/node' {
16
20
  export interface BrowserProviderOptions {
@@ -37,6 +41,15 @@ declare module 'vitest/node' {
37
41
  iframe: FrameLocator
38
42
  context: BrowserContext
39
43
  }
44
+
45
+ export interface ToMatchScreenshotOptions
46
+ extends Omit<
47
+ ScreenshotMatcherOptions,
48
+ "comparatorName" | "comparatorOptions"
49
+ > {}
50
+
51
+ export interface ToMatchScreenshotComparators
52
+ extends ScreenshotComparatorRegistry {}
40
53
  }
41
54
 
42
55
  type PWHoverOptions = NonNullable<Parameters<Page['hover']>[1]>
@@ -1,6 +1,10 @@
1
1
  import type { remote, ClickOptions, DragAndDropOptions } from 'webdriverio'
2
2
  import '../matchers.js'
3
3
  import type {} from "vitest/node"
4
+ import type {
5
+ ScreenshotComparatorRegistry,
6
+ ScreenshotMatcherOptions,
7
+ } from "@vitest/browser/context";
4
8
 
5
9
  declare module 'vitest/node' {
6
10
  export interface BrowserProviderOptions extends Partial<
@@ -19,4 +23,13 @@ declare module 'vitest/node' {
19
23
  export interface BrowserCommandContext {
20
24
  browser: WebdriverIO.Browser
21
25
  }
26
+
27
+ export interface ToMatchScreenshotOptions
28
+ extends Omit<
29
+ ScreenshotMatcherOptions,
30
+ "comparatorName" | "comparatorOptions"
31
+ > {}
32
+
33
+ export interface ToMatchScreenshotComparators
34
+ extends ScreenshotComparatorRegistry {}
22
35
  }
package/utils.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  // should be in sync with tester/public-utils.ts
2
- // we cannot bundle it because vitest depend on the @vitest/browser and vise versa
2
+ // we cannot bundle it because vitest depend on the @vitest/browser and vice versa
3
3
  // fortunately, the file is quite small
4
4
 
5
5
  import { LocatorSelectors, Locator } from '@vitest/browser/context'