1"use strict";(self.webpackChunkplaywright_dev=self.webpackChunkplaywright_dev||[]).push([["44"],{96558(e,t,s){s.r(t),s.d(t,{metadata:()=>r,default:()=>h,frontMatter:()=>o,contentTitle:()=>l,toc:()=>c,assets:()=>d});var r=JSON.parse('{"id":"test-webserver","title":"Web server","description":"Introduction","source":"@site/versioned_docs/version-stable/test-webserver.mdx","sourceDirName":".","slug":"/test-webserver","permalink":"/docs/test-webserver","draft":false,"unlisted":false,"tags":[],"version":"stable","frontMatter":{"id":"test-webserver","title":"Web server"},"sidebar":"docs","previous":{"title":"UI Mode","permalink":"/docs/test-ui-mode"},"next":{"title":"Library","permalink":"/docs/library"}}'),n=s(74848),i=s(28453);s(13554),s(41647),s(83137);let o={id:"test-webserver",title:"Web server"},l,d={},c=[{value:"Introduction",id:"introduction",level:2},{value:"Configuring a web server",id:"configuring-a-web-server",level:2},{value:"Adding a server timeout",id:"adding-a-server-timeout",level:2},{value:"Adding a baseURL",id:"adding-a-baseurl",level:2},{value:"Multiple web servers",id:"multiple-web-servers",level:2}];function a(e){let t={a:"a",code:"code",h2:"h2",p:"p",pre:"pre",strong:"strong",table:"table",tbody:"tbody",td:"td",th:"th",thead:"thead",tr:"tr",...(0,i.R)(),...e.components};return(0,n.jsxs)(n.Fragment,{children:[(0,n.jsx)(t.h2,{id:"introduction",children:"Introduction"}),"\n",(0,n.jsxs)(t.p,{children:["Playwright comes with a ",(0,n.jsx)(t.code,{children:"webServer"})," option in the config file which gives you the ability to launch a local dev server before running your tests. This is ideal for when writing your tests during development and when you don't have a staging or production url to test against."]}),"\n",(0,n.jsx)(t.h2,{id:"configuring-a-web-server",children:"Configuring a web server"}),"\n",(0,n.jsxs)(t.p,{children:["Use the ",(0,n.jsx)(t.code,{children:"webServer"})," property in your Playwright config to launch a development web server during the tests."]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-js",metastring:'title="playwright.config.ts"',children:"import { defineConfig } from '@playwright/test';\n\nexport default defineConfig({\n // Run your local dev server before starting the tests\n webServer: {\n command: 'npm run start',\n url: 'http://localhost:3000',\n reuseExistingServer: !process.env.CI,\n stdout: 'ignore',\n stderr: 'pipe',\n },\n});\n"})}),"\n",(0,n.jsxs)(t.table,{children:[(0,n.jsx)(t.thead,{children:(0,n.jsxs)(t.tr,{children:[(0,n.jsx)(t.th,{style:{textAlign:"left"},children:"Property"}),(0,n.jsx)(t.th,{style:{textAlign:"left"},children:"Description"})]})}),(0,n.jsxs)(t.tbody,{children:[(0,n.jsxs)(t.tr,{children:[(0,n.jsx)(t.td,{style:{textAlign:"left"},children:(0,n.jsx)(t.a,{href:"/docs/api/class-testconfig#test-config-web-server",children:"testConfig.webServer"})}),(0,n.jsx)(t.td,{style:{textAlign:"left"},children:"Launch a development web server (or multiple) during the tests."})]}),(0,n.jsxs)(t.tr,{children:[(0,n.jsx)(t.td,{style:{textAlign:"left"},children:(0,n.jsx)(t.code,{children:"command"})}),(0,n.jsx)(t.td,{style:{textAlign:"left"},children:"Shell command to start the local dev server of your app."})]}),(0,n.jsxs)(t.tr,{children:[(0,n.jsx)(t.td,{style:{textAlign:"left"},children:(0,n.jsx)(t.code,{children:"cwd"})}),(0,n.jsx)(t.td,{style:{textAlign:"left"},children:"Current working directory of the spawned process, defaults to the directory of the configuration file."})]}),(0,n.jsxs)(t.tr,{children:[(0,n.jsx)(t.td,{style:{textAlign:"left"},children:(0,n.jsx)(t.code,{children:"env"})}),(0,n.jsxs)(t.td,{style:{textAlign:"left"},children:["Environment variables for the command. Defaults to inheriting ",(0,n.jsx)(t.code,{children:"process.env"})," with ",(0,n.jsx)(t.code,{children:"PLAYWRIGHT_TEST=1"})," added."]})]}),(0,n.jsxs)(t.tr,{children:[(0,n.jsx)(t.td,{style:{textAlign:"left"},children:(0,n.jsx)(t.code,{children:"gracefulShutdown"})}),(0,n.jsxs)(t.td,{style:{textAlign:"left"},children:["How to shut down the process. If unspecified, the process group is forcefully ",(0,n.jsx)(t.code,{children:"SIGKILL"}),"ed. If set to ",(0,n.jsx)(t.code,{children:"{ signal: 'SIGTERM', timeout: 500 }"}),", the process group is sent a ",(0,n.jsx)(t.code,{children:"SIGTERM"})," signal, followed by ",(0,n.jsx)(t.code,{children:"SIGKILL"})," if it doesn't exit within 500ms. You can also use ",(0,n.jsx)(t.code,{children:"SIGINT"})," as the signal instead. A ",(0,n.jsx)(t.code,{children:"0"})," timeout means no ",(0,n.jsx)(t.code,{children:"SIGKILL"})," will be sent. Windows doesn't support ",(0,n.jsx)(t.code,{children:"SIGTERM"})," and ",(0,n.jsx)(t.code,{children:"SIGINT"})," signals, so this option is ignored on Windows. Note that shutting down a Docker container requires ",(0,n.jsx)(t.code,{children:"SIGTERM"}),"."]})]}),(0,n.jsxs)(t.tr,{children:[(0,n.jsx)(t.td,{style:{textAlign:"left"},children:(0,n.jsx)(t.code,{children:"ignoreHTTPSErrors"})}),(0,n.jsxs)(t.td,{style:{textAlign:"left"},children:["Whether to ignore HTTPS errors when fetching the ",(0,n.jsx)(t.code,{children:"url"}),". Defaults to ",(0,n.jsx)(t.code,{children:"false"}),"."]})]}),(0,n.jsxs)(t.tr,{children:[(0,n.jsx)(t.td,{style:{textAlign:"left"},children:(0,n.jsx)(t.code,{children:"name"})}),(0,n.jsxs)(t.td,{style:{textAlign:"left"}
1,children:["Specifies a custom name for the web server. This name will be prefixed to log messages. Defaults to ",(0,n.jsx)(t.code,{children:"[WebServer]"}),"."]})]}),(0,n.jsxs)(t.tr,{children:[(0,n.jsx)(t.td,{style:{textAlign:"left"},children:(0,n.jsx)(t.code,{children:"port"})}),(0,n.jsxs)(t.td,{style:{textAlign:"left"},children:[(0,n.jsx)(t.strong,{children:"Deprecated"}),". Use ",(0,n.jsx)(t.code,{children:"url"})," instead. The port that your http server is expected to appear on. It does wait until it accepts connections. Either ",(0,n.jsx)(t.code,{children:"port"})," or ",(0,n.jsx)(t.code,{children:"url"})," should be specified."]})]}),(0,n.jsxs)(t.tr,{children:[(0,n.jsx)(t.td,{style:{textAlign:"left"},children:(0,n.jsx)(t.code,{children:"reuseExistingServer"})}),(0,n.jsxs)(t.td,{style:{textAlign:"left"},children:["If ",(0,n.jsx)(t.code,{children:"true"}),", it will re-use an existing server on the ",(0,n.jsx)(t.code,{children:"port"})," or ",(0,n.jsx)(t.code,{children:"url"})," when available. If no server is running on that ",(0,n.jsx)(t.code,{children:"port"})," or ",(0,n.jsx)(t.code,{children:"url"}),", it will run the command to start a new server. If ",(0,n.jsx)(t.code,{children:"false"}),", it will throw if an existing process is listening on the ",(0,n.jsx)(t.code,{children:"port"})," or ",(0,n.jsx)(t.code,{children:"url"}),". This should be commonly set to ",(0,n.jsx)(t.code,{children:"!process.env.CI"})," to allow the local dev server when running tests locally."]})]}),(0,n.jsxs)(t.tr,{children:[(0,n.jsx)(t.td,{style:{textAlign:"left"},children:(0,n.jsx)(t.code,{children:"stderr"})}),(0,n.jsxs)(t.td,{style:{textAlign:"left"},children:["Whether to pipe the stderr of the command to the process stderr or ignore it. Defaults to ",(0,n.jsx)(t.code,{children:'"pipe"'}),"."]})]}),(0,n.jsxs)(t.tr,{children:[(0,n.jsx)(t.td,{style:{textAlign:"left"},children:(0,n.jsx)(t.code,{children:"stdout"})}),(0,n.jsxs)(t.td,{style:{textAlign:"left"},children:["If ",(0,n.jsx)(t.code,{children:'"pipe"'}),", it will pipe the stdout of the command to the process stdout. If ",(0,n.jsx)(t.code,{children:'"ignore"'}),", it will ignore the stdout of the command. Default to ",(0,n.jsx)(t.code,{children:'"ignore"'}),"."]})]}),(0,n.jsxs)(t.tr,{children:[(0,n.jsx)(t.td,{style:{textAlign:"left"},children:(0,n.jsx)(t.code,{children:"timeout"})}),(0,n.jsx)(t.td,{style:{textAlign:"left"},children:"How long to wait for the process to start up and be available in milliseconds. Defaults to 60000."})]}),(0,n.jsxs)(t.tr,{children:[(0,n.jsx)(t.td,{style:{textAlign:"left"},children:(0,n.jsx)(t.code,{children:"url"})}),(0,n.jsxs)(t.td,{style:{textAlign:"left"},children:["URL of your http server that is expected to return a 2xx, 3xx, 400, 401, 402, or 403 status code when the server is ready to accept connections. Either ",(0,n.jsx)(t.code,{children:"port"})," or ",(0,n.jsx)(t.code,{children:"url"})," should be specified. If both ",(0,n.jsx)(t.code,{children:"url"})," and ",(0,n.jsx)(t.code,{children:"wait"})," are specified, the server is considered started when at least one of the conditions is met."]})]}),(0,n.jsxs)(t.tr,{children:[(0,n.jsx)(t.td,{style:{textAlign:"left"},children:(0,n.jsx)(t.code,{children:"wait"})}),(0,n.jsxs)(t.td,{style:{textAlign:"left"},children:["Consider command started only when given output has been produced. Takes an object with optional ",(0,n.jsx)(t.code,{children:"stdout"})," and/or ",(0,n.jsx)(t.code,{children:"stderr"})," regular expressions. Named capture groups in the regex are stored in the environment, for example ",(0,n.jsx)(t.code,{children:"/Listening on port (?<my_server_port>\\d+)/"})," will store the port number in ",(0,n.jsx)(t.code,{children:"process.env['MY_SERVER_PORT']"}),". If both ",(0,n.jsx)(t.code,{children:"url"})," and ",(0,n.jsx)(t.code,{children:"wait"})," are specified, the server is considered started when at least one of the conditions is met."]})]})]})]}),"\n",(0,n.jsx)(t.h2,{id:"adding-a-server-timeout",children:"Adding a server timeout"}),"\n",(0,n.jsx)(t.p,{children:"Webservers can sometimes take longer to boot up. In this case, you can increase the timeout to wait for the server to start."}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-js",metastring:'title="playwright.config.ts"',children:"import { defineConfig } from '@playwright/test';
1\n\nexport default defineConfig({\n // Rest of your config...\n\n // Run your local dev server before starting the tests\n webServer: {\n command: 'npm run start',\n url: 'http://localhost:3000',\n reuseExistingServer: !process.env.CI,\n timeout: 120 * 1000,\n },\n});\n"})}),"\n",(0,n.jsx)(t.h2,{id:"adding-a-baseurl",children:"Adding a baseURL"}),"\n",(0,n.jsxs)(t.p,{children:["It is also recommended to specify the ",(0,n.jsx)(t.code,{children:"baseURL"})," in the ",(0,n.jsx)(t.code,{children:"use: {}"})," section of your config, so that tests can use relative urls and you don't have to specify the full URL over and over again."]}),"\n",(0,n.jsxs)(t.p,{children:["When using ",(0,n.jsx)(t.a,{href:"/docs/api/class-page#page-goto",children:"page.goto()"}),", ",(0,n.jsx)(t.a,{href:"/docs/api/class-page#page-route",children:"page.route()"}),", ",(0,n.jsx)(t.a,{href:"/docs/api/class-page#page-wait-for-url",children:"page.waitForURL()"}),", ",(0,n.jsx)(t.a,{href:"/docs/api/class-page#page-wait-for-request",children:"page.waitForRequest()"}),", or ",(0,n.jsx)(t.a,{href:"/docs/api/class-page#page-wait-for-response",children:"page.waitForResponse()"})," it takes the base URL in consideration by using the ",(0,n.jsx)(t.a,{href:"https://developer.mozilla.org/en-US/docs/Web/API/URL/URL",children:(0,n.jsx)(t.code,{children:"URL()"})})," constructor for building the corresponding URL. For Example, by setting the baseURL to ",(0,n.jsx)(t.code,{children:"http://localhost:3000"})," and navigating to ",(0,n.jsx)(t.code,{children:"/login"})," in your tests, Playwright will run the test using ",(0,n.jsx)(t.code,{children:"http://localhost:3000/login"}),"."]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-js",metastring:'title="playwright.config.ts"',children:"import { defineConfig } from '@playwright/test';\n\nexport default defineConfig({\n // Rest of your config...\n\n // Run your local dev server before starting the tests\n webServer: {\n command: 'npm run start',\n url: 'http://localhost:3000',\n reuseExistingServer: !process.env.CI,\n },\n use: {\n baseURL: 'http://localhost:3000',\n },\n});\n"})}),"\n",(0,n.jsx)(t.p,{children:"Now you can use a relative path when navigating the page:"}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-js",metastring:'title="test.spec.ts"',children:"import { test } from '@playwright/test';\n\ntest('test', async ({ page }) => {\n // This will navigate to http://localhost:3000/login\n await page.goto('./login');\n});\n"})}),"\n",(0,n.jsx)(t.h2,{id:"multiple-web-servers",children:"Multiple web servers"}),"\n",(0,n.jsxs)(t.p,{children:["Multiple web servers (or background processes) can be launched simultaneously by providing an array of ",(0,n.jsx)(t.code,{children:"webServer"})," configurations. See ",(0,n.jsx)(t.a,{href:"/docs/api/class-testconfig#test-config-web-server",children:"testConfig.webServer"})," for more info."]}),"\n",(0,n.jsx)(t.pre,{children:(0,n.jsx)(t.code,{className:"language-js",metastring:'title="playwright.config.ts"',children:"import { defineConfig } from '@playwright/test';\n\nexport default defineConfig({\n webServer: [\n {\n command: 'npm run start',\n url: 'http://localhost:3000',\n name: 'Frontend',\n timeout: 120 * 1000,\n reuseExistingServer: !process.env.CI,\n },\n {\n command: 'npm run backend',\n url: 'http://localhost:3333',\n name: 'Backend',\n timeout: 120 * 1000,\n reuseExistingServer: !process.env.CI,\n }\n ],\n use: {\n baseURL: 'http://localhost:3000',\n },\n});\n"})})]})}function h(e={}){let{wrapper:t}={...(0,i.R)(),...e.components};return t?(0,n.jsx)(t,{...e,children:(0,n.jsx)(a,{...e})}):a(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.