diff --git a/.github/workflows/tests_primary.yml b/.github/workflows/tests_primary.yml index ff7c9dfae8..c9930d1b18 100644 --- a/.github/workflows/tests_primary.yml +++ b/.github/workflows/tests_primary.yml @@ -180,31 +180,3 @@ jobs: if: always() shell: bash - smoke_test_docker_integration: - runs-on: ubuntu-20.04 - steps: - - uses: actions/checkout@v3 - - uses: actions/setup-node@v3 - with: - node-version: 14 - - run: npm i -g npm@8 - - run: npm ci - env: - DEBUG: pw:install - PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: 1 - - run: npm run build - - run: npx playwright install --with-deps - - run: | - ./utils/docker/build.sh --amd64 remote playwright:localbuild-remote - docker run -p 5400:5400 --name pw-remote --rm -d playwright:localbuild-remote - while ! curl localhost:5400; do sleep 0.2; done - DOCKER_REMOTE=1 xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run test -- --grep '@smoke' - docker kill pw-remote - - run: ./utils/upload_flakiness_dashboard.sh ./test-results/report.json - if: always() - shell: bash - - uses: actions/upload-artifact@v3 - if: always() - with: - name: docker-remote-test-results - path: test-results diff --git a/packages/playwright-core/.npmignore b/packages/playwright-core/.npmignore index f381bda141..132b57f597 100644 --- a/packages/playwright-core/.npmignore +++ b/packages/playwright-core/.npmignore @@ -14,8 +14,6 @@ lib/**/injected/ # Include all binaries that we ship with the package. !bin/* -# Include all shell files in the lib/containers/* -!lib/containers/*.sh # Include FFMPEG !third_party/ffmpeg/* # Include generated types and entrypoint. diff --git a/packages/playwright-core/src/cli/cli.ts b/packages/playwright-core/src/cli/cli.ts index 1675abd7f0..81d8785b8c 100755 --- a/packages/playwright-core/src/cli/cli.ts +++ b/packages/playwright-core/src/cli/cli.ts @@ -35,7 +35,6 @@ import { spawn } from 'child_process'; import { wrapInASCIIBox, isLikelyNpxGlobal, assert } from '../utils'; import type { Executable } from '../server'; import { registry, writeDockerVersion } from '../server'; -import { addContainerCLI } from '../containers/'; const packageJSON = require('../../package.json'); @@ -290,8 +289,6 @@ Examples: $ show-trace https://example.com/trace.zip`); -addContainerCLI(program); - if (!process.env.PW_LANG_NAME) { let playwrightTestPackagePath = null; const resolvePwTestPaths = [__dirname, process.cwd()]; @@ -562,15 +559,13 @@ async function openPage(context: BrowserContext, url: string | undefined): Promi async function open(options: Options, url: string | undefined, language: string) { const { context, launchOptions, contextOptions } = await launchContext(options, !!process.env.PWTEST_CLI_HEADLESS, process.env.PWTEST_CLI_EXECUTABLE_PATH); - if (!process.env.PW_DISABLE_RECORDER) { - await context._enableRecorder({ - language, - launchOptions, - contextOptions, - device: options.device, - saveStorage: options.saveStorage, - }); - } + await context._enableRecorder({ + language, + launchOptions, + contextOptions, + device: options.device, + saveStorage: options.saveStorage, + }); await openPage(context, url); if (process.env.PWTEST_CLI_EXIT) await Promise.all(context.pages().map(p => p.close())); diff --git a/packages/playwright-core/src/containers/DEPS.list b/packages/playwright-core/src/containers/DEPS.list deleted file mode 100644 index 748a4f6213..0000000000 --- a/packages/playwright-core/src/containers/DEPS.list +++ /dev/null @@ -1,6 +0,0 @@ -[*] -../utils/ -../utilsBundle.ts -../cli/ -../remote/ -../third_party/ diff --git a/packages/playwright-core/src/containers/container_entrypoint.sh b/packages/playwright-core/src/containers/container_entrypoint.sh deleted file mode 100755 index c2cdc0b803..0000000000 --- a/packages/playwright-core/src/containers/container_entrypoint.sh +++ /dev/null @@ -1,40 +0,0 @@ -#!/bin/bash -set -e - -trap "cd $(pwd -P)" EXIT -cd "$(dirname "$0")" - -SCREEN_WIDTH=1360 -SCREEN_HEIGHT=1020 -SCREEN_DEPTH=24 -SCREEN_DPI=96 -GEOMETRY="$SCREEN_WIDTH""x""$SCREEN_HEIGHT""x""$SCREEN_DEPTH" - -# Launch x11 -nohup /usr/bin/xvfb-run --server-num=$DISPLAY_NUM \ - --listen-tcp \ - --server-args="-screen 0 "$GEOMETRY" -fbdir /var/tmp -dpi "$SCREEN_DPI" -listen tcp -noreset -ac +extension RANDR" \ - /usr/bin/fluxbox -display "$DISPLAY" >/dev/null 2>&1 & - -# Launch x11vnc -nohup x11vnc -noprimary -nosetprimary -forever -shared -rfbport 5900 -rfbportv6 5900 -display "$DISPLAY" >/dev/null 2>&1 & - -# Launch novnc -nohup /opt/bin/noVNC/utils/novnc_proxy --listen 7900 --vnc localhost:5900 >/dev/null 2>&1 & - -# Wait for x11 display to start -for i in $(seq 1 500); do - if xdpyinfo -display $DISPLAY >/dev/null 2>&1; then - break - fi - sleep 0.1 -done - -# Make sure to re-start container agent if something goes wrong. -# The approach taken from: https://stackoverflow.com/a/697064/314883 -until npx playwright container start-agent --novnc-endpoint="http://127.0.0.1:7900" --port 5400; do - echo "Server crashed with exit code $?. Respawning.." >&2 - sleep 1 -done - - diff --git a/packages/playwright-core/src/containers/container_install_deps.sh b/packages/playwright-core/src/containers/container_install_deps.sh deleted file mode 100755 index b3e485fdf4..0000000000 --- a/packages/playwright-core/src/containers/container_install_deps.sh +++ /dev/null @@ -1,85 +0,0 @@ -export NOVNC_REF='1.3.0' -export WEBSOCKIFY_REF='0.10.0' -export DEBIAN_FRONTEND=noninteractive - -# Install FluxBox, VNC & noVNC -mkdir -p /opt/bin && chmod +x /dev/shm \ - && apt-get update && apt-get install -y unzip fluxbox x11vnc \ - && curl -L -o noVNC.zip "https://github.com/novnc/noVNC/archive/v${NOVNC_REF}.zip" \ - && unzip -x noVNC.zip \ - && rm -rf noVNC-${NOVNC_REF}/{docs,tests} \ - && mv noVNC-${NOVNC_REF} /opt/bin/noVNC \ - && cp /opt/bin/noVNC/vnc.html /opt/bin/noVNC/index.html \ - && rm noVNC.zip \ - && curl -L -o websockify.zip "https://github.com/novnc/websockify/archive/v${WEBSOCKIFY_REF}.zip" \ - && unzip -x websockify.zip \ - && rm websockify.zip \ - && rm -rf websockify-${WEBSOCKIFY_REF}/{docs,tests} \ - && mv websockify-${WEBSOCKIFY_REF} /opt/bin/noVNC/utils/websockify - -# Patch noVNC - -cat <<'EOF' > /opt/bin/noVNC/clip.patch -diff --git a/app/ui.js b/app/ui.js -index cb6a9fd..dbe42e0 100644 ---- a/app/ui.js -+++ b/app/ui.js -@@ -951,6 +951,7 @@ const UI = { - clipboardReceive(e) { - Log.Debug(">> UI.clipboardReceive: " + e.detail.text.substr(0, 40) + "..."); - document.getElementById('noVNC_clipboard_text').value = e.detail.text; -+ navigator.clipboard.writeText(e.detail.text).catch(() => {}); - Log.Debug("<< UI.clipboardReceive"); - }, - -diff --git a/core/rfb.js b/core/rfb.js -index ea3bf58..fad57bc 100644 ---- a/core/rfb.js -+++ b/core/rfb.js -@@ -176,6 +176,7 @@ export default class RFB extends EventTargetMixin { - handleMouse: this._handleMouse.bind(this), - handleWheel: this._handleWheel.bind(this), - handleGesture: this._handleGesture.bind(this), -+ handleFocus: () => navigator.clipboard.readText().then(this.clipboardPasteFrom.bind(this)).catch(() => {}) - }; - - // main setup -@@ -515,6 +516,7 @@ export default class RFB extends EventTargetMixin { - this._canvas.addEventListener("gesturestart", this._eventHandlers.handleGesture); - this._canvas.addEventListener("gesturemove", this._eventHandlers.handleGesture); - this._canvas.addEventListener("gestureend", this._eventHandlers.handleGesture); -+ window.addEventListener('focus', this._eventHandlers.handleFocus); - - Log.Debug("<< RFB.connect"); - } -@@ -522,6 +524,7 @@ export default class RFB extends EventTargetMixin { - _disconnect() { - Log.Debug(">> RFB.disconnect"); - this._cursor.detach(); -+ window.removeEventListener('focus', this._eventHandlers.handleFocus); - this._canvas.removeEventListener("gesturestart", this._eventHandlers.handleGesture); - this._canvas.removeEventListener("gesturemove", this._eventHandlers.handleGesture); - this._canvas.removeEventListener("gestureend", this._eventHandlers.handleGesture); -EOF - -cd /opt/bin/noVNC -git apply clip.patch - -# Configure FluxBox menus -mkdir /root/.fluxbox -cat <<'EOF' > /root/.fluxbox/menu - [begin] (fluxbox) - [submenu] (Browsers) {} - [exec] (Chromium) { cd /ms-playwright-agent && PW_DISABLE_RECORDER=1 npx playwright open --browser chromium } <> - [exec] (Firefox) { cd /ms-playwright-agent && PW_DISABLE_RECORDER=1 npx playwright open --browser firefox } <> - [exec] (WebKit) { cd /ms-playwright-agent && PW_DISABLE_RECORDER=1 npx playwright open --browser webkit } <> - [end] - [include] (/etc/X11/fluxbox/fluxbox-menu) - [end] -EOF - -cat <<'EOF' > /root/.fluxbox/lastwallpaper -$center $full|/ms-playwright-agent/node_modules/playwright-core/lib/server/chromium/appIcon.png||:99 -$center $full|/ms-playwright-agent/node_modules/playwright-core/lib/server/chromium/appIcon.png||:99.0 -EOF - diff --git a/packages/playwright-core/src/containers/index.ts b/packages/playwright-core/src/containers/index.ts deleted file mode 100644 index c80c87fd4d..0000000000 --- a/packages/playwright-core/src/containers/index.ts +++ /dev/null @@ -1,105 +0,0 @@ -/** - * 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. - */ -/* eslint-disable no-console */ - -import path from 'path'; -import { spawnAsync } from '../utils/spawnAsync'; -import { gracefullyCloseAll } from '../utils/processLauncher'; -import { createGuid } from '../utils'; -import type { Command } from '../utilsBundle'; -import { debug } from '../utilsBundle'; -import type { AddressInfo } from 'net'; -import http from 'http'; -import { PlaywrightServer } from '../remote/playwrightServer'; - -const { ProxyServer } = require('../third_party/http_proxy.js'); -const debugLog = debug('pw:container'); - -export function addContainerCLI(program: Command) { - const ctrCommand = program.command('container', { hidden: true }) - .description(`Manage container integration (EXPERIMENTAL)`); - - ctrCommand.command('install-services', { hidden: true }) - .description('install services required to run container agent') - .action(async function() { - const { code } = await spawnAsync('bash', [path.join(__dirname, 'container_install_deps.sh')], { stdio: 'inherit' }); - if (code !== 0) - throw new Error('Failed to install server dependencies!'); - }); - - ctrCommand.command('entrypoint', { hidden: true }) - .description('launch all services and container agent') - .action(async function() { - await spawnAsync('bash', [path.join(__dirname, 'container_entrypoint.sh')], { stdio: 'inherit' }); - }); - - ctrCommand.command('start-agent', { hidden: true }) - .description('start container agent') - .option('--port ', 'port number') - .option('--novnc-endpoint ', 'novnc server endpoint') - .action(async function(options) { - launchContainerAgent(+(options.port ?? '0'), options.novncEndpoint); - }); -} - -async function launchContainerAgent(port: number, novncEndpoint: string) { - const novncWSPath = createGuid(); - const server = new PlaywrightServer({ - path: '/' + createGuid(), - maxConnections: Infinity, - }); - await server.listen(undefined); - const serverEndpoint = server.address(); - process.on('exit', () => server.close().catch(console.error)); - process.stdin.on('close', () => selfDestruct()); - - const vncProxy = new ProxyServer(novncEndpoint, debugLog); - const serverProxy = new ProxyServer(serverEndpoint, debugLog); - - const httpServer = http.createServer((request, response) => { - if (request.url === '/' && request.method === 'GET') { - response.writeHead(307, { - Location: `/screen/?resize=scale&autoconnect=1&path=${novncWSPath}`, - }).end(); - } else if (request.url?.startsWith('/screen')) { - request.url = request.url.substring('/screen'.length); - vncProxy.web(request, response); - } else { - serverProxy.web(request, response); - } - }); - httpServer.on('error', error => debugLog(error)); - httpServer.on('upgrade', (request, socket, head) => { - if (request.url === '/' + novncWSPath) - vncProxy.ws(request, socket, head); - else - serverProxy.ws(request, socket, head); - }); - httpServer.listen(port, '0.0.0.0', () => { - const { port } = httpServer.address() as AddressInfo; - console.log(`Playwright Container running on http://localhost:${port}`); - }); -} - -function selfDestruct() { - // Force exit after 30 seconds. - setTimeout(() => process.exit(0), 30000); - // Meanwhile, try to gracefully close all browsers. - gracefullyCloseAll().then(() => { - process.exit(0); - }); -} - diff --git a/packages/playwright-core/src/remote/playwrightServer.ts b/packages/playwright-core/src/remote/playwrightServer.ts index 767d5adef7..c15fd37558 100644 --- a/packages/playwright-core/src/remote/playwrightServer.ts +++ b/packages/playwright-core/src/remote/playwrightServer.ts @@ -49,7 +49,6 @@ export class PlaywrightServer { private _preLaunchedPlaywright: Playwright | undefined; private _wsServer: WebSocketServer | undefined; private _options: ServerOptions; - private _address: string = ''; constructor(options: ServerOptions) { this._options = options; @@ -59,10 +58,6 @@ export class PlaywrightServer { this._preLaunchedPlaywright = options.preLaunchedAndroidDevice._android._playwrightOptions.rootSdkObject as Playwright; } - address(): string { - return this._address; - } - async listen(port: number = 0): Promise { const server = http.createServer((request: http.IncomingMessage, response: http.ServerResponse) => { if (request.method === 'GET' && request.url === '/json') { @@ -79,12 +74,11 @@ export class PlaywrightServer { const wsEndpoint = await new Promise((resolve, reject) => { server.listen(port, () => { const address = server.address(); - if (!address || typeof address === 'string') { + if (!address) { reject(new Error('Could not bind server socket')); return; } - this._address = `http://127.0.0.1:${address.port}`; - const wsEndpoint = `ws://127.0.0.1:${address.port}${this._options.path}`; + const wsEndpoint = typeof address === 'string' ? `${address}${this._options.path}` : `ws://127.0.0.1:${address.port}${this._options.path}`; resolve(wsEndpoint); }).on('error', reject); }); diff --git a/packages/playwright-core/src/third_party/http_proxy.js b/packages/playwright-core/src/third_party/http_proxy.js deleted file mode 100644 index 8a273effb1..0000000000 --- a/packages/playwright-core/src/third_party/http_proxy.js +++ /dev/null @@ -1,165 +0,0 @@ -/** - * node-http-proxy - * - * Copyright (c) 2010-2016 Charlie Robbins, Jarrett Cruger & the Contributors. - * Modifications copyright (c) Microsoft Corporation. - * - * Permission is hereby granted, free of charge, to any person obtaining - * a copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sublicense, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice shall be - * included in all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - */ -const URL = require('url'); -const http = require('http'); -const https = require('https'); - -const upgradeHeader = /(^|,)\s*upgrade\s*($|,)/i; - -// This is a stripped-down version of -// https://github.com/http-party/node-http-proxy -// library that implements a basic reverse proxy -// for both HTTP and WS connections. -class ProxyServer { - constructor(target, log = () => {}) { - this._target = URL.parse(target); - this._log = log; - if (this._target.path !== '/') - throw new Error('ERROR: target must have no path'); - this._agent = this._target.protocol === 'https:' ? https : http; - } - - web(req, res) { - if ((req.method === 'DELETE' || req.method === 'OPTIONS') && !req.headers['content-length']) { - req.headers['content-length'] = '0'; - delete req.headers['transfer-encoding']; - } - - // Request initalization - const options = { - protocol: this._target.protocol, - hostname: this._target.hostname, - port: this._target.port, - path: req.url, - method: req.method, - headers: req.headers, - }; - if (typeof options.headers.connection !== 'string' || !upgradeHeader.test(options.headers.connection)) - options.headers.connection = 'close'; - const proxyReq = this._agent.request(options); - - req.on('aborted', () => proxyReq.abort()); - - const errorHandler = error => { - this._log(error); - if (req.socket.destroyed && err.code === 'ECONNRESET') - return proxyReq.abort(); - } - req.on('error', errorHandler); - proxyReq.on('error', errorHandler); - - req.pipe(proxyReq); - - proxyReq.on('response', proxyRes => { - if (!res.headersSent) { - if (req.httpVersion !== '2.0' && !proxyRes.headers.connection) - proxyRes.headers.connection = req.headers.connection || 'keep-alive'; - for (const [key, value] of Object.entries(proxyRes.headers)) { - if (value !== undefined) - res.setHeader(String(key).trim(), value); - } - - res.statusCode = proxyRes.statusCode; - if (proxyRes.statusMessage) - res.statusMessage = proxyRes.statusMessage; - } - if (!res.finished) - proxyRes.pipe(res); - }); - } - - ws(req, socket, head) { - if (req.method !== 'GET' || !req.headers.upgrade || req.headers.upgrade.toLowerCase() !== 'websocket') { - socket.destroy(); - return; - } - - socket.setTimeout(0); - socket.setNoDelay(true); - socket.setKeepAlive(true, 0); - - if (head && head.length) - socket.unshift(head); - - const proxyReq = this._agent.request({ - protocol: this._target.protocol, - hostname: this._target.hostname, - port: this._target.port, - path: req.url, - method: req.method, - headers: req.headers, - }); - - // Error Handler - const errorHandler = err => { - this._log(err); - socket.end(); - } - socket.on('error', errorHandler); - proxyReq.on('error', errorHandler); - proxyReq.on('response', function (res) { - // if upgrade event isn't going to happen, close the socket - if (!res.upgrade) { - socket.write(createHTTPHeader('HTTP/' + res.httpVersion + ' ' + res.statusCode + ' ' + res.statusMessage, res.headers)); - res.pipe(socket); - } - }); - proxyReq.on('upgrade', function(proxyRes, proxySocket, proxyHead) { - proxySocket.on('error', errorHandler); - - // The pipe below will end proxySocket if socket closes cleanly, but not - // if it errors (eg, vanishes from the net and starts returning - // EHOSTUNREACH). We need to do that explicitly. - socket.on('error', () => proxySocket.end()); - - proxySocket.setTimeout(0); - proxySocket.setNoDelay(true); - proxySocket.setKeepAlive(true, 0); - - if (proxyHead && proxyHead.length) - proxySocket.unshift(proxyHead); - - // - // Remark: Handle writing the headers to the socket when switching protocols - // Also handles when a header is an array - // - socket.write(createHTTPHeader('HTTP/1.1 101 Switching Protocols', proxyRes.headers)); - proxySocket.pipe(socket).pipe(proxySocket); - }); - return proxyReq.end(); - } -} - -function createHTTPHeader(line, headers) { - const lines = [line]; - for (const [key, arrayOrValue] of Object.entries(headers)) { - for (const value of [arrayOrValue].flat()) - lines.push(key + ': ' + value); - } - return lines.join('\r\n') + '\r\n\r\n'; -} - -module.exports = { ProxyServer }; diff --git a/tests/android/browser.spec.ts b/tests/android/browser.spec.ts index 6ebb93b0e9..b04672d0e4 100644 --- a/tests/android/browser.spec.ts +++ b/tests/android/browser.spec.ts @@ -56,7 +56,6 @@ test('androidDevice.launchBrowser should throw for bad proxy server value', asyn }); test('androidDevice.launchBrowser should pass proxy config', async ({ androidDevice, server, mode, loopback }) => { - test.skip(mode === 'docker_remote', 'proxy is not supported for remote connection'); server.setRoute('/target.html', async (req, res) => { res.end('Served by the proxy'); }); diff --git a/tests/config/platformFixtures.ts b/tests/config/platformFixtures.ts index 8f9a9ebef5..4a044c8dcc 100644 --- a/tests/config/platformFixtures.ts +++ b/tests/config/platformFixtures.ts @@ -24,7 +24,7 @@ export type PlatformWorkerFixtures = { }; export const platformTest = test.extend<{}, PlatformWorkerFixtures>({ - platform: [process.env.PWTEST_MODE === 'docker_remote' ? 'linux' : process.platform as 'win32' | 'darwin' | 'linux', { scope: 'worker' }], + platform: [process.platform as 'win32' | 'darwin' | 'linux', { scope: 'worker' }], isWindows: [process.platform === 'win32', { scope: 'worker' }], isMac: [process.platform === 'darwin', { scope: 'worker' }], isLinux: [process.platform === 'linux', { scope: 'worker' }], diff --git a/tests/config/testMode.ts b/tests/config/testMode.ts index ae8f2dde71..49b49eb495 100644 --- a/tests/config/testMode.ts +++ b/tests/config/testMode.ts @@ -17,7 +17,7 @@ import { start } from '../../packages/playwright-core/lib/outofprocess'; import type { Playwright } from '../../packages/playwright-core/lib/client/playwright'; -export type TestModeName = 'default' | 'driver' | 'service' | 'docker_remote'; +export type TestModeName = 'default' | 'driver' | 'service'; interface TestMode { setup(): Promise; diff --git a/tests/config/testModeFixtures.ts b/tests/config/testModeFixtures.ts index 079522dada..ac72bd4ad3 100644 --- a/tests/config/testModeFixtures.ts +++ b/tests/config/testModeFixtures.ts @@ -37,7 +37,6 @@ export const testModeTest = test.extend { const testMode = { default: new DefaultTestMode(), - docker_remote: new DefaultTestMode(), service: new DefaultTestMode(), driver: new DriverTestMode(), }[mode]; diff --git a/tests/library/capabilities.spec.ts b/tests/library/capabilities.spec.ts index da164e5654..06113df24f 100644 --- a/tests/library/capabilities.spec.ts +++ b/tests/library/capabilities.spec.ts @@ -66,7 +66,6 @@ it('should respect CSP @smoke', async ({ page, server }) => { }); it('should play video @smoke', async ({ page, asset, browserName, platform, mode }) => { - it.skip(mode === 'docker_remote', 'local paths do not work with remote setup'); // TODO: the test passes on Windows locally but fails on GitHub Action bot, // apparently due to a Media Pack issue in the Windows Server. // Also the test is very flaky on Linux WebKit. @@ -85,7 +84,6 @@ it('should play video @smoke', async ({ page, asset, browserName, platform, mode }); it('should play webm video @smoke', async ({ page, asset, browserName, platform, mode }) => { - it.skip(mode === 'docker_remote', 'local paths do not work with remote setup'); it.fixme(browserName === 'webkit' && platform === 'darwin' && parseInt(os.release(), 10) === 20, 'Does not work on BigSur'); it.fixme(browserName === 'webkit' && platform === 'win32'); diff --git a/tests/library/download.spec.ts b/tests/library/download.spec.ts index 71efd9b735..8bfe003142 100644 --- a/tests/library/download.spec.ts +++ b/tests/library/download.spec.ts @@ -51,7 +51,6 @@ it.describe('download event', () => { }); it('should report download when navigation turns into download @smoke', async ({ browser, server, browserName, mode }) => { - it.skip(mode === 'docker_remote', 'local paths do not work remote connection'); const page = await browser.newPage(); const [download, responseOrError] = await Promise.all([ page.waitForEvent('download'), diff --git a/tests/library/playwright.config.ts b/tests/library/playwright.config.ts index d40ed8428d..af08a59ede 100644 --- a/tests/library/playwright.config.ts +++ b/tests/library/playwright.config.ts @@ -34,7 +34,7 @@ const getExecutablePath = (browserName: BrowserName) => { return process.env.WKPATH; }; -const mode: TestModeName = (process.env.PWTEST_MODE ?? 'default') as ('default' | 'driver' | 'service' | 'docker_remote'); +const mode: TestModeName = (process.env.PWTEST_MODE ?? 'default') as ('default' | 'driver' | 'service'); const headed = process.argv.includes('--headed'); const channel = process.env.PWTEST_CHANNEL as any; const video = !!process.env.PWTEST_VIDEO; @@ -100,10 +100,6 @@ for (const browserName of browserNames) { executablePath, devtools }, - connectOptions: mode === 'docker_remote' ? { - wsEndpoint: 'http://localhost:5400', - _exposeNetwork: '*', - } as any : undefined, trace: trace ? 'on' : undefined, coverageName: browserName, }, diff --git a/tests/library/proxy.spec.ts b/tests/library/proxy.spec.ts index e053e4b9d2..8338b2710c 100644 --- a/tests/library/proxy.spec.ts +++ b/tests/library/proxy.spec.ts @@ -29,7 +29,6 @@ it('should throw for bad server value', async ({ browserType }) => { }); it('should use proxy @smoke', async ({ browserType, server, mode }) => { - it.skip(mode === 'docker_remote', 'proxy is not supported for remote connection'); server.setRoute('/target.html', async (req, res) => { res.end('Served by the proxy'); }); diff --git a/utils/build/build.js b/utils/build/build.js index 1a159ef7de..e5adcbab24 100644 --- a/utils/build/build.js +++ b/utils/build/build.js @@ -318,13 +318,6 @@ copyFiles.push({ ignored: ['**/.eslintrc.js', '**/webpack*.config.js', '**/injected/**/*'] }); -// Copy all shell files if we happen to use any. -copyFiles.push({ - files: 'packages/playwright-core/src/**/*.sh', - from: 'packages/playwright-core/src', - to: 'packages/playwright-core/lib', -}); - // Sometimes we require JSON files that babel ignores. // For example, deviceDescriptorsSource.json copyFiles.push({ diff --git a/utils/docker/Dockerfile.remote b/utils/docker/Dockerfile.remote deleted file mode 100644 index 24d66910fd..0000000000 --- a/utils/docker/Dockerfile.remote +++ /dev/null @@ -1,51 +0,0 @@ -FROM ubuntu:focal - -ARG DEBIAN_FRONTEND=noninteractive -ARG TZ=America/Los_Angeles -ARG DOCKER_IMAGE_NAME_TEMPLATE="mcr.microsoft.com/playwright:v%version%-vrt" - -# === INSTALL Node.js === - -RUN apt-get update && \ - # Install Node 18 - apt-get install -y curl wget gpg && \ - curl -sL https://deb.nodesource.com/setup_18.x | bash - && \ - apt-get install -y nodejs && \ - # Feature-parity with node.js base images. - apt-get install -y --no-install-recommends git openssh-client && \ - npm install -g yarn && \ - # clean apt cache - rm -rf /var/lib/apt/lists/* && \ - # Create the pwuser - adduser pwuser - -# === BAKE BROWSERS INTO IMAGE === - -ENV PLAYWRIGHT_BROWSERS_PATH=/ms-playwright - -# 1. Add tip-of-tree Playwright package to install its browsers. -# The package should be built beforehand from tip-of-tree Playwright. -COPY ./playwright-core.tar.gz /tmp/playwright-core.tar.gz - -# 2. Bake in Playwright Agent. -# Playwright Agent is used to bake in browsers and browser dependencies, -# and run docker server later on. -# Browsers will be downloaded in `/ms-playwright`. -# Note: make sure to set 777 to the registry so that any user can access -# registry. -RUN mkdir /ms-playwright && \ - mkdir /ms-playwright-agent && \ - cd /ms-playwright-agent && npm init -y && \ - npm i /tmp/playwright-core.tar.gz && \ - npx playwright mark-docker-image "${DOCKER_IMAGE_NAME_TEMPLATE}" && \ - npx playwright install --with-deps && \ - npx playwright container install-services && \ - rm /tmp/playwright-core.tar.gz && \ - chmod -R 777 /ms-playwright && \ - rm -rf /var/lib/apt/lists/* - -WORKDIR /ms-playwright-agent -ENV DISPLAY_NUM=99 -ENV DISPLAY=:99 -EXPOSE 5400 -ENTRYPOINT npx playwright container entrypoint diff --git a/utils/docker/build.sh b/utils/docker/build.sh index 057171ba96..1d69a5d918 100755 --- a/utils/docker/build.sh +++ b/utils/docker/build.sh @@ -3,7 +3,7 @@ set -e set +x if [[ ($1 == '--help') || ($1 == '-h') || ($1 == '') || ($2 == '') ]]; then - echo "usage: $(basename $0) {--arm64,--amd64} {focal,jammy,remote} playwright:localbuild-focal" + echo "usage: $(basename $0) {--arm64,--amd64} {focal,jammy} playwright:localbuild-focal" echo echo "Build Playwright docker image and tag it as 'playwright:localbuild-focal'." echo "Once image is built, you can run it with" diff --git a/utils/docker/publish_docker.sh b/utils/docker/publish_docker.sh index 2c1976c939..3e78a338d5 100755 --- a/utils/docker/publish_docker.sh +++ b/utils/docker/publish_docker.sh @@ -53,11 +53,6 @@ if [[ "$RELEASE_CHANNEL" == "stable" ]]; then JAMMY_TAGS+=("jammy") fi -REMOTE_TAGS=( - "next-remote" - "v${PW_VERSION}-remote" -) - tag_and_push() { local source="$1" local target="$2" @@ -73,10 +68,8 @@ publish_docker_images_with_arch_suffix() { TAGS=("${FOCAL_TAGS[@]}") elif [[ "$FLAVOR" == "jammy" ]]; then TAGS=("${JAMMY_TAGS[@]}") - elif [[ "$FLAVOR" == "remote" ]]; then - TAGS=("${REMOTE_TAGS[@]}") else - echo "ERROR: unknown flavor - $FLAVOR. Must be either 'focal', 'jammy' or 'remote'" + echo "ERROR: unknown flavor - $FLAVOR. Must be either 'focal' or 'jammy'" exit 1 fi local ARCH="$2" @@ -101,10 +94,8 @@ publish_docker_manifest () { TAGS=("${FOCAL_TAGS[@]}") elif [[ "$FLAVOR" == "jammy" ]]; then TAGS=("${JAMMY_TAGS[@]}") - elif [[ "$FLAVOR" == "remote" ]]; then - TAGS=("${REMOTE_TAGS[@]}") else - echo "ERROR: unknown flavor - $FLAVOR. Must be either 'focal', 'jammy' or 'remote'" + echo "ERROR: unknown flavor - $FLAVOR. Must be either 'focal' or 'jammy'" exit 1 fi @@ -131,6 +122,3 @@ publish_docker_images_with_arch_suffix jammy amd64 publish_docker_images_with_arch_suffix jammy arm64 publish_docker_manifest jammy amd64 arm64 -publish_docker_images_with_arch_suffix remote amd64 -publish_docker_images_with_arch_suffix remote arm64 -publish_docker_manifest remote amd64 arm64