diff --git a/packages/playwright-test/src/index.ts b/packages/playwright-test/src/index.ts index 7ca77a5e0c..e29931346a 100644 --- a/packages/playwright-test/src/index.ts +++ b/packages/playwright-test/src/index.ts @@ -17,6 +17,7 @@ import * as fs from 'fs'; import * as path from 'path'; import type { APIRequestContext, BrowserContext, BrowserContextOptions, LaunchOptions, Page, Tracing, Video } from 'playwright-core'; +import type { BrowserType as BrowserTypeImpl } from 'playwright-core/lib/client/browserType'; import * as playwrightLibrary from 'playwright-core'; import { createGuid, debugMode, removeFolders, addInternalStackPrefix, mergeTraceFiles, saveTraceFile } from 'playwright-core/lib/utils'; import type { Fixtures, PlaywrightTestArgs, PlaywrightTestOptions, PlaywrightWorkerArgs, PlaywrightWorkerOptions, ScreenshotMode, TestInfo, TestType, TraceMode, VideoMode } from '../types/test'; @@ -64,21 +65,11 @@ const playwrightFixtures: Fixtures = ({ channel: [({ launchOptions }, use) => use(launchOptions.channel), { scope: 'worker', option: true }], launchOptions: [{}, { scope: 'worker', option: true }], connectOptions: [({}, use) => { - const wsEndpoint = process.env.PW_TEST_CONNECT_WS_ENDPOINT; - if (!wsEndpoint) - return use(undefined); - let headers = process.env.PW_TEST_CONNECT_HEADERS ? JSON.parse(process.env.PW_TEST_CONNECT_HEADERS) : undefined; - if (process.env.PW_TEST_REUSE_CONTEXT) { - headers = { - ...headers, - 'x-playwright-reuse-context': '1', - }; - } - return use({ - wsEndpoint, - headers, - _exposeNetwork: process.env.PW_TEST_CONNECT_EXPOSE_NETWORK, - } as any); + // Usually, when connect options are specified (e.g, in the config or in the environment), + // all launch() calls are turned into connect() calls. + // However, when running in "reuse browser" mode and connecting to the reusable server, + // only the default "browser" fixture should turn into reused browser. + use(process.env.PW_TEST_REUSE_CONTEXT ? undefined : connectOptionsFromEnv()); }, { scope: 'worker', option: true }], screenshot: ['off', { scope: 'worker', option: true }], video: ['off', { scope: 'worker', option: true }], @@ -109,19 +100,36 @@ const playwrightFixtures: Fixtures = ({ options.channel = channel; for (const browserType of [playwright.chromium, playwright.firefox, playwright.webkit]) { - (browserType as any)._defaultLaunchOptions = options; - (browserType as any)._defaultConnectOptions = connectOptions; + (browserType as BrowserTypeImpl)._defaultLaunchOptions = options; + (browserType as BrowserTypeImpl)._defaultConnectOptions = connectOptions; } await use(options); for (const browserType of [playwright.chromium, playwright.firefox, playwright.webkit]) { - (browserType as any)._defaultLaunchOptions = undefined; - (browserType as any)._defaultConnectOptions = undefined; + (browserType as BrowserTypeImpl)._defaultLaunchOptions = undefined; + (browserType as BrowserTypeImpl)._defaultConnectOptions = undefined; } }, { scope: 'worker', auto: true }], - browser: [async ({ playwright, browserName }, use, testInfo) => { + browser: [async ({ playwright, browserName, _browserOptions }, use, testInfo) => { if (!['chromium', 'firefox', 'webkit'].includes(browserName)) throw new Error(`Unexpected browserName "${browserName}", must be one of "chromium", "firefox" or "webkit"`); + + // Support for "reuse browser" mode. + const connectOptions = connectOptionsFromEnv(); + if (connectOptions && process.env.PW_TEST_REUSE_CONTEXT) { + const browser = await playwright[browserName].connect({ + ...connectOptions, + headers: { + 'x-playwright-reuse-context': '1', + 'x-playwright-launch-options': JSON.stringify(_browserOptions), + ...connectOptions.headers, + }, + }); + await use(browser); + await browser.close(); + return; + } + const browser = await playwright[browserName].launch(); await use(browser); await browser.close(); @@ -617,6 +625,18 @@ function normalizeScreenshotMode(screenshot: PlaywrightWorkerOptions['screenshot const kTracingStarted = Symbol('kTracingStarted'); +function connectOptionsFromEnv() { + const wsEndpoint = process.env.PW_TEST_CONNECT_WS_ENDPOINT; + if (!wsEndpoint) + return undefined; + const headers = process.env.PW_TEST_CONNECT_HEADERS ? JSON.parse(process.env.PW_TEST_CONNECT_HEADERS) : undefined; + return { + wsEndpoint, + headers, + _exposeNetwork: process.env.PW_TEST_CONNECT_EXPOSE_NETWORK, + }; +} + export const test = _baseTest.extend(playwrightFixtures); export default test;