diff --git a/packages/playwright-core/src/cli/docker.ts b/packages/playwright-core/src/cli/docker.ts index 50ec3081d925eb..ae3db97f0333af 100644 --- a/packages/playwright-core/src/cli/docker.ts +++ b/packages/playwright-core/src/cli/docker.ts @@ -171,22 +171,6 @@ export async function installImage() { console.log(`Done!`); } -export async function wsEndpoint(): Promise { - await ensureDockerIsRunning(); - const result = await wsEndpointInternal(); - if (!result) { - throw new Error(`\n` + utils.wrapInASCIIBox([ - `Docker container is not running!`, - `Please run docker container first:`, - ``, - ` npx playwright docker start`, - ``, - `<3 Playwright Team`, - ].join('\n'), 1)); - } - return result; -} - async function wsEndpointInternal(): Promise { const containerId = await findRunningDockerContainerId(); if (!containerId) @@ -207,7 +191,20 @@ async function wsEndpointInternal(): Promise { return webSocketLine ? 'ws://' + webSocketLine.substring(LINE_PREFIX.length) : undefined; } -export async function startContainer() { +export async function containerInfo(): Promise<{wsEndpoint: string, vncSession: string}|undefined> { + await ensureDockerIsRunning(); + const wsEndpoint = await wsEndpointInternal(); + return wsEndpoint ? containerInfoInternal(wsEndpoint) : undefined; +} + +function containerInfoInternal(wsEndpoint: string): { wsEndpoint: string, vncSession: string } { + return { + wsEndpoint, + vncSession: `http://127.0.0.1:7900?path=${utils.createGuid()}&resize=scale`, + }; +} + +export async function ensureContainer(): Promise<{ wsEndpoint: string, vncSession: string }> { await ensureDockerIsRunning(); const pwImage = await findDockerImage(VRT_IMAGE_NAME); if (!pwImage) { @@ -220,10 +217,10 @@ export async function startContainer() { `<3 Playwright Team`, ].join('\n'), 1)); } - if (await wsEndpointInternal()) { - console.log(`Container is already running.`); - return; - } + + let wsEndpoint = await wsEndpointInternal(); + if (wsEndpoint) + return containerInfoInternal(wsEndpoint); await launchContainer({ image: pwImage, @@ -234,24 +231,15 @@ export async function startContainer() { // Wait for the service to become available. const startTime = Date.now(); - let endpoint = undefined; const timeouts = [0, 100, 100, 200, 500, 1000]; do { await new Promise(x => setTimeout(x, timeouts.shift() ?? 1000)); - endpoint = await wsEndpointInternal(); - } while (!endpoint && Date.now() < startTime + 60000); + wsEndpoint = await wsEndpointInternal(); + } while (!wsEndpoint && Date.now() < startTime + 60000); - if (!endpoint) + if (!wsEndpoint) throw new Error('Failed to launch docker container!'); - - /* eslint-disable no-console */ - console.log(`✨ Launched Playwright ${getPlaywrightVersion()} Docker Container ✨`); - console.log(``); - console.log(`- VNC session: http://127.0.0.1:7900?path=${utils.createGuid()}&resize=scale`); - console.log(`- WS endpoint: ${endpoint}`); - console.log(``); - console.log(`You can now run tests with browsers inside this container:`); - console.log(` npx playwright docker test`); + return containerInfoInternal(wsEndpoint); } export async function stopContainer() { diff --git a/packages/playwright-test/src/cli.ts b/packages/playwright-test/src/cli.ts index face478712d9aa..41fe85b499ba07 100644 --- a/packages/playwright-test/src/cli.ts +++ b/packages/playwright-test/src/cli.ts @@ -18,6 +18,7 @@ import type { Command } from 'playwright-core/lib/utilsBundle'; import * as docker from 'playwright-core/lib/cli/docker'; +import * as utils from 'playwright-core/lib/utils'; import fs from 'fs'; import url from 'url'; import path from 'path'; @@ -36,6 +37,17 @@ export function addTestCommands(program: Command) { addDockerCommand(program); } +const dockerStartupMessage = (vncSession: string, wsEndpoint: string) => ([ + `Playwright launched docker container to run browsers.`, + `- VNC session: ${vncSession}`, + `- WS endpoint: ${wsEndpoint}`, + ``, + `Please stop container manually when it is no longer needed:`, + ``, + ` npx playwright docker stop`, + ``, +].join('\n')); + function addDockerCommand(program: Command) { const dockerCommand = program.command('docker', { hidden: true }); @@ -47,8 +59,14 @@ function addDockerCommand(program: Command) { dockerCommand.command('start') .description('Start container') - .action(function(options) { - docker.startContainer(); + .action(async function(options) { + if (await docker.containerInfo()) { + console.log('Container is already running.'); + return; + } + const info = await docker.ensureContainer(); + /* eslint-disable no-console */ + console.log(dockerStartupMessage(info.vncSession, info.wsEndpoint)); }); dockerCommand.command('stop') @@ -91,10 +109,19 @@ function addTestCommand(program: Command, isDocker: boolean) { command.action(async (args, opts) => { try { if (isDocker) { - const wsEndpoint = await docker.wsEndpoint(); - if (!wsEndpoint) - throw new Error(`Playwright docker container is not running; run "npx playwright docker start" first`); - process.env.PW_TEST_CONNECT_WS_ENDPOINT = await docker.wsEndpoint(); + let info = await docker.containerInfo(); + if (info) { + /* eslint-disable no-console */ + console.log(utils.wrapInASCIIBox([ + `Running browsers in a pre-launched docker container.`, + `- VNC session: ${info.vncSession}`, + ].join('\n'), 1)); + } else { + info = await docker.ensureContainer(); + /* eslint-disable no-console */ + console.log(utils.wrapInASCIIBox(dockerStartupMessage(info.vncSession, info.wsEndpoint), 1)); + } + process.env.PW_TEST_CONNECT_WS_ENDPOINT = info.wsEndpoint; process.env.PW_TEST_CONNECT_HEADERS = JSON.stringify({ 'x-playwright-proxy': '*', });