From bd698efaef0994871d99b6367c268f812f5cd357 Mon Sep 17 00:00:00 2001 From: Johannes Loher Date: Wed, 5 Apr 2023 10:39:35 +0200 Subject: [PATCH] fix(webServer): follow relative redirects when checking the url (#22035) Fixes https://github.com/microsoft/playwright/issues/22144 --- docs/src/test-api/class-testconfig.md | 2 +- packages/playwright-core/src/utils/network.ts | 2 +- packages/playwright-test/types/test.d.ts | 3 ++- tests/playwright-test/web-server.spec.ts | 26 +++++++++++++++++++ 4 files changed, 30 insertions(+), 3 deletions(-) diff --git a/docs/src/test-api/class-testconfig.md b/docs/src/test-api/class-testconfig.md index c9e885a4e2..558a361c56 100644 --- a/docs/src/test-api/class-testconfig.md +++ b/docs/src/test-api/class-testconfig.md @@ -595,7 +595,7 @@ export default defineConfig({ - type: ?<[Object]|[Array]<[Object]>> - `command` <[string]> Shell command to start. For example `npm run start`.. - `port` ?<[int]> The port that your http server is expected to appear on. It does wait until it accepts connections. Exactly one of `port` or `url` is required. - - `url` ?<[string]> The url on 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. Exactly one of `port` or `url` is required. + - `url` ?<[string]> The url on 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. Redirects (3xx status codes) are being followed and the new location is checked. Exactly one of `port` or `url` is required. - `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. diff --git a/packages/playwright-core/src/utils/network.ts b/packages/playwright-core/src/utils/network.ts index 0f12929707..08d8029b5e 100644 --- a/packages/playwright-core/src/utils/network.ts +++ b/packages/playwright-core/src/utils/network.ts @@ -71,7 +71,7 @@ export function httpRequest(params: HTTPRequestParams, onResponse: (r: http.Inco const requestCallback = (res: http.IncomingMessage) => { const statusCode = res.statusCode || 0; if (statusCode >= 300 && statusCode < 400 && res.headers.location) - httpRequest({ ...params, url: res.headers.location }, onResponse, onError); + httpRequest({ ...params, url: new URL.URL(res.headers.location, params.url).toString() }, onResponse, onError); else onResponse(res); }; diff --git a/packages/playwright-test/types/test.d.ts b/packages/playwright-test/types/test.d.ts index 6d804e0502..dc3d6ccf92 100644 --- a/packages/playwright-test/types/test.d.ts +++ b/packages/playwright-test/types/test.d.ts @@ -5911,7 +5911,8 @@ interface TestConfigWebServer { /** * The url on 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. Exactly one of `port` or `url` is required. + * server is ready to accept connections. Redirects (3xx status codes) are being followed and the new location is + * checked. Exactly one of `port` or `url` is required. */ url?: string; diff --git a/tests/playwright-test/web-server.spec.ts b/tests/playwright-test/web-server.spec.ts index a8621818b0..0d463ccf84 100644 --- a/tests/playwright-test/web-server.spec.ts +++ b/tests/playwright-test/web-server.spec.ts @@ -457,6 +457,32 @@ test('should send Accept header', async ({ runInlineTest, server }) => { expect(acceptHeader).toBe('*/*'); }); +test('should follow redirects', async ({ runInlineTest, server }) => { + server.setRedirect('/redirect', '/redirected-to'); + server.setRoute('/redirected-to', (req, res) => { + res.end('hello'); + }); + const result = await runInlineTest({ + 'test.spec.ts': ` + import { test, expect } from '@playwright/test'; + test('connect to the server', async ({baseURL, page}) => { + await page.goto('http://localhost:${server.PORT}/redirect'); + expect(await page.textContent('body')).toBe('hello'); + }); + `, + 'playwright.config.ts': ` + module.exports = { + webServer: { + command: 'node ${JSON.stringify(SIMPLE_SERVER_PATH)} ${server.PORT}', + url: 'http://localhost:${server.PORT}/redirect', + reuseExistingServer: true, + } + }; + `, + }); + expect(result.exitCode).toBe(0); +}); + test('should create multiple servers', async ({ runInlineTest }, { workerIndex }) => { const port = workerIndex * 2 + 10500; const result = await runInlineTest({