From d40afa2fbf5100798386bd704797fe714d2e3e1b Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Tue, 22 Dec 2020 14:54:13 -0800 Subject: [PATCH] feat(cli): first few cli commands (#4773) This sets up cli capabilities and brings in a few commands from playwright-cli. --- index.js | 8 +- package-lock.json | 3 +- package.json | 4 + packages/build_package.js | 3 + packages/common/index.js | 5 +- .../installation-tests/installation-tests.sh | 91 ++++- packages/installation-tests/sanity.js | 2 +- packages/playwright-android/index.js | 9 +- packages/playwright-electron/index.js | 9 +- src/cli/cli.ts | 355 ++++++++++++++++++ src/inprocess.ts | 9 +- utils/check_deps.js | 3 + 12 files changed, 470 insertions(+), 31 deletions(-) create mode 100755 src/cli/cli.ts diff --git a/index.js b/index.js index b60cba9d41..c1b4fa08a1 100644 --- a/index.js +++ b/index.js @@ -16,10 +16,4 @@ const { setUnderTest } = require('./lib/utils/utils'); setUnderTest(); // Note: we must call setUnderTest before initializing. - -const { Playwright } = require('./lib/server/playwright'); -const { setupInProcess } = require('./lib/inprocess'); -const path = require('path'); - -const playwright = new Playwright(__dirname, require(path.join(__dirname, 'browsers.json'))['browsers']); -module.exports = setupInProcess(playwright); +module.exports = require('./lib/inprocess'); diff --git a/package-lock.json b/package-lock.json index 58ce9fdc2d..d733fb470e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2389,8 +2389,7 @@ "commander": { "version": "6.2.0", "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.0.tgz", - "integrity": "sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==", - "dev": true + "integrity": "sha512-zP4jEKbe8SHzKJYQmq8Y9gYjtO/POJLgIdKgV7B9qNmABVFVc+ctqSX6iXh4mCpJfRBOabiZ2YKPg8ciDw6C+Q==" }, "commondir": { "version": "1.0.1", diff --git a/package.json b/package.json index 01a98765dd..de8fb85e79 100644 --- a/package.json +++ b/package.json @@ -38,7 +38,11 @@ "name": "Microsoft Corporation" }, "license": "Apache-2.0", + "bin": { + "playwright": "./lib/cli/cli.js" + }, "dependencies": { + "commander": "^6.1.0", "debug": "^4.1.1", "extract-zip": "^2.0.1", "https-proxy-agent": "^5.0.0", diff --git a/packages/build_package.js b/packages/build_package.js index 34446b5111..e511399376 100755 --- a/packages/build_package.js +++ b/packages/build_package.js @@ -139,6 +139,9 @@ if (!args.some(arg => arg === '--no-cleanup')) { engines: pwInternalJSON.engines, homepage: pwInternalJSON.homepage, main: 'index.js', + bin: { + playwright: './lib/cli/cli.js', + }, exports: { // Root import: we have a wrapper ES Module to support the following syntax. // const { chromium } = require('playwright'); diff --git a/packages/common/index.js b/packages/common/index.js index 8c14f60ade..4b9607bba4 100644 --- a/packages/common/index.js +++ b/packages/common/index.js @@ -14,7 +14,4 @@ * limitations under the License. */ -const { Playwright } = require('./lib/server/playwright'); -const { setupInProcess } = require('./lib/inprocess'); - -module.exports = setupInProcess(new Playwright(__dirname, require('./browsers.json')['browsers'])); +module.exports = require('./lib/inprocess'); diff --git a/packages/installation-tests/installation-tests.sh b/packages/installation-tests/installation-tests.sh index e123b8264d..adad67007f 100755 --- a/packages/installation-tests/installation-tests.sh +++ b/packages/installation-tests/installation-tests.sh @@ -52,6 +52,8 @@ function run_tests { test_playwright_global_installation_cross_package test_playwright_electron_should_work test_electron_types + test_playwright_cli_should_work + test_playwright_cli_install_should_work } function test_screencast { @@ -64,10 +66,13 @@ function test_screencast { PLAYWRIGHT_BROWSERS_PATH="${BROWSERS}" npm install ${PLAYWRIGHT_WEBKIT_TGZ} PLAYWRIGHT_BROWSERS_PATH="${BROWSERS}" npm install ${PLAYWRIGHT_CHROMIUM_TGZ} + echo "Running screencast.js" PLAYWRIGHT_BROWSERS_PATH="${BROWSERS}" node screencast.js playwright PLAYWRIGHT_BROWSERS_PATH="${BROWSERS}" node screencast.js playwright-chromium PLAYWRIGHT_BROWSERS_PATH="${BROWSERS}" node screencast.js playwright-webkit PLAYWRIGHT_BROWSERS_PATH="${BROWSERS}" node screencast.js playwright-firefox + + echo "${FUNCNAME[0]} success" } function test_typescript_types { @@ -90,6 +95,8 @@ function test_typescript_types { echo "Checking types of ${PKG_NAME}" echo "import { Page } from '${PKG_NAME}';" > "${PKG_NAME}.ts" && tsc "${PKG_NAME}.ts" done; + + echo "${FUNCNAME[0]} success" } function test_playwright_global_installation { @@ -102,8 +109,12 @@ function test_playwright_global_installation { exit 1 fi copy_test_scripts + + echo "Running sanity.js" node sanity.js playwright none PLAYWRIGHT_BROWSERS_PATH="${BROWSERS}" node sanity.js playwright + + echo "${FUNCNAME[0]} success" } function test_playwright_global_installation_cross_package { @@ -122,10 +133,13 @@ function test_playwright_global_installation_cross_package { copy_test_scripts + echo "Running sanity.js" # Every package should be able to launch. PLAYWRIGHT_BROWSERS_PATH="${BROWSERS}" node sanity.js playwright-chromium all PLAYWRIGHT_BROWSERS_PATH="${BROWSERS}" node sanity.js playwright-firefox all PLAYWRIGHT_BROWSERS_PATH="${BROWSERS}" node sanity.js playwright-webkit all + + echo "${FUNCNAME[0]} success" } # @see https://github.com/microsoft/playwright/issues/1651 @@ -142,6 +156,8 @@ function test_playwright_global_installation_subsequent_installs { # Note: the flag `--unahdnled-rejections=strict` will force node to terminate in case # of UnhandledPromiseRejection. PLAYWRIGHT_BROWSERS_PATH="${BROWSERS}" node --unhandled-rejections=strict node_modules/playwright/install.js + + echo "${FUNCNAME[0]} success" } function test_skip_browser_download { @@ -157,6 +173,8 @@ function test_skip_browser_download { echo "local browsers folder should be empty" exit 1 fi + + echo "${FUNCNAME[0]} success" } function test_playwright_should_work { @@ -176,10 +194,15 @@ function test_playwright_should_work { exit 1 fi copy_test_scripts + + echo "Running sanity.js" node sanity.js playwright if [[ "${NODE_VERSION}" == *"v14."* ]]; then + echo "Running esm.js" node esm-playwright.mjs fi + + echo "${FUNCNAME[0]} success" } function test_playwright_chromium_should_work { @@ -199,10 +222,15 @@ function test_playwright_chromium_should_work { exit 1 fi copy_test_scripts + + echo "Running sanity.js" node sanity.js playwright-chromium if [[ "${NODE_VERSION}" == *"v14."* ]]; then + echo "Running esm.js" node esm-playwright-chromium.mjs fi + + echo "${FUNCNAME[0]} success" } function test_playwright_webkit_should_work { @@ -222,10 +250,15 @@ function test_playwright_webkit_should_work { exit 1 fi copy_test_scripts + + echo "Running sanity.js" node sanity.js playwright-webkit if [[ "${NODE_VERSION}" == *"v14."* ]]; then + echo "Running esm.js" node esm-playwright-webkit.mjs fi + + echo "${FUNCNAME[0]} success" } function test_playwright_firefox_should_work { @@ -245,10 +278,15 @@ function test_playwright_firefox_should_work { exit 1 fi copy_test_scripts + + echo "Running sanity.js" node sanity.js playwright-firefox if [[ "${NODE_VERSION}" == *"v14."* ]]; then + echo "Running esm.js" node esm-playwright-firefox.mjs fi + + echo "${FUNCNAME[0]} success" } function test_playwright_electron_should_work { @@ -257,7 +295,11 @@ function test_playwright_electron_should_work { npm install ${PLAYWRIGHT_ELECTRON_TGZ} npm install electron@9.0 copy_test_scripts + + echo "Running sanity-electron.js" xvfb-run --auto-servernum -- bash -c "node sanity-electron.js" + + echo "${FUNCNAME[0]} success" } function test_electron_types { @@ -267,13 +309,59 @@ function test_electron_types { npm install -D typescript@3.8 npm install -D @types/node@10.17 echo "import { Page, electron, ElectronApplication, ElectronLauncher } from 'playwright-electron';" > "test.ts" + + echo "Running tsc" npx tsc "test.ts" + + echo "${FUNCNAME[0]} success" +} + +function test_playwright_cli_should_work { + initialize_test "${FUNCNAME[0]}" + + npm install ${PLAYWRIGHT_TGZ} + + echo "Running playwright screenshot" + + node_modules/.bin/playwright screenshot about:blank one.png + if [[ ! -f one.png ]]; then + echo 'node_modules/.bin/playwright does not work' + exit 1 + fi + + npx playwright screenshot about:blank two.png + if [[ ! -f two.png ]]; then + echo 'npx playwright does not work' + exit 1 + fi + + echo "${FUNCNAME[0]} success" +} + +function test_playwright_cli_install_should_work { + initialize_test "${FUNCNAME[0]}" + + PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm install ${PLAYWRIGHT_TGZ} + + local BROWSERS="$(pwd -P)/browsers" + echo "Running playwright install" + PLAYWRIGHT_BROWSERS_PATH="${BROWSERS}" npx playwright install + if [[ ! -d "${BROWSERS}" ]]; then + echo "Directory for shared browsers was not created!" + exit 1 + fi + copy_test_scripts + + echo "Running sanity.js" + node sanity.js playwright none + PLAYWRIGHT_BROWSERS_PATH="${BROWSERS}" node sanity.js playwright + + echo "${FUNCNAME[0]} success" } function initialize_test { cd ${TEST_ROOT} local TEST_NAME="./$1" - mkdir ${TEST_NAME} && cd ${TEST_NAME} && npm init -y echo "=====================================================================================" echo "=====================================================================================" echo @@ -281,6 +369,7 @@ function initialize_test { echo echo "=====================================================================================" echo "=====================================================================================" + mkdir ${TEST_NAME} && cd ${TEST_NAME} && npm init -y } # Run all tests diff --git a/packages/installation-tests/sanity.js b/packages/installation-tests/sanity.js index 49337a3b46..8a548edd5e 100644 --- a/packages/installation-tests/sanity.js +++ b/packages/installation-tests/sanity.js @@ -42,7 +42,7 @@ const installer = require(requireName + '/lib/install/installer'); await browser.close(); } catch (e) { console.error(`Should be able to launch ${browserType} from ${requireName}`); - console.error(err); + console.error(e); process.exit(1); } } diff --git a/packages/playwright-android/index.js b/packages/playwright-android/index.js index 1a06625778..b1901919de 100644 --- a/packages/playwright-android/index.js +++ b/packages/playwright-android/index.js @@ -14,10 +14,5 @@ * limitations under the License. */ -const { Playwright } = require('./lib/server/playwright'); -const { setupInProcess } = require('./lib/inprocess'); - -const playwrightServer = new Playwright(__dirname, require('./browsers.json')['browsers']); -const playwright = setupInProcess(playwrightServer); -playwright.android = playwright._android; -module.exports = playwright; +module.exports = require('./lib/inprocess'); +module.exports.android = module.exports._android; diff --git a/packages/playwright-electron/index.js b/packages/playwright-electron/index.js index f998e5aa2d..fa1134b48d 100644 --- a/packages/playwright-electron/index.js +++ b/packages/playwright-electron/index.js @@ -14,10 +14,5 @@ * limitations under the License. */ -const { Playwright } = require('./lib/server/playwright'); -const { setupInProcess } = require('./lib/inprocess'); - -const playwrightServer = new Playwright(__dirname, require('./browsers.json')['browsers']); -const playwright = setupInProcess(playwrightServer); -playwright.electron = playwright._electron; -module.exports = playwright; +module.exports = require('./lib/inprocess'); +module.exports.electron = module.exports._electron; diff --git a/src/cli/cli.ts b/src/cli/cli.ts new file mode 100755 index 0000000000..633bcf55ca --- /dev/null +++ b/src/cli/cli.ts @@ -0,0 +1,355 @@ +#!/usr/bin/env node + +/** + * 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 * as path from 'path'; +import * as program from 'commander'; +import * as os from 'os'; +import * as fs from 'fs'; +import { installBrowsersWithProgressBar } from '../install/installer'; + +// TODO: we can import from '../..' instead, but that requires generating types +// before build, and currently type generator depends on the build. +import type { Browser, BrowserContext, Page, BrowserType } from '../client/api'; +import type { Playwright } from '../client/playwright'; +import type { BrowserContextOptions, LaunchOptions } from '../client/types'; +const playwright = require('../inprocess') as Playwright; + +program + .version('Version ' + require('../../package.json').version) + .option('-b, --browser ', 'browser to use, one of cr, chromium, ff, firefox, wk, webkit', 'chromium') + .option('--color-scheme ', 'emulate preferred color scheme, "light" or "dark"') + .option('--device ', 'emulate device, for example "iPhone 11"') + .option('--geolocation ', 'specify geolocation coordinates, for example "37.819722,-122.478611"') + .option('--lang ', 'specify language / locale, for example "en-GB"') + .option('--load-storage ', 'load context storage state from the file, previously saved with --save-storage') + .option('--proxy-server ', 'specify proxy server, for example "http://myproxy:3128" or "socks5://myproxy:8080"') + .option('--save-storage ', 'save context storage state at the end, for later use with --load-storage') + .option('--timezone