1"use strict";(self.webpackChunkplaywright_dev=self.webpackChunkplaywright_dev||[]).push([["5008"],{69451(e,t,s){s.r(t),s.d(t,{metadata:()=>n,default:()=>h,frontMatter:()=>l,contentTitle:()=>o,toc:()=>a,assets:()=>c});var n=JSON.parse('{"id":"api/class-testproject","title":"TestProject","description":"Playwright Test supports running multiple test projects at the same time. This is useful for running tests in multiple configurations. For example, consider running tests against multiple browsers. This type describes format of a project in the configuration file, to access resolved configuration parameters at run time use [FullProject].","source":"@site/docs/api/class-testproject.mdx","sourceDirName":"api","slug":"/api/class-testproject","permalink":"/docs/next/api/class-testproject","draft":false,"unlisted":false,"tags":[],"version":"current","frontMatter":{"id":"class-testproject","title":"TestProject"},"sidebar":"api","previous":{"title":"TestOptions","permalink":"/docs/next/api/class-testoptions"},"next":{"title":"TestStepInfo","permalink":"/docs/next/api/class-teststepinfo"}}'),r=s(74848),i=s(28453);s(13554),s(41647),s(83137);let l={id:"class-testproject",title:"TestProject"},o,c={},a=[{value:"Properties",id:"properties",level:2},{value:"dependencies",id:"test-project-dependencies",level:3},{value:"expect",id:"test-project-expect",level:3},{value:"fullyParallel",id:"test-project-fully-parallel",level:3},{value:"grep",id:"test-project-grep",level:3},{value:"grepInvert",id:"test-project-grep-invert",level:3},{value:"ignoreSnapshots",id:"test-project-ignore-snapshots",level:3},{value:"metadata",id:"test-project-metadata",level:3},{value:"name",id:"test-project-name",level:3},{value:"outputDir",id:"test-project-output-dir",level:3},{value:"repeatEach",id:"test-project-repeat-each",level:3},{value:"respectGitIgnore",id:"test-project-respect-git-ignore",level:3},{value:"retries",id:"test-project-retries",level:3},{value:"snapshotDir",id:"test-project-snapshot-dir",level:3},{value:"snapshotPathTemplate",id:"test-project-snapshot-path-template",level:3},{value:"teardown",id:"test-project-teardown",level:3},{value:"testDir",id:"test-project-test-dir",level:3},{value:"testIgnore",id:"test-project-test-ignore",level:3},{value:"testMatch",id:"test-project-test-match",level:3},{value:"timeout",id:"test-project-timeout",level:3},{value:"use",id:"test-project-use",level:3},{value:"workers",id:"test-project-workers",level:3}];function d(e){let t={a:"a",admonition:"admonition",code:"code",em:"em",h2:"h2",h3:"h3",hr:"hr",li:"li",ol:"ol",p:"p",pre:"pre",strong:"strong",ul:"ul",...(0,i.R)(),...e.components};return(0,r.jsxs)(r.Fragment,{children:[(0,r.jsxs)(t.p,{children:["Playwright Test supports running multiple test projects at the same time. This is useful for running tests in multiple configurations. For example, consider running tests against multiple browsers. This type describes format of a project in the configuration file, to access resolved configuration parameters at run time use ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-fullproject",title:"FullProject",children:"FullProject"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"TestProject"})," encapsulates configuration specific to a single project. Projects are configured in ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testconfig#test-config-projects",children:"testConfig.projects"})," specified in the ",(0,r.jsx)(t.a,{href:"/docs/next/test-configuration",children:"configuration file"}),". Note that all properties of ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testproject",title:"TestProject",children:"TestProject"})," are available in the top-level ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testconfig",title:"TestConfig",children:"TestConfig"}),", in which case they are shared between all projects."]}),"\n",(0,r.jsx)(t.p,{children:"Here is an example configuration that runs every test in Chromium, Firefox and WebKit, both Desktop and Mobile versions."}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",metastring:'title="playwright.config.ts"',children:"import { defineConfig, devices } from '@playwright/test';
1\n\nexport default defineConfig({\n // Options shared for all projects.\n timeout: 30000,\n use: {\n ignoreHTTPSErrors: true,\n },\n\n // Options specific to each project.\n projects: [\n {\n name: 'chromium',\n use: devices['Desktop Chrome'],\n },\n {\n name: 'firefox',\n use: devices['Desktop Firefox'],\n },\n {\n name: 'webkit',\n use: devices['Desktop Safari'],\n },\n {\n name: 'Mobile Chrome',\n use: devices['Pixel 5'],\n },\n {\n name: 'Mobile Safari',\n use: devices['iPhone 12'],\n },\n ],\n});\n"})}),"\n",(0,r.jsx)(t.hr,{}),"\n",(0,r.jsx)(t.h2,{id:"properties",children:"Properties"}),"\n",(0,r.jsx)(t.h3,{id:"test-project-dependencies",children:"dependencies"}),"\n",(0,r.jsx)("font",{size:"2",style:{position:"relative",top:"-20px"},children:"Added in: v1.31"}),"\n",(0,r.jsx)("x-search",{children:"testProject.dependencies"}),"\n",(0,r.jsxs)(t.p,{children:["List of projects that need to run before any test in this project runs. Dependencies can be useful for configuring the global setup actions in a way that every action is in a form of a test. Passing ",(0,r.jsx)(t.code,{children:"--no-deps"})," argument ignores the dependencies and behaves as if they were not specified."]}),"\n",(0,r.jsx)(t.p,{children:"Using dependencies allows global setup to produce traces and other artifacts, see the setup steps in the test report, etc."}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Usage"})}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",metastring:'title="playwright.config.ts"',children:"import { defineConfig } from '@playwright/test';\n\nexport default defineConfig({\n projects: [\n {\n name: 'setup',\n testMatch: /global.setup\\.ts/,\n },\n {\n name: 'chromium',\n use: devices['Desktop Chrome'],\n dependencies: ['setup'],\n },\n {\n name: 'firefox',\n use: devices['Desktop Firefox'],\n dependencies: ['setup'],\n },\n {\n name: 'webkit',\n use: devices['Desktop Safari'],\n dependencies: ['setup'],\n },\n ],\n});\n"})}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Type"})}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array",title:"Array",children:"Array"}),"<",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type",title:"string",children:"string"}),">"]}),"\n"]}),"\n",(0,r.jsx)(t.hr,{}),"\n",(0,r.jsx)(t.h3,{id:"test-project-expect",children:"expect"}),"\n",(0,r.jsx)("font",{size:"2",style:{position:"relative",top:"-20px"},children:"Added in: v1.10"}),"\n",(0,r.jsx)("x-search",{children:"testProject.expect"}),"\n",(0,r.jsxs)(t.p,{children:["Configuration for the ",(0,r.jsx)(t.code,{children:"expect"})," assertion library."]}),"\n",(0,r.jsxs)(t.p,{children:["Use ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testconfig#test-config-expect",children:"testConfig.expect"})," to change this option for all projects."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Usage"})}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",children:"testProject.expect\n"})}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Type"})}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object",title:"Object",children:"Object"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"timeout"})," ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type",title:"Number",children:"number"})," ",(0,r.jsx)(t.em,{children:"(optional)"})]}),"\n",(0,r.jsx)(t.p,{children:"Default timeout for async expect matchers in milliseconds, defaults to 5000ms."}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"toHaveScreenshot"})," ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object",title:"Object",children:"Object"})," ",(0,r.jsx)(t.em,{children:"(optional)"})]}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"threshold"})," ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type",title:"Number",children:"number"})," ",(0,r.jsx)(t.em,{children:"(optional)"})]}),"\n",(0,r.jsxs)(t.p,{children:["an acceptable perceived color difference between the same pixel in compared images, ranging from ",(0,r.jsx)(t.code,{children:"0"})," (strict) and ",(0,r.jsx)(t.code,{children:"1"})," (lax). ",(0,r.jsx)(t.code,{children:'"pixelmatch"'})," comparator computes color difference in ",(0,r.jsx)(t.a,{href:"https://en.wikipedia.org/wiki/YIQ",children:"YIQ color space"})," and defaults ",(0,r.jsx)(t.code,{children:"threshold"})," value to ",(0,r.jsx)(t.code,{children:"0.2"}),"."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"maxDiffPixels"})," ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type",title:"Number",children:"number"})," ",(0,r.jsx)(t.em,{children:"(optional)"})]}),"\n",(0,r.jsx)(t.p,{children:"an acceptable amount of pixels that could be different, unset by default."}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"maxDiffPixelRatio"})," ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type",title:"Number",children:"number"})," ",(0,r.jsx)(t.em,{children:"(optional)"})]}),"\n",(0,r.jsxs)(t.p,{children:["an acceptable ratio of pixels that are different to the total amount of pixels, between ",(0,r.jsx)(t.code,{children:"0"})," and ",(0,r.jsx)(t.code,{children:"1"})," , unset by default."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"animations"}),' "allow" | "disabled" ',(0,r.jsx)(t.em,{children:"(optional)"})]}),"\n",(0,r.jsxs)(t.p,{children:["See ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-page#page-screenshot-option-animations",children:"animations"})," in ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-page#page-screenshot",children:"page.screenshot()"}),". Defaults to ",(0,r.jsx)(t.code,{children:'"disabled"'}),"."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"caret"}),' "hide" | "initial" ',(0,r.jsx)(t.em,{children:"(optional)"})]}),"\n",(0,r.jsxs)(t.p,{children:["See ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-page#page-screenshot-option-caret",children:"caret"})," in ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-page#page-screenshot",children:"page.screenshot()"}),". Defaults to ",(0,r.jsx)(t.code,{children:'"hide"'}),"."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"scale"}),' "css" | "device" ',(0,r.jsx)(t.em,{children:"(optional)"})]}),"\n",(0,r.jsxs)(t.p,{children:["See ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-page#page-screenshot-option-scale",children:"scale"})," in ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-page#page-screenshot",children:"page.screenshot()"}),". Defaults to ",(0,r.jsx)(t.code,{children:'"css"'}),"."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"stylePath"})," ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type",title:"string",children:"string"})," | ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array",title:"Array",children:"Array"}),"<",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type",title:"string",children:"string"}),"> ",(0,r.jsx)(t.em,{children:"(optional)"})]}),"\n",(0,r.jsxs)(t.p,{children:["See ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-page#page-screenshot-option-style",children:"style"})," in ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-page#page-screenshot",children:"page.screenshot()"}),"."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"pathTemplate"})," ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type",title:"string",children:"string"})," ",(0,r.jsx)(t.em,{children:"(optional)"})]}),"\n",(0,r.jsxs)(t.p,{children:["A template controlling location of the screenshots. See ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testproject#test-project-snapsh
1ot-path-template",children:"testProject.snapshotPathTemplate"})," for details."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"timeout"})," ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type",title:"Number",children:"number"})," ",(0,r.jsx)(t.em,{children:"(optional)"})]}),"\n",(0,r.jsxs)(t.p,{children:["Default timeout for ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-pageassertions#page-assertions-to-have-screenshot-1",children:"expect(page).toHaveScreenshot()"})," in milliseconds, defaults to the global expect timeout. Setting to ",(0,r.jsx)(t.code,{children:"0"})," disables the timeout."]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["Configuration for the ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-pageassertions#page-assertions-to-have-screenshot-1",children:"expect(page).toHaveScreenshot()"})," method."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"toMatchAriaSnapshot"})," ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object",title:"Object",children:"Object"})," ",(0,r.jsx)(t.em,{children:"(optional)"})]}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"pathTemplate"})," ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type",title:"string",children:"string"})," ",(0,r.jsx)(t.em,{children:"(optional)"})]}),"\n",(0,r.jsxs)(t.p,{children:["A template controlling location of the aria snapshots. See ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testproject#test-project-snapshot-path-template",children:"testProject.snapshotPathTemplate"})," for details."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"children"}),' "contain" | "equal" | "deep-equal" ',(0,r.jsx)(t.em,{children:"(optional)"})]}),"\n",(0,r.jsxs)(t.p,{children:["Controls how children of the snapshot root are matched against the actual accessibility tree. This is equivalent to adding a ",(0,r.jsx)(t.code,{children:"/children"})," property at the top of every aria snapshot template. Individual snapshots can override this by including an explicit ",(0,r.jsx)(t.code,{children:"/children"})," property."]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["Configuration for the ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-locatorassertions#locator-assertions-to-match-aria-snapshot-2",children:"expect(locator).toMatchAriaSnapshot()"})," method."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"toMatchSnapshot"})," ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object",title:"Object",children:"Object"})," ",(0,r.jsx)(t.em,{children:"(optional)"})]}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"threshold"})," ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type",title:"Number",children:"number"})," ",(0,r.jsx)(t.em,{children:"(optional)"})]}),"\n",(0,r.jsxs)(t.p,{children:["an acceptable perceived color difference between the same pixel in compared images, ranging from ",(0,r.jsx)(t.code,{children:"0"})," (strict) and ",(0,r.jsx)(t.code,{children:"1"})," (lax). ",(0,r.jsx)(t.code,{children:'"pixelmatch"'})," comparator computes color difference in ",(0,r.jsx)(t.a,{href:"https://en.wikipedia.org/wiki/YIQ",children:"YIQ color space"})," and defaults ",(0,r.jsx)(t.code,{children:"threshold"})," value to ",(0,r.jsx)(t.code,{children:"0.2"}),"."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"maxDiffPixels"})," ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type",title:"Number",children:"number"})," ",(0,r.jsx)(t.em,{children:"(optional)"})]}),"\n",(0,r.jsx)(t.p,{children:"an acceptable amount of pixels that could be different, unset by default."}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"maxDiffPixelRatio"})," ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type",title:"Number",children:"number"})," ",(0,r.jsx)(t.em,{children:"(optional)"})]}),"\n",(0,r.jsxs)(t.p,{children:["an acceptable ratio of pixels that are different to the total amount of pixels, between ",(0,r.jsx)(t.code,{children:"0"})," and ",(0,r.jsx)(t.code,{children:"1"})," , unset by default."]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["Configuration for the ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-snapshotassertions#snapshot-assertions-to-match-snapshot-1",children:"expect(value).toMatchSnapshot()"})," method."]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"toPass"})," ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object",title:"Object",children:"Object"})," ",(0,r.jsx)(t.em,{children:"(optional)"})]}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"timeout"})," ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type",title:"Number",children:"number"})," ",(0,r.jsx)(t.em,{children:"(optional)"})]}),"\n",(0,r.jsx)(t.p,{children:"timeout for toPass method in milliseconds."}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:["\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"intervals"})," ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array",title:"Array",children:"Array"}),"<",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type",title:"Number",children:"number"}),"> ",(0,r.jsx)(t.em,{children:"(optional)"})]}),"\n",(0,r.jsx)(t.p,{children:"probe intervals for toPass method in milliseconds."}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["Configuration for the ",(0,r.jsx)(t.a,{href:"/docs/next/test-assertions",children:"expect(value).toPass()"})," method."]}),"\n"]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,r.jsx)(t.hr,{}),"\n",(0,r.jsx)(t.h3,{id:"test-project-fully-parallel",children:"fullyParallel"}),"\n",(0,r.jsx)("font",{size:"2",style:{position:"relative",top:"-20px"},children:"Added in: v1.10"}),"\n",(0,r.jsx)("x-search",{children:"testProject.fullyParallel"}),"\n",(0,r.jsxs)(t.p,{children:["Playwright Test runs tests in parallel. In order to achieve that, it runs several worker processes that run at the same time. By default, ",(0,r.jsx)(t.strong,{children:"test files"})," are run in parallel. Tests in a single file are run in order, in the same worker process."]}),"\n",(0,r.jsx)(t.p,{children:"You can configure entire test project to concurrently run all tests in all files using this option."}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Usage"})}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",children:"testProject.fullyParallel\n"})}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Type"})}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Boolean_type",title:"Boolean",children:"boolean"})}),"\n"]}),"\n",(0,r.jsx)(t.hr,{}),"\n",(0,r.jsx)(t.h3,{id:"test-project-grep",children:"grep"}),"\n",(0,r.jsx)("font",{size:"2",style:{position:"relative",top:"-20px"},children:"Added in: v1.10"}),"\n",(0,r.jsx)("x-search",{children:"testProject.grep"}),"\n",(0,r.jsxs)(t.p,{children:["Filter to only run tests with a title matching one of the patterns. For example, passing ",(0,r.jsx)(t.code,{children:"grep: /cart/"}),' should only run tests with "cart" in the title. Also available globally and in the ',(0,r.jsx)(t.a,{href:"/docs/next/test-cli",children:"command line"})," with the ",(0,r.jsx)(t.code,{children:"-g"})," option. The regular expression will be tested against the string that consists of the project name, the test file name, the ",(0,r.jsx)(t.code,{children:"test.describe"}
1)," name (if any), the test name and the test tags divided by spaces, e.g. ",(0,r.jsx)(t.code,{children:"chromium my-test.spec.ts my-suite my-test"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"grep"})," option is also useful for ",(0,r.jsx)(t.a,{href:"/docs/next/test-annotations#tag-tests",children:"tagging tests"}),"."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Usage"})}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",children:"testProject.grep\n"})}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Type"})}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp",title:"RegExp",children:"RegExp"})," | ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array",title:"Array",children:"Array"}),"<",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp",title:"RegExp",children:"RegExp"}),">"]}),"\n"]}),"\n",(0,r.jsx)(t.hr,{}),"\n",(0,r.jsx)(t.h3,{id:"test-project-grep-invert",children:"grepInvert"}),"\n",(0,r.jsx)("font",{size:"2",style:{position:"relative",top:"-20px"},children:"Added in: v1.10"}),"\n",(0,r.jsx)("x-search",{children:"testProject.grepInvert"}),"\n",(0,r.jsxs)(t.p,{children:["Filter to only run tests with a title ",(0,r.jsx)(t.strong,{children:"not"})," matching any of the patterns. This is the opposite of ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testproject#test-project-grep",children:"testProject.grep"}),". Also available globally and in the ",(0,r.jsx)(t.a,{href:"/docs/next/test-cli",children:"command line"})," with the ",(0,r.jsx)(t.code,{children:"--grep-invert"})," option."]}),"\n",(0,r.jsxs)(t.p,{children:[(0,r.jsx)(t.code,{children:"grepInvert"})," option is also useful for ",(0,r.jsx)(t.a,{href:"/docs/next/test-annotations#tag-tests",children:"tagging tests"}),"."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Usage"})}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",children:"testProject.grepInvert\n"})}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Type"})}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp",title:"RegExp",children:"RegExp"})," | ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array",title:"Array",children:"Array"}),"<",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp",title:"RegExp",children:"RegExp"}),">"]}),"\n"]}),"\n",(0,r.jsx)(t.hr,{}),"\n",(0,r.jsx)(t.h3,{id:"test-project-ignore-snapshots",children:"ignoreSnapshots"}),"\n",(0,r.jsx)("font",{size:"2",style:{position:"relative",top:"-20px"},children:"Added in: v1.44"}),"\n",(0,r.jsx)("x-search",{children:"testProject.ignoreSnapshots"}),"\n",(0,r.jsxs)(t.p,{children:["Whether to skip snapshot expectations, such as ",(0,r.jsx)(t.code,{children:"expect(value).toMatchSnapshot()"})," and ",(0,r.jsx)(t.code,{children:"await expect(page).toHaveScreenshot()"}),"."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Usage"})}),"\n",(0,r.jsx)(t.p,{children:"The following example will only perform screenshot assertions on Chromium."}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",metastring:'title="playwright.config.ts"',children:"import { defineConfig } from '@playwright/test';\n\nexport default defineConfig({\n projects: [\n {\n name: 'chromium',\n use: devices['Desktop Chrome'],\n },\n {\n name: 'firefox',\n use: devices['Desktop Firefox'],\n ignoreSnapshots: true,\n },\n {\n name: 'webkit',\n use: devices['Desktop Safari'],\n ignoreSnapshots: true,\n },\n ],\n});\n"})}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Type"})}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Boolean_type",title:"Boolean",children:"boolean"})}),"\n"]}),"\n",(0,r.jsx)(t.hr,{}),"\n",(0,r.jsx)(t.h3,{id:"test-project-metadata",children:"metadata"}),"\n",(0,r.jsx)("font",{size:"2",style:{position:"relative",top:"-20px"},children:"Added in: v1.10"}),"\n",(0,r.jsx)("x-search",{children:"testProject.metadata"}),"\n",(0,r.jsx)(t.p,{children:"Metadata that will be put directly to the test report serialized as JSON."}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Usage"})}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",children:"testProject.metadata\n"})}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Type"})}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object",title:"Object<string, any>",children:"Metadata"})}),"\n"]}),"\n",(0,r.jsx)(t.hr,{}),"\n",(0,r.jsx)(t.h3,{id:"test-project-name",children:"name"}),"\n",(0,r.jsx)("font",{size:"2",style:{position:"relative",top:"-20px"},children:"Added in: v1.10"}),"\n",(0,r.jsx)("x-search",{children:"testProject.name"}),"\n",(0,r.jsx)(t.p,{children:"Project name is visible in the report and during test execution."}),"\n",(0,r.jsx)(t.admonition,{type:"warning",children:(0,r.jsx)(t.p,{children:"Playwright executes the configuration file multiple times. Do not dynamically produce non-stable values in your configuration."})}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Usage"})}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",children:"testProject.name\n"})}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Type"})}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type",title:"string",children:"string"})}),"\n"]}),"\n",(0,r.jsx)(t.hr,{}),"\n",(0,r.jsx)(t.h3,{id:"test-project-output-dir",children:"outputDir"}),"\n",(0,r.jsx)("font",{size:"2",style:{position:"relative",top:"-20px"},children:"Added in: v1.10"}),"\n",(0,r.jsx)("x-search",{children:"testProject.outputDir"}),"\n",(0,r.jsxs)(t.p,{children:["The output directory for files created during test execution. Defaults to ",(0,r.jsx)(t.code,{children:"<package.json-directory>/test-results"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["This directory is cleaned at the start. When running a test, a unique subdirectory inside the ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testproject#test-project-output-dir",children:"testProject.outputDir"})," is created, guaranteeing that test running in parallel do not conflict. This directory can be accessed by ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testinfo#test-info-output-dir",children:"testInfo.outputDir"})," and ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testinfo#test-info-output-path",children:"testInfo.outputPath()"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["Here is an example that uses ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testinfo#test-info-output-path",children:"testInfo.outputPath()"})," to create a temporary file."]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",children:"import { test, expect } from '@playwright/test';\nimport fs from 'fs';\n\ntest('example test', async ({}, testInfo) =>
1 {\n const file = testInfo.outputPath('temporary-file.txt');\n await fs.promises.writeFile(file, 'Put some data to the file', 'utf8');\n});\n"})}),"\n",(0,r.jsxs)(t.p,{children:["Use ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testconfig#test-config-output-dir",children:"testConfig.outputDir"})," to change this option for all projects."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Usage"})}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",children:"testProject.outputDir\n"})}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Type"})}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type",title:"string",children:"string"})}),"\n"]}),"\n",(0,r.jsx)(t.hr,{}),"\n",(0,r.jsx)(t.h3,{id:"test-project-repeat-each",children:"repeatEach"}),"\n",(0,r.jsx)("font",{size:"2",style:{position:"relative",top:"-20px"},children:"Added in: v1.10"}),"\n",(0,r.jsx)("x-search",{children:"testProject.repeatEach"}),"\n",(0,r.jsx)(t.p,{children:"The number of times to repeat each test, useful for debugging flaky tests."}),"\n",(0,r.jsxs)(t.p,{children:["Use ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testconfig#test-config-repeat-each",children:"testConfig.repeatEach"})," to change this option for all projects."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Usage"})}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",children:"testProject.repeatEach\n"})}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Type"})}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type",title:"Number",children:"number"})}),"\n"]}),"\n",(0,r.jsx)(t.hr,{}),"\n",(0,r.jsx)(t.h3,{id:"test-project-respect-git-ignore",children:"respectGitIgnore"}),"\n",(0,r.jsx)("font",{size:"2",style:{position:"relative",top:"-20px"},children:"Added in: v1.45"}),"\n",(0,r.jsx)("x-search",{children:"testProject.respectGitIgnore"}),"\n",(0,r.jsxs)(t.p,{children:["Whether to skip entries from ",(0,r.jsx)(t.code,{children:".gitignore"})," when searching for test files. By default, if neither ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testconfig#test-config-test-dir",children:"testConfig.testDir"})," nor ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testproject#test-project-test-dir",children:"testProject.testDir"})," are explicitly specified, Playwright will ignore any test files matching ",(0,r.jsx)(t.code,{children:".gitignore"})," entries. This option allows to override that behavior."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Usage"})}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",children:"testProject.respectGitIgnore\n"})}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Type"})}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Boolean_type",title:"Boolean",children:"boolean"})}),"\n"]}),"\n",(0,r.jsx)(t.hr,{}),"\n",(0,r.jsx)(t.h3,{id:"test-project-retries",children:"retries"}),"\n",(0,r.jsx)("font",{size:"2",style:{position:"relative",top:"-20px"},children:"Added in: v1.10"}),"\n",(0,r.jsx)("x-search",{children:"testProject.retries"}),"\n",(0,r.jsxs)(t.p,{children:["The maximum number of retry attempts given to failed tests. Learn more about ",(0,r.jsx)(t.a,{href:"/docs/next/test-retries#retries",children:"test retries"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["Use ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-test#test-describe-configure",children:"test.describe.configure()"})," to change the number of retries for a specific file or a group of tests."]}),"\n",(0,r.jsxs)(t.p,{children:["Use ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testconfig#test-config-retries",children:"testConfig.retries"})," to change this option for all projects."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Usage"})}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",children:"testProject.retries\n"})}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Type"})}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type",title:"Number",children:"number"})}),"\n"]}),"\n",(0,r.jsx)(t.hr,{}
1),"\n",(0,r.jsx)(t.h3,{id:"test-project-snapshot-dir",children:"snapshotDir"}),"\n",(0,r.jsx)("font",{size:"2",style:{position:"relative",top:"-20px"},children:"Added in: v1.10"}),"\n",(0,r.jsx)("x-search",{children:"testProject.snapshotDir"}),"\n",(0,r.jsxs)(t.p,{children:["The base directory, relative to the config file, for snapshot files created with ",(0,r.jsx)(t.code,{children:"toMatchSnapshot"}),". Defaults to ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testproject#test-project-test-dir",children:"testProject.testDir"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["The directory for each test can be accessed by ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testinfo#test-info-snapshot-dir",children:"testInfo.snapshotDir"})," and ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testinfo#test-info-snapshot-path",children:"testInfo.snapshotPath()"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["This path will serve as the base directory for each test file snapshot directory. Setting ",(0,r.jsx)(t.code,{children:"snapshotDir"})," to ",(0,r.jsx)(t.code,{children:"'snapshots'"}),", the ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testinfo#test-info-snapshot-dir",children:"testInfo.snapshotDir"})," would resolve to ",(0,r.jsx)(t.code,{children:"snapshots/a.spec.js-snapshots"}),"."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Usage"})}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",children:"testProject.snapshotDir\n"})}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Type"})}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type",title:"string",children:"string"})}),"\n"]}),"\n",(0,r.jsx)(t.hr,{}),"\n",(0,r.jsx)(t.h3,{id:"test-project-snapshot-path-template",children:"snapshotPathTemplate"}),"\n",(0,r.jsx)("font",{size:"2",style:{position:"relative",top:"-20px"},children:"Added in: v1.28"}),"\n",(0,r.jsx)("x-search",{children:"testProject.snapshotPathTemplate"}),"\n",(0,r.jsxs)(t.p,{children:["This option configures a template controlling location of snapshots generated by ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-pageassertions#page-assertions-to-have-screenshot-1",children:"expect(page).toHaveScreenshot()"}),", ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-locatorassertions#locator-assertions-to-match-aria-snapshot-2",children:"expect(locator).toMatchAriaSnapshot()"})," and ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-snapshotassertions#snapshot-assertions-to-match-snapshot-1",children:"expect(value).toMatchSnapshot()"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["You can configure templates for each assertion separately in ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testconfig#test-config-expect",children:"testConfig.expect"}),"."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Usage"})}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",metastring:'title="playwright.config.ts"',children:"import { defineConfig } from '@playwright/test';\n\nexport default defineConfig({\n testDir: './tests',\n\n // Single template for all assertions\n snapshotPathTemplate: '{testDir}/__screenshots__/{testFilePath}/{arg}{ext}',\n\n // Assertion-specific templates\n expect: {\n toHaveScreenshot: {\n pathTemplate: '{testDir}/__screenshots__{/projectName}/{testFilePath}/{arg}{ext}',\n },\n toMatchAriaSnapshot: {\n pathTemplate: '{testDir}/__snapshots__/{testFilePath}/{arg}{ext}',\n },\n },\n});\n"})}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Type"})}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type",title:"string",children:"string"})}),"\n"]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Details"})}),"\n",(0,r.jsx)(t.p,{children:'The value might include some "tokens" that will be replaced with actual values during test execution.'}),"\n",(0,r.jsx)(t.p,{children:"Consider the following file structure:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-txt",children:"playwright.config.ts\ntests/\n\u2514\u2500\u2500 page/\n \u2514\u2500\u2500 page-click.spec.ts\n"})}),"\n",(0,r.jsxs)(t.p,{children:["And the following ",(0,r.jsx)(t.code,{children:"page-click.spec.ts"})," that uses ",(0,r.jsx)(t.code,{children:"toHaveScreenshot()"})," call:"]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",metastring:'title="page-click.spec.ts"',children:"import { test, expect } from '@playwright/test';\n\ntest.describe('suite', () => {\n test('test should work', async ({ page }) =>
1 {\n await expect(page).toHaveScreenshot(['foo', 'bar', 'baz.png']);\n });\n});\n"})}),"\n",(0,r.jsx)(t.p,{children:"The list of supported tokens:"}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.code,{children:"{arg}"})," - Relative snapshot path ",(0,r.jsx)(t.strong,{children:"without extension"}),". This comes from the arguments passed to ",(0,r.jsx)(t.code,{children:"toHaveScreenshot()"}),", ",(0,r.jsx)(t.code,{children:"toMatchAriaSnapshot()"})," or ",(0,r.jsx)(t.code,{children:"toMatchSnapshot()"}),"; if called without arguments, this will be an auto-generated snapshot name.","\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["Value: ",(0,r.jsx)(t.code,{children:"foo/bar/baz"})]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.code,{children:"{ext}"})," - Snapshot extension (with the leading dot).","\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["Value: ",(0,r.jsx)(t.code,{children:".png"})]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.code,{children:"{platform}"})," - The value of ",(0,r.jsx)(t.code,{children:"process.platform"}),"."]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.code,{children:"{projectName}"})," - Project's file-system-sanitized name, if any.","\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["Value: ",(0,r.jsx)(t.code,{children:"''"})," (empty string)."]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.code,{children:"{snapshotDir}"})," - Project's ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testproject#test-project-snapshot-dir",children:"testProject.snapshotDir"}),".","\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["Value: ",(0,r.jsx)(t.code,{children:"/home/playwright/tests"})," (since ",(0,r.jsx)(t.code,{children:"snapshotDir"})," is not provided in config, it defaults to ",(0,r.jsx)(t.code,{children:"testDir"}),")"]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.code,{children:"{testDir}"})," - Project's ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testproject#test-project-test-dir",children:"testProject.testDir"}),".","\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["Value: ",(0,r.jsx)(t.code,{children:"/home/playwright/tests"})," (absolute path since ",(0,r.jsx)(t.code,{children:"testDir"})," is resolved relative to directory with config)"]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.code,{children:"{testFileDir}"})," - Directories in relative path from ",(0,r.jsx)(t.code,{children:"testDir"})," to ",(0,r.jsx)(t.strong,{children:"test file"}),".","\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["Value: ",(0,r.jsx)(t.code,{children:"page"})]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.code,{children:"{testFileBaseName}"})," - Test file name without the last extension.","\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["Value: ",(0,r.jsx)(t.code,{children:"page-click.spec"})]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.code,{children:"{testFileName}"})," - Test file name with extension.","\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["Value: ",(0,r.jsx)(t.code,{children:"page-click.spec.ts"})]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.code,{children:"{testFilePath}"})," - Relative path from ",(0,r.jsx)(t.code,{children:"testDir"})," to ",(0,r.jsx)(t.strong,{children:"test file"}),".","\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["Value: ",(0,r.jsx)(t.code,{children:"page/page-click.spec.ts"})]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.code,{children:"{testName}"})," - File-system-sanitized test title, including parent describes but excluding file name.","\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:["Value: ",(0,r.jsx)(t.code,{children:"suite-test-should-work"})]}),"\n"]}),"\n"]}),"\n"]}),"\n",(0,r.jsxs)(t.p,{children:["Each token can be preceded with a single character that will be used ",(0,r.jsx)(t.strong,{children:"only if"})," this token has non-empty value."]}),"\n",(0,r.jsx)(t.p,{children:"Consider the following config:"}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",metastring:'title="playwright.config.ts"',children:"import { defineConfig } from '@playwright/test';
1\n\nexport default defineConfig({\n snapshotPathTemplate: '__screenshots__{/projectName}/{testFilePath}/{arg}{ext}',\n testMatch: 'example.spec.ts',\n projects: [\n { use: { browserName: 'firefox' } },\n { name: 'chromium', use: { browserName: 'chromium' } },\n ],\n});\n"})}),"\n",(0,r.jsx)(t.p,{children:"In this config:"}),"\n",(0,r.jsxs)(t.ol,{children:["\n",(0,r.jsxs)(t.li,{children:["First project ",(0,r.jsx)(t.strong,{children:"does not"})," have a name, so its snapshots will be stored in ",(0,r.jsx)(t.code,{children:"<configDir>/__screenshots__/example.spec.ts/..."}),"."]}),"\n",(0,r.jsxs)(t.li,{children:["Second project ",(0,r.jsx)(t.strong,{children:"does"})," have a name, so its snapshots will be stored in ",(0,r.jsx)(t.code,{children:"<configDir>/__screenshots__/chromium/example.spec.ts/.."}),"."]}),"\n",(0,r.jsxs)(t.li,{children:["Since ",(0,r.jsx)(t.code,{children:"snapshotPathTemplate"})," resolves to relative path, it will be resolved relative to ",(0,r.jsx)(t.code,{children:"configDir"}),"."]}),"\n",(0,r.jsxs)(t.li,{children:["Forward slashes ",(0,r.jsx)(t.code,{children:'"/"'})," can be used as path separators on any platform."]}),"\n"]}),"\n",(0,r.jsx)(t.hr,{}),"\n",(0,r.jsx)(t.h3,{id:"test-project-teardown",children:"teardown"}),"\n",(0,r.jsx)("font",{size:"2",style:{position:"relative",top:"-20px"},children:"Added in: v1.34"}),"\n",(0,r.jsx)("x-search",{children:"testProject.teardown"}),"\n",(0,r.jsx)(t.p,{children:"Name of a project that needs to run after this and all dependent projects have finished. Teardown is useful to cleanup any resources acquired by this project."}),"\n",(0,r.jsxs)(t.p,{children:["Passing ",(0,r.jsx)(t.code,{children:"--no-deps"})," argument ignores ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testproject#test-project-teardown",children:"testProject.teardown"})," and behaves as if it was not specified."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Usage"})}),"\n",(0,r.jsx)(t.p,{children:'A common pattern is a "setup" dependency that has a corresponding "teardown":'}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",metastring:'title="playwright.config.ts"',children:"import { defineConfig } from '@playwright/test';\n\nexport default defineConfig({\n projects: [\n {\n name: 'setup',\n testMatch: /global.setup\\.ts/,\n teardown: 'teardown',\n },\n {\n name: 'teardown',\n testMatch: /global.teardown\\.ts/,\n },\n {\n name: 'chromium',\n use: devices['Desktop Chrome'],\n dependencies: ['setup'],\n },\n {\n name: 'firefox',\n use: devices['Desktop Firefox'],\n dependencies: ['setup'],\n },\n {\n name: 'webkit',\n use: devices['Desktop Safari'],\n dependencies: ['setup'],\n },\n ],\n});\n"})}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Type"})}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type",title:"string",children:"string"})}),"\n"]}),"\n",(0,r.jsx)(t.hr,{}),"\n",(0,r.jsx)(t.h3,{id:"test-project-test-dir",children:"testDir"}),"\n",(0,r.jsx)("font",{size:"2",style:{position:"relative",top:"-20px"},children:"Added in: v1.10"}),"\n",(0,r.jsx)("x-search",{children:"testProject.testDir"}),"\n",(0,r.jsx)(t.p,{children:"Directory that will be recursively scanned for test files. Defaults to the directory of the configuration file."}),"\n",(0,r.jsx)(t.p,{children:"Each project can use a different directory. Here is an example that runs smoke tests in three browsers and all other tests in stable Chrome browser."}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",metastring:'title="playwright.config.ts"',children:"import { defineConfig } from '@playwright/test';\n\nexport default defineConfig({\n projects: [\n {\n name: 'Smoke Chromium',\n testDir: './smoke-tests',\n use: {\n browserName: 'chromium',\n }\n },\n {\n name: 'Smoke WebKit',\n testDir: './smoke-tests',\n use: {\n browserName: 'webkit',\n }\n },\n {\n name: 'Smoke Firefox',\n testDir: './smoke-tests',\n use: {\n browserName: 'firefox',\n }\n },\n {\n name: 'Chrome Stable',\n testDir: './',\n use: {\n browserName: 'chromium',\n channel: 'chrome',\n }\n },\n ],\n});\n"})}),"\n",(0,r.jsxs)(t.p,{children:["Use ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testconfig#test-config-test-dir",children:"testConfig.testDir"})," to change this option for all projects."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Usage"})}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",children:"testProject.testDir\n"})}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Type"})}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type",title:"string",children:"string"})}),"\n"]}),"\n",(0,r.jsx)(t.hr,{}),"\n",(0,r.jsx)(t.h3,{id:"test-project-test-ignore",children:"testIgnore"}),"\n",(0,r.jsx)("font",{size:"2",style:{position:"relative",top:"-20px"},children:"Added in: v1.10"}),"\n",(0,r.jsx)("x-search",{children:"testProject.testIgnore"}),"\n",(0,r.jsx)(t.p,{children:"Files matching one of these patterns are not executed as test files. Matching is performed against the absolute file path. Strings are treated as glob patterns."}),"\n",(0,r.jsxs)(t.p,{children:["For example, ",(0,r.jsx)(t.code,{children:"'**/test-assets/**'"})," will ignore any files in the ",(0,r.jsx)(t.code,{children:"test-assets"})," directory."]}),"\n",(0,r.jsxs)(t.p,{children:["Use ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testconfig#test-config-test-ignore",children:"testConfig.testIgnore"})," to change this option for all projects."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Usage"})}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",children:"testProject.testIgnore\n"})}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Type"})}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type",title:"string",children:"string"})," | ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp",title:"RegExp",children:"RegExp"})," | ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array",title:"Array",children:"Array"}),"<",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type",title:"string",children:"string"})," | ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp",title:"RegExp",children:"RegExp"}),">"]}),"\n"]}),"\n",(0,r.jsx)(t.hr,{}),"\n",(0,r.jsx)(t.h3,{id:"test-project-test-match",children:"testMatch"}),"\n",(0,r.jsx)("font",{size:"2",style:{position:"relative",top:"-20px"},children:"Added in: v1.10"}),"\n",(0,r.jsx)("x-search",{children:"testProject.testMatch"}),"\n",(0,r.jsx)(t.p,{children:"Only the files matching one of these patterns are executed as test files. Matching is performed against the absolute file path. Strings are treated as glob patterns."}),"\n",(0,r.jsxs)(t.p,{children:["By default, Playwright looks for files matching the following glob pattern: ",(0,r.jsx)(t.code,{children:"**/*.@(spec|test).?(c|m)[jt]s?(x)"}),". This means JavaScript or TypeScript files with ",(0,r.jsx)(t.code,{children:'".test"'})," or ",(0,r.jsx)(t.code,{children:'".spec"'})," suffix, for example ",(0,r.jsx)(t.code,{children:"login-screen.wrong-credentials.spec.ts"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["Use ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testconfig#test-config-test-match",children:"testConfig.testMatch"})," to change this option for all projects."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Usage"})}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",children:"testProject.testMatch\n"})}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Type"})}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type",title:"string",children:"string"})," | ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp",title:"RegExp",children:"RegExp"})," | ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array",title:"Array",children:"Array"}),"<",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type",title:"string",children:"string"})," | ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp",title:"RegExp",children:"RegExp"}),">"]}),"\n"]}),"\n",(0,r.jsx)(t.hr,{}),"\n",(0,r.jsx)(t.h3,{id:"test-project-timeout",children:"timeout"}),"\n",(0,r.jsx)("font",{size:"2",style:{position:"relative",top:"-20px"},children:"Added in: v1.10"}),"\n",(0,r.jsx)("x-search",{children:"testProject.timeout"}),"\n",(0,r.jsx)(t.p,{children:"Timeout for each test in milliseconds. Defaults to 30 seconds."}),"\n",(0,r.jsxs)(t.p,{children:["This is a base timeout for all tests. Each test can configure its own timeout with ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-test#test-set-timeout",children:"test.
1setTimeout()"}),". Each file or a group of tests can configure the timeout with ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-test#test-describe-configure",children:"test.describe.configure()"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["Use ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testconfig#test-config-timeout",children:"testConfig.timeout"})," to change this option for all projects."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Usage"})}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",children:"testProject.timeout\n"})}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Type"})}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type",title:"Number",children:"number"})}),"\n"]}),"\n",(0,r.jsx)(t.hr,{}),"\n",(0,r.jsx)(t.h3,{id:"test-project-use",children:"use"}),"\n",(0,r.jsx)("font",{size:"2",style:{position:"relative",top:"-20px"},children:"Added in: v1.10"}),"\n",(0,r.jsx)("x-search",{children:"testProject.use"}),"\n",(0,r.jsxs)(t.p,{children:["Options for all tests in this project, for example ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testoptions#test-options-browser-name",children:"testOptions.browserName"}),". Learn more about ",(0,r.jsx)(t.a,{href:"/docs/next/test-configuration",children:"configuration"})," and see ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testoptions",title:"TestOptions",children:"available options"}),"."]}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",metastring:'title="playwright.config.ts"',children:"import { defineConfig } from '@playwright/test';\n\nexport default defineConfig({\n projects: [\n {\n name: 'Chromium',\n use: {\n browserName: 'chromium',\n },\n },\n ],\n});\n"})}),"\n",(0,r.jsxs)(t.p,{children:["Use ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testconfig#test-config-use",children:"testConfig.use"})," to change this option for all projects."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Usage"})}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",children:"testProject.use\n"})}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Type"})}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsx)(t.li,{children:(0,r.jsx)(t.a,{href:"/docs/next/api/class-testoptions",title:"TestOptions",children:"TestOptions"})}),"\n"]}),"\n",(0,r.jsx)(t.hr,{}),"\n",(0,r.jsx)(t.h3,{id:"test-project-workers",children:"workers"}),"\n",(0,r.jsx)("font",{size:"2",style:{position:"relative",top:"-20px"},children:"Added in: v1.52"}),"\n",(0,r.jsx)("x-search",{children:"testProject.workers"}),"\n",(0,r.jsxs)(t.p,{children:["The maximum number of concurrent worker processes to use for parallelizing tests from this project. Can also be set as percentage of logical CPU cores, e.g. ",(0,r.jsx)(t.code,{children:"'50%'."})]}),"\n",(0,r.jsx)(t.p,{children:"This could be useful, for example, when all tests from a project share a single resource like a test account, and therefore cannot be executed in parallel. Limiting workers to one for such a project will prevent simultaneous use of the shared resource."}),"\n",(0,r.jsxs)(t.p,{children:["Note that the global ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testconfig#test-config-workers",children:"testConfig.workers"})," limit applies to the total number of worker processes. However, Playwright will limit the number of workers used for this project by the value of ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testproject#test-project-workers",children:"testProject.workers"}),"."]}),"\n",(0,r.jsxs)(t.p,{children:["By default, there is no limit per project. See ",(0,r.jsx)(t.a,{href:"/docs/next/api/class-testconfig#test-config-workers",children:"testConfig.workers"})," for the default of the total worker limit."]}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Usage"})}),"\n",(0,r.jsx)(t.pre,{children:(0,r.jsx)(t.code,{className:"language-js",metastring:'title="playwright.config.ts"',children:"import { defineConfig } from '@playwright/test';
1\n\nexport default defineConfig({\n workers: 10, // total workers limit\n\n projects: [\n {\n name: 'runs in parallel',\n },\n {\n name: 'one at a time',\n workers: 1, // workers limit for this project\n },\n ],\n});\n"})}),"\n",(0,r.jsx)(t.p,{children:(0,r.jsx)(t.strong,{children:"Type"})}),"\n",(0,r.jsxs)(t.ul,{children:["\n",(0,r.jsxs)(t.li,{children:[(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#Number_type",title:"Number",children:"number"})," | ",(0,r.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Data_structures#String_type",title:"string",children:"string"})]}),"\n"]})]})}function h(e={}){let{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,r.jsx)(t,{...e,children:(0,r.jsx)(d,{...e})}):d(e)}}}]);
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.