2020-08-10 16:48:34 -07:00
|
|
|
/**
|
|
|
|
* Copyright Microsoft Corporation. All rights reserved.
|
|
|
|
*
|
|
|
|
* 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-09-25 19:27:09 -07:00
|
|
|
import { config } from '@playwright/test-runner';
|
|
|
|
import assert from 'assert';
|
|
|
|
import childProcess from 'child_process';
|
2020-08-10 16:48:34 -07:00
|
|
|
import fs from 'fs';
|
2020-09-25 19:27:09 -07:00
|
|
|
import path from 'path';
|
2020-09-18 15:52:14 -07:00
|
|
|
import util from 'util';
|
2020-09-25 23:30:46 -07:00
|
|
|
import type { Browser, BrowserContext, BrowserType, Page } from '../index';
|
2020-08-22 15:13:51 -07:00
|
|
|
import { Connection } from '../lib/client/connection';
|
2020-08-21 18:46:11 -07:00
|
|
|
import { Transport } from '../lib/protocol/transport';
|
2020-08-19 17:47:24 -07:00
|
|
|
import { installCoverageHooks } from './coverage';
|
2020-09-25 23:30:46 -07:00
|
|
|
import { fixtures as httpFixtures } from './http.fixtures';
|
|
|
|
import { fixtures as implFixtures } from './impl.fixtures';
|
|
|
|
import { fixtures as platformFixtures, options as platformOptions } from './platform.fixtures';
|
|
|
|
import { fixtures as playwrightFixtures, options as playwrightOptions, PlaywrightParameters } from './upstream.fixtures';
|
|
|
|
export { expect } from '@playwright/test/out/matcher.fixtures';
|
2020-09-25 12:52:06 -07:00
|
|
|
export { config } from '@playwright/test-runner';
|
2020-09-10 21:31:46 -07:00
|
|
|
|
2020-09-18 15:52:14 -07:00
|
|
|
const removeFolderAsync = util.promisify(require('rimraf'));
|
|
|
|
|
2020-09-25 23:30:46 -07:00
|
|
|
type AllParameters = {
|
2020-09-11 10:02:07 -07:00
|
|
|
browserName: string;
|
|
|
|
};
|
|
|
|
|
2020-09-25 23:30:46 -07:00
|
|
|
type AllWorkerFixtures = {
|
2020-09-10 21:31:46 -07:00
|
|
|
golden: (path: string) => string;
|
|
|
|
};
|
|
|
|
|
2020-09-25 23:30:46 -07:00
|
|
|
type AllTestFixtures = {
|
2020-09-18 15:52:14 -07:00
|
|
|
createUserDataDir: () => Promise<string>;
|
2020-09-10 21:31:46 -07:00
|
|
|
launchPersistent: (options?: Parameters<BrowserType<Browser>['launchPersistentContext']>[1]) => Promise<{context: BrowserContext, page: Page}>;
|
|
|
|
};
|
|
|
|
|
2020-09-25 23:30:46 -07:00
|
|
|
export const fixtures = playwrightFixtures
|
|
|
|
.union(httpFixtures)
|
|
|
|
.union(platformFixtures)
|
|
|
|
.union(implFixtures)
|
|
|
|
.declareParameters<AllParameters>()
|
|
|
|
.declareWorkerFixtures<AllWorkerFixtures>()
|
|
|
|
.declareTestFixtures<AllTestFixtures>();
|
|
|
|
const { defineTestFixture, defineWorkerFixture, overrideWorkerFixture } = fixtures;
|
2020-09-11 10:02:07 -07:00
|
|
|
|
2020-09-10 21:31:46 -07:00
|
|
|
export const it = fixtures.it;
|
|
|
|
export const fit = fixtures.fit;
|
|
|
|
export const xit = fixtures.xit;
|
|
|
|
export const describe = fixtures.describe;
|
|
|
|
export const fdescribe = fixtures.fdescribe;
|
|
|
|
export const xdescribe = fixtures.xdescribe;
|
|
|
|
export const beforeEach = fixtures.beforeEach;
|
|
|
|
export const afterEach = fixtures.afterEach;
|
|
|
|
export const beforeAll = fixtures.beforeAll;
|
|
|
|
export const afterAll = fixtures.afterAll;
|
2020-08-10 16:48:34 -07:00
|
|
|
|
2020-08-22 16:44:56 -07:00
|
|
|
export const options = {
|
2020-09-25 23:30:46 -07:00
|
|
|
...platformOptions,
|
|
|
|
...playwrightOptions,
|
2020-09-16 21:36:36 -07:00
|
|
|
CHROMIUM: (parameters: PlaywrightParameters) => parameters.browserName === 'chromium',
|
|
|
|
FIREFOX: (parameters: PlaywrightParameters) => parameters.browserName === 'firefox',
|
|
|
|
WEBKIT: (parameters: PlaywrightParameters) => parameters.browserName === 'webkit',
|
2020-08-22 16:44:56 -07:00
|
|
|
WIRE: !!process.env.PWWIRE,
|
2020-08-28 04:20:29 -07:00
|
|
|
};
|
2020-08-10 16:48:34 -07:00
|
|
|
|
2020-08-28 04:20:29 -07:00
|
|
|
const getExecutablePath = browserName => {
|
2020-08-10 16:48:34 -07:00
|
|
|
if (browserName === 'chromium' && process.env.CRPATH)
|
2020-08-15 04:34:42 +02:00
|
|
|
return process.env.CRPATH;
|
2020-08-10 16:48:34 -07:00
|
|
|
if (browserName === 'firefox' && process.env.FFPATH)
|
2020-08-15 04:34:42 +02:00
|
|
|
return process.env.FFPATH;
|
2020-08-10 16:48:34 -07:00
|
|
|
if (browserName === 'webkit' && process.env.WKPATH)
|
2020-08-15 04:34:42 +02:00
|
|
|
return process.env.WKPATH;
|
2020-08-28 04:20:29 -07:00
|
|
|
};
|
2020-08-15 04:34:42 +02:00
|
|
|
|
2020-09-25 23:30:46 -07:00
|
|
|
overrideWorkerFixture('defaultBrowserOptions', async ({browserName}, runTest) => {
|
2020-08-28 04:20:29 -07:00
|
|
|
const executablePath = getExecutablePath(browserName);
|
2020-08-10 16:48:34 -07:00
|
|
|
if (executablePath)
|
|
|
|
console.error(`Using executable at ${executablePath}`);
|
2020-09-18 11:54:00 -07:00
|
|
|
await runTest({
|
2020-08-10 16:48:34 -07:00
|
|
|
handleSIGINT: false,
|
2020-08-22 16:44:56 -07:00
|
|
|
slowMo: options.SLOW_MO,
|
|
|
|
headless: options.HEADLESS,
|
2020-09-18 11:54:00 -07:00
|
|
|
executablePath,
|
2020-09-25 12:52:06 -07:00
|
|
|
artifactsPath: config.outputDir,
|
2020-08-10 16:48:34 -07:00
|
|
|
});
|
|
|
|
});
|
|
|
|
|
2020-09-25 23:30:46 -07:00
|
|
|
overrideWorkerFixture('playwright', async ({browserName, testWorkerIndex, platform}, test) => {
|
2020-09-16 21:36:36 -07:00
|
|
|
assert(platform); // Depend on platform to generate all tests.
|
2020-08-10 16:48:34 -07:00
|
|
|
const {coverage, uninstall} = installCoverageHooks(browserName);
|
2020-08-22 16:44:56 -07:00
|
|
|
if (options.WIRE) {
|
2020-09-06 21:36:22 -07:00
|
|
|
require('../lib/utils/utils').setUnderTest();
|
2020-08-10 16:48:34 -07:00
|
|
|
const connection = new Connection();
|
2020-08-24 17:32:55 -07:00
|
|
|
const spawnedProcess = childProcess.fork(path.join(__dirname, '..', 'lib', 'server.js'), [], {
|
2020-08-10 16:48:34 -07:00
|
|
|
stdio: 'pipe',
|
|
|
|
detached: true,
|
|
|
|
});
|
|
|
|
spawnedProcess.unref();
|
|
|
|
const onExit = (exitCode, signal) => {
|
|
|
|
throw new Error(`Server closed with exitCode=${exitCode} signal=${signal}`);
|
|
|
|
};
|
|
|
|
spawnedProcess.on('exit', onExit);
|
|
|
|
const transport = new Transport(spawnedProcess.stdin, spawnedProcess.stdout);
|
|
|
|
connection.onmessage = message => transport.send(JSON.stringify(message));
|
|
|
|
transport.onmessage = message => connection.dispatch(JSON.parse(message));
|
|
|
|
const playwrightObject = await connection.waitForObjectWithKnownName('Playwright');
|
2020-08-12 17:51:07 -07:00
|
|
|
await test(playwrightObject);
|
|
|
|
spawnedProcess.removeListener('exit', onExit);
|
|
|
|
spawnedProcess.stdin.destroy();
|
|
|
|
spawnedProcess.stdout.destroy();
|
|
|
|
spawnedProcess.stderr.destroy();
|
|
|
|
await teardownCoverage();
|
2020-08-10 16:48:34 -07:00
|
|
|
} else {
|
2020-09-04 16:31:52 -07:00
|
|
|
const playwright = require('../index');
|
|
|
|
await test(playwright);
|
2020-08-12 17:51:07 -07:00
|
|
|
await teardownCoverage();
|
2020-08-10 16:48:34 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
async function teardownCoverage() {
|
|
|
|
uninstall();
|
2020-09-23 14:52:06 -07:00
|
|
|
const coveragePath = path.join(__dirname, 'coverage-report', testWorkerIndex + '.json');
|
2020-08-10 16:48:34 -07:00
|
|
|
const coverageJSON = [...coverage.keys()].filter(key => coverage.get(key));
|
|
|
|
await fs.promises.mkdir(path.dirname(coveragePath), { recursive: true });
|
|
|
|
await fs.promises.writeFile(coveragePath, JSON.stringify(coverageJSON, undefined, 2), 'utf8');
|
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2020-09-11 10:02:07 -07:00
|
|
|
defineWorkerFixture('golden', async ({browserName}, test) => {
|
2020-08-20 17:45:10 -07:00
|
|
|
await test(p => path.join(browserName, p));
|
|
|
|
});
|
|
|
|
|
2020-09-23 14:52:06 -07:00
|
|
|
defineTestFixture('createUserDataDir', async ({testOutputDir}, runTest) => {
|
2020-09-18 15:52:14 -07:00
|
|
|
let counter = 0;
|
|
|
|
const dirs: string[] = [];
|
|
|
|
async function createUserDataDir() {
|
|
|
|
const dir = path.join(testOutputDir, `user-data-dir-${counter++}`);
|
|
|
|
dirs.push(dir);
|
|
|
|
await fs.promises.mkdir(dir, { recursive: true });
|
|
|
|
return dir;
|
2020-08-20 17:45:10 -07:00
|
|
|
}
|
2020-09-18 15:52:14 -07:00
|
|
|
await runTest(createUserDataDir);
|
|
|
|
// Remove user data dirs, because we cannot upload them as test result artifacts.
|
|
|
|
// - Firefox removes lock file later, repsumably from another watchdog process?
|
|
|
|
// - WebKit has circular symlinks that makes CI go crazy.
|
|
|
|
await Promise.all(dirs.map(dir => removeFolderAsync(dir).catch(e => {})));
|
2020-08-10 16:48:34 -07:00
|
|
|
});
|
|
|
|
|
2020-09-18 15:52:14 -07:00
|
|
|
defineTestFixture('launchPersistent', async ({createUserDataDir, defaultBrowserOptions, browserType}, test) => {
|
2020-08-24 20:26:06 -07:00
|
|
|
let context;
|
|
|
|
async function launchPersistent(options) {
|
|
|
|
if (context)
|
|
|
|
throw new Error('can only launch one persitent context');
|
2020-09-18 15:52:14 -07:00
|
|
|
const userDataDir = await createUserDataDir();
|
|
|
|
context = await browserType.launchPersistentContext(userDataDir, {...defaultBrowserOptions, ...options});
|
2020-08-24 20:26:06 -07:00
|
|
|
const page = context.pages()[0];
|
|
|
|
return {context, page};
|
|
|
|
}
|
|
|
|
await test(launchPersistent);
|
|
|
|
if (context)
|
|
|
|
await context.close();
|
|
|
|
});
|