chore(docker): address docker offline comments (#17377)

This patch:
- Removes all `process.exit(1)` from `docker.ts` and instead throws
  errors.
- Drops the `npx playwright docker test` command. We agreed to
  engage docker when `PLAYWRIGHT_DOCKER` environment variable
  is set.
- Introduces hidden `npx playwright docker status` command that
  dumps a JSON with docker status:
  ```sh
  aslushnikov:~/prog/playwright$ npx playwright docker status
  {
    "dockerEngineRunning": true,
    "imageName": "playwright:local-1.27.0-next-focal",
    "imageIsPulled": true,
"containerWSEndpoing":
"ws://127.0.0.1:55077/eafeb84c-571b-4d12-ac51-f6a2b43e9155",
"containerVNCEndpoint":
"http://127.0.0.1:55076/?path=fb6d4add-9adf-4c3c-b335-893bdc235cd7&resize=scale&autoconnect=1"
  }
  ```
This commit is contained in:
Andrey Lushnikov 2022-09-15 15:48:12 -07:00 committed by GitHub
parent 30ff27843a
commit b09ea69024
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 88 additions and 51 deletions

View File

@ -179,14 +179,22 @@ Docker integration usage:
npx playwright docker start
```
1. Run tests inside Docker container. Note that this command accepts all the same arguments
as a regular `npx playwright test` command.
1. Run tests inside Docker container using the `PLAYWRIGHT_DOCKER` environment variable.
You can set this environment variable as a part of your config:
```bash js
npx playwright docker test
```ts
// playwright.config.ts
import type { PlaywrightTestConfig } from '@playwright/test';
process.env.PLAYWRIGHT_DOCKER = '1';
const config: PlaywrightTestConfig = {
/* ... configuration ... */
};
export default config;
```
Note that this command will detect running Docker container, and auto-launch it if needed.
NOTE: Playwright will automatically detect a running Docker container or start it if needed.
1. Finally, stop background Docker container when you're done working with tests:
@ -194,17 +202,3 @@ Docker integration usage:
npx playwright docker stop
```
Playwright Test sets `PLAYWRIGHT_DOCKER` environment variable when it uses Docker integration.
You can use this variable to customize config or tests behavior, for example:
```ts
// playwright.config.ts
import type { PlaywrightTestConfig } from '@playwright/test';
const config: PlaywrightTestConfig = {
// Ignore all snapshot expectations when running outside
// of docker integration.
ignoreSnapshots: !process.env.PLAYWRIGHT_DOCKER,
};
export default config;
```

View File

@ -30,7 +30,7 @@ import { baseFullConfig, defaultTimeout, fileIsModule } from './loader';
import type { TraceMode } from './types';
export function addTestCommands(program: Command) {
addTestCommand(program, false /* isDocker */);
addTestCommand(program);
addShowReportCommand(program);
addListFilesCommand(program);
addDockerCommand(program);
@ -38,41 +38,58 @@ export function addTestCommands(program: Command) {
function addDockerCommand(program: Command) {
const dockerCommand = program.command('docker')
.description(`run tests in Docker (EXPERIMENTAL)`);
.description(`Manage Docker integration (EXPERIMENTAL)`);
dockerCommand.command('build')
.description('build local docker image')
.action(async function(options) {
await docker.buildPlaywrightImage();
try {
await docker.buildPlaywrightImage();
} catch (e) {
console.error(e.stack ? e : e.message);
}
});
dockerCommand.command('start')
.description('start docker container')
.action(async function(options) {
await docker.startPlaywrightContainer();
try {
await docker.startPlaywrightContainer();
} catch (e) {
console.error(e.stack ? e : e.message);
}
});
dockerCommand.command('stop')
.description('stop docker container')
.action(async function(options) {
await docker.stopAllPlaywrightContainers();
try {
await docker.stopAllPlaywrightContainers();
} catch (e) {
console.error(e.stack ? e : e.message);
}
});
dockerCommand.command('delete-image', { hidden: true })
.description('delete docker image, if any')
.action(async function(options) {
await docker.deletePlaywrightImage();
try {
await docker.deletePlaywrightImage();
} catch (e) {
console.error(e.stack ? e : e.message);
}
});
addTestCommand(dockerCommand, true /* isDocker */);
dockerCommand.command('print-status-json', { hidden: true })
.description('print docker status')
.action(async function(options) {
await docker.printDockerStatus();
});
}
function addTestCommand(program: Command, isDocker: boolean) {
function addTestCommand(program: Command) {
const command = program.command('test [test-filter...]');
if (isDocker)
command.description('run tests with Playwright Test and browsers inside docker container');
else
command.description('run tests with Playwright Test');
command.description('run tests with Playwright Test');
command.option('--browser <browser>', `Browser to use for tests, one of "all", "chromium", "firefox" or "webkit" (default: "chromium")`);
command.option('--headed', `Run tests in headed browsers (default: headless)`);
command.option('--debug', `Run tests with Playwright Inspector. Shortcut for "PWDEBUG=1" environment variable and "--timeout=0 --maxFailures=1 --headed --workers=1" options`);
@ -100,8 +117,6 @@ function addTestCommand(program: Command, isDocker: boolean) {
command.option('-x', `Stop after the first failure`);
command.action(async (args, opts) => {
try {
if (isDocker)
process.env.PLAYWRIGHT_DOCKER = '1';
await runTests(args, opts);
} catch (e) {
console.error(e);
@ -113,10 +128,10 @@ Arguments [test-filter...]:
Pass arguments to filter test files. Each argument is treated as a regular expression.
Examples:
$ npx playwright${isDocker ? ' docker ' : ' '}test my.spec.ts
$ npx playwright${isDocker ? ' docker ' : ' '}test some.spec.ts:42
$ npx playwright${isDocker ? ' docker ' : ' '}test --headed
$ npx playwright${isDocker ? ' docker ' : ' '}test --browser=webkit`);
$ npx playwright test my.spec.ts
$ npx playwright test some.spec.ts:42
$ npx playwright test --headed
$ npx playwright test --browser=webkit`);
}
function addListFilesCommand(program: Command) {

View File

@ -85,7 +85,7 @@ export async function buildPlaywrightImage() {
// Use our docker build scripts in development mode!
if (!process.env.PWTEST_DOCKER_BASE_IMAGE) {
const arch = process.arch === 'arm64' ? '--arm64' : '--amd64';
console.error(utils.wrapInASCIIBox([
throw createStacklessError(utils.wrapInASCIIBox([
`You are in DEVELOPMENT mode!`,
``,
`1. Build local base image`,
@ -93,7 +93,6 @@ export async function buildPlaywrightImage() {
`2. Use the local base to build VRT image:`,
` PWTEST_DOCKER_BASE_IMAGE=playwright:localbuild npx playwright docker build`,
].join('\n'), 1));
process.exit(1);
}
baseImageName = process.env.PWTEST_DOCKER_BASE_IMAGE;
} else {
@ -168,6 +167,19 @@ interface ContainerInfo {
vncSession: string;
}
export async function printDockerStatus() {
const isDockerEngine = await dockerApi.checkEngineRunning();
const imageIsPulled = isDockerEngine && !!(await findDockerImage(VRT_IMAGE_NAME));
const info = isDockerEngine ? await containerInfo() : undefined;
console.log(JSON.stringify({
dockerEngineRunning: isDockerEngine,
imageName: VRT_IMAGE_NAME,
imageIsPulled,
containerWSEndpoing: info?.wsEndpoint ?? '',
containerVNCEndpoint: info?.vncSession ?? '',
}, null, 2));
}
async function containerInfo(): Promise<ContainerInfo|undefined> {
const allContainers = await dockerApi.listContainers();
const pwDockerImage = await findDockerImage(VRT_IMAGE_NAME);
@ -201,7 +213,7 @@ async function containerInfo(): Promise<ContainerInfo|undefined> {
async function ensurePlaywrightContainerOrDie(): Promise<ContainerInfo> {
const pwImage = await findDockerImage(VRT_IMAGE_NAME);
if (!pwImage) {
console.error('\n' + utils.wrapInASCIIBox([
throw createStacklessError('\n' + utils.wrapInASCIIBox([
`Failed to find local docker image.`,
`Please build local docker image with the following command:`,
``,
@ -209,7 +221,6 @@ async function ensurePlaywrightContainerOrDie(): Promise<ContainerInfo> {
``,
`<3 Playwright Team`,
].join('\n'), 1));
process.exit(1);
}
let info = await containerInfo();
@ -242,14 +253,13 @@ async function ensurePlaywrightContainerOrDie(): Promise<ContainerInfo> {
async function checkDockerEngineIsRunningOrDie() {
if (await dockerApi.checkEngineRunning())
return;
console.error(utils.wrapInASCIIBox([
throw createStacklessError(utils.wrapInASCIIBox([
`Docker is not running!`,
`Please install and launch docker:`,
``,
` https://docs.docker.com/get-docker`,
``,
].join('\n'), 1));
process.exit(1);
}
async function findDockerImage(imageName: string): Promise<dockerApi.DockerImage|undefined> {
@ -257,3 +267,8 @@ async function findDockerImage(imageName: string): Promise<dockerApi.DockerImage
return images.find(image => image.names.includes(imageName));
}
function createStacklessError(message: string) {
const error = new Error(message);
error.stack = '';
return error;
}

View File

@ -30,8 +30,9 @@ test.beforeAll(async ({ exec }) => {
test('make sure it tells to run `npx playwright docker build` when image is not instaleld', async ({ exec }) => {
await exec('npm i --foreground-scripts @playwright/test');
const result = await exec('npx playwright docker test docker.spec.js', {
const result = await exec('npx playwright test docker.spec.js', {
expectToExitWithError: true,
env: { PLAYWRIGHT_DOCKER: '1' },
});
expect(result).toContain('npx playwright docker build');
});
@ -52,7 +53,9 @@ test.describe('installed image', () => {
test('make sure it auto-starts container', async ({ exec }) => {
await exec('npm i --foreground-scripts @playwright/test');
await exec('npx playwright docker stop');
const result = await exec('npx playwright docker test docker.spec.js --grep platform');
const result = await exec('npx playwright test docker.spec.js --grep platform', {
env: { PLAYWRIGHT_DOCKER: '1' },
});
expect(result).toContain('@chromium Linux');
});
@ -71,7 +74,9 @@ test.describe('installed image', () => {
test('all browsers work headless', async ({ exec }) => {
await exec('npm i --foreground-scripts @playwright/test');
const result = await exec('npx playwright docker test docker.spec.js --grep platform --browser all');
const result = await exec('npx playwright test docker.spec.js --grep platform --browser all', {
env: { PLAYWRIGHT_DOCKER: '1' },
});
expect(result).toContain('@chromium Linux');
expect(result).toContain('@webkit Linux');
expect(result).toContain('@firefox Linux');
@ -92,18 +97,24 @@ test.describe('installed image', () => {
test('all browsers work headed', async ({ exec }) => {
await exec('npm i --foreground-scripts @playwright/test');
{
const result = await exec(`npx playwright docker test docker.spec.js --headed --grep userAgent --browser chromium`);
const result = await exec(`npx playwright test docker.spec.js --headed --grep userAgent --browser chromium`, {
env: { PLAYWRIGHT_DOCKER: '1' },
});
expect(result).toContain('@chromium');
expect(result).not.toContain('Headless');
expect(result).toContain(' Chrome/');
}
{
const result = await exec(`npx playwright docker test docker.spec.js --headed --grep userAgent --browser webkit`);
const result = await exec(`npx playwright test docker.spec.js --headed --grep userAgent --browser webkit`, {
env: { PLAYWRIGHT_DOCKER: '1' },
});
expect(result).toContain('@webkit');
expect(result).toContain(' Version/');
}
{
const result = await exec(`npx playwright docker test docker.spec.js --headed --grep userAgent --browser firefox`);
const result = await exec(`npx playwright test docker.spec.js --headed --grep userAgent --browser firefox`, {
env: { PLAYWRIGHT_DOCKER: '1' },
});
expect(result).toContain('@firefox');
expect(result).toContain(' Firefox/');
}
@ -111,8 +122,9 @@ test.describe('installed image', () => {
test('screenshots should use __screenshots__ folder', async ({ exec, tmpWorkspace }) => {
await exec('npm i --foreground-scripts @playwright/test');
await exec('npx playwright docker test docker.spec.js --grep screenshot --browser all', {
await exec('npx playwright test docker.spec.js --grep screenshot --browser all', {
expectToExitWithError: true,
env: { PLAYWRIGHT_DOCKER: '1' },
});
await expect(path.join(tmpWorkspace, '__screenshots__', 'firefox', 'docker.spec.js', 'img.png')).toExistOnFS();
await expect(path.join(tmpWorkspace, '__screenshots__', 'chromium', 'docker.spec.js', 'img.png')).toExistOnFS();
@ -126,8 +138,9 @@ test.describe('installed image', () => {
server.setRoute('/', (request, response) => {
response.end('Hello from host');
});
const result = await exec('npx playwright docker test docker.spec.js --grep localhost --browser all', {
const result = await exec('npx playwright test docker.spec.js --grep localhost --browser all', {
env: {
PLAYWRIGHT_DOCKER: '1',
TEST_PORT: TEST_PORT + '',
},
});