chore: move container integration back to playwright-core (#17487)

This commit is contained in:
Andrey Lushnikov 2022-09-21 15:45:43 -04:00 committed by GitHub
parent 0abb1c773b
commit d431958603
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 130 additions and 103 deletions

View file

@ -24,6 +24,7 @@
"./lib/outofprocess": "./lib/outofprocess.js",
"./lib/utils": "./lib/utils/index.js",
"./lib/common/userAgent": "./lib/common/userAgent.js",
"./lib/containers/docker": "./lib/containers/docker.js",
"./lib/utils/comparators": "./lib/utils/comparators.js",
"./lib/utils/eventsHelper": "./lib/utils/eventsHelper.js",
"./lib/utils/fileUtils": "./lib/utils/fileUtils.js",

View file

@ -13,6 +13,7 @@
[cli.ts]
../server/trace/viewer/traceViewer.ts
../server/
../containers/
[driver.ts]
../**

View file

@ -38,6 +38,7 @@ import type { GridFactory } from '../grid/gridServer';
import { GridServer } from '../grid/gridServer';
import type { Executable } from '../server';
import { registry, writeDockerVersion } from '../server';
import { addDockerCLI } from '../containers/docker';
const packageJSON = require('../../package.json');
@ -114,6 +115,7 @@ function checkBrowsersToInstall(args: string[]): Executable[] {
return executables;
}
program
.command('install [browser...]')
.description('ensure browsers necessary for this version of Playwright are installed')
@ -305,6 +307,8 @@ Examples:
$ show-trace https://example.com/trace.zip`);
addDockerCLI(program);
if (!process.env.PW_LANG_NAME) {
let playwrightTestPackagePath = null;
const resolvePwTestPaths = [__dirname, process.cwd()];

View file

@ -0,0 +1,4 @@
[*]
../utils/
../utilsBundle.ts
../common/

View file

@ -17,13 +17,11 @@
import path from 'path';
import fs from 'fs';
import { colors } from 'playwright-core/lib/utilsBundle';
import { spawnAsync } from 'playwright-core/lib/utils/spawnAsync';
import * as utils from 'playwright-core/lib/utils';
import { getPlaywrightVersion } from 'playwright-core/lib/common/userAgent';
import { spawnAsync } from '../utils/spawnAsync';
import * as utils from '../utils';
import { getPlaywrightVersion } from '../common/userAgent';
import * as dockerApi from './dockerApi';
import type { TestRunnerPlugin } from '../plugins';
import type { FullConfig, Reporter, Suite } from '../../types/testReporter';
import type { Command } from '../utilsBundle';
const VRT_IMAGE_DISTRO = 'focal';
const VRT_IMAGE_NAME = `playwright:local-${getPlaywrightVersion()}-${VRT_IMAGE_DISTRO}`;
@ -31,7 +29,7 @@ const VRT_CONTAINER_NAME = `playwright-${getPlaywrightVersion()}-${VRT_IMAGE_DIS
const VRT_CONTAINER_LABEL_NAME = 'dev.playwright.vrt-service.version';
const VRT_CONTAINER_LABEL_VALUE = '1';
export async function startPlaywrightContainer() {
async function startPlaywrightContainer() {
await checkDockerEngineIsRunningOrDie();
let info = await containerInfo();
@ -52,7 +50,7 @@ export async function startPlaywrightContainer() {
].join('\n'));
}
export async function stopAllPlaywrightContainers() {
async function stopAllPlaywrightContainers() {
await checkDockerEngineIsRunningOrDie();
const allContainers = await dockerApi.listContainers();
@ -63,7 +61,7 @@ export async function stopAllPlaywrightContainers() {
})));
}
export async function deletePlaywrightImage() {
async function deletePlaywrightImage() {
await checkDockerEngineIsRunningOrDie();
const dockerImage = await findDockerImage(VRT_IMAGE_NAME);
@ -75,7 +73,7 @@ export async function deletePlaywrightImage() {
await dockerApi.removeImage(dockerImage.imageId);
}
export async function buildPlaywrightImage() {
async function buildPlaywrightImage() {
await checkDockerEngineIsRunningOrDie();
const isDevelopmentMode = getPlaywrightVersion().includes('next');
@ -130,44 +128,12 @@ export async function buildPlaywrightImage() {
console.log(`Done!`);
}
export const dockerPlugin: TestRunnerPlugin = {
name: 'playwright:docker',
async setup(config: FullConfig, configDir: string, rootSuite: Suite, reporter: Reporter) {
if (!process.env.PLAYWRIGHT_DOCKER)
return;
const print = (text: string) => reporter.onStdOut?.(text);
const println = (text: string) => reporter.onStdOut?.(text + '\n');
println(colors.dim('Using docker container to run browsers.'));
await checkDockerEngineIsRunningOrDie();
let info = await containerInfo();
if (!info) {
print(colors.dim(`Starting docker container... `));
const time = Date.now();
info = await ensurePlaywrightContainerOrDie();
const deltaMs = (Date.now() - time);
println(colors.dim('Done in ' + (deltaMs / 1000).toFixed(1) + 's'));
println(colors.dim('The Docker container will keep running after tests finished.'));
println(colors.dim('Stop manually using:'));
println(colors.dim(' npx playwright docker stop'));
}
println(colors.dim(`View screen: ${info.vncSession}`));
println('');
process.env.PW_TEST_CONNECT_WS_ENDPOINT = info.wsEndpoint;
process.env.PW_TEST_CONNECT_HEADERS = JSON.stringify({
'x-playwright-proxy': '*',
});
},
};
interface ContainerInfo {
wsEndpoint: string;
vncSession: string;
}
export async function printDockerStatus() {
async function printDockerStatus() {
const isDockerEngine = await dockerApi.checkEngineRunning();
const imageIsPulled = isDockerEngine && !!(await findDockerImage(VRT_IMAGE_NAME));
const info = isDockerEngine ? await containerInfo() : undefined;
@ -180,7 +146,7 @@ export async function printDockerStatus() {
}, null, 2));
}
async function containerInfo(): Promise<ContainerInfo|undefined> {
export async function containerInfo(): Promise<ContainerInfo|undefined> {
const allContainers = await dockerApi.listContainers();
const pwDockerImage = await findDockerImage(VRT_IMAGE_NAME);
const container = allContainers.find(container => container.imageId === pwDockerImage?.imageId && container.state === 'running');
@ -210,7 +176,7 @@ async function containerInfo(): Promise<ContainerInfo|undefined> {
return wsEndpoint && vncSession ? { wsEndpoint, vncSession } : undefined;
}
async function ensurePlaywrightContainerOrDie(): Promise<ContainerInfo> {
export async function ensurePlaywrightContainerOrDie(): Promise<ContainerInfo> {
const pwImage = await findDockerImage(VRT_IMAGE_NAME);
if (!pwImage) {
throw createStacklessError('\n' + utils.wrapInASCIIBox([
@ -284,7 +250,7 @@ async function ensurePlaywrightContainerOrDie(): Promise<ContainerInfo> {
return info;
}
async function checkDockerEngineIsRunningOrDie() {
export async function checkDockerEngineIsRunningOrDie() {
if (await dockerApi.checkEngineRunning())
return;
throw createStacklessError(utils.wrapInASCIIBox([
@ -306,3 +272,54 @@ function createStacklessError(message: string) {
error.stack = '';
return error;
}
export function addDockerCLI(program: Command) {
const dockerCommand = program.command('docker')
.description(`Manage Docker integration (EXPERIMENTAL)`);
dockerCommand.command('build')
.description('build local docker image')
.action(async function(options) {
try {
await buildPlaywrightImage();
} catch (e) {
console.error(e.stack ? e : e.message);
}
});
dockerCommand.command('start')
.description('start docker container')
.action(async function(options) {
try {
await startPlaywrightContainer();
} catch (e) {
console.error(e.stack ? e : e.message);
}
});
dockerCommand.command('stop')
.description('stop docker container')
.action(async function(options) {
try {
await 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) {
try {
await deletePlaywrightImage();
} catch (e) {
console.error(e.stack ? e : e.message);
}
});
dockerCommand.command('print-status-json', { hidden: true })
.description('print docker status')
.action(async function(options) {
await printDockerStatus();
});
}

View file

@ -1,6 +1,5 @@
[*]
./utilsBundle.ts
docker/
matchers/
reporters/
third_party/

View file

@ -17,7 +17,6 @@
/* eslint-disable no-console */
import type { Command } from 'playwright-core/lib/utilsBundle';
import * as docker from './docker/docker';
import fs from 'fs';
import url from 'url';
import path from 'path';
@ -33,58 +32,6 @@ export function addTestCommands(program: Command) {
addTestCommand(program);
addShowReportCommand(program);
addListFilesCommand(program);
addDockerCommand(program);
}
function addDockerCommand(program: Command) {
const dockerCommand = program.command('docker')
.description(`Manage Docker integration (EXPERIMENTAL)`);
dockerCommand.command('build')
.description('build local docker image')
.action(async function(options) {
try {
await docker.buildPlaywrightImage();
} catch (e) {
console.error(e.stack ? e : e.message);
}
});
dockerCommand.command('start')
.description('start docker container')
.action(async function(options) {
try {
await docker.startPlaywrightContainer();
} catch (e) {
console.error(e.stack ? e : e.message);
}
});
dockerCommand.command('stop')
.description('stop docker container')
.action(async function(options) {
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) {
try {
await docker.deletePlaywrightImage();
} catch (e) {
console.error(e.stack ? e : e.message);
}
});
dockerCommand.command('print-status-json', { hidden: true })
.description('print docker status')
.action(async function(options) {
await docker.printDockerStatus();
});
}
function addTestCommand(program: Command) {

View file

@ -0,0 +1,54 @@
/**
* Copyright (c) Microsoft Corporation.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import type { TestRunnerPlugin } from '.';
import type { FullConfig, Reporter, Suite } from '../../types/testReporter';
import { colors } from 'playwright-core/lib/utilsBundle';
import { checkDockerEngineIsRunningOrDie, containerInfo, ensurePlaywrightContainerOrDie } from 'playwright-core/lib/containers/docker';
export const dockerPlugin: TestRunnerPlugin = {
name: 'playwright:docker',
async setup(config: FullConfig, configDir: string, rootSuite: Suite, reporter: Reporter) {
if (!process.env.PLAYWRIGHT_DOCKER)
return;
const print = (text: string) => reporter.onStdOut?.(text);
const println = (text: string) => reporter.onStdOut?.(text + '\n');
println(colors.dim('Using docker container to run browsers.'));
await checkDockerEngineIsRunningOrDie();
let info = await containerInfo();
if (!info) {
print(colors.dim(`Starting docker container... `));
const time = Date.now();
info = await ensurePlaywrightContainerOrDie();
const deltaMs = (Date.now() - time);
println(colors.dim('Done in ' + (deltaMs / 1000).toFixed(1) + 's'));
println(colors.dim('The Docker container will keep running after tests finished.'));
println(colors.dim('Stop manually using:'));
println(colors.dim(' npx playwright docker stop'));
}
println(colors.dim(`View screen: ${info.vncSession}`));
println('');
process.env.PW_TEST_CONNECT_WS_ENDPOINT = info.wsEndpoint;
process.env.PW_TEST_CONNECT_HEADERS = JSON.stringify({
'x-playwright-proxy': '*',
});
},
};

View file

@ -45,7 +45,7 @@ import { SigIntWatcher } from './sigIntWatcher';
import type { TestRunnerPlugin } from './plugins';
import { setRunnerToAddPluginsTo } from './plugins';
import { webServerPluginsForConfig } from './plugins/webServerPlugin';
import { dockerPlugin } from './docker/docker';
import { dockerPlugin } from './plugins/dockerPlugin';
import { MultiMap } from 'playwright-core/lib/utils/multimap';
const removeFolderAsync = promisify(rimraf);

View file

@ -301,14 +301,14 @@ copyFiles.push({
// Babel doesn't touch JS files, so copy them manually.
// For example: diff_match_patch.js
copyFiles.push({
files: 'packages/playwright-core/src/**/*.js',
files: 'packages/playwright-core/src/**/*.(js|sh)',
from: 'packages/playwright-core/src',
to: 'packages/playwright-core/lib',
ignored: ['**/.eslintrc.js', '**/webpack*.config.js', '**/injected/**/*']
});
copyFiles.push({
files: 'packages/playwright-test/src/**/*.(js|sh)',
files: 'packages/playwright-test/src/**/*.sh',
from: 'packages/playwright-test/src',
to: 'packages/playwright-test/lib',
ignored: ['**/.eslintrc.js']