chore: port installation tests to @playwright/test (#13644)

This commit is contained in:
Ross Wollman 2022-04-25 09:30:14 -07:00 коммит произвёл GitHub
Родитель 2e6ef8f622
Коммит e69e836c40
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
88 изменённых файлов: 1225 добавлений и 1092 удалений

2
.github/workflows/tests_secondary.yml поставляемый
Просмотреть файл

@ -134,7 +134,7 @@ jobs:
- run: npm run build
- run: npx playwright install-deps
- name: INSTALLATION TESTS
run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- bash installation-tests/run_all_tests.sh
run: xvfb-run --auto-servernum --server-args="-screen 0 1280x960x24" -- npm run itest
headful_linux:
name: "Headful Linux"

2
.gitignore поставляемый
Просмотреть файл

@ -25,3 +25,5 @@ playwright-report
/packages/playwright/README.md
/packages/playwright-core/api.json
.env
/tests/installation/output/
/tests/installation/.registry.json

1
installation-tests/.gitignore поставляемый
Просмотреть файл

@ -1 +0,0 @@
output

Просмотреть файл

@ -1,24 +0,0 @@
# Installation Tests
These tests check end-to-end installation and operation of Playwright.
Each test is set with a separate folder that contains all scripts from
`fixture-scripts` folder and dummy package.json.
To create a new test, create a new file that starts with `test_*.sh`
with the following header:
```bash
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@" # initialize test
```
To run all tests:
```bash
./run_all_tests.sh
```
To install local builds of `playwright` packages in tests, do `npm_i playwright`.
Each test run will get its own npm state. You can use `local-playwright-registry <package>` to
ensure it was installed as part of the test run, and that it was a local copy.

Просмотреть файл

@ -1,274 +0,0 @@
#!/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.
*/
// ============================================
// See `./local-playwright-registry help` for
// usage and help.
// ============================================
const crypto = require('crypto');
const { spawn } = require('child_process');
const fs = require('fs');
const path = require('path');
const http = require('http');
const https = require('https');
// WORK_DIR should be a local directory the Registry can work in through its lifetime. It will not be removed automatically.
const WORK_DIR = path.join(process.cwd(), '.playwright-registry');
// ACCESS_LOGS records which packages have been served locally vs. proxied to the official npm registry.
const ACCESS_LOGS = path.join(WORK_DIR, 'access.log');
// REGISTRY_URL_FILE is the URL to us to connect to the registy. It is allocated dynamically and shows up on disk only once the packages are actually available for download.
const REGISTRY_URL_FILE = path.join(WORK_DIR, 'registry.url.txt');
const kPublicNpmRegistry = 'https://registry.npmjs.org';
const kContentTypeAbbreviatedMetadata = 'application/vnd.npm.install-v1+json';
class Registry {
constructor() {
this._objectsDir = path.join(WORK_DIR, 'objects');
this._packageMeta = new Map();
this._address = '';
this._log = () => { };
}
async init() {
await fs.promises.mkdir(this._objectsDir, { recursive: true });
await fs.promises.writeFile(ACCESS_LOGS, '');
this._log = msg => fs.appendFileSync(ACCESS_LOGS, `${msg}\n`);
await Promise.all([
this._addPackage('playwright', getEnvOrDie('PLAYWRIGHT_TGZ')),
this._addPackage('playwright-core', getEnvOrDie('PLAYWRIGHT_CORE_TGZ')),
this._addPackage('playwright-chromium', getEnvOrDie('PLAYWRIGHT_CHROMIUM_TGZ')),
this._addPackage('playwright-firefox',getEnvOrDie('PLAYWRIGHT_FIREFOX_TGZ')),
this._addPackage('playwright-webkit',getEnvOrDie('PLAYWRIGHT_WEBKIT_TGZ')),
this._addPackage('@playwright/test',getEnvOrDie('PLAYWRIGHT_TEST_TGZ')),
]);
// Minimal Server that implements essential endpoints from the NPM Registry API.
// See https://github.com/npm/registry/blob/master/docs/REGISTRY-API.md.
this._server = http.createServer(async (req, res) => {
this._log(`REQUEST: ${req.method} ${req.url}`);
// 1. Only support GET requests
if (req.method !== 'GET') {
res.writeHead(405).end();
return;
}
// 2. Determine what package is being asked for.
// The paths we can handle look like:
// - /<userSuppliedPackageName>/*/<userSuppliedTarName i.e. some *.tgz>
// - /<userSuppliedPackageName>/*
// - /<userSuppliedPackageName>
const url = new URL(req.url, kPublicNpmRegistry);
let [, userSuppliedPackageName, , userSuppliedTarName] = url.pathname.split('/');
if (userSuppliedPackageName)
userSuppliedPackageName = decodeURIComponent(userSuppliedPackageName);
if (userSuppliedTarName)
userSuppliedTarName = decodeURIComponent(userSuppliedTarName);
// 3. If we have local metadata, serve directly (otherwise, proxy to upstream).
if (this._packageMeta.has(userSuppliedPackageName)) {
const [metadata, objectPath] = this._packageMeta.get(userSuppliedPackageName);
if (userSuppliedTarName) { // Tar ball request.
if (path.basename(objectPath) !== userSuppliedTarName) {
res.writeHead(404).end();
return;
}
this._log(`LOCAL ${userSuppliedPackageName} tar`);
const fileStream = fs.createReadStream(objectPath);
fileStream.pipe(res, { end: true });
fileStream.on('error', console.error);
res.on('error', console.error);
return;
} else { // Metadata request.
this._log(`LOCAL ${userSuppliedPackageName} metadata`);
res.setHeader('content-type', kContentTypeAbbreviatedMetadata);
res.write(JSON.stringify(metadata));
res.end();
return;
}
} else { // Fall through to official registry.
this._log(`PROXIED ${userSuppliedPackageName}`);
const client = { req, res };
const toNpm = https.request({
host: url.host,
headers: { ...req.headers, 'host': url.host },
method: req.method,
path: url.pathname,
searchParams: url.searchParams,
protocol: 'https:',
}, fromNpm => {
client.res.writeHead(fromNpm.statusCode, fromNpm.statusMessage, fromNpm.headers);
fromNpm.on('error', console.error);
fromNpm.pipe(client.res, { end: true });
});
client.req.pipe(toNpm);
client.req.on('error', console.error);
return;
}
});
this._server.listen(undefined, 'localhost', () => {
this._address = new URL(`http://localhost:${this._server.address().port}`).toString();
// We now have an address to make tarball paths fully qualified.
for (const [,[metadata]] of this._packageMeta.entries()) {
for (const [,version] of Object.entries(metadata.versions))
version.dist.tarball = this._address + version.dist.tarball;
}
fs.writeFileSync(REGISTRY_URL_FILE, this._address.toString());
});
process.on('exit', () => {
console.log('closing server');
this._server.close(console.error);
});
}
async _addPackage(pkg, tarPath) {
const tmpDir = await fs.promises.mkdtemp(path.join(WORK_DIR, '.staging-package-'));
const { stderr, code } = await spawnAsync('tar', ['-xvzf', tarPath, '-C', tmpDir]);
if (!!code)
throw new Error(`Failed to untar ${pkg}: ${stderr}`);
const packageJson = JSON.parse((await fs.promises.readFile(path.join(tmpDir, 'package', 'package.json'), 'utf8')));
if (pkg !== packageJson.name)
throw new Error(`Package name mismatch: ${pkg} is called ${packageJson.name} in its package.json`);
const shasum = crypto.createHash('sha1').update(await fs.promises.readFile(tarPath)).digest().toString('hex');
const metadata = {
'dist-tags': {
latest: packageJson.version,
[packageJson.version]: packageJson.version,
},
'modified': new Date().toISOString(),
'name': pkg,
'versions': {
[packageJson.version]: {
_hasShrinkwrap: false,
name: pkg,
version: packageJson.version,
dependencies: packageJson.dependencies || {},
optionalDependencies: packageJson.optionalDependencies || {},
devDependencies: packageJson.devDependencies || {},
bundleDependencies: packageJson.bundleDependencies || {},
peerDependencies: packageJson.peerDependencies || {},
bin: packageJson.bin || {},
directories: packageJson.directories || [],
dist: {
// This needs to be updated later with a full address.
tarball: `${encodeURIComponent(pkg)}/-/${shasum}.tgz`,
shasum,
},
engines: packageJson.engines || {},
},
},
};
const object = path.join(this._objectsDir, `${shasum}.tgz`);
await fs.promises.copyFile(tarPath, object);
this._packageMeta.set(pkg, [metadata, object]);
}
static async registryFactory() {
const registry = new Registry();
await registry.init();
return registry;
}
static async waitForReady() {
const OVERALL_TIMEOUT_MS = 60000;
const registryUrl = await new Promise(async (res, rej) => {
setTimeout(rej.bind(null, new Error('Timeout: Registry failed to become ready.')), OVERALL_TIMEOUT_MS);
while (true) {
const registryUrl = await fs.promises.readFile(REGISTRY_URL_FILE, 'utf8').catch(() => null);
if (registryUrl)
return res(registryUrl);
await new Promise(r => setTimeout(r, 500));
}
});
console.log(registryUrl);
process.exit(0);
}
static async assertLocalPkg(pkg) {
const logs = await fs.promises.readFile(ACCESS_LOGS, 'utf8');
const lines = logs.split(`\n`);
if (lines.includes(`LOCAL ${pkg} metadata`) && lines.includes(`LOCAL ${pkg} tar`) && !lines.includes(`PROXIED ${pkg} metadata`))
return;
console.log('Expected LOCAL metadata and tar, and no PROXIED logs for:', pkg);
console.log('Logs:');
console.log(lines.join(`\n`));
process.exit(1);
}
}
const getEnvOrDie = varName => {
const v = process.env[varName];
if (!v)
throw new Error(`${varName} environment variable MUST be set.`);
return v;
};
const spawnAsync = (cmd, args, options) => {
const process = spawn(cmd, args, Object.assign({ windowsHide: true }, options));
return new Promise(resolve => {
let stdout = '';
let stderr = '';
if (process.stdout)
process.stdout.on('data', data => stdout += data);
if (process.stderr)
process.stderr.on('data', data => stderr += data);
process.on('close', code => resolve({ stdout, stderr, code }));
process.on('error', error => resolve({ stdout, stderr, code: 0, error }));
});
};
const commands = {
'help': async () => {
console.log(`
A minimal, inefficent npm registry to serve local npm packages, or fall through
to the offical npm registry. This is useful for testing npm and npx utilities,
but should NOT, be used for anything more.
Commands:
- help.......................: prints this help message
- start......................: starts the registry server
- wait-for-ready.............: blocks waiting for the server to print
that it's actually ready and serving the
packages you published!
- assert-downloaded <package>: confirms that <package> was served locally,
AND never proxied to the official registry.`);
},
'start': Registry.registryFactory,
'wait-for-ready': Registry.waitForReady,
'assert-served-from-local-tgz': ([pkg]) => Registry.assertLocalPkg(pkg),
};
(async () => {
const command = commands[process.argv[2]];
if (!command) {
console.log(`${process.argv[2]} not a valid command:`);
await commands['help']();
process.exit(1);
}
await command(process.argv.slice(3));
})();

Просмотреть файл

@ -1,57 +0,0 @@
#!/bin/bash
args=""
pkgs=""
for i in "$@"; do
if [[ "$i" == "playwright" ]]; then
args="${args} ${PLAYWRIGHT_TGZ}"
pkgs="${pkgs} playwright"
elif [[ $i == "playwright-core" ]]; then
args="${args} ${PLAYWRIGHT_CORE_TGZ}"
pkgs="${pkgs} playwright-core"
elif [[ $i == "playwright-firefox" ]]; then
args="${args} ${PLAYWRIGHT_FIREFOX_TGZ}"
pkgs="${pkgs} playwright-firefox"
elif [[ $i == "playwright-chromium" ]]; then
args="${args} ${PLAYWRIGHT_CHROMIUM_TGZ}"
pkgs="${pkgs} playwright-chromium"
elif [[ $i == "playwright-webkit" ]]; then
args="${args} ${PLAYWRIGHT_WEBKIT_TGZ}"
pkgs="${pkgs} playwright-webkit"
elif [[ $i == "@playwright/test" ]]; then
args="${args} ${PLAYWRIGHT_TEST_TGZ}"
pkgs="${pkgs} @playwright/test"
elif [[ $i == "-"* ]]; then
args="${args} $i"
else
echo "ERROR: cannot install package $i using npm_i. Use regular npm instead"
fi
done
npm install $args 2>&1
SCRIPT=$(cat <<EOF
const path = require('path');
const fs = require('fs');
const packages = process.argv.slice(1);
console.log('Verifying local installation of:', packages.join(', '));
for (const package of packages) {
const expectedDir = process.env.EXPECTED_NODE_MODULES_PARENT;
const packageJsonPath = path.join(path.dirname(require.resolve(package)), 'package.json');
if (!packageJsonPath.startsWith(expectedDir)) {
console.error('Local resolution of package failed. Package:', package, 'Expected:', expectedDir, 'Got:', path.dirname(packageJsonPath));
process.exit(1);
}
const expectedVersion = JSON.parse(fs.readFileSync(packageJsonPath, 'utf8')).version;
if (expectedVersion !== process.env.PLAYWRIGHT_VERSION_UNDER_TEST) {
console.error('Version of local package did not match expectation. Package:', package, 'Expected:', expectedVersion, 'Got:', process.env.PLAYWRIGHT_VERSION_UNDER_TEST);
process.exit(1);
}
}
console.log('Confirmed local installation of:', packages.join(', '));
EOF
)
node -e "${SCRIPT}" $pkgs

Просмотреть файл

@ -1,3 +0,0 @@
#!/bin/bash
npx --yes playwright $@ 2>&1

Просмотреть файл

@ -1,130 +0,0 @@
#!/bin/bash
# break script execution if some command returns non-zero exit code
set -e
TEST_FRAMEWORK_RUN_ROOT="/tmp/playwright-installation-tests"
function build_packages() {
local PACKAGE_BUILDER="../../utils/pack_package.js"
rm -rf ./output
mkdir ./output
pushd ./output >/dev/null
node ${PACKAGE_BUILDER} playwright-core "${PLAYWRIGHT_CORE_TGZ}" 2>&1 1>/dev/null
node ${PACKAGE_BUILDER} playwright-test "${PLAYWRIGHT_TEST_TGZ}" 2>&1 1>/dev/null
node ${PACKAGE_BUILDER} playwright "${PLAYWRIGHT_TGZ}" 2>&1 1>/dev/null
node ${PACKAGE_BUILDER} playwright-chromium "${PLAYWRIGHT_CHROMIUM_TGZ}" 2>&1 1>/dev/null
node ${PACKAGE_BUILDER} playwright-webkit "${PLAYWRIGHT_WEBKIT_TGZ}" 2>&1 1>/dev/null
node ${PACKAGE_BUILDER} playwright-firefox "${PLAYWRIGHT_FIREFOX_TGZ}" 2>&1 1>/dev/null
popd >/dev/null
}
function cecho(){
local RED="\033[0;31m"
local GREEN="\033[0;32m"
local YELLOW="\033[1;33m"
local NC="\033[0m" # No Color
printf "${!1}${2} ${NC}\n"
}
function report_test_result {
RV=$?
set +x
if [[ $RV == 0 ]]; then
echo
cecho "GREEN" "<<<<<<<<<<<<"
cecho "GREEN" " Test '${TEST_FILE}' PASSED"
cecho "GREEN" "<<<<<<<<<<<<"
else
cecho "RED" "<<<<<<<<<<<<"
cecho "RED" " Test '${TEST_FILE}' FAILED"
cecho "RED" " To debug locally, run:"
cecho "RED" " bash ${TEST_FILE}"
cecho "RED" "<<<<<<<<<<<<"
echo
fi
echo
}
function setup_env_variables() {
# Package paths.
NODE_VERSION=$(node -e "console.log(process.version.slice(1).split('.')[0])")
export PLAYWRIGHT_CORE_TGZ="${PWD}/output/playwright-core.tgz"
export PLAYWRIGHT_TGZ="${PWD}/output/playwright.tgz"
export PLAYWRIGHT_CHROMIUM_TGZ="${PWD}/output/playwright-chromium.tgz"
export PLAYWRIGHT_WEBKIT_TGZ="${PWD}/output/playwright-webkit.tgz"
export PLAYWRIGHT_FIREFOX_TGZ="${PWD}/output/playwright-firefox.tgz"
export PLAYWRIGHT_TEST_TGZ="${PWD}/output/playwright-test.tgz"
PLAYWRIGHT_CHECKOUT="${PWD}/.."
export PLAYWRIGHT_VERSION_UNDER_TEST="$(node ${PLAYWRIGHT_CHECKOUT}/utils/workspace.js --get-version)"
}
function clean_test_root() {
rm -rf "${TEST_FRAMEWORK_RUN_ROOT}"
mkdir -p "${TEST_FRAMEWORK_RUN_ROOT}"
}
function initialize_test {
trap "report_test_result; kill %1; cd $(pwd -P);" EXIT
cd "$(dirname $0)"
# cleanup environment
unset PLAYWRIGHT_DOWNLOAD_HOST
unset PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD
export PLAYWRIGHT_BROWSERS_PATH=0
local SCRIPTS_PATH="$(pwd -P)"
setup_env_variables
TEST_FILE=$(basename $0)
TEST_NAME=$(basename ${0%%.sh})
# Check if test tries to install using npm directly
if grep 'npm i.*playwright' "$0" 2>&1 >/dev/null; then
# If it does, this is an error: you will miss output
cecho "RED" "ERROR: test tries to install playwright-family package from NPM registry!"
cecho "RED" " Do not use NPM to install playwright packages!"
cecho "RED" " Instead, use 'npm_i' command to install local package"
exit 1
fi
if [[ "$1" != "--no-build" && "$2" != "--no-build" ]]; then
echo 'Building packages... NOTE: run with `--no-build` to reuse previous builds'
build_packages
else
if [[ ! -f "${PLAYWRIGHT_TGZ}" || \
! -f "${PLAYWRIGHT_CORE_TGZ}" || \
! -f "${PLAYWRIGHT_CHROMIUM_TGZ}" || \
! -f "${PLAYWRIGHT_WEBKIT_TGZ}" || \
! -f "${PLAYWRIGHT_FIREFOX_TGZ}" || \
! -f "${PLAYWRIGHT_TEST_TGZ}" ]]; then
echo 'ERROR: cannot run test with `--no-build` flag! One of the packages is missing!'
exit 1
fi
fi
if [[ "$1" != "--do-not-clean-test-root" && "$2" != "--do-not-clean-test-root" ]]; then
clean_test_root
fi
cd ${TEST_FRAMEWORK_RUN_ROOT}
cecho "YELLOW" ">>>>>>>>>>>>"
cecho "YELLOW" " Running test - '${TEST_FILE}'"
cecho "YELLOW" " Workdir - ${PWD}/${TEST_NAME}"
cecho "YELLOW" ">>>>>>>>>>>>"
mkdir ${TEST_NAME} && cd ${TEST_NAME} && npm init -y 1>/dev/null 2>/dev/null
cp "${SCRIPTS_PATH}/fixture-scripts/"* .
export PATH="${SCRIPTS_PATH}/bin:${PATH}"
# Start up our local registry and configure npm to use it
local-playwright-registry start &
TEST_TMP_NPM_SCRATCH_SPACE="${TEST_FRAMEWORK_RUN_ROOT}/${TEST_NAME}--npm-scratch-space"
export npm_config_prefix="$TEST_TMP_NPM_SCRATCH_SPACE/npm_prefix"
export npm_config_cache="$TEST_TMP_NPM_SCRATCH_SPACE/npm_cache"
export npm_config_registry="$(local-playwright-registry wait-for-ready)"
export EXPECTED_NODE_MODULES_PARENT="$(pwd -P)"
# Enable bash lines logging.
set -x
}

Просмотреть файл

@ -1,60 +0,0 @@
#!/bin/bash
set -e
set +x
function report_results() {
echo
if [[ -n "${FAILED_TESTS}" ]]; then
cecho "RED" "SOME TESTS FAILED! To debug:"
cecho "RED" "${FAILED_TESTS}"
exit 1
else
cecho "GREEN" "All tests passed!"
exit 0
fi
}
trap "report_results; cd $(pwd -P)" EXIT
cd "$(dirname $0)"
source ./initialize_test.sh
setup_env_variables
echo "Building packages..."
build_packages
clean_test_root
function gh_echo {
if [[ -z "${GITHUB_ACTIONS}" ]]; then
return
fi
echo "$@"
}
FAILED_TESTS=""
TOTAL=$(ls -1 test_*.sh | wc -l | tr -d ' ')
COUNTER=1
for i in test_*.sh
do
set +e
cecho "YELLOW" "Running ${COUNTER}/${TOTAL} - $i..."
COUNTER=$(( COUNTER + 1 ))
OUTPUT=$(bash $i --multitest --no-build 2>&1)
RV=$?
set -e
if [[ "${RV}" != 0 ]]; then
FAILED_TESTS="${FAILED_TESTS}- ${i}\n"
gh_echo "::group::FAILED - $i"
cecho "RED" "FAILED - $i"
echo "${OUTPUT}"
gh_echo "::endgroup::"
else
gh_echo "::group::PASSED - $i"
cecho "GREEN" "PASSED - $i"
gh_echo "${OUTPUT}"
gh_echo "::endgroup::"
fi
done

Просмотреть файл

@ -1,11 +0,0 @@
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@"
npm_i playwright-core
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm_i playwright
npm i -D typescript@3.8
npm i -D @types/node@14
echo "import { AndroidDevice, _android, AndroidWebView, Page } from 'playwright';" > "test.ts"
echo "Running tsc"
npx --yes -p typescript@3.7.5 tsc "test.ts"

Просмотреть файл

@ -1,8 +0,0 @@
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@"
npm_i playwright-core
node "./download-chromedriver.js" "${PWD}"
export PWTEST_CHROMEDRIVER="${PWD}/chromedriver"
cd "${PLAYWRIGHT_CHECKOUT}"
npm run test -- --reporter=list selenium.spec

Просмотреть файл

@ -1,12 +0,0 @@
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@"
npm_i playwright-core
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm_i playwright
npm i electron@12
npm i -D typescript@3.8
npm i -D @types/node@14
echo "import { Page, _electron, ElectronApplication, Electron } from 'playwright';" > "test.ts"
echo "Running tsc"
npx --yes -p typescript@3.7.5 tsc "test.ts"

Просмотреть файл

@ -1,20 +0,0 @@
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@"
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm_i playwright{,-core,-webkit,-firefox,-chromium}
# test subshell installation
OUTPUT=$(npm_i --foreground-script @playwright/test)
SCRIPT=$(cat <<EOF
const packageJSON = require('./package.json');
for (const [entry, value] of Object.entries(packageJSON.dependencies)) {
if (!value.startsWith('file:')) {
console.log('ERROR: entry ' + entry + ' installed from NPM registry!');
process.exit(1);
}
}
EOF
)
# make sure all dependencies are locally installed.
node -e "${SCRIPT}"

Просмотреть файл

@ -1,22 +0,0 @@
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@"
echo "Running codegen command without installing"
OUTPUT="$(npx_playwright codegen || true)"
local-playwright-registry assert-served-from-local-tgz playwright
if [[ "${OUTPUT}" != *'Please run the following command to download new browsers'* ]]; then
echo "ERROR: should instruct user to download browsers"
exit 1
fi
if [[ "${OUTPUT}" == *"chromium"*"downloaded"* ]]; then
echo "ERROR: should not download chromium"
exit 1
fi
if [[ "${OUTPUT}" == *"webkit"*"downloaded"* ]]; then
echo "ERROR: should not download webkit"
exit 1
fi
if [[ "${OUTPUT}" == *"firefox"*"downloaded"* ]]; then
echo "ERROR: should not download firefox"
exit 1
fi

Просмотреть файл

@ -1,22 +0,0 @@
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@"
echo "Running global help command without first installing project"
OUTPUT="$(npx_playwright --help)"
local-playwright-registry assert-served-from-local-tgz playwright
if [[ "${OUTPUT}" == *'To avoid unexpected behavior, please install your dependencies first'* ]]; then
echo "ERROR: should not warn user about global installation"
exit 1
fi
if [[ "${OUTPUT}" == *"chromium"*"downloaded"* ]]; then
echo "ERROR: should not download chromium"
exit 1
fi
if [[ "${OUTPUT}" == *"webkit"*"downloaded"* ]]; then
echo "ERROR: should not download webkit"
exit 1
fi
if [[ "${OUTPUT}" == *"firefox"*"downloaded"* ]]; then
echo "ERROR: should not download firefox"
exit 1
fi

Просмотреть файл

@ -1,26 +0,0 @@
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@"
echo "Running install explcitly"
OUTPUT="$(npx_playwright install || true)"
local-playwright-registry assert-served-from-local-tgz playwright
if [[ "${OUTPUT}" == *'Please run the following command to download new browsers'* ]]; then
echo "ERROR: should not tell the user to run install"
exit 1
fi
if [[ "${OUTPUT}" != *'To avoid unexpected behavior, please install your dependencies first'* ]]; then
echo "ERROR: should warn user about global installation"
exit 1
fi
if [[ "${OUTPUT}" != *"chromium"*"downloaded"* ]]; then
echo "ERROR: should download chromium"
exit 1
fi
if [[ "${OUTPUT}" != *"firefox"*"downloaded"* ]]; then
echo "ERROR: should download firefox"
exit 1
fi
if [[ "${OUTPUT}" != *"webkit"*"downloaded"* ]]; then
echo "ERROR: should download webkit"
exit 1
fi

Просмотреть файл

@ -1,28 +0,0 @@
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@"
npm_i playwright-core
OUTPUT=$(npm_i --foreground-script playwright-chromium)
if [[ "${OUTPUT}" == *'To avoid unexpected behavior, please install your dependencies first'* ]]; then
echo "ERROR: should not warn user about global installation"
exit 1
fi
if [[ "${OUTPUT}" != *"chromium"* ]]; then
echo "ERROR: should download chromium"
exit 1
fi
if [[ "${OUTPUT}" == *"firefox"* ]]; then
echo "ERROR: should not download firefox"
exit 1
fi
if [[ "${OUTPUT}" == *"webkit"* ]]; then
echo "ERROR: should not download webkit"
exit 1
fi
echo "Running sanity.js"
node sanity.js playwright-chromium
if [[ ${NODE_VERSION} -ge 14 ]]; then
echo "Running esm.js"
node esm-playwright-chromium.mjs
fi

Просмотреть файл

@ -1,38 +0,0 @@
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@"
npm_i playwright-core
npm_i playwright
echo "Running playwright codegen"
OUTPUT=$(PWTEST_CLI_EXIT=1 npx playwright codegen)
if [[ "${OUTPUT}" != *"@playwright/test"* ]]; then
echo "ERROR: missing @playwright/test in the output"
exit 1
fi
if [[ "${OUTPUT}" != *"{ page }"* ]]; then
echo "ERROR: missing { page } in the output"
exit 1
fi
echo "Running playwright codegen --target=javascript"
OUTPUT=$(PWTEST_CLI_EXIT=1 npx playwright codegen --target=javascript)
if [[ "${OUTPUT}" != *"playwright"* ]]; then
echo "ERROR: missing playwright in the output"
exit 1
fi
if [[ "${OUTPUT}" != *"page.close"* ]]; then
echo "ERROR: missing page.close in the output"
exit 1
fi
echo "Running playwright codegen --target=python"
OUTPUT=$(PWTEST_CLI_EXIT=1 npx playwright codegen --target=python)
if [[ "${OUTPUT}" != *"chromium.launch"* ]]; then
echo "ERROR: missing chromium.launch in the output"
exit 1
fi
if [[ "${OUTPUT}" != *"browser.close"* ]]; then
echo "ERROR: missing browser.close in the output"
exit 1
fi

Просмотреть файл

@ -1,50 +0,0 @@
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@"
npm_i playwright-core
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm_i playwright
BROWSERS="$(pwd -P)/browsers"
echo "Running playwright install chromium"
OUTPUT=$(PLAYWRIGHT_BROWSERS_PATH=${BROWSERS} npx playwright install chromium)
if [[ "${OUTPUT}" != *"chromium"* ]]; then
echo "ERROR: should download chromium"
exit 1
fi
if [[ "${OUTPUT}" != *"ffmpeg"* ]]; then
echo "ERROR: should download ffmpeg"
exit 1
fi
if [[ "${OUTPUT}" == *"webkit"* ]]; then
echo "ERROR: should not download webkit"
exit 1
fi
if [[ "${OUTPUT}" == *"firefox"* ]]; then
echo "ERROR: should not download firefox"
exit 1
fi
echo "Running playwright install"
OUTPUT=$(PLAYWRIGHT_BROWSERS_PATH=${BROWSERS} npx playwright install)
if [[ "${OUTPUT}" == *"chromium"* ]]; then
echo "ERROR: should not download chromium"
exit 1
fi
if [[ "${OUTPUT}" == *"ffmpeg"* ]]; then
echo "ERROR: should not download ffmpeg"
exit 1
fi
if [[ "${OUTPUT}" != *"webkit"* ]]; then
echo "ERROR: should download webkit"
exit 1
fi
if [[ "${OUTPUT}" != *"firefox"* ]]; then
echo "ERROR: should download firefox"
exit 1
fi
echo "Running sanity.js"
node sanity.js playwright none
PLAYWRIGHT_BROWSERS_PATH="${BROWSERS}" node sanity.js playwright

Просмотреть файл

@ -1,19 +0,0 @@
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@"
npm_i playwright-core
npm_i playwright
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

Просмотреть файл

@ -1,12 +0,0 @@
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@"
npm_i playwright-core
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm_i playwright
echo "Running playwright install"
PLAYWRIGHT_BROWSERS_PATH="0" npx playwright install
echo "Running driver-client.js"
PLAYWRIGHT_BROWSERS_PATH="0" node driver-client.js

Просмотреть файл

@ -1,9 +0,0 @@
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@"
npm_i playwright-core
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm_i playwright
npm i electron@9.0
echo "Running sanity-electron.js"
node sanity-electron.js

Просмотреть файл

@ -1,28 +0,0 @@
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@"
npm_i playwright-core
OUTPUT=$(npm_i --foreground-script playwright-firefox)
if [[ "${OUTPUT}" == *'To avoid unexpected behavior, please install your dependencies first'* ]]; then
echo "ERROR: should not warn user about global installation"
exit 1
fi
if [[ "${OUTPUT}" == *"chromium"* ]]; then
echo "ERROR: should not download chromium"
exit 1
fi
if [[ "${OUTPUT}" != *"firefox"* ]]; then
echo "ERROR: should download firefox"
exit 1
fi
if [[ "${OUTPUT}" == *"webkit"* ]]; then
echo "ERROR: should not download webkit"
exit 1
fi
echo "Running sanity.js"
node sanity.js playwright-firefox
if [[ ${NODE_VERSION} -ge 14 ]]; then
echo "Running esm.js"
node esm-playwright-firefox.mjs
fi

Просмотреть файл

@ -1,14 +0,0 @@
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@"
BROWSERS="$(pwd -P)/browsers"
npm_i playwright-core
PLAYWRIGHT_BROWSERS_PATH="${BROWSERS}" npm_i playwright
if [[ ! -d "${BROWSERS}" ]]; then
echo "Directory for shared browsers was not created!"
exit 1
fi
echo "Running sanity.js"
node sanity.js playwright none
PLAYWRIGHT_BROWSERS_PATH="${BROWSERS}" node sanity.js playwright

Просмотреть файл

@ -1,20 +0,0 @@
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@"
npm_i playwright-core
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm_i playwright-firefox
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm_i playwright-webkit
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm_i playwright-chromium
BROWSERS="$(pwd -P)/browsers"
PLAYWRIGHT_BROWSERS_PATH="${BROWSERS}" npm_i playwright
if [[ ! -d "${BROWSERS}" ]]; then
echo "Directory for shared browsers was not created!"
exit 1
fi
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

Просмотреть файл

@ -1,16 +0,0 @@
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@"
# @see https://github.com/microsoft/playwright/issues/1651
BROWSERS="$(pwd -P)/browsers"
mkdir install-1 && pushd install-1 && npm init -y
npm_i playwright-core
PLAYWRIGHT_BROWSERS_PATH="${BROWSERS}" npm_i playwright
# Note: the `npm install` would not actually crash, the error
# is merely logged to the console. To reproduce the error, we should make
# sure that script's install.js can be run subsequently without unhandled promise rejections.
# 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

Просмотреть файл

@ -1,31 +0,0 @@
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@"
npm_i playwright-core
OUTPUT=$(npm_i --foreground-script playwright)
if [[ "${OUTPUT}" != *"chromium"* ]]; then
echo "ERROR: should download chromium"
exit 1
fi
if [[ "${OUTPUT}" != *"firefox"* ]]; then
echo "ERROR: should download firefox"
exit 1
fi
if [[ "${OUTPUT}" != *"webkit"* ]]; then
echo "ERROR: should download webkit"
exit 1
fi
echo "Running sanity.js"
node sanity.js playwright
if [[ ${NODE_VERSION} -ge 14 ]]; then
echo "Running esm.js"
node esm-playwright.mjs
fi
echo "Running playwright test"
if npx playwright test -c .; then
echo "ERROR: should not be able to run tests with just playwright package"
exit 1
fi

Просмотреть файл

@ -1,13 +0,0 @@
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@"
# Make sure that browsers path is resolved relative to the `npm install` call location.
mkdir foo
cd foo
npm_i playwright-core
PLAYWRIGHT_BROWSERS_PATH="../relative" npm_i playwright
cd ..
echo "Running sanity.js"
PLAYWRIGHT_BROWSERS_PATH="./relative" node sanity.js playwright

Просмотреть файл

@ -1,8 +0,0 @@
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@"
npm_i playwright-core
PLAYWRIGHT_BROWSERS_PATH="" HOME=. npm_i playwright
echo "Running sanity.js"
# Firefox does not work with relative HOME.
PLAYWRIGHT_BROWSERS_PATH="" HOME=. node sanity.js playwright chromium webkit

Просмотреть файл

@ -1,12 +0,0 @@
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@"
npm_i playwright-core
npm_i playwright
OUTPUT="$(node validate-dependencies.js)"
if [[ "${OUTPUT}" != *"PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS"* ]]; then
echo "ERROR: validateDependencies was not called"
exit 1
fi

Просмотреть файл

@ -1,12 +0,0 @@
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@"
npm_i playwright-core
npm_i playwright
OUTPUT="$(node validate-dependencies-skip-executable-path.js)"
if [[ "${OUTPUT}" == *"PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS"* ]]; then
echo "ERROR: validateDependencies was called"
exit 1
fi

Просмотреть файл

@ -1,28 +0,0 @@
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@"
npm_i playwright-core
OUTPUT=$(npm_i --foreground-script playwright-webkit)
if [[ "${OUTPUT}" == *'To avoid unexpected behavior, please install your dependencies first'* ]]; then
echo "ERROR: should not warn user about global installation"
exit 1
fi
if [[ "${OUTPUT}" == *"chromium"* ]]; then
echo "ERROR: should not download chromium"
exit 1
fi
if [[ "${OUTPUT}" == *"firefox"* ]]; then
echo "ERROR: should not download firefox"
exit 1
fi
if [[ "${OUTPUT}" != *"webkit"* ]]; then
echo "ERROR: should download webkit"
exit 1
fi
echo "Running sanity.js"
node sanity.js playwright-webkit
if [[ ${NODE_VERSION} -ge 14 ]]; then
echo "Running esm.js"
node esm-playwright-webkit.mjs
fi

Просмотреть файл

@ -1,16 +0,0 @@
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@"
BROWSERS="$(pwd -P)/browsers"
npm_i playwright-core
PLAYWRIGHT_BROWSERS_PATH="${BROWSERS}" npm_i playwright
PLAYWRIGHT_BROWSERS_PATH="${BROWSERS}" npm_i playwright-firefox
PLAYWRIGHT_BROWSERS_PATH="${BROWSERS}" npm_i playwright-webkit
PLAYWRIGHT_BROWSERS_PATH="${BROWSERS}" npm_i playwright-chromium
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

Просмотреть файл

@ -1,15 +0,0 @@
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@"
npm_i playwright-core
OUTPUT=$(PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm_i --foreground-script playwright)
if [[ "${OUTPUT}" != *"Skipping browsers download because"* ]]; then
echo "missing log message that browsers download is skipped"
exit 1
fi
if [[ -d ./node_modules/playwright/.local-browsers ]]; then
echo "local browsers folder should be empty"
exit 1
fi

Просмотреть файл

@ -1,23 +0,0 @@
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@"
npm_i playwright-core
OUTPUT=$(PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm_i --foreground-script playwright)
if [[ "${OUTPUT}" != *"Skipping browsers download because"* ]]; then
echo "missing log message that browsers download is skipped"
exit 1
fi
if [[ "$(uname)" != "Linux" ]]; then
echo
echo "Skipping test on non-Linux platform"
echo
return
fi
OUTPUT=$(PWDEBUG=1 node inspector-custom-executable.js)
if [[ "${OUTPUT}" != *"SUCCESS"* ]]; then
echo "missing log message that launch succeeded: ${OUTPUT}"
exit 1
fi

Просмотреть файл

@ -1,29 +0,0 @@
#!/bin/bash
source ./initialize_test.sh && initialize_test "$@"
# @types/node@14.18.9 is the last version which is compatibel with typescript@3.7.5.
# After @types/node@14.18.9 URLSearchParams from @types/node conflicts with typescript's
# shipped types and it results in a type error / build failure.
npm i -D @types/node@14.18.9
# install all packages.
npm_i playwright-core
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm_i playwright
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm_i playwright-firefox
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm_i playwright-webkit
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm_i playwright-chromium
PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD=1 npm_i @playwright/test
# typecheck all packages.
for PKG_NAME in "playwright" \
"playwright-core" \
"playwright-firefox" \
"playwright-chromium" \
"playwright-webkit"
do
echo "Checking types of ${PKG_NAME}"
echo "import { Page } from '${PKG_NAME}';" > "${PKG_NAME}.ts" && npx --yes -p typescript@3.7.5 tsc "${PKG_NAME}.ts"
done;
echo "Checking types of @playwright/test"
echo npx --yes -p typescript@3.7.5 tsc "playwright-test-types.ts"

Просмотреть файл

@ -18,6 +18,7 @@
"wtest": "playwright test --config=tests/library/playwright.config.ts --project=webkit",
"atest": "playwright test --config=tests/android/playwright.config.ts",
"etest": "playwright test --config=tests/electron/playwright.config.ts",
"itest": "playwright test --config=tests/installation/playwright.config.ts",
"test-html-reporter": "playwright test --config=packages/html-reporter",
"test-web": "playwright test --config=packages/web",
"ttest": "node ./tests/playwright-test/stable-test-runner/node_modules/@playwright/test/cli test --config=tests/playwright-test/playwright.config.ts",

Просмотреть файл

@ -0,0 +1,25 @@
/**
* 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 { test } from './npmTest';
test('android types', async ({ exec, tsc, writeFiles }) => {
await exec('npm i --foreground-scripts playwright', { env: { PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1' } });
await writeFiles({
'test.ts':
`import { AndroidDevice, _android, AndroidWebView, Page } from 'playwright';`,
});
await tsc('test.ts');
});

Просмотреть файл

@ -0,0 +1,23 @@
/**
* 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 path from 'path';
import { test } from './npmTest';
test('connect to selenium', async ({ exec, tmpWorkspace }, testInfo) => {
await exec('npm i --foreground-scripts playwright-core');
await exec(`node ./download-chromedriver.js ${path.join(tmpWorkspace)}`);
await exec(`npm run test -- --reporter=list selenium.spec --output=${testInfo.outputPath('tmp-test-results')}`, { cwd: path.join(__dirname, '..', '..'), env: { PWTEST_CHROMEDRIVER: path.join(tmpWorkspace, 'chromedriver') } });
});

Просмотреть файл

@ -0,0 +1,22 @@
/**
* 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 { test } from './npmTest';
test('driver should work', async ({ exec }) => {
await exec('npm i --foreground-scripts playwright', { env: { PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1' } });
await exec('npx playwright install');
await exec('node driver-client.js');
});

Просмотреть файл

@ -0,0 +1,25 @@
/**
* 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 { test } from './npmTest';
test('electron types', async ({ exec, tsc, writeFiles }) => {
await exec('npm i --foreground-scripts playwright electron@12', { env: { PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1' } });
await writeFiles({
'test.ts':
`import { Page, _electron, ElectronApplication, Electron } from 'playwright';`
});
await tsc('test.ts');
});

25
tests/installation/expect.d.ts поставляемый Normal file
Просмотреть файл

@ -0,0 +1,25 @@
/**
* 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.
*/
export {}
declare global {
namespace PlaywrightTest {
interface Matchers<R, T> {
toHaveLoggedSoftwareDownload(browsers: ("chromium" | "firefox" | "webkit" | "ffmpeg")[]): R;
}
}
}

Просмотреть файл

@ -0,0 +1,60 @@
/**
* 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 path from 'path';
import { spawnAsync } from 'playwright-core/lib/utils/spawnAsync';
import { rimraf } from 'playwright-core/lib/utilsBundle';
import { promisify } from 'util';
import fs from 'fs';
const PACKAGE_BUILDER_SCRIPT = path.join(__dirname, '..', '..', 'utils', 'pack_package.js');
const TMP_WORKSPACE = '/tmp/pwt/workspaces';
async function globalSetup() {
await promisify(rimraf)(TMP_WORKSPACE);
console.log(`Temporary workspaces will be created in ${TMP_WORKSPACE}. They will not be removed at the end. Set DEBUG=itest to determine which sub-dir a specific test is using.`);
await fs.promises.mkdir(TMP_WORKSPACE, { recursive: true });
if (process.env.PWTEST_INSTALLATION_TEST_SKIP_PACKAGE_BUILDS) {
console.log('Skipped building packages. Unset PWTEST_INSTALLATION_TEST_SKIP_PACKAGE_BUILDS to build packages.');
return;
}
console.log('Building packages. Set PWTEST_INSTALLATION_TEST_SKIP_PACKAGE_BUILDS to skip.');
const outputDir = path.join(__dirname, 'output');
await promisify(rimraf)(outputDir);
await fs.promises.mkdir(outputDir, { recursive: true });
const build = async (buildTarget: string, pkgNameOverride?: string) => {
const outPath = path.resolve(path.join(outputDir, `${buildTarget}.tgz`));
const { code, stderr, stdout } = await spawnAsync('node', [PACKAGE_BUILDER_SCRIPT, buildTarget, outPath]);
if (!!code)
throw new Error(`Failed to build: ${buildTarget}:\n${stderr}\n${stdout}`);
console.log('Built:', pkgNameOverride || buildTarget);
return [pkgNameOverride || buildTarget, outPath];
};
const builds = await Promise.all([
build('playwright-core'),
build('playwright-test', '@playwright/test'),
build('playwright'),
build('playwright-chromium'),
build('playwright-firefox'),
build('playwright-webkit'),
]);
await fs.promises.writeFile(path.join(__dirname, './.registry.json'), JSON.stringify(Object.fromEntries(builds)));
}
export default globalSetup;

Просмотреть файл

@ -0,0 +1,36 @@
/**
* 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 path from 'path';
import { test, expect } from './npmTest';
import fs from 'fs';
test('installs local packages', async ({ registry, exec, tmpWorkspace }) => {
const packages = ['playwright', 'playwright-core', 'playwright-chromium', 'playwright-firefox', 'playwright-webkit', '@playwright/test'];
await exec('npm i --foreground-scripts', ...packages, { env: { PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1' } });
const output = await exec('node', path.join(__dirname, '..', '..', 'utils', 'workspace.js'), '--get-version');
const expectedPlaywrightVersion = output.trim();
for (const pkg of packages) {
await test.step(`check version and installation location of ${pkg}`, async () => {
registry.assertLocalPackage(pkg);
const result = await exec('node', `--eval='console.log(JSON.stringify(require.resolve("${pkg}")))'`);
const pkgJsonPath = path.join(path.dirname(JSON.parse(result)), 'package.json');
expect(pkgJsonPath.startsWith(path.join(tmpWorkspace, 'node_modules'))).toBeTruthy();
const installedVersion = JSON.parse(await fs.promises.readFile(pkgJsonPath, 'utf8')).version;
expect(installedVersion).toBe(expectedPlaywrightVersion);
});
}
});

Просмотреть файл

@ -0,0 +1,172 @@
/**
* 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-next-line spaced-comment
/// <reference path="./expect.d.ts" />
import { test as _test, expect as _expect } from '@playwright/test';
import fs from 'fs';
import path from 'path';
import debugLogger from 'debug';
import { Registry } from './registry';
import { spawnAsync } from './spawnAsync';
const debug = debugLogger('itest');
/**
* A minimal NPM Registry Server that can serve local packages, or proxy to the upstream registry.
* This is useful in test installation behavior of packages that aren't yet published. It's particularly helpful
* when your installation requires transitive dependencies that are also not yet published.
*
* See https://github.com/npm/registry/blob/master/docs/REGISTRY-API.md for information on the offical APIs.
*/
_expect.extend({
toHaveLoggedSoftwareDownload(received: any, browsers: ('chromium' | 'firefox' | 'webkit' | 'ffmpeg')[]) {
if (typeof received !== 'string')
throw new Error(`Expected argument to be a string.`);
const downloaded = new Set();
for (const [, browser] of received.matchAll(/^.*(chromium|firefox|webkit|ffmpeg) v\d+ downloaded.*$/img))
downloaded.add(browser);
const expected = browsers;
if (expected.length === downloaded.size && expected.every(browser => downloaded.has(browser)))
return { pass: true };
return {
pass: false,
message: () => [
`Browser download expectation failed!`,
` expected: ${[...expected].sort().join(', ')}`,
` actual: ${[...downloaded].sort().join(', ')}`,
].join('\n'),
};
}
});
const expect = _expect;
export type ExecOptions = { cwd?: string, env?: Record<string, string>, message?: string, expectToExitWithError?: boolean };
export type ArgsOrOptions = [] | [...string[]] | [...string[], ExecOptions] | [ExecOptions];
export const test = _test.extend<{
_autoCopyScripts: void,
tmpWorkspace: string,
nodeMajorVersion: number,
installedSoftwareOnDisk: (registryPath?: string) => Promise<string[]>;
writeFiles: (nameToContents: Record<string, string>) => Promise<void>,
exec: (cmd: string, ...argsAndOrOptions: ArgsOrOptions) => Promise<string>
tsc: (...argsAndOrOptions: ArgsOrOptions) => Promise<string>,
registry: Registry,
}>({
_autoCopyScripts: [async ({ tmpWorkspace }, use) => {
const dstDir = path.join(tmpWorkspace);
const sourceDir = path.join(__dirname, 'fixture-scripts');
const contents = await fs.promises.readdir(sourceDir);
await Promise.all(contents.map(f => fs.promises.copyFile(path.join(sourceDir, f), path.join(dstDir, f))));
await use();
}, {
auto: true,
}],
nodeMajorVersion: async ({}, use) => {
await use(+process.versions.node.split('.')[0]);
},
writeFiles: async ({ tmpWorkspace }, use) => {
await use(async (nameToContents: Record<string, string>) => {
for (const [name, contents] of Object.entries(nameToContents))
await fs.promises.writeFile(path.join(tmpWorkspace, name), contents);
});
},
tmpWorkspace: async ({}, use) => {
// We want a location that won't have a node_modules dir anywhere along its path
const tmpWorkspace = path.join('/tmp/pwt/workspaces', path.basename(test.info().outputDir));
await fs.promises.mkdir(tmpWorkspace);
debug(`Workspace Folder: ${tmpWorkspace}`);
await spawnAsync('npm', ['init', '-y'], {
cwd: tmpWorkspace,
});
await use(tmpWorkspace);
},
registry: async ({}, use, testInfo) => {
const port = testInfo.workerIndex + 16123;
const url = `http://127.0.0.1:${port}`;
const registry = new Registry(testInfo.outputPath('registry'), url);
await registry.start(JSON.parse((await fs.promises.readFile(path.join(__dirname, './.registry.json'), 'utf8'))));
await use(registry);
await registry.shutdown();
},
installedSoftwareOnDisk: async ({ tmpWorkspace }, use) => {
await use(async (registryPath?: string) => fs.promises.readdir(registryPath || path.join(tmpWorkspace, 'browsers')).catch(() => []).then(files => files.map(f => f.split('-')[0]).filter(f => !f.startsWith('.'))));
},
exec: async ({ registry, tmpWorkspace }, use, testInfo) => {
await use(async (cmd: string, ...argsAndOrOptions: [] | [...string[]] | [...string[], ExecOptions] | [ExecOptions]) => {
let args: string[] = [];
let options: ExecOptions = {};
if (typeof argsAndOrOptions[argsAndOrOptions.length - 1] === 'object')
options = argsAndOrOptions.pop() as ExecOptions;
args = argsAndOrOptions as string[];
let result!: Awaited<ReturnType<typeof spawnAsync>>;
await test.step(`exec: ${[cmd, ...args].join(' ')}`, async () => {
result = await spawnAsync(cmd, args, {
shell: true,
cwd: options.cwd ?? tmpWorkspace,
// NB: We end up running npm-in-npm, so it's important that we do NOT forward process.env and instead cherry-pick environment variables.
env: {
'PATH': process.env.PATH,
'DISPLAY': process.env.DISPLAY,
'XAUTHORITY': process.env.XAUTHORITY,
'PLAYWRIGHT_BROWSERS_PATH': path.join(tmpWorkspace, 'browsers'),
'npm_config_cache': testInfo.outputPath('npm_cache'),
'npm_config_registry': registry.url(),
'npm_config_prefix': testInfo.outputPath('npm_global'),
...options.env,
}
});
});
const stdio = `${result.stdout}\n${result.stderr}`;
await testInfo.attach(`${[cmd, ...args].join(' ')}`, { body: `COMMAND: ${[cmd, ...args].join(' ')}\n\nEXIT CODE: ${result.code}\n\n====== STDIO + STDERR ======\n\n${stdio}` });
// This means something is really off with spawn
if (result.error)
throw result.error;
// User expects command to fail
if (options.expectToExitWithError) {
if (result.code === 0) {
const message = options.message ? ` Message: ${options.message}` : '';
throw new Error(`Expected the command to exit with an error, but exited cleanly.${message}`);
}
} else if (result.code !== 0) {
const message = options.message ? ` Message: ${options.message}` : '';
throw new Error(`Expected the command to exit cleanly (0 status code), but exited with ${result.code}.${message}`);
}
return stdio;
});
},
tsc: async ({ exec }, use) => {
await exec('npm i --foreground-scripts typescript@3.8 @types/node@14');
await use((...args: ArgsOrOptions) => exec('npx', '-p', 'typescript@3.8', 'tsc', ...args));
},
});
export { expect };

Просмотреть файл

@ -0,0 +1,23 @@
/**
* 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 { test, expect } from './npmTest';
test('npx playwright --help should not download browsers', async ({ exec, installedSoftwareOnDisk }) => {
const result = await exec('npx playwright --help');
expect(result).toHaveLoggedSoftwareDownload([]);
expect(await installedSoftwareOnDisk()).toEqual([]);
expect(result).not.toContain(`To avoid unexpected behavior, please install your dependencies first`);
});

Просмотреть файл

@ -0,0 +1,24 @@
/**
* 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 { test, expect } from './npmTest';
test('npx playwright install global', async ({ exec, installedSoftwareOnDisk }) => {
const result = await exec('npx playwright install');
expect(result).toHaveLoggedSoftwareDownload(['chromium', 'ffmpeg', 'firefox', 'webkit']);
expect(await installedSoftwareOnDisk()).toEqual(['chromium', 'ffmpeg', 'firefox', 'webkit']);
expect(result).not.toContain(`Please run the following command to download new browsers`);
expect(result).toContain(`To avoid unexpected behavior, please install your dependencies first`);
});

Просмотреть файл

@ -0,0 +1,23 @@
/**
* 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 { test, expect } from './npmTest';
test('npx playwright codegen', async ({ exec, installedSoftwareOnDisk }) => {
const stdio = await exec('npx playwright codegen', { expectToExitWithError: true });
expect(stdio).toHaveLoggedSoftwareDownload([]);
expect(await installedSoftwareOnDisk()).toEqual([]);
expect(stdio).toContain(`Please run the following command to download new browsers`);
});

Просмотреть файл

@ -0,0 +1,38 @@
/**
* 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 { test, expect } from './npmTest';
test('codegen should work', async ({ exec }) => {
await exec('npm i --foreground-scripts playwright');
await test.step('codegen without arguments', async () => {
const result = await exec('npx playwright codegen', { env: { PWTEST_CLI_EXIT: '1' } });
expect(result).toContain(`@playwright/test`);
expect(result).toContain(`{ page }`);
});
await test.step('codegen --target=javascript', async () => {
const result = await exec('npx playwright codegen --target=javascript', { env: { PWTEST_CLI_EXIT: '1' } });
expect(result).toContain(`playwright`);
expect(result).toContain(`page.close`);
});
await test.step('codegen --target=python', async () => {
const result = await exec('npx playwright codegen --target=python', { env: { PWTEST_CLI_EXIT: '1' } });
expect(result).toContain(`chromium.launch`);
expect(result).toContain(`browser.close`);
});
});

Просмотреть файл

@ -0,0 +1,35 @@
/**
* 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 { test, expect } from './npmTest';
test('codegen should work', async ({ exec, installedSoftwareOnDisk }) => {
await exec('npm i --foreground-scripts playwright', { env: { PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1' } });
await test.step('playwright install chromium', async () => {
const result = await exec('npx playwright install chromium');
expect(result).toHaveLoggedSoftwareDownload(['chromium', 'ffmpeg']);
expect(await installedSoftwareOnDisk()).toEqual(['chromium', 'ffmpeg']);
});
await test.step('playwright install', async () => {
const result = await exec('npx playwright install');
expect(result).toHaveLoggedSoftwareDownload(['firefox', 'webkit']);
expect(await installedSoftwareOnDisk()).toEqual(['chromium', 'ffmpeg', 'firefox', 'webkit']);
});
await exec('node sanity.js playwright none', { env: { PLAYWRIGHT_BROWSERS_PATH: undefined } });
await exec('node sanity.js playwright');
});

Просмотреть файл

@ -0,0 +1,27 @@
/**
* 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 { test } from './npmTest';
import fs from 'fs';
import path from 'path';
test('playwright cli screenshot should work', async ({ exec, tmpWorkspace }) => {
await exec('npm i --foreground-scripts playwright');
await exec('./node_modules/.bin/playwright screenshot about:blank one.png');
await fs.promises.stat(path.join(tmpWorkspace, 'one.png'));
await exec('npx playwright screenshot about:blank two.png');
await fs.promises.stat(path.join(tmpWorkspace, 'two.png'));
});

Просмотреть файл

@ -0,0 +1,21 @@
/**
* 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 { test } from './npmTest';
test('electron should work', async ({ exec }) => {
await exec('npm i --foreground-scripts playwright electron@9.0', { env: { PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1' } });
await exec('node sanity-electron.js');
});

Просмотреть файл

@ -0,0 +1,28 @@
/**
* 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 { test, expect } from './npmTest';
test('global installation cross package', async ({ exec, installedSoftwareOnDisk }) => {
const packages = ['playwright-chromium', 'playwright-firefox', 'playwright-webkit'];
for (const pkg of packages)
await exec('npm i --foreground-scripts', pkg, { env: { PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1' } });
const result = await exec('npm i --foreground-scripts playwright');
expect(result).toHaveLoggedSoftwareDownload(['chromium', 'ffmpeg', 'firefox', 'webkit']);
expect(await installedSoftwareOnDisk()).toEqual(['chromium', 'ffmpeg', 'firefox', 'webkit']);
for (const pkg of packages)
await test.step(pkg, () => exec('node ./sanity.js', pkg, 'all'));
});

Просмотреть файл

@ -0,0 +1,24 @@
/**
* 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 { test, expect } from './npmTest';
test('global installation', async ({ exec, installedSoftwareOnDisk }) => {
const result = await exec('npm i --foreground-scripts playwright');
expect(result).toHaveLoggedSoftwareDownload(['chromium', 'ffmpeg', 'firefox', 'webkit']);
expect(await installedSoftwareOnDisk()).toEqual(['chromium', 'ffmpeg', 'firefox', 'webkit']);
await exec('node sanity.js playwright none', { env: { PLAYWRIGHT_BROWSERS_PATH: undefined } });
await exec('node ./sanity.js playwright');
});

Просмотреть файл

@ -0,0 +1,28 @@
/**
* 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 { test } from './npmTest';
import path from 'path';
test('subsequent installs works', async ({ exec }) => {
test.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/1651' });
await exec('npm i --foreground-scripts playwright');
// Note: the `npm install` would not actually crash, the error
// is merely logged to the console. To reproduce the error, we should make
// sure that script's install.js can be run subsequently without unhandled promise rejections.
// Note: the flag `--unhandled-rejections=strict` will force node to terminate in case
// of UnhandledPromiseRejection.
await exec('node --unhandled-rejections=strict', path.join('./node_modules', 'playwright', 'install.js'));
});

Просмотреть файл

@ -0,0 +1,25 @@
/**
* 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 { test } from './npmTest';
import fs from 'fs';
import path from 'path';
test('playwright should work with relative home path', async ({ exec, tmpWorkspace }) => {
await fs.promises.mkdir(path.join(tmpWorkspace, 'foo'));
// Make sure that browsers path is resolved relative to the `npm install` call location.
await exec('npm i --foreground-scripts playwright', { cwd: path.join(tmpWorkspace, 'foo'), env: { PLAYWRIGHT_BROWSERS_PATH: '../relative' } });
await exec('node sanity.js playwright', { env: { PLAYWRIGHT_BROWSERS_PATH: './relative' } });
});

Просмотреть файл

@ -0,0 +1,23 @@
/**
* 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 { test } from './npmTest';
test('playwright should work with relative home path', async ({ exec }) => {
const env = { PLAYWRIGHT_BROWSERS_PATH: '0', HOME: '.' };
await exec('npm i --foreground-scripts playwright', { env });
// Firefox does not work with relative HOME.
await exec('node sanity.js playwright chromium webkit', { env });
});

Просмотреть файл

@ -0,0 +1,27 @@
/**
* 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 { test, expect } from './npmTest';
test(`playwright should work`, async ({ exec, nodeMajorVersion, installedSoftwareOnDisk }) => {
const result = await exec('npm i --foreground-scripts playwright');
expect(result).toHaveLoggedSoftwareDownload(['chromium', 'ffmpeg', 'firefox', 'webkit']);
expect(await installedSoftwareOnDisk()).toEqual(['chromium', 'ffmpeg', 'firefox', 'webkit']);
await exec('node ./sanity.js playwright');
if (nodeMajorVersion >= 14)
await exec('node esm-playwright.mjs');
const stdio = await exec('npx playwright', 'test', '-c', '.', { expectToExitWithError: true });
expect(stdio).toContain(`Please install @playwright/test package to use Playwright Test.`);
});

Просмотреть файл

@ -0,0 +1,28 @@
/**
* 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 { test } from './npmTest';
test('@playwright/test should work', async ({ exec, nodeMajorVersion }) => {
await exec('npm i --foreground-scripts @playwright/test');
await exec('npx playwright test -c .', { expectToExitWithError: true, message: 'should not be able to run tests without installing browsers' });
await exec('npx playwright install');
await exec('npx playwright test -c . --browser=all --reporter=list,json sample.spec.js', { env: { PLAYWRIGHT_JSON_OUTPUT_NAME: 'report.json' } });
await exec('node ./read-json-report.js ./report.json');
await exec('node sanity.js @playwright/test');
if (nodeMajorVersion >= 14)
await exec('node', 'esm-playwright-test.mjs');
});

Просмотреть файл

@ -0,0 +1,24 @@
/**
* 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 { test, expect } from './npmTest';
test('@playwright/test stacks should work', async ({ exec }) => {
await exec('npm i --foreground-scripts @playwright/test');
await exec('npx playwright install chromium');
const output = await exec('npx playwright test -c . failing.spec.js', { expectToExitWithError: true, env: { DEBUG: 'pw:api' } });
expect(output).toContain('expect.toHaveText started');
expect(output).toContain('failing.spec.js:5:38');
});

Просмотреть файл

@ -0,0 +1,33 @@
/**
* 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 { test, expect } from './npmTest';
for (const pkg of ['playwright-chromium', 'playwright-firefox', 'playwright-webkit']) {
test(`${pkg} should work`, async ({ exec, nodeMajorVersion, installedSoftwareOnDisk }) => {
const result = await exec('npm i --foreground-scripts', pkg);
const browserName = pkg.split('-')[1];
const expectedSoftware = [browserName];
if (browserName === 'chromium')
expectedSoftware.push('ffmpeg');
expect(result).toHaveLoggedSoftwareDownload(expectedSoftware as any);
expect(await installedSoftwareOnDisk()).toEqual(expectedSoftware);
expect(result).not.toContain(`To avoid unexpected behavior, please install your dependencies first`);
await exec('node ./sanity.js', pkg);
if (nodeMajorVersion >= 14)
await exec('node', `esm-${pkg}.mjs`);
});
}

Просмотреть файл

@ -0,0 +1,32 @@
/**
* 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 path from 'path';
import type { PlaywrightTestConfig } from '@playwright/test';
import { config as loadEnv } from 'dotenv';
loadEnv({ path: path.join(__dirname, '..', '..', '.env') });
const config: PlaywrightTestConfig = {
testIgnore: '**\/fixture-scripts/**',
globalSetup: path.join(__dirname, 'globalSetup'),
timeout: 5 * 60 * 1000,
retries: 0,
reporter: process.env.CI ? 'dot' : [['list'], ['html', { open: 'on-failure' }]],
forbidOnly: !!process.env.CI,
workers: 1,
};
export default config;

Просмотреть файл

@ -0,0 +1,184 @@
/**
* 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 crypto from 'crypto';
import fs from 'fs';
import type { Server } from 'http';
import http from 'http';
import https from 'https';
import path from 'path';
import { spawnAsync } from './spawnAsync';
const kPublicNpmRegistry = 'https://registry.npmjs.org';
const kContentTypeAbbreviatedMetadata = 'application/vnd.npm.install-v1+json';
export class Registry {
private _workDir: string;
private _url: string;
private _objectsDir: string;
private _packageMeta: Map<string, [any, string]> = new Map();
private _log: { pkg: string, status: 'PROXIED' | 'LOCAL', type?: 'tar' | 'metadata' }[] = [];
private _server: Server;
constructor(workDir: string, url: string) {
this._workDir = workDir;
this._objectsDir = path.join(this._workDir);
this._url = url;
}
url() { return this._url; }
async shutdown() {
return new Promise<void>((res, rej) => this._server.close(err => err ? rej(err) : res()));
}
async start(packages: { [pkg: string]: string }) {
await fs.promises.mkdir(this._workDir, { recursive: true });
await fs.promises.mkdir(this._objectsDir, { recursive: true });
await Promise.all(Object.entries(packages).map(([pkg, tar]) => this._addPackage(pkg, tar)));
this._server = http.createServer(async (req, res) => {
// 1. Only support GET requests
if (req.method !== 'GET')
return res.writeHead(405).end();
// 2. Determine what package is being asked for.
// The paths we can handle look like:
// - /<userSuppliedPackageName>/*/<userSuppliedTarName i.e. some *.tgz>
// - /<userSuppliedPackageName>/*
// - /<userSuppliedPackageName>
const url = new URL(req.url, kPublicNpmRegistry);
let [/* empty */, userSuppliedPackageName, /* empty */, userSuppliedTarName] = url.pathname.split('/');
if (userSuppliedPackageName)
userSuppliedPackageName = decodeURIComponent(userSuppliedPackageName);
if (userSuppliedTarName)
userSuppliedTarName = decodeURIComponent(userSuppliedTarName);
// 3. If we have local metadata, serve directly (otherwise, proxy to upstream).
if (this._packageMeta.has(userSuppliedPackageName)) {
const [metadata, objectPath] = this._packageMeta.get(userSuppliedPackageName);
if (userSuppliedTarName) { // Tarball request.
if (path.basename(objectPath) !== userSuppliedTarName) {
res.writeHead(404).end();
return;
}
this._logAccess({ status: 'LOCAL', type: 'tar', pkg: userSuppliedPackageName });
const fileStream = fs.createReadStream(objectPath);
fileStream.pipe(res, { end: true });
fileStream.on('error', console.log);
res.on('error', console.log);
return;
} else { // Metadata request.
this._logAccess({ status: 'LOCAL', type: 'metadata', pkg: userSuppliedPackageName });
res.setHeader('content-type', kContentTypeAbbreviatedMetadata);
res.write(JSON.stringify(metadata, null, ' '));
res.end();
}
} else { // Fall through to official registry
this._logAccess({ status: 'PROXIED', pkg: userSuppliedPackageName });
const client = { req, res };
const toNpm = https.request({
host: url.host,
headers: { ...req.headers, 'host': url.host },
method: req.method,
path: url.pathname,
searchParams: url.searchParams,
protocol: 'https:',
}, fromNpm => {
client.res.writeHead(fromNpm.statusCode, fromNpm.statusMessage, fromNpm.headers);
fromNpm.on('error', err => console.log(`error: `, err));
fromNpm.pipe(client.res, { end: true });
});
client.req.pipe(toNpm);
client.req.on('error', err => console.log(`error: `, err));
}
});
this._server.listen(Number.parseInt(new URL(this._url).port, 10), 'localhost');
await new Promise<void>((res, rej) => {
this._server.on('listening', () => res());
this._server.on('error', rej);
});
}
public assertLocalPackage(pkg) {
const summary = this._log.reduce((acc, f) => {
if (f.pkg === pkg) {
acc.local = f.status === 'LOCAL' || acc.local;
acc.proxied = f.status === 'PROXIED' || acc.proxied;
}
return acc;
}, { local: false, proxied: false });
if (summary.local && !summary.proxied)
return;
throw new Error(`${pkg} was not accessed strictly locally: local: ${summary.local}, proxied: ${summary.proxied}`);
}
private async _addPackage(pkg: string, tarPath: string) {
const tmpDir = await fs.promises.mkdtemp(path.join(this._workDir, '.staging-package-'));
const { stderr, code } = await spawnAsync('tar', ['-xvzf', tarPath, '-C', tmpDir]);
if (!!code)
throw new Error(`Failed to untar ${pkg}: ${stderr}`);
const packageJson = JSON.parse((await fs.promises.readFile(path.join(tmpDir, 'package', 'package.json'), 'utf8')));
if (pkg !== packageJson.name)
throw new Error(`Package name mismatch: ${pkg} is called ${packageJson.name} in its package.json`);
const now = new Date().toISOString();
const shasum = crypto.createHash('sha1').update(await fs.promises.readFile(tarPath)).digest().toString('hex');
const tarball = new URL(this._url);
tarball.pathname = `${tarball.pathname}${tarball.pathname.endsWith('/') ? '' : '/'}${encodeURIComponent(pkg)}/-/${shasum}.tgz`;
const metadata = {
'dist-tags': {
latest: packageJson.version,
[packageJson.version]: packageJson.version,
},
'modified': now,
'name': pkg,
'versions': {
[packageJson.version]: {
_hasShrinkwrap: false,
name: pkg,
version: packageJson.version,
dependencies: packageJson.dependencies || {},
optionalDependencies: packageJson.optionalDependencies || {},
devDependencies: packageJson.devDependencies || {},
bundleDependencies: packageJson.bundleDependencies || {},
peerDependencies: packageJson.peerDependencies || {},
bin: packageJson.bin || {},
directories: packageJson.directories || [],
scripts: packageJson.scripts || {},
dist: {
tarball: tarball.toString(),
shasum,
},
engines: packageJson.engines || {},
},
},
};
const object = path.join(this._objectsDir, `${shasum}.tgz`);
await fs.promises.copyFile(tarPath, object);
this._packageMeta.set(pkg, [metadata, object]);
}
private _logAccess(info: {status: 'PROXIED' | 'LOCAL', pkg: string, type?: 'tar' | 'metadata'}) {
this._log.push(info);
}
}

Просмотреть файл

@ -0,0 +1,23 @@
/**
* 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 { test } from './npmTest';
test('screencast works', async ({ exec }) => {
const packages = ['playwright', 'playwright-chromium', 'playwright-firefox', 'playwright-webkit'];
await exec('npm i --foreground-scripts', ...packages);
for (const pkg of packages)
await test.step(pkg, () => exec('node ./screencast.js', pkg));
});

Просмотреть файл

@ -0,0 +1,25 @@
/**
* 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 { test, expect } from './npmTest';
test('should skip download', async ({ exec }) => {
const installOutput = await exec('npm i --foreground-scripts playwright', { env: { PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1' } });
expect(installOutput).toContain('Skipping browsers download because');
if (process.platform === 'linux') {
const output = await exec('node inspector-custom-executable.js', { env: { PWDEBUG: '1' } });
expect(output).toContain('SUCCESS');
}
});

Просмотреть файл

@ -0,0 +1,23 @@
/**
* 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 { test, expect } from './npmTest';
test('PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD should skip browser installs', async ({ exec, installedSoftwareOnDisk }) => {
const result = await exec('npm i --foreground-scripts playwright', { env: { PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1' } });
expect(result).toHaveLoggedSoftwareDownload([]);
expect(await installedSoftwareOnDisk()).toEqual([]);
expect(result).toContain(`Skipping browsers download because`);
});

Просмотреть файл

@ -0,0 +1,48 @@
/**
* 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 { SpawnOptions } from 'child_process';
import { spawn } from 'child_process';
import debugLogger from 'debug';
const debugExec = debugLogger('itest:exec');
const debugExecStdout = debugLogger('itest:exec:stdout');
const debugExecStderr = debugLogger('itest:exec:stderr');
export function spawnAsync(cmd: string, args: string[], options: SpawnOptions = {}): Promise<{stdout: string, stderr: string, code: number | null, error?: Error}> {
// debugExec(`CWD: ${options.cwd || process.cwd()}`);
// debugExec(`ENV: ${Object.entries(options.env || {}).map(([key, value]) => `${key}=${value}`).join(' ')}`);
debugExec([cmd, ...args].join(' '));
const p = spawn(cmd, args, Object.assign({ windowsHide: true }, options));
return new Promise(resolve => {
let stdout = '';
let stderr = '';
if (p.stdout) {
p.stdout.on('data', data => {
debugExecStdout(data.toString());
stdout += data;
});
}
if (p.stderr) {
p.stderr.on('data', data => {
debugExecStderr(data.toString());
stderr += data;
});
}
p.on('close', code => resolve({ stdout, stderr, code }));
p.on('error', error => resolve({ stdout, stderr, code: 0, error }));
});
}

Просмотреть файл

@ -0,0 +1,37 @@
/**
* 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 { test } from './npmTest';
test('typescript types should work', async ({ exec, tsc, writeFiles }) => {
const libraryPackages = [
'playwright',
'playwright-core',
'playwright-firefox',
'playwright-webkit',
'playwright-chromium',
];
await exec('npm i @playwright/test', ...libraryPackages, { env: { PLAYWRIGHT_SKIP_BROWSER_DOWNLOAD: '1' } });
for (const libraryPackage of libraryPackages) {
const filename = libraryPackage + '.ts';
await writeFiles({
[filename]: `import { Page } from '${libraryPackage}';`,
});
await tsc(filename);
}
await tsc('playwright-test-types.ts');
});

Просмотреть файл

@ -0,0 +1,30 @@
/**
* 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 { test, expect } from './npmTest';
test.describe('validate dependencies', () => {
test('default (on)', async ({ exec }) => {
await exec('npm i --foreground-scripts playwright');
const result = await exec('node ./validate-dependencies.js');
expect(result).toContain(`PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS`);
});
test('disabled (off)', async ({ exec }) => {
await exec('npm i --foreground-scripts playwright');
const result = await exec('node ./validate-dependencies-skip-executable-path.js');
expect(result).not.toContain(`PLAYWRIGHT_SKIP_VALIDATE_HOST_REQUIREMENTS`);
});
});