2019-11-19 05:18:28 +03:00
|
|
|
/**
|
|
|
|
* Copyright 2017 Google Inc. All rights reserved.
|
2019-12-11 00:21:51 +03:00
|
|
|
* Modifications copyright (c) Microsoft Corporation.
|
2019-11-19 05:18:28 +03:00
|
|
|
*
|
|
|
|
* 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.
|
|
|
|
*/
|
2020-04-02 04:02:43 +03:00
|
|
|
|
2020-04-10 04:14:29 +03:00
|
|
|
const fs = require('fs');
|
|
|
|
const readline = require('readline');
|
2020-04-07 03:21:42 +03:00
|
|
|
const TestRunner = require('../utils/testrunner/');
|
2020-04-10 04:14:29 +03:00
|
|
|
const {Environment} = require('../utils/testrunner/Test');
|
2019-11-19 05:18:28 +03:00
|
|
|
|
2020-04-11 06:31:50 +03:00
|
|
|
function collect(browserNames) {
|
|
|
|
let parallel = 1;
|
|
|
|
if (process.env.PW_PARALLEL_TESTS)
|
|
|
|
parallel = parseInt(process.env.PW_PARALLEL_TESTS.trim(), 10);
|
|
|
|
const parallelArgIndex = process.argv.indexOf('-j');
|
|
|
|
if (parallelArgIndex !== -1)
|
|
|
|
parallel = parseInt(process.argv[parallelArgIndex + 1], 10);
|
|
|
|
require('events').defaultMaxListeners *= parallel;
|
|
|
|
|
|
|
|
let timeout = process.env.CI ? 30 * 1000 : 10 * 1000;
|
|
|
|
if (!isNaN(process.env.TIMEOUT))
|
|
|
|
timeout = parseInt(process.env.TIMEOUT * 1000, 10);
|
|
|
|
const MAJOR_NODEJS_VERSION = parseInt(process.version.substring(1).split('.')[0], 10);
|
|
|
|
if (MAJOR_NODEJS_VERSION >= 8 && require('inspector').url()) {
|
|
|
|
console.log('Detected inspector - disabling timeout to be debugger-friendly');
|
|
|
|
timeout = 0;
|
|
|
|
}
|
2020-03-28 18:49:00 +03:00
|
|
|
|
2020-04-11 06:31:50 +03:00
|
|
|
const config = require('./test.config');
|
|
|
|
|
|
|
|
const testRunner = new TestRunner({
|
|
|
|
timeout,
|
2020-04-15 02:31:09 +03:00
|
|
|
totalTimeout: process.env.CI ? 30 * 60 * 1000 : 0, // 30 minutes on CI
|
2020-04-11 06:31:50 +03:00
|
|
|
parallel,
|
|
|
|
breakOnFailure: process.argv.indexOf('--break-on-failure') !== -1,
|
|
|
|
verbose: process.argv.includes('--verbose'),
|
|
|
|
summary: !process.argv.includes('--verbose'),
|
|
|
|
showSlowTests: process.env.CI ? 5 : 0,
|
|
|
|
showMarkedAsFailingTests: 10,
|
2020-04-10 04:14:29 +03:00
|
|
|
});
|
2020-04-11 06:31:50 +03:00
|
|
|
if (config.setupTestRunner)
|
|
|
|
config.setupTestRunner(testRunner);
|
2020-04-10 04:14:29 +03:00
|
|
|
|
2020-04-11 06:31:50 +03:00
|
|
|
for (const [key, value] of Object.entries(testRunner.api()))
|
|
|
|
global[key] = value;
|
|
|
|
|
|
|
|
// TODO: this should be a preinstalled playwright by default.
|
|
|
|
const playwrightPath = config.playwrightPath;
|
|
|
|
const playwright = require(playwrightPath);
|
2020-04-10 04:14:29 +03:00
|
|
|
|
2020-04-11 06:31:50 +03:00
|
|
|
const playwrightEnvironment = new Environment('Playwright');
|
|
|
|
playwrightEnvironment.beforeAll(async state => {
|
|
|
|
state.playwright = playwright;
|
|
|
|
global.playwright = playwright;
|
2020-04-10 04:14:29 +03:00
|
|
|
});
|
2020-04-11 06:31:50 +03:00
|
|
|
playwrightEnvironment.afterAll(async state => {
|
|
|
|
delete state.playwright;
|
|
|
|
delete global.playwright;
|
2020-04-10 04:14:29 +03:00
|
|
|
});
|
2020-04-11 06:31:50 +03:00
|
|
|
|
|
|
|
testRunner.collector().useEnvironment(playwrightEnvironment);
|
|
|
|
for (const e of config.globalEnvironments || [])
|
|
|
|
testRunner.collector().useEnvironment(e);
|
|
|
|
|
|
|
|
for (const browserName of browserNames) {
|
|
|
|
const browserType = playwright[browserName];
|
|
|
|
const browserTypeEnvironment = new Environment('BrowserType');
|
|
|
|
browserTypeEnvironment.beforeAll(async state => {
|
|
|
|
state.browserType = browserType;
|
|
|
|
});
|
|
|
|
browserTypeEnvironment.afterAll(async state => {
|
|
|
|
delete state.browserType;
|
|
|
|
});
|
|
|
|
|
|
|
|
// TODO: maybe launch options per browser?
|
|
|
|
const launchOptions = {
|
|
|
|
...(config.launchOptions || {}),
|
|
|
|
handleSIGINT: false,
|
|
|
|
};
|
|
|
|
if (launchOptions.executablePath)
|
|
|
|
launchOptions.executablePath = launchOptions.executablePath[browserName];
|
|
|
|
if (launchOptions.executablePath) {
|
|
|
|
const YELLOW_COLOR = '\x1b[33m';
|
|
|
|
const RESET_COLOR = '\x1b[0m';
|
|
|
|
console.warn(`${YELLOW_COLOR}WARN: running ${browserName} tests with ${launchOptions.executablePath}${RESET_COLOR}`);
|
|
|
|
browserType._executablePath = launchOptions.executablePath;
|
|
|
|
delete launchOptions.executablePath;
|
|
|
|
} else {
|
|
|
|
if (!fs.existsSync(browserType.executablePath()))
|
|
|
|
throw new Error(`Browser is not downloaded. Run 'npm install' and try to re-run tests`);
|
2020-04-10 04:14:29 +03:00
|
|
|
}
|
2020-04-11 06:31:50 +03:00
|
|
|
|
|
|
|
const browserEnvironment = new Environment(browserName);
|
2020-04-20 17:52:26 +03:00
|
|
|
let logger;
|
2020-04-11 06:31:50 +03:00
|
|
|
browserEnvironment.beforeAll(async state => {
|
2020-04-20 17:52:26 +03:00
|
|
|
state.browser = await state.browserType.launch({...launchOptions, loggerSink: {
|
|
|
|
isEnabled: (name, severity) => {
|
|
|
|
return name === 'browser' ||
|
|
|
|
(name === 'protocol' && config.dumpProtocolOnFailure);
|
|
|
|
},
|
|
|
|
log: (name, severity, message, args) => {
|
|
|
|
if (logger)
|
|
|
|
logger(name, severity, message);
|
|
|
|
}
|
|
|
|
}});
|
2020-04-11 06:31:50 +03:00
|
|
|
});
|
|
|
|
browserEnvironment.afterAll(async state => {
|
2020-04-13 01:30:53 +03:00
|
|
|
await state.browser.close();
|
2020-04-11 06:31:50 +03:00
|
|
|
delete state.browser;
|
|
|
|
});
|
|
|
|
browserEnvironment.beforeEach(async(state, testRun) => {
|
2020-04-20 17:52:26 +03:00
|
|
|
logger = (name, severity, message) => {
|
|
|
|
if (name === 'browser') {
|
|
|
|
if (severity === 'warning')
|
|
|
|
testRun.log(`\x1b[31m[browser]\x1b[0m ${message}`)
|
|
|
|
else
|
|
|
|
testRun.log(`\x1b[33m[browser]\x1b[0m ${message}`)
|
|
|
|
} else if (name === 'protocol' && config.dumpProtocolOnFailure) {
|
|
|
|
testRun.log(`\x1b[32m[protocol]\x1b[0m ${message}`)
|
2020-04-11 06:31:50 +03:00
|
|
|
}
|
2020-04-20 17:52:26 +03:00
|
|
|
}
|
2020-04-11 06:31:50 +03:00
|
|
|
});
|
|
|
|
browserEnvironment.afterEach(async (state, testRun) => {
|
2020-04-20 17:52:26 +03:00
|
|
|
logger = null;
|
|
|
|
if (config.dumpProtocolOnFailure) {
|
|
|
|
if (testRun.ok())
|
|
|
|
testRun.output().splice(0);
|
|
|
|
}
|
2020-04-11 06:31:50 +03:00
|
|
|
});
|
|
|
|
|
|
|
|
const pageEnvironment = new Environment('Page');
|
|
|
|
pageEnvironment.beforeEach(async state => {
|
|
|
|
state.context = await state.browser.newContext();
|
|
|
|
state.page = await state.context.newPage();
|
|
|
|
});
|
|
|
|
pageEnvironment.afterEach(async state => {
|
|
|
|
await state.context.close();
|
|
|
|
state.context = null;
|
|
|
|
state.page = null;
|
|
|
|
});
|
|
|
|
|
|
|
|
const suiteName = { 'chromium': 'Chromium', 'firefox': 'Firefox', 'webkit': 'WebKit' }[browserName];
|
|
|
|
describe(suiteName, () => {
|
|
|
|
// In addition to state, expose these two on global so that describes can access them.
|
|
|
|
global.playwright = playwright;
|
|
|
|
global.browserType = browserType;
|
|
|
|
|
|
|
|
testRunner.collector().useEnvironment(browserTypeEnvironment);
|
|
|
|
|
|
|
|
for (const spec of config.specs || []) {
|
|
|
|
const skip = spec.browsers && !spec.browsers.includes(browserName);
|
|
|
|
(skip ? xdescribe : describe)(spec.title || '', () => {
|
|
|
|
for (const e of spec.environments || ['page']) {
|
|
|
|
if (e === 'browser') {
|
|
|
|
testRunner.collector().useEnvironment(browserEnvironment);
|
|
|
|
} else if (e === 'page') {
|
|
|
|
testRunner.collector().useEnvironment(browserEnvironment);
|
|
|
|
testRunner.collector().useEnvironment(pageEnvironment);
|
|
|
|
} else {
|
|
|
|
testRunner.collector().useEnvironment(e);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
for (const file of spec.files || []) {
|
|
|
|
require(file);
|
|
|
|
delete require.cache[require.resolve(file)];
|
|
|
|
}
|
|
|
|
});
|
2020-04-10 04:14:29 +03:00
|
|
|
}
|
|
|
|
|
2020-04-11 06:31:50 +03:00
|
|
|
delete global.browserType;
|
|
|
|
delete global.playwright;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
for (const [key, value] of Object.entries(testRunner.api())) {
|
|
|
|
// expect is used when running tests, while the rest of api is not.
|
|
|
|
if (key !== 'expect')
|
|
|
|
delete global[key];
|
|
|
|
}
|
2020-04-10 04:14:29 +03:00
|
|
|
|
2020-04-11 06:31:50 +03:00
|
|
|
const filterArgIndex = process.argv.indexOf('--filter');
|
|
|
|
if (filterArgIndex !== -1) {
|
|
|
|
const filter = process.argv[filterArgIndex + 1];
|
|
|
|
testRunner.focusMatchingTests(new RegExp(filter, 'i'));
|
|
|
|
}
|
2020-04-10 04:14:29 +03:00
|
|
|
|
2020-04-17 04:09:25 +03:00
|
|
|
const repeatArgIndex = process.argv.indexOf('--repeat');
|
|
|
|
if (repeatArgIndex !== -1) {
|
|
|
|
const repeat = parseInt(process.argv[repeatArgIndex + 1], 10);
|
|
|
|
if (!isNaN(repeat))
|
|
|
|
testRunner.repeatAll(repeat);
|
|
|
|
}
|
|
|
|
|
2020-04-11 06:31:50 +03:00
|
|
|
return testRunner;
|
2020-04-07 18:10:31 +03:00
|
|
|
}
|
2020-04-02 04:02:43 +03:00
|
|
|
|
2020-04-11 06:31:50 +03:00
|
|
|
module.exports = collect;
|
2019-11-19 05:18:28 +03:00
|
|
|
|
2020-04-11 06:31:50 +03:00
|
|
|
if (require.main === module) {
|
|
|
|
console.log('Testing on Node', process.version);
|
|
|
|
const browserNames = ['chromium', 'firefox', 'webkit'].filter(name => {
|
|
|
|
return process.env.BROWSER === name || process.env.BROWSER === 'all';
|
|
|
|
});
|
|
|
|
const testRunner = collect(browserNames);
|
|
|
|
testRunner.run().then(() => { delete global.expect; });
|
|
|
|
}
|