mirror of
https://github.com/microsoft/playwright.git
synced 2024-10-27 05:46:28 +03:00
test: roll to folio@0.4.0-alpha3 (#6262)
This commit is contained in:
parent
2333eb09a6
commit
11882cdda7
24
package-lock.json
generated
24
package-lock.json
generated
@ -8140,9 +8140,9 @@
|
||||
}
|
||||
},
|
||||
"folio": {
|
||||
"version": "0.3.21-alpha",
|
||||
"resolved": "https://registry.npmjs.org/folio/-/folio-0.3.21-alpha.tgz",
|
||||
"integrity": "sha512-gCP36QBOAfVWOWydY2vJi32mV+7mUYr+o0c+Jw25edAfZCZndkztIMpvB9dXAKct1g5f7wY5n1bTBH0ZunMWXg==",
|
||||
"version": "0.4.0-alpha4",
|
||||
"resolved": "https://registry.npmjs.org/folio/-/folio-0.4.0-alpha4.tgz",
|
||||
"integrity": "sha512-/M8DQEPg2H6HuBgcCN8A5xa/s7wS5Dsu9F0jUHXv6dft+qvgMQY9TWi998EWZ7jn7SxakBnpLRUPbrLFiyIK0g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@babel/code-frame": "^7.10.4",
|
||||
@ -10034,9 +10034,9 @@
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
|
||||
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
|
||||
"integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
@ -10125,9 +10125,9 @@
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
|
||||
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
|
||||
"integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
@ -10193,9 +10193,9 @@
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
|
||||
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
|
||||
"version": "4.1.1",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.1.tgz",
|
||||
"integrity": "sha512-diHzdDKxcU+bAsUboHLPEDQiw0qEe0qd7SYUn3HgcFlWgbDcfLGswOHYeGrHKzG9z6UYf01d9VFMfZxPM1xZSg==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
|
@ -87,7 +87,7 @@
|
||||
"eslint-plugin-notice": "^0.9.10",
|
||||
"eslint-plugin-react-hooks": "^4.2.0",
|
||||
"file-loader": "^6.1.0",
|
||||
"folio": "=0.3.21-alpha",
|
||||
"folio": "=0.4.0-alpha4",
|
||||
"formidable": "^1.2.2",
|
||||
"html-webpack-plugin": "^4.4.1",
|
||||
"ncp": "^2.0.0",
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test, expect } from '../config/androidTest';
|
||||
import { androidTest as test, expect } from '../config/androidTest';
|
||||
|
||||
test('androidDevice.model', async function({ androidDevice }) {
|
||||
expect(androidDevice.model()).toBe('sdk_gphone_x86_arm');
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
import fs from 'fs';
|
||||
import { PNG } from 'pngjs';
|
||||
import { test, expect } from '../config/androidTest';
|
||||
import { androidTest as test, expect } from '../config/androidTest';
|
||||
|
||||
test('androidDevice.shell', async function({ androidDevice }) {
|
||||
const output = await androidDevice.shell('echo 123');
|
||||
@ -28,7 +28,7 @@ test('androidDevice.open', async function({ androidDevice }) {
|
||||
await socket.write(Buffer.from('321\n'));
|
||||
const output = await new Promise(resolve => socket.on('data', resolve));
|
||||
expect(output.toString()).toBe('321\n');
|
||||
const closedPromise = new Promise(resolve => socket.on('close', resolve));
|
||||
const closedPromise = new Promise<void>(resolve => socket.on('close', resolve));
|
||||
await socket.close();
|
||||
await closedPromise;
|
||||
});
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test, expect } from '../config/androidTest';
|
||||
import { androidTest as test, expect } from '../config/androidTest';
|
||||
|
||||
test('androidDevice.webView', async function({ androidDevice }) {
|
||||
expect(androidDevice.webViews().length).toBe(0);
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/contextTest';
|
||||
import { contextTest as it, expect } from './config/browserTest';
|
||||
|
||||
it('should close browser with beforeunload page', async ({server, browserType, browserOptions }) => {
|
||||
const browser = await browserType.launch(browserOptions);
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test, expect } from './config/browserTest';
|
||||
import { browserTest as test, expect } from './config/browserTest';
|
||||
|
||||
test('should create new page', async function({browser}) {
|
||||
const page1 = await browser.newPage();
|
||||
|
@ -15,8 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/contextTest';
|
||||
import { slowTest as playwrightTest } from './config/playwrightTest';
|
||||
import { contextTest as it, slowPlaywrightTest, expect } from './config/browserTest';
|
||||
|
||||
it('should work', async ({context, page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
@ -158,7 +157,7 @@ it('should isolate send cookie header', async ({server, context, browser}) => {
|
||||
}
|
||||
});
|
||||
|
||||
playwrightTest('should isolate cookies between launches', async ({browserType, server, browserOptions}) => {
|
||||
slowPlaywrightTest('should isolate cookies between launches', async ({browserType, server, browserOptions}) => {
|
||||
const browser1 = await browserType.launch(browserOptions);
|
||||
const context1 = await browser1.newContext();
|
||||
await context1.addCookies([{url: server.EMPTY_PAGE, name: 'cookie-in-context-1', value: 'value', expires: Date.now() / 1000 + 10000}]);
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/contextTest';
|
||||
import { contextTest as it, expect } from './config/browserTest';
|
||||
|
||||
it('should work with browser context scripts', async ({ context, server }) => {
|
||||
await context.addInitScript(() => window['temp'] = 123);
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/browserTest';
|
||||
import { browserTest as it, expect } from './config/browserTest';
|
||||
import { verifyViewport } from './config/utils';
|
||||
|
||||
it('should create new context', async function({browser}) {
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/contextTest';
|
||||
import { contextTest as it, expect } from './config/browserTest';
|
||||
|
||||
it('should clear cookies', async ({context, page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/contextTest';
|
||||
import { contextTest as it, expect } from './config/browserTest';
|
||||
|
||||
it('should return no cookies in pristine browser context', async ({context, page, server}) => {
|
||||
expect(await context.cookies()).toEqual([]);
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/browserTest';
|
||||
import { browserTest as it, expect } from './config/browserTest';
|
||||
|
||||
it('should fail without credentials', async ({browser, server, browserName, headful}) => {
|
||||
it.fail(browserName === 'chromium' && headful);
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/browserTest';
|
||||
import { browserTest as it, expect } from './config/browserTest';
|
||||
import { attachFrame } from './config/utils';
|
||||
|
||||
it('should bypass CSP meta tag', async ({browser, server}) => {
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/browserTest';
|
||||
import { browserTest as it, expect } from './config/browserTest';
|
||||
|
||||
it.describe('device', () => {
|
||||
it.beforeEach(async ({browserName}) => {
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/browserTest';
|
||||
import { browserTest as it, expect } from './config/browserTest';
|
||||
|
||||
it('should fetch lodpi assets', async ({ contextFactory, server}) => {
|
||||
const context = await contextFactory({
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/contextTest';
|
||||
import { contextTest as it, expect } from './config/browserTest';
|
||||
|
||||
it('expose binding should work', async ({context}) => {
|
||||
let bindingSource;
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/browserTest';
|
||||
import { browserTest as it, expect } from './config/browserTest';
|
||||
|
||||
it('should affect accept-language header', async ({browser, server}) => {
|
||||
const context = await browser.newContext({ locale: 'fr-CH' });
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/browserTest';
|
||||
import { browserTest as it, expect } from './config/browserTest';
|
||||
|
||||
it('should have url', async ({browser, server}) => {
|
||||
const context = await browser.newContext();
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/browserTest';
|
||||
import { browserTest as it, expect } from './config/browserTest';
|
||||
import type { Browser } from '../index';
|
||||
|
||||
let browser: Browser;
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/browserTest';
|
||||
import { browserTest as it, expect } from './config/browserTest';
|
||||
|
||||
it('should intercept', async ({browser, server}) => {
|
||||
const context = await browser.newContext();
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/browserTest';
|
||||
import { browserTest as it, expect } from './config/browserTest';
|
||||
|
||||
it('should override extra headers from browser context', async ({browser, server}) => {
|
||||
const context = await browser.newContext({
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/browserTest';
|
||||
import { browserTest as it, expect } from './config/browserTest';
|
||||
import fs from 'fs';
|
||||
|
||||
it('should capture local storage', async ({ contextFactory }) => {
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/browserTest';
|
||||
import { browserTest as it, expect } from './config/browserTest';
|
||||
|
||||
it('should work', async ({ browser }) => {
|
||||
const func = () => new Date(1479579154987).toString();
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/browserTest';
|
||||
import { browserTest as it, expect } from './config/browserTest';
|
||||
import { attachFrame } from './config/utils';
|
||||
|
||||
it('should work', async ({browser, server}) => {
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/browserTest';
|
||||
import { browserTest as it, expect } from './config/browserTest';
|
||||
|
||||
it.describe('mobile viewport', () => {
|
||||
it.beforeEach(async ({ browserName }) => {
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/pageTest';
|
||||
import { test as browserTest } from './config/browserTest';
|
||||
import { browserTest } from './config/browserTest';
|
||||
import { verifyViewport } from './config/utils';
|
||||
|
||||
it.beforeEach(async ({ isElectron, isAndroid }) => {
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import fs from 'fs';
|
||||
import { test, expect } from './config/playwrightTest';
|
||||
import { playwrightTest as test, expect } from './config/browserTest';
|
||||
|
||||
test('browserType.executablePath should work', async ({ browserType, browserChannel, browserOptions }) => {
|
||||
test.skip(!!browserChannel, 'We skip browser download when testing a channel');
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { slowTest as test, expect } from './config/playwrightTest';
|
||||
import { slowPlaywrightTest as test, expect } from './config/browserTest';
|
||||
import fs from 'fs';
|
||||
import * as path from 'path';
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/playwrightTest';
|
||||
import { playwrightTest as it, expect } from './config/browserTest';
|
||||
|
||||
it.describe('launch server', () => {
|
||||
it.beforeEach(async ({ mode}) => {
|
||||
@ -45,7 +45,7 @@ it.describe('launch server', () => {
|
||||
it('should fire "close" event during kill', async ({browserType, browserOptions}) => {
|
||||
const order = [];
|
||||
const browserServer = await browserType.launchServer(browserOptions);
|
||||
const closedPromise = new Promise(f => browserServer.on('close', () => {
|
||||
const closedPromise = new Promise<void>(f => browserServer.on('close', () => {
|
||||
order.push('closed');
|
||||
f();
|
||||
}));
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, slowTest, expect } from './config/playwrightTest';
|
||||
import { playwrightTest as it, slowPlaywrightTest as slowTest, expect } from './config/browserTest';
|
||||
|
||||
it('should reject all promises when browser is closed', async ({browserType, browserOptions}) => {
|
||||
const browser = await browserType.launch(browserOptions);
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
import os from 'os';
|
||||
import url from 'url';
|
||||
import { test as it, expect } from './config/contextTest';
|
||||
import { contextTest as it, expect } from './config/browserTest';
|
||||
|
||||
it('Web Assembly should work', async function({page, server, browserName, platform}) {
|
||||
it.fail(browserName === 'webkit' && platform === 'win32');
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import domain from 'domain';
|
||||
import { test as it, expect } from './config/playwrightTest';
|
||||
import { playwrightTest as it, expect } from './config/browserTest';
|
||||
|
||||
it('should scope context handles', async ({browserType, browserOptions, server}) => {
|
||||
const browser = await browserType.launch(browserOptions);
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import { test as pageTest, expect } from '../config/pageTest';
|
||||
import { test as playwrightTest } from '../config/playwrightTest';
|
||||
import { playwrightTest } from '../config/browserTest';
|
||||
import http from 'http';
|
||||
|
||||
pageTest.describe('chromium', () => {
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from '../config/playwrightTest';
|
||||
import { playwrightTest as it, expect } from '../config/browserTest';
|
||||
|
||||
it.beforeEach(async ({ browserName }) => {
|
||||
it.skip(browserName !== 'chromium');
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from '../config/playwrightTest';
|
||||
import { playwrightTest as it, expect } from '../config/browserTest';
|
||||
import type { Browser, Page } from '../../index';
|
||||
|
||||
it.describe('oopif', () => {
|
||||
|
@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import { test as it, expect } from '../config/pageTest';
|
||||
import { test as browserTest } from '../config/browserTest';
|
||||
import { browserTest } from '../config/browserTest';
|
||||
|
||||
it.describe('session', () => {
|
||||
it.beforeEach(async ({ browserName }) => {
|
||||
@ -58,7 +58,7 @@ it.describe('session', () => {
|
||||
page.on('console', console.log);
|
||||
// generate a script in page and wait for the event.
|
||||
await Promise.all([
|
||||
new Promise(f => client.on('Debugger.scriptParsed', event => {
|
||||
new Promise<void>(f => client.on('Debugger.scriptParsed', event => {
|
||||
if (event.url === 'foo.js')
|
||||
f();
|
||||
})),
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from '../config/browserTest';
|
||||
import { browserTest as it, expect } from '../config/browserTest';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test, expect } from '../config/cliTest';
|
||||
import { cliTest as test, expect } from '../config/cliTest';
|
||||
import * as http from 'http';
|
||||
|
||||
test.describe('cli codegen', () => {
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test, expect } from '../config/cliTest';
|
||||
import { cliTest as test, expect } from '../config/cliTest';
|
||||
import * as http from 'http';
|
||||
import * as url from 'url';
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
import { test, expect } from '../config/cliTest';
|
||||
import { cliTest as test, expect } from '../config/cliTest';
|
||||
|
||||
const emptyHTML = new URL('file://' + path.join(__dirname, '..', 'assets', 'empty.html')).toString();
|
||||
const launchOptions = (channel: string) => {
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { test, expect } from '../config/cliTest';
|
||||
import { cliTest as test, expect } from '../config/cliTest';
|
||||
|
||||
const emptyHTML = new URL('file://' + path.join(__dirname, '..', 'assets', 'empty.html')).toString();
|
||||
const launchOptions = (channel: string) => {
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { test, expect } from '../config/cliTest';
|
||||
import { cliTest as test, expect } from '../config/cliTest';
|
||||
|
||||
const emptyHTML = new URL('file://' + path.join(__dirname, '..', 'assets', 'empty.html')).toString();
|
||||
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { test, expect } from '../config/cliTest';
|
||||
import { cliTest as test, expect } from '../config/cliTest';
|
||||
|
||||
const emptyHTML = new URL('file://' + path.join(__dirname, '..', 'assets', 'empty.html')).toString();
|
||||
const launchOptions = (channel: string) => {
|
||||
|
@ -16,7 +16,7 @@
|
||||
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { test, expect } from '../config/cliTest';
|
||||
import { cliTest as test, expect } from '../config/cliTest';
|
||||
|
||||
const emptyHTML = new URL('file://' + path.join(__dirname, '..', 'assets', 'empty.html')).toString();
|
||||
const launchOptions = (channel: string) => {
|
||||
|
@ -17,9 +17,8 @@
|
||||
import * as folio from 'folio';
|
||||
import * as path from 'path';
|
||||
import { test as pageTest } from './pageTest';
|
||||
import { test as androidTest } from './androidTest';
|
||||
import { ServerEnv } from './serverEnv';
|
||||
import { AndroidEnv, AndroidPageEnv } from './androidEnv';
|
||||
import { AndroidEnv, androidTest } from './androidTest';
|
||||
import type { BrowserContext } from '../../index';
|
||||
|
||||
const config: folio.Config = {
|
||||
testDir: path.join(__dirname, '..'),
|
||||
@ -41,6 +40,34 @@ if (process.env.CI) {
|
||||
]);
|
||||
}
|
||||
|
||||
const serverEnv = new ServerEnv('10.0.2.2');
|
||||
pageTest.runWith(folio.merge(serverEnv, new AndroidPageEnv()), { tag: 'android' });
|
||||
androidTest.runWith(folio.merge(serverEnv, new AndroidEnv()), { tag: 'android' });
|
||||
class AndroidPageEnv extends AndroidEnv {
|
||||
private _context?: BrowserContext;
|
||||
|
||||
async beforeAll(args: any, workerInfo: folio.WorkerInfo) {
|
||||
await super.beforeAll(args, workerInfo);
|
||||
this._context = await this._device!.launchBrowser();
|
||||
}
|
||||
|
||||
async beforeEach(args: any, testInfo: folio.TestInfo) {
|
||||
const result = await super.beforeEach(args, testInfo);
|
||||
const page = await this._context!.newPage();
|
||||
return { ...result, browserVersion: this._browserVersion, page };
|
||||
}
|
||||
|
||||
async afterEach({}, testInfo: folio.TestInfo) {
|
||||
for (const page of this._context!.pages())
|
||||
await page.close();
|
||||
}
|
||||
}
|
||||
|
||||
const envConfig = {
|
||||
tag: 'android',
|
||||
options: {
|
||||
mode: 'default' as const,
|
||||
engine: 'android' as const,
|
||||
loopback: '10.0.2.2',
|
||||
}
|
||||
};
|
||||
|
||||
pageTest.runWith(envConfig, new AndroidPageEnv());
|
||||
androidTest.runWith(envConfig);
|
||||
|
@ -1,103 +0,0 @@
|
||||
/**
|
||||
* 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 { Env, WorkerInfo, TestInfo } from 'folio';
|
||||
import type { AndroidDevice, BrowserContext } from '../../index';
|
||||
import * as os from 'os';
|
||||
import { AndroidTestArgs } from './androidTest';
|
||||
import { PageTestArgs } from './pageTest';
|
||||
|
||||
require('../../lib/utils/utils').setUnderTest();
|
||||
const playwright: typeof import('../../index') = require('../../index');
|
||||
|
||||
export class AndroidEnv implements Env<AndroidTestArgs> {
|
||||
protected _device?: AndroidDevice;
|
||||
protected _browserVersion: string;
|
||||
|
||||
async beforeAll(workerInfo: WorkerInfo) {
|
||||
this._device = (await playwright._android.devices())[0];
|
||||
await this._device.shell('am force-stop org.chromium.webview_shell');
|
||||
await this._device.shell('am force-stop com.android.chrome');
|
||||
this._browserVersion = (await this._device.shell('dumpsys package com.android.chrome'))
|
||||
.toString('utf8')
|
||||
.split('\n')
|
||||
.find(line => line.includes('versionName='))
|
||||
.trim()
|
||||
.split('=')[1];
|
||||
this._device.setDefaultTimeout(90000);
|
||||
}
|
||||
|
||||
async beforeEach(testInfo: TestInfo) {
|
||||
// Use chromium screenshots.
|
||||
testInfo.snapshotPathSegment = 'chromium';
|
||||
testInfo.data = {
|
||||
browserName: 'chromium',
|
||||
platform: 'Android',
|
||||
headful: true,
|
||||
browserVersion: this._browserVersion,
|
||||
};
|
||||
return {
|
||||
mode: 'default' as const,
|
||||
isChromium: true,
|
||||
isFirefox: false,
|
||||
isWebKit: false,
|
||||
isAndroid: true,
|
||||
isElectron: false,
|
||||
browserName: 'chromium' as const,
|
||||
browserChannel: undefined,
|
||||
isWindows: os.platform() === 'win32',
|
||||
isMac: os.platform() === 'darwin',
|
||||
isLinux: os.platform() === 'linux',
|
||||
platform: os.platform() as ('win32' | 'darwin' | 'linux'),
|
||||
video: false,
|
||||
headful: true,
|
||||
toImpl: (playwright as any)._toImpl,
|
||||
playwright,
|
||||
androidDevice: this._device!,
|
||||
};
|
||||
}
|
||||
|
||||
async afterAll(workerInfo: WorkerInfo) {
|
||||
if (this._device)
|
||||
await this._device.close();
|
||||
this._device = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export class AndroidPageEnv extends AndroidEnv implements Env<PageTestArgs> {
|
||||
private _context?: BrowserContext;
|
||||
|
||||
async beforeAll(workerInfo: WorkerInfo) {
|
||||
await super.beforeAll(workerInfo);
|
||||
this._context = await this._device!.launchBrowser();
|
||||
}
|
||||
|
||||
async beforeEach(testInfo: TestInfo) {
|
||||
const result = await super.beforeEach(testInfo);
|
||||
const page = await this._context!.newPage();
|
||||
return {
|
||||
...result,
|
||||
browserVersion: this._browserVersion,
|
||||
androidDevice: undefined,
|
||||
page,
|
||||
};
|
||||
}
|
||||
|
||||
async afterEach(testInfo: TestInfo) {
|
||||
for (const page of this._context!.pages())
|
||||
await page.close();
|
||||
}
|
||||
}
|
@ -14,14 +14,46 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { newTestType } from 'folio';
|
||||
import type { AndroidDevice } from '../../index';
|
||||
import type { CommonTestArgs } from './pageTest';
|
||||
import type { ServerTestArgs } from './serverTest';
|
||||
import { CommonWorkerArgs, test as baseTest } from './baseTest';
|
||||
import * as folio from 'folio';
|
||||
export { expect } from 'folio';
|
||||
|
||||
export type AndroidTestArgs = CommonTestArgs & {
|
||||
type AndroidTestArgs = {
|
||||
androidDevice: AndroidDevice;
|
||||
};
|
||||
|
||||
export const test = newTestType<AndroidTestArgs & ServerTestArgs>();
|
||||
export class AndroidEnv {
|
||||
protected _device?: AndroidDevice;
|
||||
protected _browserVersion: string;
|
||||
|
||||
async beforeAll(args: CommonWorkerArgs, workerInfo: folio.WorkerInfo) {
|
||||
this._device = (await args.playwright._android.devices())[0];
|
||||
await this._device.shell('am force-stop org.chromium.webview_shell');
|
||||
await this._device.shell('am force-stop com.android.chrome');
|
||||
this._browserVersion = (await this._device.shell('dumpsys package com.android.chrome'))
|
||||
.toString('utf8')
|
||||
.split('\n')
|
||||
.find(line => line.includes('versionName='))
|
||||
.trim()
|
||||
.split('=')[1];
|
||||
this._device.setDefaultTimeout(90000);
|
||||
}
|
||||
|
||||
async beforeEach({}, testInfo: folio.TestInfo): Promise<AndroidTestArgs> {
|
||||
testInfo.data.platform = 'Android';
|
||||
testInfo.data.headful = true;
|
||||
testInfo.data.browserVersion = this._browserVersion;
|
||||
return {
|
||||
androidDevice: this._device!,
|
||||
};
|
||||
}
|
||||
|
||||
async afterAll({}, workerInfo: folio.WorkerInfo) {
|
||||
if (this._device)
|
||||
await this._device.close();
|
||||
this._device = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
export const androidTest = baseTest.extend(new AndroidEnv());
|
||||
|
296
tests/config/baseTest.ts
Normal file
296
tests/config/baseTest.ts
Normal file
@ -0,0 +1,296 @@
|
||||
/**
|
||||
* 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 { TestServer } from '../../utils/testserver';
|
||||
import * as folio from 'folio';
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
import socks from 'socksv5';
|
||||
import { installCoverageHooks } from './coverage';
|
||||
import * as childProcess from 'child_process';
|
||||
import { start } from '../../lib/outofprocess';
|
||||
import { PlaywrightClient } from '../../lib/remote/playwrightClient';
|
||||
|
||||
export type BrowserName = 'chromium' | 'firefox' | 'webkit';
|
||||
type Mode = 'default' | 'driver' | 'service';
|
||||
type BaseTestArgs = {
|
||||
mode: Mode;
|
||||
platform: 'win32' | 'darwin' | 'linux';
|
||||
video: boolean;
|
||||
headful: boolean;
|
||||
|
||||
playwright: typeof import('../../index');
|
||||
toImpl: (rpcObject: any) => any;
|
||||
browserName: BrowserName;
|
||||
browserChannel: string | undefined;
|
||||
|
||||
isChromium: boolean;
|
||||
isFirefox: boolean;
|
||||
isWebKit: boolean;
|
||||
isAndroid: boolean;
|
||||
isElectron: boolean;
|
||||
isWindows: boolean;
|
||||
isMac: boolean;
|
||||
isLinux: boolean;
|
||||
};
|
||||
|
||||
type BaseWorkerArgs = {
|
||||
playwright: typeof import('../../index');
|
||||
browserName: BrowserName;
|
||||
channel: string | undefined;
|
||||
};
|
||||
|
||||
type BaseOptions = {
|
||||
mode: Mode;
|
||||
engine: 'chromium' | 'firefox' | 'webkit' | 'android' | 'electron';
|
||||
channel?: string;
|
||||
video?: boolean;
|
||||
headful?: boolean;
|
||||
};
|
||||
|
||||
class DriverMode {
|
||||
private _playwrightObject: any;
|
||||
|
||||
async setup(workerInfo: folio.WorkerInfo) {
|
||||
this._playwrightObject = await start();
|
||||
return this._playwrightObject;
|
||||
}
|
||||
|
||||
async teardown() {
|
||||
await this._playwrightObject.stop();
|
||||
}
|
||||
}
|
||||
|
||||
class ServiceMode {
|
||||
private _playwrightObejct: any;
|
||||
private _client: any;
|
||||
private _serviceProcess: childProcess.ChildProcess;
|
||||
|
||||
async setup(workerInfo: folio.WorkerInfo) {
|
||||
const port = 10507 + workerInfo.workerIndex;
|
||||
this._serviceProcess = childProcess.fork(path.join(__dirname, '..', '..', 'lib', 'cli', 'cli.js'), ['run-server', String(port)], {
|
||||
stdio: 'pipe'
|
||||
});
|
||||
this._serviceProcess.stderr.pipe(process.stderr);
|
||||
await new Promise<void>(f => {
|
||||
this._serviceProcess.stdout.on('data', data => {
|
||||
if (data.toString().includes('Listening on'))
|
||||
f();
|
||||
});
|
||||
});
|
||||
this._serviceProcess.on('exit', this._onExit);
|
||||
this._client = await PlaywrightClient.connect(`ws://localhost:${port}/ws`);
|
||||
this._playwrightObejct = this._client.playwright();
|
||||
return this._playwrightObejct;
|
||||
}
|
||||
|
||||
async teardown() {
|
||||
await this._client.close();
|
||||
this._serviceProcess.removeListener('exit', this._onExit);
|
||||
const processExited = new Promise(f => this._serviceProcess.on('exit', f));
|
||||
this._serviceProcess.kill();
|
||||
await processExited;
|
||||
}
|
||||
|
||||
private _onExit(exitCode, signal) {
|
||||
throw new Error(`Server closed with exitCode=${exitCode} signal=${signal}`);
|
||||
}
|
||||
}
|
||||
|
||||
class DefaultMode {
|
||||
async setup(workerInfo: folio.WorkerInfo) {
|
||||
return require('../../index');
|
||||
}
|
||||
|
||||
async teardown() {
|
||||
}
|
||||
}
|
||||
|
||||
class BaseEnv {
|
||||
private _mode: DriverMode | ServiceMode | DefaultMode;
|
||||
private _options: BaseOptions;
|
||||
private _playwright: typeof import('../../index');
|
||||
|
||||
optionsType(): BaseOptions {
|
||||
return {} as any;
|
||||
}
|
||||
|
||||
private _browserName(): BrowserName {
|
||||
return (this._options.engine === 'android' || this._options.engine === 'electron') ? 'chromium' : this._options.engine;
|
||||
}
|
||||
|
||||
async beforeAll(options: BaseOptions, workerInfo: folio.WorkerInfo): Promise<BaseWorkerArgs> {
|
||||
this._options = options;
|
||||
this._mode = {
|
||||
default: new DefaultMode(),
|
||||
service: new ServiceMode(),
|
||||
driver: new DriverMode(),
|
||||
}[this._options.mode];
|
||||
require('../../lib/utils/utils').setUnderTest();
|
||||
this._playwright = await this._mode.setup(workerInfo);
|
||||
return {
|
||||
playwright: this._playwright,
|
||||
browserName: this._browserName(),
|
||||
channel: this._options.channel,
|
||||
};
|
||||
}
|
||||
|
||||
async beforeEach({}, testInfo: folio.TestInfo): Promise<BaseTestArgs> {
|
||||
const browserName = this._browserName();
|
||||
testInfo.snapshotPathSegment = browserName;
|
||||
testInfo.data = {
|
||||
browserName,
|
||||
};
|
||||
if (this._options.headful)
|
||||
testInfo.data.headful = true;
|
||||
if (this._options.mode !== 'default')
|
||||
testInfo.data.mode = this._options.mode;
|
||||
if (this._options.video)
|
||||
testInfo.data.video = true;
|
||||
return {
|
||||
playwright: this._playwright,
|
||||
browserName,
|
||||
browserChannel: this._options.channel,
|
||||
isChromium: browserName === 'chromium',
|
||||
isFirefox: browserName === 'firefox',
|
||||
isWebKit: browserName === 'webkit',
|
||||
isAndroid: this._options.engine === 'android',
|
||||
isElectron: this._options.engine === 'electron',
|
||||
isWindows: process.platform === 'win32',
|
||||
isMac: process.platform === 'darwin',
|
||||
isLinux: process.platform === 'linux',
|
||||
headful: !!this._options.headful,
|
||||
video: !!this._options.video,
|
||||
mode: this._options.mode,
|
||||
platform: process.platform as ('win32' | 'darwin' | 'linux'),
|
||||
toImpl: (this._playwright as any)._toImpl,
|
||||
};
|
||||
}
|
||||
|
||||
async afterAll({}, workerInfo: folio.WorkerInfo) {
|
||||
await this._mode.teardown();
|
||||
}
|
||||
}
|
||||
|
||||
type ServerTestArgs = {
|
||||
asset: (path: string) => string;
|
||||
socksPort: number;
|
||||
server: TestServer;
|
||||
httpsServer: TestServer;
|
||||
};
|
||||
|
||||
type ServerOptions = {
|
||||
loopback?: string;
|
||||
};
|
||||
|
||||
class ServerEnv {
|
||||
private _server: TestServer;
|
||||
private _httpsServer: TestServer;
|
||||
private _socksServer: any;
|
||||
private _socksPort: number;
|
||||
|
||||
optionsType(): ServerOptions {
|
||||
return {};
|
||||
}
|
||||
|
||||
async beforeAll(options: ServerOptions, workerInfo: folio.WorkerInfo) {
|
||||
const assetsPath = path.join(__dirname, '..', 'assets');
|
||||
const cachedPath = path.join(__dirname, '..', 'assets', 'cached');
|
||||
|
||||
const port = 8907 + workerInfo.workerIndex * 3;
|
||||
this._server = await TestServer.create(assetsPath, port, options.loopback);
|
||||
this._server.enableHTTPCache(cachedPath);
|
||||
|
||||
const httpsPort = port + 1;
|
||||
this._httpsServer = await TestServer.createHTTPS(assetsPath, httpsPort, options.loopback);
|
||||
this._httpsServer.enableHTTPCache(cachedPath);
|
||||
|
||||
this._socksServer = socks.createServer((info, accept, deny) => {
|
||||
let socket;
|
||||
if ((socket = accept(true))) {
|
||||
// Catch and ignore ECONNRESET errors.
|
||||
socket.on('error', () => {});
|
||||
const body = '<html><title>Served by the SOCKS proxy</title></html>';
|
||||
socket.end([
|
||||
'HTTP/1.1 200 OK',
|
||||
'Connection: close',
|
||||
'Content-Type: text/html',
|
||||
'Content-Length: ' + Buffer.byteLength(body),
|
||||
'',
|
||||
body
|
||||
].join('\r\n'));
|
||||
}
|
||||
});
|
||||
this._socksPort = port + 2;
|
||||
this._socksServer.listen(this._socksPort, 'localhost');
|
||||
this._socksServer.useAuth(socks.auth.None());
|
||||
return {};
|
||||
}
|
||||
|
||||
async beforeEach({}, testInfo: folio.TestInfo): Promise<ServerTestArgs> {
|
||||
this._server.reset();
|
||||
this._httpsServer.reset();
|
||||
return {
|
||||
asset: (p: string) => path.join(__dirname, '..', 'assets', ...p.split('/')),
|
||||
server: this._server,
|
||||
httpsServer: this._httpsServer,
|
||||
socksPort: this._socksPort,
|
||||
};
|
||||
}
|
||||
|
||||
async afterAll({}, workerInfo: folio.WorkerInfo) {
|
||||
await Promise.all([
|
||||
this._server.stop(),
|
||||
this._httpsServer.stop(),
|
||||
this._socksServer.close(),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
type CoverageOptions = {
|
||||
coverageName?: string;
|
||||
};
|
||||
|
||||
class CoverageEnv {
|
||||
private _coverage: ReturnType<typeof installCoverageHooks> | undefined;
|
||||
|
||||
optionsType(): CoverageOptions {
|
||||
return {};
|
||||
}
|
||||
|
||||
async beforeAll(options: CoverageOptions, workerInfo: folio.WorkerInfo) {
|
||||
if (options.coverageName)
|
||||
this._coverage = installCoverageHooks(options.coverageName);
|
||||
return {};
|
||||
}
|
||||
|
||||
async afterAll({}, workerInfo: folio.WorkerInfo) {
|
||||
if (!this._coverage)
|
||||
return;
|
||||
const { coverage, uninstall } = this._coverage;
|
||||
uninstall();
|
||||
const coveragePath = path.join(__dirname, '..', 'coverage-report', workerInfo.workerIndex + '.json');
|
||||
const coverageJSON = Array.from(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');
|
||||
}
|
||||
}
|
||||
|
||||
export type CommonOptions = BaseOptions;
|
||||
export type CommonTestArgs = BaseTestArgs & ServerTestArgs;
|
||||
export type CommonWorkerArgs = BaseWorkerArgs;
|
||||
|
||||
export const test = folio.test.extend(new CoverageEnv()).extend(new ServerEnv()).extend(new BaseEnv());
|
@ -1,286 +0,0 @@
|
||||
/**
|
||||
* 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 { Env, WorkerInfo, TestInfo } from 'folio';
|
||||
import type { Browser, BrowserContext, BrowserContextOptions, BrowserType, LaunchOptions } from '../../index';
|
||||
import { start } from '../../lib/outofprocess';
|
||||
import { PlaywrightClient } from '../../lib/remote/playwrightClient';
|
||||
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 * as childProcess from 'child_process';
|
||||
import { PlaywrightTestArgs } from './playwrightTest';
|
||||
import { BrowserTestArgs } from './browserTest';
|
||||
import { RemoteServer, RemoteServerOptions } from './remoteServer';
|
||||
|
||||
const mkdtempAsync = util.promisify(fs.mkdtemp);
|
||||
|
||||
export type BrowserName = 'chromium' | 'firefox' | 'webkit';
|
||||
|
||||
type TestOptions = {
|
||||
mode: 'default' | 'driver' | 'service';
|
||||
video?: boolean;
|
||||
traceDir?: string;
|
||||
};
|
||||
|
||||
class DriverMode {
|
||||
private _playwrightObject: any;
|
||||
|
||||
async setup(workerInfo: WorkerInfo) {
|
||||
this._playwrightObject = await start();
|
||||
return this._playwrightObject;
|
||||
}
|
||||
|
||||
async teardown() {
|
||||
await this._playwrightObject.stop();
|
||||
}
|
||||
}
|
||||
|
||||
class ServiceMode {
|
||||
private _playwrightObejct: any;
|
||||
private _client: any;
|
||||
private _serviceProcess: childProcess.ChildProcess;
|
||||
|
||||
async setup(workerInfo: WorkerInfo) {
|
||||
const port = 10507 + workerInfo.workerIndex;
|
||||
this._serviceProcess = childProcess.fork(path.join(__dirname, '..', '..', 'lib', 'cli', 'cli.js'), ['run-server', String(port)], {
|
||||
stdio: 'pipe'
|
||||
});
|
||||
this._serviceProcess.stderr.pipe(process.stderr);
|
||||
await new Promise<void>(f => {
|
||||
this._serviceProcess.stdout.on('data', data => {
|
||||
if (data.toString().includes('Listening on'))
|
||||
f();
|
||||
});
|
||||
});
|
||||
this._serviceProcess.on('exit', this._onExit);
|
||||
this._client = await PlaywrightClient.connect(`ws://localhost:${port}/ws`);
|
||||
this._playwrightObejct = this._client.playwright();
|
||||
return this._playwrightObejct;
|
||||
}
|
||||
|
||||
async teardown() {
|
||||
await this._client.close();
|
||||
this._serviceProcess.removeListener('exit', this._onExit);
|
||||
const processExited = new Promise(f => this._serviceProcess.on('exit', f));
|
||||
this._serviceProcess.kill();
|
||||
await processExited;
|
||||
}
|
||||
|
||||
private _onExit(exitCode, signal) {
|
||||
throw new Error(`Server closed with exitCode=${exitCode} signal=${signal}`);
|
||||
}
|
||||
}
|
||||
|
||||
class DefaultMode {
|
||||
async setup(workerInfo: WorkerInfo) {
|
||||
return require('../../index');
|
||||
}
|
||||
|
||||
async teardown() {
|
||||
}
|
||||
}
|
||||
|
||||
export class PlaywrightEnv implements Env<PlaywrightTestArgs> {
|
||||
private _mode: DriverMode | ServiceMode | DefaultMode;
|
||||
protected _browserName: BrowserName;
|
||||
protected _options: LaunchOptions & TestOptions;
|
||||
protected _browserOptions: LaunchOptions;
|
||||
private _playwright: typeof import('../../index');
|
||||
protected _browserType: BrowserType;
|
||||
private _userDataDirs: string[] = [];
|
||||
private _persistentContext: BrowserContext | undefined;
|
||||
private _remoteServer: RemoteServer | undefined;
|
||||
|
||||
constructor(browserName: BrowserName, options: LaunchOptions & TestOptions) {
|
||||
this._browserName = browserName;
|
||||
this._options = options;
|
||||
this._mode = {
|
||||
default: new DefaultMode(),
|
||||
service: new ServiceMode(),
|
||||
driver: new DriverMode(),
|
||||
}[this._options.mode];
|
||||
}
|
||||
|
||||
async beforeAll(workerInfo: WorkerInfo) {
|
||||
require('../../lib/utils/utils').setUnderTest();
|
||||
this._playwright = await this._mode.setup(workerInfo);
|
||||
this._browserType = this._playwright[this._browserName];
|
||||
const options = {
|
||||
...this._options,
|
||||
_traceDir: this._options.traceDir,
|
||||
handleSIGINT: false,
|
||||
};
|
||||
this._browserOptions = options;
|
||||
}
|
||||
|
||||
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: TestInfo) {
|
||||
// Different screenshots per browser.
|
||||
testInfo.snapshotPathSegment = this._browserName;
|
||||
testInfo.data = {
|
||||
browserName: this._browserName,
|
||||
};
|
||||
const headful = !this._browserOptions.headless;
|
||||
if (headful)
|
||||
testInfo.data.headful = true;
|
||||
if (this._options.mode !== 'default')
|
||||
testInfo.data.mode = this._options.mode;
|
||||
if (this._options.video)
|
||||
testInfo.data.video = true;
|
||||
return {
|
||||
playwright: this._playwright,
|
||||
browserName: this._browserName,
|
||||
browserType: this._browserType,
|
||||
browserChannel: this._options.channel,
|
||||
browserOptions: this._browserOptions,
|
||||
isChromium: this._browserName === 'chromium',
|
||||
isFirefox: this._browserName === 'firefox',
|
||||
isWebKit: this._browserName === 'webkit',
|
||||
isAndroid: false,
|
||||
isElectron: false,
|
||||
isWindows: os.platform() === 'win32',
|
||||
isMac: os.platform() === 'darwin',
|
||||
isLinux: os.platform() === 'linux',
|
||||
headful,
|
||||
video: !!this._options.video,
|
||||
mode: this._options.mode,
|
||||
platform: os.platform() as ('win32' | 'darwin' | 'linux'),
|
||||
createUserDataDir: this._createUserDataDir.bind(this),
|
||||
launchPersistent: this._launchPersistent.bind(this),
|
||||
toImpl: (this._playwright as any)._toImpl,
|
||||
startRemoteServer: this._startRemoteServer.bind(this),
|
||||
};
|
||||
}
|
||||
|
||||
async afterEach(testInfo: 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 = [];
|
||||
}
|
||||
|
||||
async afterAll(workerInfo: WorkerInfo) {
|
||||
await this._mode.teardown();
|
||||
}
|
||||
}
|
||||
|
||||
export class BrowserEnv extends PlaywrightEnv implements Env<BrowserTestArgs> {
|
||||
private _browser: Browser | undefined;
|
||||
private _contextOptions: BrowserContextOptions;
|
||||
private _contexts: BrowserContext[] = [];
|
||||
protected _browserVersion: string;
|
||||
|
||||
constructor(browserName: BrowserName, options: LaunchOptions & BrowserContextOptions & TestOptions) {
|
||||
super(browserName, options);
|
||||
this._contextOptions = options;
|
||||
}
|
||||
|
||||
async beforeAll(workerInfo: WorkerInfo) {
|
||||
await super.beforeAll(workerInfo);
|
||||
this._browser = await this._browserType.launch(this._browserOptions);
|
||||
this._browserVersion = this._browser.version();
|
||||
}
|
||||
|
||||
async beforeEach(testInfo: TestInfo) {
|
||||
const result = await super.beforeEach(testInfo);
|
||||
const debugName = path.relative(testInfo.config.outputDir, testInfo.outputPath('')).replace(/[\/\\]/g, '-');
|
||||
const contextOptions = {
|
||||
recordVideo: this._options.video ? { dir: testInfo.outputPath('') } : undefined,
|
||||
_debugName: debugName,
|
||||
...this._contextOptions,
|
||||
} 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 {
|
||||
...result,
|
||||
browser: this._browser,
|
||||
contextOptions: this._contextOptions as BrowserContextOptions,
|
||||
contextFactory,
|
||||
};
|
||||
}
|
||||
|
||||
async afterEach(testInfo: TestInfo) {
|
||||
for (const context of this._contexts)
|
||||
await context.close();
|
||||
this._contexts = [];
|
||||
await super.afterEach(testInfo);
|
||||
}
|
||||
|
||||
async afterAll(workerInfo: WorkerInfo) {
|
||||
if (this._browser)
|
||||
await this._browser.close();
|
||||
this._browser = undefined;
|
||||
await super.afterAll(workerInfo);
|
||||
}
|
||||
}
|
||||
|
||||
export class PageEnv extends BrowserEnv {
|
||||
async beforeEach(testInfo: TestInfo) {
|
||||
const result = await super.beforeEach(testInfo);
|
||||
const context = await result.contextFactory();
|
||||
const page = await context.newPage();
|
||||
return {
|
||||
...result,
|
||||
browserVersion: this._browserVersion,
|
||||
context,
|
||||
page,
|
||||
};
|
||||
}
|
||||
}
|
@ -14,17 +14,200 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { newTestType } from 'folio';
|
||||
import type { Browser, BrowserContextOptions, BrowserContext } from '../../index';
|
||||
import type { PlaywrightTestArgs } from './playwrightTest';
|
||||
import type { ServerTestArgs } from './serverTest';
|
||||
export { expect } from 'folio';
|
||||
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';
|
||||
import { CommonOptions, CommonTestArgs, CommonWorkerArgs, test as baseTest } from './baseTest';
|
||||
|
||||
export type BrowserTestArgs = PlaywrightTestArgs & {
|
||||
const mkdtempAsync = util.promisify(fs.mkdtemp);
|
||||
|
||||
type PlaywrightTestArgs = {
|
||||
browserType: BrowserType;
|
||||
browserOptions: LaunchOptions;
|
||||
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;
|
||||
};
|
||||
|
||||
type PlaywrightEnvWorkerArgs = {
|
||||
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 {};
|
||||
}
|
||||
|
||||
async beforeAll(args: CommonWorkerArgs & PlaywrightEnvOptions & CommonOptions, workerInfo: folio.WorkerInfo): Promise<PlaywrightEnvWorkerArgs> {
|
||||
this._browserType = args.playwright[args.browserName];
|
||||
this._browserOptions = {
|
||||
...args.launchOptions,
|
||||
_traceDir: args.traceDir,
|
||||
channel: args.channel,
|
||||
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 {
|
||||
browserType: this._browserType,
|
||||
browserOptions: this._browserOptions,
|
||||
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 = [];
|
||||
}
|
||||
}
|
||||
|
||||
export const playwrightTest = baseTest.extend(new PlaywrightEnv());
|
||||
export const slowPlaywrightTest = baseTest.extend(new PlaywrightEnv());
|
||||
|
||||
type BrowserEnvOptions = {
|
||||
contextOptions?: BrowserContextOptions;
|
||||
};
|
||||
|
||||
type BrowserTestArgs = {
|
||||
browser: Browser;
|
||||
browserVersion: string;
|
||||
contextOptions: BrowserContextOptions;
|
||||
contextFactory: (options?: BrowserContextOptions) => Promise<BrowserContext>;
|
||||
};
|
||||
|
||||
export const test = newTestType<BrowserTestArgs & ServerTestArgs>();
|
||||
export const slowTest = newTestType<BrowserTestArgs & ServerTestArgs>();
|
||||
class BrowserEnv {
|
||||
private _browser: Browser | undefined;
|
||||
private _contextOptions: BrowserContextOptions;
|
||||
private _contexts: BrowserContext[] = [];
|
||||
protected _browserVersion: string;
|
||||
|
||||
optionsType(): BrowserEnvOptions {
|
||||
return {};
|
||||
}
|
||||
|
||||
async beforeAll(args: PlaywrightEnvWorkerArgs, workerInfo: folio.WorkerInfo) {
|
||||
this._browser = await args.browserType.launch(args.browserOptions);
|
||||
this._browserVersion = this._browser.version();
|
||||
}
|
||||
|
||||
async beforeEach(options: CommonTestArgs, testInfo: folio.TestInfo): Promise<BrowserTestArgs> {
|
||||
const debugName = path.relative(testInfo.config.outputDir, testInfo.outputDir).replace(/[\/\\]/g, '-');
|
||||
const contextOptions = {
|
||||
recordVideo: options.video ? { dir: testInfo.outputPath('') } : undefined,
|
||||
_debugName: debugName,
|
||||
...this._contextOptions,
|
||||
} 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,
|
||||
contextOptions: this._contextOptions as BrowserContextOptions,
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
export const browserTest = playwrightTest.extend(new BrowserEnv());
|
||||
export const slowBrowserTest = slowPlaywrightTest.extend(new BrowserEnv());
|
||||
|
||||
type ContextTestArgs = {
|
||||
context: BrowserContext;
|
||||
page: Page;
|
||||
};
|
||||
|
||||
class ContextEnv {
|
||||
async beforeEach(args: BrowserTestArgs, testInfo: folio.TestInfo): Promise<ContextTestArgs> {
|
||||
const context = await args.contextFactory();
|
||||
const page = await context.newPage();
|
||||
return {
|
||||
context,
|
||||
page,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export const contextTest = browserTest.extend(new ContextEnv());
|
||||
|
||||
export { expect } from 'folio';
|
||||
|
@ -1,83 +0,0 @@
|
||||
/**
|
||||
* 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 { Env, TestInfo, WorkerInfo } from 'folio';
|
||||
import { PageEnv } from './browserEnv';
|
||||
import { CLIMock, CLITestArgs, Recorder } from './cliTest';
|
||||
import * as http from 'http';
|
||||
import { chromium } from '../../index';
|
||||
|
||||
export class CLIEnv extends PageEnv implements Env<CLITestArgs> {
|
||||
private _server: http.Server | undefined;
|
||||
private _handler = (req: http.IncomingMessage, res: http.ServerResponse) => res.end();
|
||||
private _port: number;
|
||||
private _cli: CLIMock | undefined;
|
||||
|
||||
async beforeAll(workerInfo: WorkerInfo) {
|
||||
await super.beforeAll(workerInfo);
|
||||
|
||||
this._port = 10907 + workerInfo.workerIndex * 2;
|
||||
this._server = http.createServer((req: http.IncomingMessage, res: http.ServerResponse) => this._handler(req, res)).listen(this._port);
|
||||
process.env.PWTEST_RECORDER_PORT = String(this._port + 1);
|
||||
}
|
||||
|
||||
private _runCLI(args: string[]) {
|
||||
this._cli = new CLIMock(this._browserName, this._browserOptions.channel, !!this._browserOptions.headless, args);
|
||||
return this._cli;
|
||||
}
|
||||
|
||||
async beforeEach(testInfo: TestInfo) {
|
||||
const result = await super.beforeEach(testInfo);
|
||||
const { page, context, toImpl } = result;
|
||||
const recorderPageGetter = async () => {
|
||||
while (!toImpl(context).recorderAppForTest)
|
||||
await new Promise(f => setTimeout(f, 100));
|
||||
const wsEndpoint = toImpl(context).recorderAppForTest.wsEndpoint;
|
||||
const browser = await chromium.connectOverCDP({ wsEndpoint });
|
||||
const c = browser.contexts()[0];
|
||||
return c.pages()[0] || await c.waitForEvent('page');
|
||||
};
|
||||
return {
|
||||
...result,
|
||||
httpServer: {
|
||||
setHandler: newHandler => this._handler = newHandler,
|
||||
PREFIX: `http://127.0.0.1:${this._port}`,
|
||||
},
|
||||
runCLI: this._runCLI.bind(this),
|
||||
openRecorder: async () => {
|
||||
await (page.context() as any)._enableRecorder({ language: 'javascript', startRecording: true });
|
||||
return new Recorder(page, await recorderPageGetter());
|
||||
},
|
||||
recorderPageGetter,
|
||||
};
|
||||
}
|
||||
|
||||
async afterEach(testInfo: TestInfo) {
|
||||
if (this._cli) {
|
||||
await this._cli.exited;
|
||||
this._cli = undefined;
|
||||
}
|
||||
await super.afterEach(testInfo);
|
||||
}
|
||||
|
||||
async afterAll(workerInfo: WorkerInfo) {
|
||||
if (this._server) {
|
||||
this._server.close();
|
||||
this._server = undefined;
|
||||
}
|
||||
await super.afterAll(workerInfo);
|
||||
}
|
||||
}
|
@ -14,33 +14,78 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { newTestType } from 'folio';
|
||||
import type { Page, BrowserContext } from '../../index';
|
||||
import type { ServerTestArgs } from './serverTest';
|
||||
import type { BrowserTestArgs } from './browserTest';
|
||||
import { contextTest } from './browserTest';
|
||||
import type { Page } from '../../index';
|
||||
import * as http from 'http';
|
||||
import * as path from 'path';
|
||||
import type { Source } from '../../src/server/supplements/recorder/recorderTypes';
|
||||
import { ChildProcess, spawn } from 'child_process';
|
||||
import { chromium } from '../../index';
|
||||
import * as folio from 'folio';
|
||||
export { expect } from 'folio';
|
||||
|
||||
interface CLIHTTPServer {
|
||||
setHandler: (handler: http.RequestListener) => void
|
||||
PREFIX: string
|
||||
setHandler: (handler: http.RequestListener) => void;
|
||||
PREFIX: string;
|
||||
}
|
||||
|
||||
export type CLITestArgs = BrowserTestArgs & {
|
||||
page: Page;
|
||||
context: BrowserContext;
|
||||
type CLITestArgs = {
|
||||
httpServer: CLIHTTPServer;
|
||||
recorderPageGetter: () => Promise<Page>;
|
||||
openRecorder: () => Promise<Recorder>;
|
||||
runCLI: (args: string[]) => CLIMock;
|
||||
};
|
||||
|
||||
export const test = newTestType<CLITestArgs & ServerTestArgs>();
|
||||
export const cliTest = contextTest.extend({
|
||||
async beforeAll({}, workerInfo: folio.WorkerInfo) {
|
||||
this._port = 10907 + workerInfo.workerIndex * 2;
|
||||
this._server = http.createServer((req: http.IncomingMessage, res: http.ServerResponse) => this._handler(req, res)).listen(this._port);
|
||||
process.env.PWTEST_RECORDER_PORT = String(this._port + 1);
|
||||
},
|
||||
|
||||
export class Recorder {
|
||||
async beforeEach({ page, context, toImpl, browserName, browserChannel, headful, mode }, testInfo: folio.TestInfo): Promise<CLITestArgs> {
|
||||
testInfo.skip(mode === 'service');
|
||||
const recorderPageGetter = async () => {
|
||||
while (!toImpl(context).recorderAppForTest)
|
||||
await new Promise(f => setTimeout(f, 100));
|
||||
const wsEndpoint = toImpl(context).recorderAppForTest.wsEndpoint;
|
||||
const browser = await chromium.connectOverCDP({ wsEndpoint });
|
||||
const c = browser.contexts()[0];
|
||||
return c.pages()[0] || await c.waitForEvent('page');
|
||||
};
|
||||
return {
|
||||
httpServer: {
|
||||
setHandler: newHandler => this._handler = newHandler,
|
||||
PREFIX: `http://127.0.0.1:${this._port}`,
|
||||
},
|
||||
runCLI: (cliArgs: string[]) => {
|
||||
this._cli = new CLIMock(browserName, browserChannel, !headful, cliArgs);
|
||||
return this._cli;
|
||||
},
|
||||
openRecorder: async () => {
|
||||
await (page.context() as any)._enableRecorder({ language: 'javascript', startRecording: true });
|
||||
return new Recorder(page, await recorderPageGetter());
|
||||
},
|
||||
recorderPageGetter,
|
||||
};
|
||||
},
|
||||
|
||||
async afterEach({}, testInfo: folio.TestInfo) {
|
||||
if (this._cli) {
|
||||
await this._cli.exited;
|
||||
this._cli = undefined;
|
||||
}
|
||||
},
|
||||
|
||||
async afterAll({}, workerInfo: folio.WorkerInfo) {
|
||||
if (this._server) {
|
||||
this._server.close();
|
||||
this._server = undefined;
|
||||
}
|
||||
},
|
||||
});
|
||||
|
||||
class Recorder {
|
||||
page: Page;
|
||||
_highlightCallback: Function
|
||||
_highlightInstalled: boolean
|
||||
@ -129,7 +174,7 @@ export class Recorder {
|
||||
}
|
||||
}
|
||||
|
||||
export class CLIMock {
|
||||
class CLIMock {
|
||||
private process: ChildProcess;
|
||||
private data: string;
|
||||
private waitForText: string;
|
||||
|
@ -1,28 +0,0 @@
|
||||
/**
|
||||
* 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 { newTestType } from 'folio';
|
||||
import type { BrowserContext, Page } from '../../index';
|
||||
import type { BrowserTestArgs } from './browserTest';
|
||||
import type { ServerTestArgs } from './serverTest';
|
||||
export { expect } from 'folio';
|
||||
|
||||
// Context test guarantees an isolated context.
|
||||
export type ContextTestArgs = BrowserTestArgs & {
|
||||
context: BrowserContext;
|
||||
page: Page;
|
||||
};
|
||||
export const test = newTestType<ContextTestArgs & ServerTestArgs>();
|
@ -93,35 +93,6 @@ function installCoverageHooks(browserName) {
|
||||
return {coverage, uninstall};
|
||||
}
|
||||
|
||||
class CoverageEnv {
|
||||
/**
|
||||
* @param {string} browserName
|
||||
*/
|
||||
constructor(browserName) {
|
||||
this.browserName = browserName;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('folio').WorkerInfo} workerInfo
|
||||
*/
|
||||
async beforeAll(workerInfo) {
|
||||
this.coverage = installCoverageHooks(this.browserName);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param {import('folio').WorkerInfo} workerInfo
|
||||
*/
|
||||
async afterAll(workerInfo) {
|
||||
const { coverage, uninstall } = this.coverage;
|
||||
uninstall();
|
||||
const coveragePath = path.join(__dirname, '..', 'coverage-report', workerInfo.workerIndex + '.json');
|
||||
const coverageJSON = Array.from(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');
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
installCoverageHooks,
|
||||
CoverageEnv
|
||||
};
|
||||
|
@ -16,15 +16,10 @@
|
||||
|
||||
import * as folio from 'folio';
|
||||
import * as path from 'path';
|
||||
import { test as playwrightTest, slowTest as playwrightSlowTest } from './playwrightTest';
|
||||
import { test as browserTest, slowTest as browserSlowTest } from './browserTest';
|
||||
import { test as contextTest } from './contextTest';
|
||||
import { playwrightTest, slowPlaywrightTest, contextTest } from './browserTest';
|
||||
import { test as pageTest } from './pageTest';
|
||||
import { test as cliTest } from './cliTest';
|
||||
import { PlaywrightEnv, BrowserEnv, PageEnv, BrowserName } from './browserEnv';
|
||||
import { ServerEnv } from './serverEnv';
|
||||
import { CLIEnv } from './cliEnv';
|
||||
import { CoverageEnv } from './coverage';
|
||||
import { BrowserName, CommonTestArgs, CommonWorkerArgs } from './baseTest';
|
||||
import type { Browser, BrowserContext } from '../../index';
|
||||
|
||||
const config: folio.Config = {
|
||||
testDir: path.join(__dirname, '..'),
|
||||
@ -55,27 +50,69 @@ const getExecutablePath = (browserName: BrowserName) => {
|
||||
return process.env.WKPATH;
|
||||
};
|
||||
|
||||
type WorkerOptionsFor<T> = T extends folio.TestType<infer T, infer W, infer TO, infer WO> ? WO : any;
|
||||
type AllOptions = WorkerOptionsFor<typeof contextTest>;
|
||||
|
||||
class PageEnv {
|
||||
private _browser: Browser
|
||||
private _browserVersion: string;
|
||||
private _context: BrowserContext | undefined;
|
||||
|
||||
async beforeAll(args: AllOptions & CommonWorkerArgs, workerInfo: folio.WorkerInfo) {
|
||||
this._browser = await args.playwright[args.browserName].launch({
|
||||
...args.launchOptions,
|
||||
_traceDir: args.traceDir,
|
||||
channel: args.channel,
|
||||
headless: !args.headful,
|
||||
handleSIGINT: false,
|
||||
} as any);
|
||||
this._browserVersion = this._browser.version();
|
||||
return {};
|
||||
}
|
||||
|
||||
async beforeEach(args: AllOptions & CommonTestArgs, testInfo: folio.TestInfo) {
|
||||
testInfo.data.browserVersion = this._browserVersion;
|
||||
this._context = await this._browser.newContext({
|
||||
recordVideo: args.video ? { dir: testInfo.outputPath('') } : undefined,
|
||||
...args.contextOptions,
|
||||
});
|
||||
const page = await this._context.newPage();
|
||||
return { context: this._context, page, browserVersion: this._browserVersion };
|
||||
}
|
||||
|
||||
async afterEach({}) {
|
||||
if (this._context)
|
||||
await this._context.close();
|
||||
this._context = undefined;
|
||||
}
|
||||
|
||||
async afterAll({}, workerInfo: folio.WorkerInfo) {
|
||||
await this._browser.close();
|
||||
}
|
||||
}
|
||||
|
||||
const browsers = ['chromium', 'webkit', 'firefox'] as BrowserName[];
|
||||
for (const browserName of browsers) {
|
||||
const executablePath = getExecutablePath(browserName);
|
||||
if (executablePath && (process.env.FOLIO_WORKER_INDEX === undefined || process.env.FOLIO_WORKER_INDEX === ''))
|
||||
console.error(`Using executable at ${executablePath}`);
|
||||
const mode = (process.env.PWTEST_MODE || 'default') as ('default' | 'driver' | 'service');
|
||||
const options = {
|
||||
mode,
|
||||
executablePath,
|
||||
traceDir: process.env.PWTRACE ? path.join(config.outputDir, 'trace') : undefined,
|
||||
headless: !process.env.HEADFUL,
|
||||
channel: process.env.PWTEST_CHANNEL as any,
|
||||
video: !!process.env.PWTEST_VIDEO,
|
||||
const envConfig = {
|
||||
options: {
|
||||
mode,
|
||||
engine: browserName,
|
||||
headful: !!process.env.HEADFUL,
|
||||
channel: process.env.PWTEST_CHANNEL as any,
|
||||
video: !!process.env.PWTEST_VIDEO,
|
||||
traceDir: process.env.PWTRACE ? path.join(config.outputDir, 'trace') : undefined,
|
||||
launchOptions: {
|
||||
executablePath,
|
||||
},
|
||||
coverageName: browserName,
|
||||
},
|
||||
tag: browserName,
|
||||
};
|
||||
const commonEnv = folio.merge(new CoverageEnv(browserName), new ServerEnv());
|
||||
playwrightTest.runWith(folio.merge(commonEnv, new PlaywrightEnv(browserName, options)), { tag: browserName });
|
||||
playwrightSlowTest.runWith(folio.merge(commonEnv, new PlaywrightEnv(browserName, options)), { timeout: config.timeout * 3, tag: browserName });
|
||||
browserTest.runWith(folio.merge(commonEnv, new BrowserEnv(browserName, options)), { tag: browserName });
|
||||
browserSlowTest.runWith(folio.merge(commonEnv, new BrowserEnv(browserName, options)), { timeout: config.timeout * 3, tag: browserName });
|
||||
pageTest.runWith(folio.merge(commonEnv, new PageEnv(browserName, options)), { tag: browserName });
|
||||
contextTest.runWith(folio.merge(commonEnv, new PageEnv(browserName, options)), { tag: browserName });
|
||||
if (mode !== 'service')
|
||||
cliTest.runWith(folio.merge(commonEnv, new CLIEnv(browserName, options)), { tag: browserName });
|
||||
playwrightTest.runWith(envConfig);
|
||||
slowPlaywrightTest.runWith({ ...envConfig, timeout: config.timeout * 3 });
|
||||
pageTest.runWith(envConfig, new PageEnv());
|
||||
}
|
||||
|
@ -16,11 +16,8 @@
|
||||
|
||||
import * as folio from 'folio';
|
||||
import * as path from 'path';
|
||||
import { test as electronTest } from './electronTest';
|
||||
import { ElectronEnv, electronTest } from './electronTest';
|
||||
import { test as pageTest } from './pageTest';
|
||||
import { ServerEnv } from './serverEnv';
|
||||
import { ElectronEnv, ElectronPageEnv } from './electronEnv';
|
||||
import { CoverageEnv } from './coverage';
|
||||
|
||||
const config: folio.Config = {
|
||||
testDir: path.join(__dirname, '..'),
|
||||
@ -42,7 +39,26 @@ if (process.env.CI) {
|
||||
]);
|
||||
}
|
||||
|
||||
const serverEnv = new ServerEnv();
|
||||
const coverageEnv = new CoverageEnv('electron');
|
||||
electronTest.runWith(folio.merge(coverageEnv, serverEnv, new ElectronEnv()), { tag: 'electron' });
|
||||
pageTest.runWith(folio.merge(coverageEnv, serverEnv, new ElectronPageEnv()), { tag: 'electron' });
|
||||
class ElectronPageEnv extends ElectronEnv {
|
||||
async beforeEach(args: any, testInfo: folio.TestInfo) {
|
||||
const result = await super.beforeEach(args, testInfo);
|
||||
const page = await result.newWindow();
|
||||
return {
|
||||
...result,
|
||||
browserVersion: this._browserVersion,
|
||||
page,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
const envConfig = {
|
||||
tag: 'electron',
|
||||
options: {
|
||||
mode: 'default' as const,
|
||||
engine: 'electron' as const,
|
||||
coverageName: 'electron'
|
||||
}
|
||||
};
|
||||
|
||||
electronTest.runWith(envConfig);
|
||||
pageTest.runWith(envConfig, new ElectronPageEnv());
|
||||
|
@ -1,93 +0,0 @@
|
||||
/**
|
||||
* 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 { Env, TestInfo } from 'folio';
|
||||
import { PlaywrightEnv } from './browserEnv';
|
||||
import * as path from 'path';
|
||||
import { ElectronTestArgs } from './electronTest';
|
||||
import { ElectronApplication, Page } from '../../index';
|
||||
import { PageTestArgs } from './pageTest';
|
||||
|
||||
export class ElectronEnv extends PlaywrightEnv implements Env<ElectronTestArgs> {
|
||||
private _electronApp: ElectronApplication | undefined;
|
||||
private _windows: Page[] = [];
|
||||
protected _browserVersion: string;
|
||||
|
||||
constructor() {
|
||||
super('chromium', { mode: 'default' });
|
||||
// This env prevents 'Electron Security Policy' console message.
|
||||
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true';
|
||||
this._browserVersion = require('electron/package.json').version;
|
||||
}
|
||||
|
||||
private async _newWindow() {
|
||||
const [ window ] = await Promise.all([
|
||||
this._electronApp!.waitForEvent('window'),
|
||||
this._electronApp!.evaluate(electron => {
|
||||
const window = new electron.BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
// Sandboxed windows share process with their window.open() children
|
||||
// and can script them. We use that heavily in our tests.
|
||||
webPreferences: { sandbox: true }
|
||||
});
|
||||
window.loadURL('about:blank');
|
||||
})
|
||||
]);
|
||||
this._windows.push(window);
|
||||
return window;
|
||||
}
|
||||
|
||||
async beforeEach(testInfo: TestInfo) {
|
||||
const result = await super.beforeEach(testInfo);
|
||||
this._electronApp = await result.playwright._electron.launch({
|
||||
args: [path.join(__dirname, 'electron-app.js')],
|
||||
});
|
||||
testInfo.data = {
|
||||
browserName: 'electron',
|
||||
browserVersion: this._browserVersion,
|
||||
};
|
||||
return {
|
||||
...result,
|
||||
isElectron: true,
|
||||
electronApp: this._electronApp,
|
||||
newWindow: this._newWindow.bind(this),
|
||||
};
|
||||
}
|
||||
|
||||
async afterEach(testInfo: TestInfo) {
|
||||
for (const window of this._windows)
|
||||
await window.close();
|
||||
this._windows = [];
|
||||
if (this._electronApp) {
|
||||
await this._electronApp.close();
|
||||
this._electronApp = undefined;
|
||||
}
|
||||
await super.afterEach(testInfo);
|
||||
}
|
||||
}
|
||||
|
||||
export class ElectronPageEnv extends ElectronEnv implements Env<PageTestArgs> {
|
||||
async beforeEach(testInfo: TestInfo) {
|
||||
const result = await super.beforeEach(testInfo);
|
||||
const page = await result.newWindow();
|
||||
return {
|
||||
...result,
|
||||
browserVersion: this._browserVersion,
|
||||
page,
|
||||
};
|
||||
}
|
||||
}
|
@ -14,15 +14,67 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { newTestType } from 'folio';
|
||||
import { CommonTestArgs, test as baseTest } from './baseTest';
|
||||
import { ElectronApplication, Page } from '../../index';
|
||||
import type { CommonTestArgs } from './pageTest';
|
||||
import type { ServerTestArgs } from './serverTest';
|
||||
import * as folio from 'folio';
|
||||
import * as path from 'path';
|
||||
export { expect } from 'folio';
|
||||
|
||||
export type ElectronTestArgs = CommonTestArgs & {
|
||||
type ElectronTestArgs = {
|
||||
electronApp: ElectronApplication;
|
||||
newWindow: () => Promise<Page>;
|
||||
};
|
||||
|
||||
export const test = newTestType<ElectronTestArgs & ServerTestArgs>();
|
||||
export class ElectronEnv {
|
||||
private _electronApp: ElectronApplication | undefined;
|
||||
private _windows: Page[] = [];
|
||||
protected _browserVersion: string;
|
||||
|
||||
private async _newWindow() {
|
||||
const [ window ] = await Promise.all([
|
||||
this._electronApp!.waitForEvent('window'),
|
||||
this._electronApp!.evaluate(electron => {
|
||||
const window = new electron.BrowserWindow({
|
||||
width: 800,
|
||||
height: 600,
|
||||
// Sandboxed windows share process with their window.open() children
|
||||
// and can script them. We use that heavily in our tests.
|
||||
webPreferences: { sandbox: true }
|
||||
});
|
||||
window.loadURL('about:blank');
|
||||
})
|
||||
]);
|
||||
this._windows.push(window);
|
||||
return window;
|
||||
}
|
||||
|
||||
async beforeAll() {
|
||||
// This env prevents 'Electron Security Policy' console message.
|
||||
process.env['ELECTRON_DISABLE_SECURITY_WARNINGS'] = 'true';
|
||||
this._browserVersion = require('electron/package.json').version;
|
||||
return {};
|
||||
}
|
||||
|
||||
async beforeEach(args: CommonTestArgs, testInfo: folio.TestInfo): Promise<ElectronTestArgs> {
|
||||
this._electronApp = await args.playwright._electron.launch({
|
||||
args: [path.join(__dirname, 'electron-app.js')],
|
||||
});
|
||||
testInfo.data.browserVersion = this._browserVersion;
|
||||
return {
|
||||
electronApp: this._electronApp,
|
||||
newWindow: this._newWindow.bind(this),
|
||||
};
|
||||
}
|
||||
|
||||
async afterEach({}, testInfo: folio.TestInfo) {
|
||||
for (const window of this._windows)
|
||||
await window.close();
|
||||
this._windows = [];
|
||||
if (this._electronApp) {
|
||||
await this._electronApp.close();
|
||||
this._electronApp = undefined;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const electronTest = baseTest.extend(new ElectronEnv());
|
||||
|
@ -14,36 +14,14 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { newTestType } from 'folio';
|
||||
import { test as baseTest } from './baseTest';
|
||||
import type { Page } from '../../index';
|
||||
import type { ServerTestArgs } from './serverTest';
|
||||
export { expect } from 'folio';
|
||||
|
||||
export type CommonTestArgs = {
|
||||
mode: 'default' | 'driver' | 'service';
|
||||
platform: 'win32' | 'darwin' | 'linux';
|
||||
video: boolean;
|
||||
headful: boolean;
|
||||
|
||||
playwright: typeof import('../../index');
|
||||
toImpl: (rpcObject: any) => any;
|
||||
browserName: 'chromium' | 'firefox' | 'webkit';
|
||||
browserChannel: string | undefined;
|
||||
|
||||
isChromium: boolean;
|
||||
isFirefox: boolean;
|
||||
isWebKit: boolean;
|
||||
isAndroid: boolean;
|
||||
isElectron: boolean;
|
||||
isWindows: boolean;
|
||||
isMac: boolean;
|
||||
isLinux: boolean;
|
||||
};
|
||||
|
||||
// Page test does not guarantee an isolated context, just a new page (because Android).
|
||||
export type PageTestArgs = CommonTestArgs & {
|
||||
export type PageTestArgs = {
|
||||
browserVersion: string;
|
||||
page: Page;
|
||||
};
|
||||
|
||||
export const test = newTestType<PageTestArgs & ServerTestArgs>();
|
||||
export const test = baseTest.declare<PageTestArgs>();
|
||||
|
@ -1,33 +0,0 @@
|
||||
/**
|
||||
* 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 { newTestType } from 'folio';
|
||||
import type { BrowserType, LaunchOptions, BrowserContext, Page } from '../../index';
|
||||
import { CommonTestArgs } from './pageTest';
|
||||
import type { ServerTestArgs } from './serverTest';
|
||||
import { RemoteServer, RemoteServerOptions } from './remoteServer';
|
||||
export { expect } from 'folio';
|
||||
|
||||
export type PlaywrightTestArgs = CommonTestArgs & {
|
||||
browserType: BrowserType;
|
||||
browserOptions: LaunchOptions;
|
||||
createUserDataDir: () => Promise<string>;
|
||||
launchPersistent: (options?: Parameters<BrowserType['launchPersistentContext']>[1]) => Promise<{ context: BrowserContext, page: Page }>;
|
||||
startRemoteServer: (options?: RemoteServerOptions) => Promise<RemoteServer>;
|
||||
};
|
||||
|
||||
export const test = newTestType<PlaywrightTestArgs & ServerTestArgs>();
|
||||
export const slowTest = newTestType<PlaywrightTestArgs & ServerTestArgs>();
|
@ -1,85 +0,0 @@
|
||||
/**
|
||||
* 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 { WorkerInfo, TestInfo, Env } from 'folio';
|
||||
import { TestServer } from '../../utils/testserver';
|
||||
import * as path from 'path';
|
||||
import socks from 'socksv5';
|
||||
import { ServerTestArgs } from './serverTest';
|
||||
|
||||
export class ServerEnv implements Env<ServerTestArgs> {
|
||||
private _server: TestServer;
|
||||
private _httpsServer: TestServer;
|
||||
private _socksServer: any;
|
||||
private _socksPort: number;
|
||||
private _loopback: string | undefined;
|
||||
|
||||
constructor(loopback?: string) {
|
||||
this._loopback = loopback;
|
||||
}
|
||||
|
||||
async beforeAll(workerInfo: WorkerInfo) {
|
||||
const assetsPath = path.join(__dirname, '..', 'assets');
|
||||
const cachedPath = path.join(__dirname, '..', 'assets', 'cached');
|
||||
|
||||
const port = 8907 + workerInfo.workerIndex * 3;
|
||||
this._server = await TestServer.create(assetsPath, port, this._loopback);
|
||||
this._server.enableHTTPCache(cachedPath);
|
||||
|
||||
const httpsPort = port + 1;
|
||||
this._httpsServer = await TestServer.createHTTPS(assetsPath, httpsPort, this._loopback);
|
||||
this._httpsServer.enableHTTPCache(cachedPath);
|
||||
|
||||
this._socksServer = socks.createServer((info, accept, deny) => {
|
||||
let socket;
|
||||
if ((socket = accept(true))) {
|
||||
// Catch and ignore ECONNRESET errors.
|
||||
socket.on('error', () => {});
|
||||
const body = '<html><title>Served by the SOCKS proxy</title></html>';
|
||||
socket.end([
|
||||
'HTTP/1.1 200 OK',
|
||||
'Connection: close',
|
||||
'Content-Type: text/html',
|
||||
'Content-Length: ' + Buffer.byteLength(body),
|
||||
'',
|
||||
body
|
||||
].join('\r\n'));
|
||||
}
|
||||
});
|
||||
this._socksPort = port + 2;
|
||||
this._socksServer.listen(this._socksPort, 'localhost');
|
||||
this._socksServer.useAuth(socks.auth.None());
|
||||
}
|
||||
|
||||
async beforeEach(testInfo: TestInfo) {
|
||||
this._server.reset();
|
||||
this._httpsServer.reset();
|
||||
return {
|
||||
asset: (p: string) => path.join(__dirname, '..', 'assets', ...p.split('/')),
|
||||
server: this._server,
|
||||
httpsServer: this._httpsServer,
|
||||
socksPort: this._socksPort,
|
||||
};
|
||||
}
|
||||
|
||||
async afterAll(workerInfo: WorkerInfo) {
|
||||
await Promise.all([
|
||||
this._server.stop(),
|
||||
this._httpsServer.stop(),
|
||||
this._socksServer.close(),
|
||||
]);
|
||||
}
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
/**
|
||||
* 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 { TestServer } from '../../utils/testserver';
|
||||
|
||||
export type ServerTestArgs = {
|
||||
asset: (path: string) => string;
|
||||
socksPort: number,
|
||||
server: TestServer;
|
||||
httpsServer: TestServer;
|
||||
};
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/playwrightTest';
|
||||
import { playwrightTest as it, expect } from './config/browserTest';
|
||||
import { parseCSS, serializeSelector as serialize } from '../src/server/common/cssParser';
|
||||
|
||||
const parse = (selector: string) => {
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/playwrightTest';
|
||||
import { playwrightTest as it, expect } from './config/browserTest';
|
||||
import { verifyViewport } from './config/utils';
|
||||
import fs from 'fs';
|
||||
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, slowTest, expect } from './config/playwrightTest';
|
||||
import { playwrightTest as it, slowPlaywrightTest as slowTest, expect } from './config/browserTest';
|
||||
import fs from 'fs';
|
||||
|
||||
it('should support hasTouch option', async ({server, launchPersistent}) => {
|
||||
@ -146,14 +146,14 @@ it('should throw if page argument is passed', async ({browserType, browserOption
|
||||
expect(error.message).toContain('can not specify page');
|
||||
});
|
||||
|
||||
it('should have passed URL when launching with ignoreDefaultArgs: true', async ({browserType, browserOptions, server, createUserDataDir, toImpl, mode}) => {
|
||||
it('should have passed URL when launching with ignoreDefaultArgs: true', async ({browserType, browserOptions, server, createUserDataDir, toImpl, mode, isFirefox}) => {
|
||||
it.skip(mode !== 'default');
|
||||
|
||||
const userDataDir = await createUserDataDir();
|
||||
const args = toImpl(browserType)._defaultArgs(browserOptions, 'persistent', userDataDir, 0).filter(a => a !== 'about:blank');
|
||||
const options = {
|
||||
...browserOptions,
|
||||
args: [...args, server.EMPTY_PAGE],
|
||||
args: isFirefox ? [...args, '-new-tab', server.EMPTY_PAGE] : [...args, server.EMPTY_PAGE],
|
||||
ignoreDefaultArgs: true,
|
||||
};
|
||||
const browserContext = await browserType.launchPersistentContext(userDataDir, options);
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/browserTest';
|
||||
import { browserTest as it, expect } from './config/browserTest';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import util from 'util';
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/playwrightTest';
|
||||
import { playwrightTest as it, expect } from './config/browserTest';
|
||||
import fs from 'fs';
|
||||
|
||||
it.describe('downloads path', () => {
|
||||
|
@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import path from 'path';
|
||||
import { test, expect } from '../config/electronTest';
|
||||
import { electronTest as test, expect } from '../config/electronTest';
|
||||
|
||||
test('should fire close event', async ({ playwright }) => {
|
||||
const electronApp = await playwright._electron.launch({
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test, expect } from '../config/electronTest';
|
||||
import { electronTest as test, expect } from '../config/electronTest';
|
||||
|
||||
test('should click the button', async ({newWindow, server}) => {
|
||||
const window = await newWindow();
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/pageTest';
|
||||
import { test as browserTest } from './config/browserTest';
|
||||
import { browserTest } from './config/browserTest';
|
||||
|
||||
it.beforeEach(async ({ isAndroid }) => {
|
||||
it.skip(isAndroid);
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/pageTest';
|
||||
import { test as browserTest } from './config/browserTest';
|
||||
import { browserTest } from './config/browserTest';
|
||||
import { verifyViewport } from './config/utils';
|
||||
import {PNG} from 'pngjs';
|
||||
import path from 'path';
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/pageTest';
|
||||
import { test as browserTest } from './config/browserTest';
|
||||
import { browserTest } from './config/browserTest';
|
||||
import { attachFrame } from './config/utils';
|
||||
|
||||
it('should think that it is focused by default', async ({page}) => {
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it } from './config/contextTest';
|
||||
import { contextTest as it } from './config/browserTest';
|
||||
|
||||
it('should load svg favicon with prefer-color-scheme', async ({page, server, browserName, browserChannel, headful, asset}) => {
|
||||
it.skip(!headful && browserName !== 'firefox', 'headless browsers, except firefox, do not request favicons');
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from '../config/playwrightTest';
|
||||
import { playwrightTest as it, expect } from '../config/browserTest';
|
||||
|
||||
it('should pass firefox user preferences', async ({browserType, browserOptions, browserName}) => {
|
||||
it.skip(browserName !== 'firefox');
|
||||
|
@ -20,7 +20,7 @@ import { attachFrame, detachFrame } from './config/utils';
|
||||
import type { Frame } from '../index';
|
||||
|
||||
function dumpFrames(frame: Frame, indentation: string = ''): string[] {
|
||||
let description = frame.url().replace(/:\d{4}\//, ':<PORT>/');
|
||||
let description = frame.url().replace(/:\d+\//, ':<PORT>/');
|
||||
if (frame.name())
|
||||
description += ' (' + frame.name() + ')';
|
||||
const result = [indentation + description];
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/browserTest';
|
||||
import { browserTest as it, expect } from './config/browserTest';
|
||||
|
||||
it('should work', async ({server, contextFactory}) => {
|
||||
const context = await contextFactory();
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/browserTest';
|
||||
import { browserTest as it, expect } from './config/browserTest';
|
||||
import fs from 'fs';
|
||||
import type { BrowserContext, BrowserContextOptions } from '../index';
|
||||
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, slowTest, expect } from './config/playwrightTest';
|
||||
import { playwrightTest as it, slowPlaywrightTest as slowTest, expect } from './config/browserTest';
|
||||
|
||||
it('should have default url when launching browser', async ({browserType, browserOptions, createUserDataDir}) => {
|
||||
const browserContext = await browserType.launchPersistentContext(await createUserDataDir(), {...browserOptions, headless: false });
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/browserTest';
|
||||
import { browserTest as it, expect } from './config/browserTest';
|
||||
|
||||
it('should work', async ({browser, httpsServer}) => {
|
||||
let error = null;
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/pageTest';
|
||||
import { test as browserTest } from './config/browserTest';
|
||||
import { browserTest } from './config/browserTest';
|
||||
import { globToRegex } from '../lib/client/clientHelper';
|
||||
import vm from 'vm';
|
||||
|
||||
@ -157,10 +157,10 @@ it('should work with regular expression passed from a different context', async
|
||||
});
|
||||
|
||||
it('should not break remote worker importScripts', async ({ page, server, isChromium, browserVersion }) => {
|
||||
it.fail(isChromium && +browserVersion.split('.')[0] < 91);
|
||||
it.fixme(isChromium && +browserVersion.split('.')[0] < 91);
|
||||
|
||||
await page.route('**', async request => {
|
||||
await request.continue();
|
||||
await page.route('**', async route => {
|
||||
await route.continue();
|
||||
});
|
||||
await page.goto(server.PREFIX + '/worker/worker-http-import.html');
|
||||
await page.waitForSelector("#status:has-text('finished')");
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/playwrightTest';
|
||||
import { playwrightTest as it, expect } from './config/browserTest';
|
||||
|
||||
it('should require top-level Errors', async ({}) => {
|
||||
const Errors = require('../lib/utils/errors.js');
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/playwrightTest';
|
||||
import { playwrightTest as it, expect } from './config/browserTest';
|
||||
|
||||
it('should log', async ({browserType, browserOptions}) => {
|
||||
const log = [];
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/pageTest';
|
||||
import { test as browserTest } from './config/browserTest';
|
||||
import { browserTest } from './config/browserTest';
|
||||
import { attachFrame } from './config/utils';
|
||||
|
||||
it.beforeEach(async ({ isAndroid }) => {
|
||||
|
@ -15,10 +15,10 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect, PageTestArgs } from './config/pageTest';
|
||||
import { test as it, expect } from './config/pageTest';
|
||||
import * as os from 'os';
|
||||
|
||||
function crash({ page, toImpl, browserName, platform, mode }: PageTestArgs) {
|
||||
function crash({ page, toImpl, browserName, platform, mode }: any) {
|
||||
if (browserName === 'chromium') {
|
||||
page.goto('chrome://crash').catch(e => {});
|
||||
} else if (browserName === 'webkit') {
|
||||
|
@ -18,7 +18,7 @@
|
||||
import url from 'url';
|
||||
import os from 'os';
|
||||
import { test as it, expect } from './config/pageTest';
|
||||
import { slowTest } from './config/browserTest';
|
||||
import { slowBrowserTest as slowTest } from './config/browserTest';
|
||||
import { expectedSSLError } from './config/utils';
|
||||
|
||||
it('should work', async ({page, server}) => {
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/browserTest';
|
||||
import { browserTest as it, expect } from './config/browserTest';
|
||||
import { attachFrame } from './config/utils';
|
||||
|
||||
it('should not be visible in context.pages', async ({contextFactory}) => {
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/pageTest';
|
||||
import { test as browserTest } from './config/browserTest';
|
||||
import { browserTest } from './config/browserTest';
|
||||
|
||||
function dimensions() {
|
||||
const rect = document.querySelector('textarea').getBoundingClientRect();
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/pageTest';
|
||||
import { test as browserTest } from './config/browserTest';
|
||||
import { browserTest } from './config/browserTest';
|
||||
import fs from 'fs';
|
||||
|
||||
it('should work', async ({page, server}) => {
|
||||
|
@ -16,7 +16,7 @@
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/pageTest';
|
||||
import { test as browserTest, slowTest as slowBrowserTest } from './config/browserTest';
|
||||
import { browserTest, slowBrowserTest } from './config/browserTest';
|
||||
import { verifyViewport } from './config/utils';
|
||||
import path from 'path';
|
||||
import fs from 'fs';
|
||||
|
@ -15,7 +15,7 @@
|
||||
*/
|
||||
|
||||
import { Page } from '../index';
|
||||
import { test as it, expect } from './config/cliTest';
|
||||
import { cliTest as it, expect } from './config/cliTest';
|
||||
|
||||
it.describe('pause', () => {
|
||||
it.beforeEach(async ({ mode }) => {
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/browserTest';
|
||||
import { browserTest as it, expect } from './config/browserTest';
|
||||
import fs from 'fs';
|
||||
|
||||
it('should be able to save file', async ({contextFactory, headful, browserName}, testInfo) => {
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/contextTest';
|
||||
import { contextTest as it, expect } from './config/browserTest';
|
||||
|
||||
function getPermission(page, name) {
|
||||
return page.evaluate(name => navigator.permissions.query({name}).then(result => result.state), name);
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/browserTest';
|
||||
import { browserTest as it, expect } from './config/browserTest';
|
||||
|
||||
it('should inherit user agent from browser context', async function({browser, server}) {
|
||||
const context = await browser.newContext({
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/playwrightTest';
|
||||
import { playwrightTest as it, expect } from './config/browserTest';
|
||||
import net from 'net';
|
||||
|
||||
it('should throw for bad server value', async ({browserType, browserOptions}) => {
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/browserTest';
|
||||
import { browserTest as it, expect } from './config/browserTest';
|
||||
|
||||
it('should work', async ({ contextFactory, server }) => {
|
||||
const context = await contextFactory();
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { slowTest as it, expect } from './config/browserTest';
|
||||
import { slowBrowserTest as it, expect } from './config/browserTest';
|
||||
import fs from 'fs';
|
||||
import path from 'path';
|
||||
import { spawnSync } from 'child_process';
|
||||
|
@ -14,7 +14,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/contextTest';
|
||||
import { contextTest as it, expect } from './config/browserTest';
|
||||
import type { Page, Frame } from '../index';
|
||||
|
||||
async function generate(pageOrFrame: Page | Frame, target: string): Promise<string> {
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { test as it, expect } from './config/browserTest';
|
||||
import { browserTest as it, expect } from './config/browserTest';
|
||||
|
||||
it('should work', async ({playwright, browser}) => {
|
||||
const createTagSelector = () => ({
|
||||
|
@ -15,7 +15,7 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import { slowTest as test, expect } from './config/playwrightTest';
|
||||
import { slowPlaywrightTest as test, expect } from './config/browserTest';
|
||||
import { execSync } from 'child_process';
|
||||
|
||||
test('should close the browser when the node process closes', async ({startRemoteServer, isWindows, server}) => {
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user