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/outofprocess": "./lib/outofprocess.js",
"./lib/utils": "./lib/utils/index.js", "./lib/utils": "./lib/utils/index.js",
"./lib/common/userAgent": "./lib/common/userAgent.js", "./lib/common/userAgent": "./lib/common/userAgent.js",
"./lib/containers/docker": "./lib/containers/docker.js",
"./lib/utils/comparators": "./lib/utils/comparators.js", "./lib/utils/comparators": "./lib/utils/comparators.js",
"./lib/utils/eventsHelper": "./lib/utils/eventsHelper.js", "./lib/utils/eventsHelper": "./lib/utils/eventsHelper.js",
"./lib/utils/fileUtils": "./lib/utils/fileUtils.js", "./lib/utils/fileUtils": "./lib/utils/fileUtils.js",

View file

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

View file

@ -38,6 +38,7 @@ import type { GridFactory } from '../grid/gridServer';
import { GridServer } from '../grid/gridServer'; import { GridServer } from '../grid/gridServer';
import type { Executable } from '../server'; import type { Executable } from '../server';
import { registry, writeDockerVersion } from '../server'; import { registry, writeDockerVersion } from '../server';
import { addDockerCLI } from '../containers/docker';
const packageJSON = require('../../package.json'); const packageJSON = require('../../package.json');
@ -114,6 +115,7 @@ function checkBrowsersToInstall(args: string[]): Executable[] {
return executables; return executables;
} }
program program
.command('install [browser...]') .command('install [browser...]')
.description('ensure browsers necessary for this version of Playwright are installed') .description('ensure browsers necessary for this version of Playwright are installed')
@ -305,6 +307,8 @@ Examples:
$ show-trace https://example.com/trace.zip`); $ show-trace https://example.com/trace.zip`);
addDockerCLI(program);
if (!process.env.PW_LANG_NAME) { if (!process.env.PW_LANG_NAME) {
let playwrightTestPackagePath = null; let playwrightTestPackagePath = null;
const resolvePwTestPaths = [__dirname, process.cwd()]; 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 path from 'path';
import fs from 'fs'; import fs from 'fs';
import { colors } from 'playwright-core/lib/utilsBundle'; import { spawnAsync } from '../utils/spawnAsync';
import { spawnAsync } from 'playwright-core/lib/utils/spawnAsync'; import * as utils from '../utils';
import * as utils from 'playwright-core/lib/utils'; import { getPlaywrightVersion } from '../common/userAgent';
import { getPlaywrightVersion } from 'playwright-core/lib/common/userAgent';
import * as dockerApi from './dockerApi'; import * as dockerApi from './dockerApi';
import type { TestRunnerPlugin } from '../plugins'; import type { Command } from '../utilsBundle';
import type { FullConfig, Reporter, Suite } from '../../types/testReporter';
const VRT_IMAGE_DISTRO = 'focal'; const VRT_IMAGE_DISTRO = 'focal';
const VRT_IMAGE_NAME = `playwright:local-${getPlaywrightVersion()}-${VRT_IMAGE_DISTRO}`; 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_NAME = 'dev.playwright.vrt-service.version';
const VRT_CONTAINER_LABEL_VALUE = '1'; const VRT_CONTAINER_LABEL_VALUE = '1';
export async function startPlaywrightContainer() { async function startPlaywrightContainer() {
await checkDockerEngineIsRunningOrDie(); await checkDockerEngineIsRunningOrDie();
let info = await containerInfo(); let info = await containerInfo();
@ -52,7 +50,7 @@ export async function startPlaywrightContainer() {
].join('\n')); ].join('\n'));
} }
export async function stopAllPlaywrightContainers() { async function stopAllPlaywrightContainers() {
await checkDockerEngineIsRunningOrDie(); await checkDockerEngineIsRunningOrDie();
const allContainers = await dockerApi.listContainers(); const allContainers = await dockerApi.listContainers();
@ -63,7 +61,7 @@ export async function stopAllPlaywrightContainers() {
}))); })));
} }
export async function deletePlaywrightImage() { async function deletePlaywrightImage() {
await checkDockerEngineIsRunningOrDie(); await checkDockerEngineIsRunningOrDie();
const dockerImage = await findDockerImage(VRT_IMAGE_NAME); const dockerImage = await findDockerImage(VRT_IMAGE_NAME);
@ -75,7 +73,7 @@ export async function deletePlaywrightImage() {
await dockerApi.removeImage(dockerImage.imageId); await dockerApi.removeImage(dockerImage.imageId);
} }
export async function buildPlaywrightImage() { async function buildPlaywrightImage() {
await checkDockerEngineIsRunningOrDie(); await checkDockerEngineIsRunningOrDie();
const isDevelopmentMode = getPlaywrightVersion().includes('next'); const isDevelopmentMode = getPlaywrightVersion().includes('next');
@ -130,44 +128,12 @@ export async function buildPlaywrightImage() {
console.log(`Done!`); 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 { interface ContainerInfo {
wsEndpoint: string; wsEndpoint: string;
vncSession: string; vncSession: string;
} }
export async function printDockerStatus() { async function printDockerStatus() {
const isDockerEngine = await dockerApi.checkEngineRunning(); const isDockerEngine = await dockerApi.checkEngineRunning();
const imageIsPulled = isDockerEngine && !!(await findDockerImage(VRT_IMAGE_NAME)); const imageIsPulled = isDockerEngine && !!(await findDockerImage(VRT_IMAGE_NAME));
const info = isDockerEngine ? await containerInfo() : undefined; const info = isDockerEngine ? await containerInfo() : undefined;
@ -180,7 +146,7 @@ export async function printDockerStatus() {
}, null, 2)); }, null, 2));
} }
async function containerInfo(): Promise<ContainerInfo|undefined> { export async function containerInfo(): Promise<ContainerInfo|undefined> {
const allContainers = await dockerApi.listContainers(); const allContainers = await dockerApi.listContainers();
const pwDockerImage = await findDockerImage(VRT_IMAGE_NAME); const pwDockerImage = await findDockerImage(VRT_IMAGE_NAME);
const container = allContainers.find(container => container.imageId === pwDockerImage?.imageId && container.state === 'running'); 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; return wsEndpoint && vncSession ? { wsEndpoint, vncSession } : undefined;
} }
async function ensurePlaywrightContainerOrDie(): Promise<ContainerInfo> { export async function ensurePlaywrightContainerOrDie(): Promise<ContainerInfo> {
const pwImage = await findDockerImage(VRT_IMAGE_NAME); const pwImage = await findDockerImage(VRT_IMAGE_NAME);
if (!pwImage) { if (!pwImage) {
throw createStacklessError('\n' + utils.wrapInASCIIBox([ throw createStacklessError('\n' + utils.wrapInASCIIBox([
@ -284,7 +250,7 @@ async function ensurePlaywrightContainerOrDie(): Promise<ContainerInfo> {
return info; return info;
} }
async function checkDockerEngineIsRunningOrDie() { export async function checkDockerEngineIsRunningOrDie() {
if (await dockerApi.checkEngineRunning()) if (await dockerApi.checkEngineRunning())
return; return;
throw createStacklessError(utils.wrapInASCIIBox([ throw createStacklessError(utils.wrapInASCIIBox([
@ -306,3 +272,54 @@ function createStacklessError(message: string) {
error.stack = ''; error.stack = '';
return error; 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 ./utilsBundle.ts
docker/
matchers/ matchers/
reporters/ reporters/
third_party/ third_party/

View file

@ -17,7 +17,6 @@
/* eslint-disable no-console */ /* eslint-disable no-console */
import type { Command } from 'playwright-core/lib/utilsBundle'; import type { Command } from 'playwright-core/lib/utilsBundle';
import * as docker from './docker/docker';
import fs from 'fs'; import fs from 'fs';
import url from 'url'; import url from 'url';
import path from 'path'; import path from 'path';
@ -33,58 +32,6 @@ export function addTestCommands(program: Command) {
addTestCommand(program); addTestCommand(program);
addShowReportCommand(program); addShowReportCommand(program);
addListFilesCommand(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) { 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 type { TestRunnerPlugin } from './plugins';
import { setRunnerToAddPluginsTo } from './plugins'; import { setRunnerToAddPluginsTo } from './plugins';
import { webServerPluginsForConfig } from './plugins/webServerPlugin'; import { webServerPluginsForConfig } from './plugins/webServerPlugin';
import { dockerPlugin } from './docker/docker'; import { dockerPlugin } from './plugins/dockerPlugin';
import { MultiMap } from 'playwright-core/lib/utils/multimap'; import { MultiMap } from 'playwright-core/lib/utils/multimap';
const removeFolderAsync = promisify(rimraf); const removeFolderAsync = promisify(rimraf);

View file

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