diff --git a/docs/src/test-api/class-testconfig.md b/docs/src/test-api/class-testconfig.md index c622b260c1..472e09baf2 100644 --- a/docs/src/test-api/class-testconfig.md +++ b/docs/src/test-api/class-testconfig.md @@ -624,7 +624,7 @@ export default config; - `ignoreHTTPSErrors` ?<[boolean]> Whether to ignore HTTPS errors when fetching the `url`. Defaults to `false`. - `timeout` ?<[int]> How long to wait for the process to start up and be available in milliseconds. Defaults to 60000. - `reuseExistingServer` ?<[boolean]> If true, it will re-use an existing server on the `port` or `url` when available. If no server is running on that `port` or `url`, it will run the command to start a new server. If `false`, it will throw if an existing process is listening on the `port` or `url`. This should be commonly set to `!process.env.CI` to allow the local dev server when running tests locally. - - `cwd` ?<[string]> Current working directory of the spawned process, `process.cwd()` by default. + - `cwd` ?<[string]> Current working directory of the spawned process, defaults to the directory of the configuration file. - `env` ?<[Object]<[string], [string]>> Environment variables to set for the command, `process.env` by default. Launch a development web server during the tests. diff --git a/packages/playwright-test/src/loader.ts b/packages/playwright-test/src/loader.ts index 1f00ab307b..7a5a70943a 100644 --- a/packages/playwright-test/src/loader.ts +++ b/packages/playwright-test/src/loader.ts @@ -96,6 +96,8 @@ export class Loader { (config as any).screenshotsDir = path.resolve(configDir, (config as any).screenshotsDir); if (config.snapshotDir !== undefined) config.snapshotDir = path.resolve(configDir, config.snapshotDir); + if (config.webServer) + config.webServer.cwd = config.webServer.cwd ? path.resolve(configDir, config.webServer.cwd) : configDir; const configUse = mergeObjects(this._defaultConfig.use, config.use); config = mergeObjects(mergeObjects(this._defaultConfig, config), { use: configUse }); diff --git a/packages/playwright-test/types/test.d.ts b/packages/playwright-test/types/test.d.ts index 98261cff1c..3d655d8554 100644 --- a/packages/playwright-test/types/test.d.ts +++ b/packages/playwright-test/types/test.d.ts @@ -930,7 +930,7 @@ interface TestConfig { reuseExistingServer?: boolean; /** - * Current working directory of the spawned process, `process.cwd()` by default. + * Current working directory of the spawned process, defaults to the directory of the configuration file. */ cwd?: string; diff --git a/tests/playwright-test/assets/simple-server.js b/tests/playwright-test/assets/simple-server.js index 2e178a3923..283b4348a7 100644 --- a/tests/playwright-test/assets/simple-server.js +++ b/tests/playwright-test/assets/simple-server.js @@ -11,4 +11,4 @@ setTimeout(() => { response.end(process.env.FOO); }); }); -}, 750); +}, process.argv[3] ? +process.argv[3] : 0)); diff --git a/tests/playwright-test/web-server.spec.ts b/tests/playwright-test/web-server.spec.ts index 49b1a0e32d..b334bfe347 100644 --- a/tests/playwright-test/web-server.spec.ts +++ b/tests/playwright-test/web-server.spec.ts @@ -18,6 +18,8 @@ import http from 'http'; import path from 'path'; import { test, expect } from './playwright-test-fixtures'; +const SIMPLE_SERVER_PATH = path.join(__dirname, 'assets', 'simple-server.js'); + test('should create a server', async ({ runInlineTest }, { workerIndex }) => { const port = workerIndex + 10500; const result = await runInlineTest({ @@ -33,7 +35,7 @@ test('should create a server', async ({ runInlineTest }, { workerIndex }) => { 'playwright.config.ts': ` module.exports = { webServer: { - command: 'node ${JSON.stringify(path.join(__dirname, 'assets', 'simple-server.js'))} ${port}', + command: 'node ${JSON.stringify(SIMPLE_SERVER_PATH)} ${port}', port: ${port}, }, globalSetup: 'globalSetup.ts', @@ -96,7 +98,7 @@ test('should create a server with environment variables', async ({ runInlineTest 'playwright.config.ts': ` module.exports = { webServer: { - command: 'node ${JSON.stringify(path.join(__dirname, 'assets', 'simple-server.js'))} ${port}', + command: 'node ${JSON.stringify(SIMPLE_SERVER_PATH)} ${port}', port: ${port}, env: { 'FOO': 'BAR', @@ -112,6 +114,64 @@ test('should create a server with environment variables', async ({ runInlineTest expect(result.report.suites[0].specs[0].tests[0].results[0].status).toContain('passed'); }); +test('should default cwd to config directory', async ({ runInlineTest }, testInfo) => { + const port = testInfo.workerIndex + 10500; + const configDir = testInfo.outputPath('foo'); + const relativeSimpleServerPath = path.relative(configDir, SIMPLE_SERVER_PATH); + const result = await runInlineTest({ + 'foo/test.spec.ts': ` + const { test } = pwt; + test('connect to the server', async ({ baseURL }) => { + expect(baseURL).toBe('http://localhost:${port}'); + }); + `, + 'foo/playwright.config.ts': ` + module.exports = { + webServer: { + command: 'node ${JSON.stringify(relativeSimpleServerPath)} ${port}', + port: ${port}, + } + }; + `, + }, {}, { DEBUG: 'pw:webserver' }, { + cwd: 'foo' + }); + expect(result.exitCode).toBe(0); + expect(result.passed).toBe(1); + expect(result.output).toContain('[WebServer] listening'); + expect(result.output).toContain('[WebServer] error from server'); +}); + +test('should resolve cwd wrt config directory', async ({ runInlineTest }, testInfo) => { + const port = testInfo.workerIndex + 10500; + const testdir = testInfo.outputPath(); + const relativeSimpleServerPath = path.relative(testdir, SIMPLE_SERVER_PATH); + const result = await runInlineTest({ + 'foo/test.spec.ts': ` + const { test } = pwt; + test('connect to the server', async ({ baseURL }) => { + expect(baseURL).toBe('http://localhost:${port}'); + }); + `, + 'foo/playwright.config.ts': ` + module.exports = { + webServer: { + command: 'node ${JSON.stringify(relativeSimpleServerPath)} ${port}', + port: ${port}, + cwd: '..', + } + }; + `, + }, {}, { DEBUG: 'pw:webserver' }, { + cwd: 'foo' + }); + expect(result.exitCode).toBe(0); + expect(result.passed).toBe(1); + expect(result.output).toContain('[WebServer] listening'); + expect(result.output).toContain('[WebServer] error from server'); +}); + + test('should create a server with url', async ({ runInlineTest }, { workerIndex }) => { const port = workerIndex + 10500; const result = await runInlineTest({ @@ -151,7 +211,7 @@ test('should time out waiting for a server', async ({ runInlineTest }, { workerI 'playwright.config.ts': ` module.exports = { webServer: { - command: 'node ${JSON.stringify(JSON.stringify(path.join(__dirname, 'assets', 'simple-server.js')))} ${port}', + command: 'node ${JSON.stringify(SIMPLE_SERVER_PATH)} ${port} 1000', port: ${port}, timeout: 100, } @@ -235,7 +295,7 @@ test('should be able to specify a custom baseURL with the server', async ({ runI 'playwright.config.ts': ` module.exports = { webServer: { - command: 'node ${JSON.stringify(path.join(__dirname, 'assets', 'simple-server.js'))} ${webServerPort}', + command: 'node ${JSON.stringify(SIMPLE_SERVER_PATH)} ${webServerPort}', port: ${webServerPort}, }, use: { @@ -269,7 +329,7 @@ test('should be able to use an existing server when reuseExistingServer:true ', 'playwright.config.ts': ` module.exports = { webServer: { - command: 'node ${JSON.stringify(path.join(__dirname, 'assets', 'simple-server.js'))} ${port}', + command: 'node ${JSON.stringify(SIMPLE_SERVER_PATH)} ${port}', port: ${port}, reuseExistingServer: true, } @@ -302,7 +362,7 @@ test('should throw when a server is already running on the given port and strict 'playwright.config.ts': ` module.exports = { webServer: { - command: 'node ${JSON.stringify(path.join(__dirname, 'assets', 'simple-server.js'))} ${port}', + command: 'node ${JSON.stringify(SIMPLE_SERVER_PATH)} ${port}', port: ${port}, reuseExistingServer: false, }