2021-04-01 16:35:26 -07:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*/
|
|
|
|
|
2021-04-29 11:11:32 -07:00
|
|
|
import * as folio from 'folio';
|
|
|
|
import type { Browser, BrowserContext, BrowserContextOptions, BrowserType, LaunchOptions, Page } from '../../index';
|
|
|
|
import { removeFolders } from '../../lib/utils/utils';
|
|
|
|
import * as path from 'path';
|
|
|
|
import * as fs from 'fs';
|
|
|
|
import * as os from 'os';
|
|
|
|
import * as util from 'util';
|
|
|
|
import { RemoteServer, RemoteServerOptions } from './remoteServer';
|
2021-04-30 13:26:13 -07:00
|
|
|
import { CommonArgs, baseTest } from './baseTest';
|
2021-04-29 11:11:32 -07:00
|
|
|
|
|
|
|
const mkdtempAsync = util.promisify(fs.mkdtemp);
|
|
|
|
|
|
|
|
type PlaywrightTestArgs = {
|
|
|
|
createUserDataDir: () => Promise<string>;
|
|
|
|
launchPersistent: (options?: Parameters<BrowserType['launchPersistentContext']>[1]) => Promise<{ context: BrowserContext, page: Page }>;
|
|
|
|
startRemoteServer: (options?: RemoteServerOptions) => Promise<RemoteServer>;
|
|
|
|
};
|
|
|
|
|
|
|
|
type PlaywrightEnvOptions = {
|
|
|
|
launchOptions?: LaunchOptions;
|
|
|
|
traceDir?: string;
|
|
|
|
};
|
|
|
|
|
2021-04-30 13:26:13 -07:00
|
|
|
type PlaywrightWorkerArgs = {
|
2021-04-29 11:11:32 -07:00
|
|
|
browserType: BrowserType;
|
|
|
|
browserOptions: LaunchOptions;
|
|
|
|
};
|
|
|
|
|
|
|
|
class PlaywrightEnv {
|
|
|
|
protected _browserOptions: LaunchOptions;
|
|
|
|
protected _browserType: BrowserType;
|
|
|
|
private _userDataDirs: string[] = [];
|
|
|
|
private _persistentContext: BrowserContext | undefined;
|
|
|
|
private _remoteServer: RemoteServer | undefined;
|
|
|
|
|
|
|
|
optionsType(): PlaywrightEnvOptions {
|
|
|
|
return {};
|
|
|
|
}
|
|
|
|
|
2021-04-30 13:26:13 -07:00
|
|
|
async beforeAll(args: CommonArgs & PlaywrightEnvOptions, workerInfo: folio.WorkerInfo): Promise<PlaywrightWorkerArgs> {
|
2021-04-29 11:11:32 -07:00
|
|
|
this._browserType = args.playwright[args.browserName];
|
|
|
|
this._browserOptions = {
|
|
|
|
...args.launchOptions,
|
|
|
|
_traceDir: args.traceDir,
|
2021-04-30 13:26:13 -07:00
|
|
|
channel: args.browserChannel,
|
2021-04-29 11:11:32 -07:00
|
|
|
headless: !args.headful,
|
|
|
|
handleSIGINT: false,
|
|
|
|
} as any;
|
|
|
|
return {
|
|
|
|
browserType: this._browserType,
|
|
|
|
browserOptions: this._browserOptions,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
private async _createUserDataDir() {
|
|
|
|
// We do not put user data dir in testOutputPath,
|
|
|
|
// because we do not want to upload them as test result artifacts.
|
|
|
|
//
|
|
|
|
// Additionally, it is impossible to upload user data dir after test run:
|
|
|
|
// - Firefox removes lock file later, presumably from another watchdog process?
|
|
|
|
// - WebKit has circular symlinks that makes CI go crazy.
|
|
|
|
const dir = await mkdtempAsync(path.join(os.tmpdir(), 'playwright-test-'));
|
|
|
|
this._userDataDirs.push(dir);
|
|
|
|
return dir;
|
|
|
|
}
|
|
|
|
|
|
|
|
private async _launchPersistent(options?: Parameters<BrowserType['launchPersistentContext']>[1]) {
|
|
|
|
if (this._persistentContext)
|
|
|
|
throw new Error('can only launch one persitent context');
|
|
|
|
const userDataDir = await this._createUserDataDir();
|
|
|
|
this._persistentContext = await this._browserType.launchPersistentContext(userDataDir, { ...this._browserOptions, ...options });
|
|
|
|
const page = this._persistentContext.pages()[0];
|
|
|
|
return { context: this._persistentContext, page };
|
|
|
|
}
|
|
|
|
|
|
|
|
private async _startRemoteServer(options?: RemoteServerOptions): Promise<RemoteServer> {
|
|
|
|
if (this._remoteServer)
|
|
|
|
throw new Error('can only start one remote server');
|
|
|
|
this._remoteServer = new RemoteServer();
|
|
|
|
await this._remoteServer._start(this._browserType, this._browserOptions, options);
|
|
|
|
return this._remoteServer;
|
|
|
|
}
|
|
|
|
|
|
|
|
async beforeEach({}, testInfo: folio.TestInfo): Promise<PlaywrightTestArgs> {
|
|
|
|
return {
|
|
|
|
createUserDataDir: this._createUserDataDir.bind(this),
|
|
|
|
launchPersistent: this._launchPersistent.bind(this),
|
|
|
|
startRemoteServer: this._startRemoteServer.bind(this),
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
async afterEach({}, testInfo: folio.TestInfo) {
|
|
|
|
if (this._persistentContext) {
|
|
|
|
await this._persistentContext.close();
|
|
|
|
this._persistentContext = undefined;
|
|
|
|
}
|
|
|
|
if (this._remoteServer) {
|
|
|
|
await this._remoteServer.close();
|
|
|
|
this._remoteServer = undefined;
|
|
|
|
}
|
|
|
|
await removeFolders(this._userDataDirs);
|
|
|
|
this._userDataDirs = [];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
type BrowserTestArgs = {
|
2021-04-01 16:35:26 -07:00
|
|
|
browser: Browser;
|
2021-04-29 11:11:32 -07:00
|
|
|
browserVersion: string;
|
2021-04-01 16:35:26 -07:00
|
|
|
contextOptions: BrowserContextOptions;
|
|
|
|
contextFactory: (options?: BrowserContextOptions) => Promise<BrowserContext>;
|
|
|
|
};
|
|
|
|
|
2021-04-29 11:11:32 -07:00
|
|
|
class BrowserEnv {
|
|
|
|
private _browser: Browser | undefined;
|
|
|
|
private _contexts: BrowserContext[] = [];
|
|
|
|
protected _browserVersion: string;
|
|
|
|
|
2021-04-30 13:26:13 -07:00
|
|
|
async beforeAll(args: PlaywrightWorkerArgs, workerInfo: folio.WorkerInfo) {
|
2021-04-29 11:11:32 -07:00
|
|
|
this._browser = await args.browserType.launch(args.browserOptions);
|
|
|
|
this._browserVersion = this._browser.version();
|
|
|
|
}
|
|
|
|
|
2021-04-30 13:26:13 -07:00
|
|
|
async beforeEach(options: CommonArgs, testInfo: folio.TestInfo): Promise<BrowserTestArgs> {
|
2021-04-29 11:11:32 -07:00
|
|
|
const debugName = path.relative(testInfo.config.outputDir, testInfo.outputDir).replace(/[\/\\]/g, '-');
|
|
|
|
const contextOptions = {
|
|
|
|
recordVideo: options.video ? { dir: testInfo.outputPath('') } : undefined,
|
|
|
|
_debugName: debugName,
|
|
|
|
} as BrowserContextOptions;
|
|
|
|
|
|
|
|
testInfo.data.browserVersion = this._browserVersion;
|
|
|
|
|
|
|
|
const contextFactory = async (options: BrowserContextOptions = {}) => {
|
|
|
|
const context = await this._browser.newContext({ ...contextOptions, ...options });
|
|
|
|
this._contexts.push(context);
|
|
|
|
return context;
|
|
|
|
};
|
|
|
|
|
|
|
|
return {
|
|
|
|
browser: this._browser,
|
|
|
|
browserVersion: this._browserVersion,
|
2021-04-30 13:26:13 -07:00
|
|
|
contextOptions,
|
2021-04-29 11:11:32 -07:00
|
|
|
contextFactory,
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
|
|
|
async afterEach({}, testInfo: folio.TestInfo) {
|
|
|
|
for (const context of this._contexts)
|
|
|
|
await context.close();
|
|
|
|
this._contexts = [];
|
|
|
|
}
|
|
|
|
|
|
|
|
async afterAll({}, workerInfo: folio.WorkerInfo) {
|
|
|
|
if (this._browser)
|
|
|
|
await this._browser.close();
|
|
|
|
this._browser = undefined;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class ContextEnv {
|
2021-04-30 13:26:13 -07:00
|
|
|
async beforeEach(args: BrowserTestArgs, testInfo: folio.TestInfo) {
|
2021-04-29 11:11:32 -07:00
|
|
|
const context = await args.contextFactory();
|
|
|
|
const page = await context.newPage();
|
2021-04-30 13:26:13 -07:00
|
|
|
return { context, page };
|
2021-04-29 11:11:32 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-04-30 13:26:13 -07:00
|
|
|
export const playwrightTest = baseTest.extend(new PlaywrightEnv());
|
|
|
|
export const slowPlaywrightTest = baseTest.extend(new PlaywrightEnv());
|
|
|
|
export const browserTest = playwrightTest.extend(new BrowserEnv());
|
|
|
|
export const slowBrowserTest = slowPlaywrightTest.extend(new BrowserEnv());
|
2021-04-29 11:11:32 -07:00
|
|
|
export const contextTest = browserTest.extend(new ContextEnv());
|
2021-04-30 07:40:22 -07:00
|
|
|
export const tracingTest = baseTest.extend(new PlaywrightEnv()).extend(new BrowserEnv()).extend(new ContextEnv());
|
2021-04-29 11:11:32 -07:00
|
|
|
|
|
|
|
export { expect } from 'folio';
|