test: remove describes (5) (#3294)
This commit is contained in:
parent
1673e62779
commit
4cbfa09c2c
38
test/browsertype-basic.spec.js
Normal file
38
test/browsertype-basic.spec.js
Normal file
|
|
@ -0,0 +1,38 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2017 Google Inc. All rights reserved.
|
||||||
|
* Modifications 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
const utils = require('./utils');
|
||||||
|
const {FFOX, CHROMIUM, WEBKIT, WIN, USES_HOOKS, CHANNEL} = testOptions;
|
||||||
|
|
||||||
|
it('browserType.executablePath should work', async({browserType}) => {
|
||||||
|
const executablePath = browserType.executablePath();
|
||||||
|
expect(fs.existsSync(executablePath)).toBe(true);
|
||||||
|
expect(fs.realpathSync(executablePath)).toBe(executablePath);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('browserType.name should work', async({browserType}) => {
|
||||||
|
if (WEBKIT)
|
||||||
|
expect(browserType.name()).toBe('webkit');
|
||||||
|
else if (FFOX)
|
||||||
|
expect(browserType.name()).toBe('firefox');
|
||||||
|
else if (CHROMIUM)
|
||||||
|
expect(browserType.name()).toBe('chromium');
|
||||||
|
else
|
||||||
|
throw new Error('Unknown browser');
|
||||||
|
});
|
||||||
73
test/browsertype-connect.spec.js
Normal file
73
test/browsertype-connect.spec.js
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2017 Google Inc. All rights reserved.
|
||||||
|
* Modifications 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
const utils = require('./utils');
|
||||||
|
const {FFOX, CHROMIUM, WEBKIT, WIN, USES_HOOKS, CHANNEL} = testOptions;
|
||||||
|
|
||||||
|
it.slow()('should be able to reconnect to a browser', async({browserType, defaultBrowserOptions, server}) => {
|
||||||
|
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
||||||
|
{
|
||||||
|
const browser = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
|
||||||
|
const browserContext = await browser.newContext();
|
||||||
|
const page = await browserContext.newPage();
|
||||||
|
await page.goto(server.EMPTY_PAGE);
|
||||||
|
await browser.close();
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const browser = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
|
||||||
|
const browserContext = await browser.newContext();
|
||||||
|
const page = await browserContext.newPage();
|
||||||
|
await page.goto(server.EMPTY_PAGE);
|
||||||
|
await browser.close();
|
||||||
|
}
|
||||||
|
await browserServer._checkLeaks();
|
||||||
|
await browserServer.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it.fail(USES_HOOKS || (CHROMIUM && WIN)).slow()('should handle exceptions during connect', async({browserType, defaultBrowserOptions, server}) => {
|
||||||
|
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
||||||
|
const __testHookBeforeCreateBrowser = () => { throw new Error('Dummy') };
|
||||||
|
const error = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint(), __testHookBeforeCreateBrowser }).catch(e => e);
|
||||||
|
await browserServer._checkLeaks();
|
||||||
|
await browserServer.close();
|
||||||
|
expect(error.message).toContain('Dummy');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should set the browser connected state', async ({browserType, defaultBrowserOptions}) => {
|
||||||
|
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
||||||
|
const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
|
||||||
|
expect(remote.isConnected()).toBe(true);
|
||||||
|
await remote.close();
|
||||||
|
expect(remote.isConnected()).toBe(false);
|
||||||
|
await browserServer._checkLeaks();
|
||||||
|
await browserServer.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw when used after isConnected returns false', async({browserType, defaultBrowserOptions}) => {
|
||||||
|
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
||||||
|
const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
|
||||||
|
const page = await remote.newPage();
|
||||||
|
await Promise.all([
|
||||||
|
browserServer.close(),
|
||||||
|
new Promise(f => remote.once('disconnected', f)),
|
||||||
|
]);
|
||||||
|
expect(remote.isConnected()).toBe(false);
|
||||||
|
const error = await page.evaluate('1 + 1').catch(e => e);
|
||||||
|
expect(error.message).toContain('has been closed');
|
||||||
|
});
|
||||||
149
test/browsertype-launch-server.spec.js
Normal file
149
test/browsertype-launch-server.spec.js
Normal file
|
|
@ -0,0 +1,149 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2017 Google Inc. All rights reserved.
|
||||||
|
* Modifications 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
const utils = require('./utils');
|
||||||
|
const {FFOX, CHROMIUM, WEBKIT, WIN, USES_HOOKS, CHANNEL} = testOptions;
|
||||||
|
|
||||||
|
it('should work', async({browserType, defaultBrowserOptions}) => {
|
||||||
|
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
||||||
|
const browser = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
|
||||||
|
const browserContext = await browser.newContext();
|
||||||
|
expect(browserContext.pages().length).toBe(0);
|
||||||
|
expect(browserServer.wsEndpoint()).not.toBe(null);
|
||||||
|
const page = await browserContext.newPage();
|
||||||
|
expect(await page.evaluate('11 * 11')).toBe(121);
|
||||||
|
await page.close();
|
||||||
|
await browser.close();
|
||||||
|
await browserServer._checkLeaks();
|
||||||
|
await browserServer.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fire "disconnected" when closing the server', async({browserType, defaultBrowserOptions}) => {
|
||||||
|
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
||||||
|
const browser = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
|
||||||
|
const disconnectedEventPromise = new Promise(resolve => browser.once('disconnected', resolve));
|
||||||
|
const closedPromise = new Promise(f => browserServer.on('close', f));
|
||||||
|
browserServer.kill();
|
||||||
|
await Promise.all([
|
||||||
|
disconnectedEventPromise,
|
||||||
|
closedPromise,
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fire "close" event during kill', async({browserType, defaultBrowserOptions}) => {
|
||||||
|
const order = [];
|
||||||
|
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
||||||
|
const closedPromise = new Promise(f => browserServer.on('close', () => {
|
||||||
|
order.push('closed');
|
||||||
|
f();
|
||||||
|
}));
|
||||||
|
await Promise.all([
|
||||||
|
browserServer.kill().then(() => order.push('killed')),
|
||||||
|
closedPromise,
|
||||||
|
]);
|
||||||
|
expect(order).toEqual(['closed', 'killed']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should return child_process instance', async ({browserType, defaultBrowserOptions}) => {
|
||||||
|
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
||||||
|
expect(browserServer.process().pid).toBeGreaterThan(0);
|
||||||
|
await browserServer.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fire close event', async ({browserType, defaultBrowserOptions}) => {
|
||||||
|
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
||||||
|
const [result] = await Promise.all([
|
||||||
|
new Promise(f => browserServer.on('close', (exitCode, signal) => f({ exitCode, signal }))),
|
||||||
|
browserServer.close(),
|
||||||
|
]);
|
||||||
|
expect(result.exitCode).toBe(0);
|
||||||
|
expect(result.signal).toBe(null);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reject navigation when browser closes', async({browserType, defaultBrowserOptions, server}) => {
|
||||||
|
server.setRoute('/one-style.css', () => {});
|
||||||
|
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
||||||
|
const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
|
||||||
|
const page = await remote.newPage();
|
||||||
|
const navigationPromise = page.goto(server.PREFIX + '/one-style.html', {timeout: 60000}).catch(e => e);
|
||||||
|
await server.waitForRequest('/one-style.css');
|
||||||
|
await remote.close();
|
||||||
|
const error = await navigationPromise;
|
||||||
|
expect(error.message).toContain('Navigation failed because page was closed!');
|
||||||
|
await browserServer._checkLeaks();
|
||||||
|
await browserServer.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reject waitForSelector when browser closes', async({browserType, defaultBrowserOptions, server}) => {
|
||||||
|
server.setRoute('/empty.html', () => {});
|
||||||
|
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
||||||
|
const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
|
||||||
|
const page = await remote.newPage();
|
||||||
|
const watchdog = page.waitForSelector('div', { state: 'attached', timeout: 60000 }).catch(e => e);
|
||||||
|
|
||||||
|
// Make sure the previous waitForSelector has time to make it to the browser before we disconnect.
|
||||||
|
await page.waitForSelector('body', { state: 'attached' });
|
||||||
|
|
||||||
|
await remote.close();
|
||||||
|
const error = await watchdog;
|
||||||
|
expect(error.message).toContain('Protocol error');
|
||||||
|
await browserServer._checkLeaks();
|
||||||
|
await browserServer.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw if used after disconnect', async({browserType, defaultBrowserOptions}) => {
|
||||||
|
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
||||||
|
const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
|
||||||
|
const page = await remote.newPage();
|
||||||
|
await remote.close();
|
||||||
|
const error = await page.evaluate('1 + 1').catch(e => e);
|
||||||
|
expect(error.message).toContain('has been closed');
|
||||||
|
await browserServer._checkLeaks();
|
||||||
|
await browserServer.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should emit close events on pages and contexts', async({browserType, defaultBrowserOptions}) => {
|
||||||
|
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
||||||
|
const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
|
||||||
|
const context = await remote.newContext();
|
||||||
|
const page = await context.newPage();
|
||||||
|
let pageClosed = false;
|
||||||
|
page.on('close', e => pageClosed = true);
|
||||||
|
await Promise.all([
|
||||||
|
new Promise(f => context.on('close', f)),
|
||||||
|
browserServer.close()
|
||||||
|
]);
|
||||||
|
expect(pageClosed).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should terminate network waiters', async({browserType, defaultBrowserOptions, server}) => {
|
||||||
|
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
||||||
|
const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
|
||||||
|
const newPage = await remote.newPage();
|
||||||
|
const results = await Promise.all([
|
||||||
|
newPage.waitForRequest(server.EMPTY_PAGE).catch(e => e),
|
||||||
|
newPage.waitForResponse(server.EMPTY_PAGE).catch(e => e),
|
||||||
|
browserServer.close()
|
||||||
|
]);
|
||||||
|
for (let i = 0; i < 2; i++) {
|
||||||
|
const message = results[i].message;
|
||||||
|
expect(message).toContain('Page closed');
|
||||||
|
expect(message).not.toContain('Timeout');
|
||||||
|
}
|
||||||
|
});
|
||||||
106
test/browsertype-launch.spec.js
Normal file
106
test/browsertype-launch.spec.js
Normal file
|
|
@ -0,0 +1,106 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2017 Google Inc. All rights reserved.
|
||||||
|
* Modifications 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
const utils = require('./utils');
|
||||||
|
const {FFOX, CHROMIUM, WEBKIT, WIN, USES_HOOKS, CHANNEL} = testOptions;
|
||||||
|
|
||||||
|
it('should reject all promises when browser is closed', async({browserType, defaultBrowserOptions}) => {
|
||||||
|
const browser = await browserType.launch(defaultBrowserOptions);
|
||||||
|
const page = await (await browser.newContext()).newPage();
|
||||||
|
let error = null;
|
||||||
|
const neverResolves = page.evaluate(() => new Promise(r => {})).catch(e => error = e);
|
||||||
|
await page.evaluate(() => new Promise(f => setTimeout(f, 0)));
|
||||||
|
await browser.close();
|
||||||
|
await neverResolves;
|
||||||
|
expect(error.message).toContain('Protocol error');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should throw if userDataDir option is passed', async({browserType, defaultBrowserOptions}) => {
|
||||||
|
let waitError = null;
|
||||||
|
const options = Object.assign({}, defaultBrowserOptions, {userDataDir: 'random-path'});
|
||||||
|
await browserType.launch(options).catch(e => waitError = e);
|
||||||
|
expect(waitError.message).toContain('launchPersistentContext');
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(FFOX)('should throw if page argument is passed', async({browserType, defaultBrowserOptions}) => {
|
||||||
|
let waitError = null;
|
||||||
|
const options = Object.assign({}, defaultBrowserOptions, { args: ['http://example.com'] });
|
||||||
|
await browserType.launch(options).catch(e => waitError = e);
|
||||||
|
expect(waitError.message).toContain('can not specify page');
|
||||||
|
});
|
||||||
|
|
||||||
|
it.fail(true)('should reject if launched browser fails immediately', async({browserType, defaultBrowserOptions}) => {
|
||||||
|
// I'm getting ENCONRESET on this one.
|
||||||
|
const options = Object.assign({}, defaultBrowserOptions, {executablePath: path.join(__dirname, 'assets', 'dummy_bad_browser_executable.js')});
|
||||||
|
let waitError = null;
|
||||||
|
await browserType.launch(options).catch(e => waitError = e);
|
||||||
|
expect(waitError.message).toContain('== logs ==');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should reject if executable path is invalid', async({browserType, defaultBrowserOptions}) => {
|
||||||
|
let waitError = null;
|
||||||
|
const options = Object.assign({}, defaultBrowserOptions, {executablePath: 'random-invalid-path'});
|
||||||
|
await browserType.launch(options).catch(e => waitError = e);
|
||||||
|
expect(waitError.message).toContain('Failed to launch');
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(USES_HOOKS)('should handle timeout', async({browserType, defaultBrowserOptions}) => {
|
||||||
|
const options = { ...defaultBrowserOptions, timeout: 5000, __testHookBeforeCreateBrowser: () => new Promise(f => setTimeout(f, 6000)) };
|
||||||
|
const error = await browserType.launch(options).catch(e => e);
|
||||||
|
expect(error.message).toContain(`browserType.launch: Timeout 5000ms exceeded.`);
|
||||||
|
expect(error.message).toContain(`[browser] <launching>`);
|
||||||
|
expect(error.message).toContain(`[browser] <launched> pid=`);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(USES_HOOKS)('should handle exception', async({browserType, defaultBrowserOptions}) => {
|
||||||
|
const e = new Error('Dummy');
|
||||||
|
const options = { ...defaultBrowserOptions, __testHookBeforeCreateBrowser: () => { throw e; }, timeout: 9000 };
|
||||||
|
const error = await browserType.launch(options).catch(e => e);
|
||||||
|
expect(error.message).toContain('Dummy');
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(USES_HOOKS)('should report launch log', async({browserType, defaultBrowserOptions}) => {
|
||||||
|
const e = new Error('Dummy');
|
||||||
|
const options = { ...defaultBrowserOptions, __testHookBeforeCreateBrowser: () => { throw e; }, timeout: 9000 };
|
||||||
|
const error = await browserType.launch(options).catch(e => e);
|
||||||
|
expect(error.message).toContain('<launching>');
|
||||||
|
});
|
||||||
|
|
||||||
|
it.slow()('should accept objects as options', async({browserType, defaultBrowserOptions}) => {
|
||||||
|
const browser = await browserType.launch({ ...defaultBrowserOptions, process });
|
||||||
|
await browser.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should fire close event for all contexts', async({browserType, defaultBrowserOptions}) => {
|
||||||
|
const browser = await browserType.launch(defaultBrowserOptions);
|
||||||
|
const context = await browser.newContext();
|
||||||
|
let closed = false;
|
||||||
|
context.on('close', () => closed = true);
|
||||||
|
await browser.close();
|
||||||
|
expect(closed).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be callable twice', async({browserType, defaultBrowserOptions}) => {
|
||||||
|
const browser = await browserType.launch(defaultBrowserOptions);
|
||||||
|
await Promise.all([
|
||||||
|
browser.close(),
|
||||||
|
browser.close(),
|
||||||
|
]);
|
||||||
|
await browser.close();
|
||||||
|
});
|
||||||
|
|
@ -1,88 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright 2018 Google Inc. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const {FFOX, CHROMIUM, WEBKIT, CHANNEL} = testOptions;
|
|
||||||
|
|
||||||
describe.skip(!CHROMIUM)('Service Worker', function() {
|
|
||||||
it('should create a worker from a service worker', async({page, server, context}) => {
|
|
||||||
const [worker] = await Promise.all([
|
|
||||||
context.waitForEvent('serviceworker'),
|
|
||||||
page.goto(server.PREFIX + '/serviceworkers/empty/sw.html')
|
|
||||||
]);
|
|
||||||
expect(await worker.evaluate(() => self.toString())).toBe('[object ServiceWorkerGlobalScope]');
|
|
||||||
});
|
|
||||||
it('serviceWorkers() should return current workers', async({page, server, context}) => {
|
|
||||||
const [worker1] = await Promise.all([
|
|
||||||
context.waitForEvent('serviceworker'),
|
|
||||||
page.goto(server.PREFIX + '/serviceworkers/empty/sw.html')
|
|
||||||
]);
|
|
||||||
let workers = context.serviceWorkers();
|
|
||||||
expect(workers.length).toBe(1);
|
|
||||||
|
|
||||||
const [worker2] = await Promise.all([
|
|
||||||
context.waitForEvent('serviceworker'),
|
|
||||||
page.goto(server.CROSS_PROCESS_PREFIX + '/serviceworkers/empty/sw.html')
|
|
||||||
]);
|
|
||||||
workers = context.serviceWorkers();
|
|
||||||
expect(workers.length).toBe(2);
|
|
||||||
expect(workers).toContain(worker1);
|
|
||||||
expect(workers).toContain(worker2);
|
|
||||||
});
|
|
||||||
it('should not create a worker from a shared worker', async({page, server, context}) => {
|
|
||||||
await page.goto(server.EMPTY_PAGE);
|
|
||||||
let serviceWorkerCreated;
|
|
||||||
context.once('serviceworker', () => serviceWorkerCreated = true);
|
|
||||||
await page.evaluate(() => {
|
|
||||||
new SharedWorker('data:text/javascript,console.log("hi")');
|
|
||||||
});
|
|
||||||
expect(serviceWorkerCreated).not.toBeTruthy();
|
|
||||||
});
|
|
||||||
it('should close service worker together with the context', async({browser, server}) => {
|
|
||||||
const context = await browser.newContext();
|
|
||||||
const page = await context.newPage();
|
|
||||||
const [worker] = await Promise.all([
|
|
||||||
context.waitForEvent('serviceworker'),
|
|
||||||
page.goto(server.PREFIX + '/serviceworkers/empty/sw.html')
|
|
||||||
]);
|
|
||||||
const messages = [];
|
|
||||||
context.on('close', () => messages.push('context'));
|
|
||||||
worker.on('close', () => messages.push('worker'));
|
|
||||||
await context.close();
|
|
||||||
expect(messages.join('|')).toBe('worker|context');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe.skip(!CHROMIUM)('Chromium-Specific Page Tests', function() {
|
|
||||||
it('Page.route should work with intervention headers', async({server, page}) => {
|
|
||||||
server.setRoute('/intervention', (req, res) => res.end(`
|
|
||||||
<script>
|
|
||||||
document.write('<script src="${server.CROSS_PROCESS_PREFIX}/intervention.js">' + '</scr' + 'ipt>');
|
|
||||||
</script>
|
|
||||||
`));
|
|
||||||
server.setRedirect('/intervention.js', '/redirect.js');
|
|
||||||
let serverRequest = null;
|
|
||||||
server.setRoute('/redirect.js', (req, res) => {
|
|
||||||
serverRequest = req;
|
|
||||||
res.end('console.log(1);');
|
|
||||||
});
|
|
||||||
|
|
||||||
await page.route('*', route => route.continue());
|
|
||||||
await page.goto(server.PREFIX + '/intervention');
|
|
||||||
// Check for feature URL substring rather than https://www.chromestatus.com to
|
|
||||||
// make it work with Edgium.
|
|
||||||
expect(serverRequest.headers.intervention).toContain('feature/5718547946799104');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
87
test/chromium/chromium.spec.js
Normal file
87
test/chromium/chromium.spec.js
Normal file
|
|
@ -0,0 +1,87 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2018 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const {FFOX, CHROMIUM, WEBKIT, CHANNEL} = testOptions;
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should create a worker from a service worker', async({page, server, context}) => {
|
||||||
|
const [worker] = await Promise.all([
|
||||||
|
context.waitForEvent('serviceworker'),
|
||||||
|
page.goto(server.PREFIX + '/serviceworkers/empty/sw.html')
|
||||||
|
]);
|
||||||
|
expect(await worker.evaluate(() => self.toString())).toBe('[object ServiceWorkerGlobalScope]');
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('serviceWorkers() should return current workers', async({page, server, context}) => {
|
||||||
|
const [worker1] = await Promise.all([
|
||||||
|
context.waitForEvent('serviceworker'),
|
||||||
|
page.goto(server.PREFIX + '/serviceworkers/empty/sw.html')
|
||||||
|
]);
|
||||||
|
let workers = context.serviceWorkers();
|
||||||
|
expect(workers.length).toBe(1);
|
||||||
|
|
||||||
|
const [worker2] = await Promise.all([
|
||||||
|
context.waitForEvent('serviceworker'),
|
||||||
|
page.goto(server.CROSS_PROCESS_PREFIX + '/serviceworkers/empty/sw.html')
|
||||||
|
]);
|
||||||
|
workers = context.serviceWorkers();
|
||||||
|
expect(workers.length).toBe(2);
|
||||||
|
expect(workers).toContain(worker1);
|
||||||
|
expect(workers).toContain(worker2);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should not create a worker from a shared worker', async({page, server, context}) => {
|
||||||
|
await page.goto(server.EMPTY_PAGE);
|
||||||
|
let serviceWorkerCreated;
|
||||||
|
context.once('serviceworker', () => serviceWorkerCreated = true);
|
||||||
|
await page.evaluate(() => {
|
||||||
|
new SharedWorker('data:text/javascript,console.log("hi")');
|
||||||
|
});
|
||||||
|
expect(serviceWorkerCreated).not.toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should close service worker together with the context', async({browser, server}) => {
|
||||||
|
const context = await browser.newContext();
|
||||||
|
const page = await context.newPage();
|
||||||
|
const [worker] = await Promise.all([
|
||||||
|
context.waitForEvent('serviceworker'),
|
||||||
|
page.goto(server.PREFIX + '/serviceworkers/empty/sw.html')
|
||||||
|
]);
|
||||||
|
const messages = [];
|
||||||
|
context.on('close', () => messages.push('context'));
|
||||||
|
worker.on('close', () => messages.push('worker'));
|
||||||
|
await context.close();
|
||||||
|
expect(messages.join('|')).toBe('worker|context');
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('Page.route should work with intervention headers', async({server, page}) => {
|
||||||
|
server.setRoute('/intervention', (req, res) => res.end(`
|
||||||
|
<script>
|
||||||
|
document.write('<script src="${server.CROSS_PROCESS_PREFIX}/intervention.js">' + '</scr' + 'ipt>');
|
||||||
|
</script>
|
||||||
|
`));
|
||||||
|
server.setRedirect('/intervention.js', '/redirect.js');
|
||||||
|
let serverRequest = null;
|
||||||
|
server.setRoute('/redirect.js', (req, res) => {
|
||||||
|
serverRequest = req;
|
||||||
|
res.end('console.log(1);');
|
||||||
|
});
|
||||||
|
|
||||||
|
await page.route('*', route => route.continue());
|
||||||
|
await page.goto(server.PREFIX + '/intervention');
|
||||||
|
// Check for feature URL substring rather than https://www.chromestatus.com to
|
||||||
|
// make it work with Edgium.
|
||||||
|
expect(serverRequest.headers.intervention).toContain('feature/5718547946799104');
|
||||||
|
});
|
||||||
|
|
@ -1,90 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright 2019 Google Inc. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const path = require('path');
|
|
||||||
const utils = require('../utils');
|
|
||||||
const {makeUserDataDir, removeUserDataDir} = utils;
|
|
||||||
const {FFOX, CHROMIUM, WEBKIT, WIN, USES_HOOKS} = testOptions;
|
|
||||||
|
|
||||||
describe.skip(!CHROMIUM)('launcher', function() {
|
|
||||||
it('should throw with remote-debugging-pipe argument', async({browserType, defaultBrowserOptions}) => {
|
|
||||||
const options = Object.assign({}, defaultBrowserOptions);
|
|
||||||
options.args = ['--remote-debugging-pipe'].concat(options.args || []);
|
|
||||||
const error = await browserType.launchServer(options).catch(e => e);
|
|
||||||
expect(error.message).toContain('Playwright manages remote debugging connection itself');
|
|
||||||
});
|
|
||||||
it('should not throw with remote-debugging-port argument', async({browserType, defaultBrowserOptions}) => {
|
|
||||||
const options = Object.assign({}, defaultBrowserOptions);
|
|
||||||
options.args = ['--remote-debugging-port=0'].concat(options.args || []);
|
|
||||||
const browser = await browserType.launchServer(options);
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
it.fail(USES_HOOKS || WIN)('should open devtools when "devtools: true" option is given', async({browserType, defaultBrowserOptions}) => {
|
|
||||||
let devtoolsCallback;
|
|
||||||
const devtoolsPromise = new Promise(f => devtoolsCallback = f);
|
|
||||||
const __testHookForDevTools = devtools => devtools.__testHookOnBinding = parsed => {
|
|
||||||
if (parsed.method === 'getPreferences')
|
|
||||||
devtoolsCallback();
|
|
||||||
};
|
|
||||||
const browser = await browserType.launch({...defaultBrowserOptions, headless: false, devtools: true, __testHookForDevTools});
|
|
||||||
const context = await browser.newContext();
|
|
||||||
await Promise.all([
|
|
||||||
devtoolsPromise,
|
|
||||||
context.newPage()
|
|
||||||
]);
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe.skip(!CHROMIUM)('extensions', () => {
|
|
||||||
it('should return background pages', async({browserType, defaultBrowserOptions}) => {
|
|
||||||
const userDataDir = await makeUserDataDir();
|
|
||||||
const extensionPath = path.join(__dirname, '..', 'assets', 'simple-extension');
|
|
||||||
const extensionOptions = {...defaultBrowserOptions,
|
|
||||||
headless: false,
|
|
||||||
args: [
|
|
||||||
`--disable-extensions-except=${extensionPath}`,
|
|
||||||
`--load-extension=${extensionPath}`,
|
|
||||||
],
|
|
||||||
};
|
|
||||||
const context = await browserType.launchPersistentContext(userDataDir, extensionOptions);
|
|
||||||
const backgroundPages = context.backgroundPages();
|
|
||||||
let backgroundPage = backgroundPages.length
|
|
||||||
? backgroundPages[0]
|
|
||||||
: await context.waitForEvent('backgroundpage');
|
|
||||||
expect(backgroundPage).toBeTruthy();
|
|
||||||
expect(context.backgroundPages()).toContain(backgroundPage);
|
|
||||||
expect(context.pages()).not.toContain(backgroundPage);
|
|
||||||
await context.close();
|
|
||||||
await removeUserDataDir(userDataDir);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe.skip(!CHROMIUM)('BrowserContext', function() {
|
|
||||||
it('should not create pages automatically', async ({browserType, defaultBrowserOptions}) => {
|
|
||||||
const browser = await browserType.launch(defaultBrowserOptions);
|
|
||||||
const browserSession = await browser.newBrowserCDPSession();
|
|
||||||
const targets = [];
|
|
||||||
browserSession.on('Target.targetCreated', async ({targetInfo}) => {
|
|
||||||
if (targetInfo.type !== 'browser')
|
|
||||||
targets.push(targetInfo);
|
|
||||||
});
|
|
||||||
await browserSession.send('Target.setDiscoverTargets', { discover: true });
|
|
||||||
await browser.newContext();
|
|
||||||
await browser.close();
|
|
||||||
expect(targets.length).toBe(0);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
86
test/chromium/launcher.spec.js
Normal file
86
test/chromium/launcher.spec.js
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2019 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
const utils = require('../utils');
|
||||||
|
const {makeUserDataDir, removeUserDataDir} = utils;
|
||||||
|
const {FFOX, CHROMIUM, WEBKIT, WIN, USES_HOOKS} = testOptions;
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should throw with remote-debugging-pipe argument', async({browserType, defaultBrowserOptions}) => {
|
||||||
|
const options = Object.assign({}, defaultBrowserOptions);
|
||||||
|
options.args = ['--remote-debugging-pipe'].concat(options.args || []);
|
||||||
|
const error = await browserType.launchServer(options).catch(e => e);
|
||||||
|
expect(error.message).toContain('Playwright manages remote debugging connection itself');
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should not throw with remote-debugging-port argument', async({browserType, defaultBrowserOptions}) => {
|
||||||
|
const options = Object.assign({}, defaultBrowserOptions);
|
||||||
|
options.args = ['--remote-debugging-port=0'].concat(options.args || []);
|
||||||
|
const browser = await browserType.launchServer(options);
|
||||||
|
await browser.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM || USES_HOOKS || WIN)('should open devtools when "devtools: true" option is given', async({browserType, defaultBrowserOptions}) => {
|
||||||
|
let devtoolsCallback;
|
||||||
|
const devtoolsPromise = new Promise(f => devtoolsCallback = f);
|
||||||
|
const __testHookForDevTools = devtools => devtools.__testHookOnBinding = parsed => {
|
||||||
|
if (parsed.method === 'getPreferences')
|
||||||
|
devtoolsCallback();
|
||||||
|
};
|
||||||
|
const browser = await browserType.launch({...defaultBrowserOptions, headless: false, devtools: true, __testHookForDevTools});
|
||||||
|
const context = await browser.newContext();
|
||||||
|
await Promise.all([
|
||||||
|
devtoolsPromise,
|
||||||
|
context.newPage()
|
||||||
|
]);
|
||||||
|
await browser.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should return background pages', async({browserType, defaultBrowserOptions}) => {
|
||||||
|
const userDataDir = await makeUserDataDir();
|
||||||
|
const extensionPath = path.join(__dirname, '..', 'assets', 'simple-extension');
|
||||||
|
const extensionOptions = {...defaultBrowserOptions,
|
||||||
|
headless: false,
|
||||||
|
args: [
|
||||||
|
`--disable-extensions-except=${extensionPath}`,
|
||||||
|
`--load-extension=${extensionPath}`,
|
||||||
|
],
|
||||||
|
};
|
||||||
|
const context = await browserType.launchPersistentContext(userDataDir, extensionOptions);
|
||||||
|
const backgroundPages = context.backgroundPages();
|
||||||
|
let backgroundPage = backgroundPages.length
|
||||||
|
? backgroundPages[0]
|
||||||
|
: await context.waitForEvent('backgroundpage');
|
||||||
|
expect(backgroundPage).toBeTruthy();
|
||||||
|
expect(context.backgroundPages()).toContain(backgroundPage);
|
||||||
|
expect(context.pages()).not.toContain(backgroundPage);
|
||||||
|
await context.close();
|
||||||
|
await removeUserDataDir(userDataDir);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should not create pages automatically', async ({browserType, defaultBrowserOptions}) => {
|
||||||
|
const browser = await browserType.launch(defaultBrowserOptions);
|
||||||
|
const browserSession = await browser.newBrowserCDPSession();
|
||||||
|
const targets = [];
|
||||||
|
browserSession.on('Target.targetCreated', async ({targetInfo}) => {
|
||||||
|
if (targetInfo.type !== 'browser')
|
||||||
|
targets.push(targetInfo);
|
||||||
|
});
|
||||||
|
await browserSession.send('Target.setDiscoverTargets', { discover: true });
|
||||||
|
await browser.newContext();
|
||||||
|
await browser.close();
|
||||||
|
expect(targets.length).toBe(0);
|
||||||
|
});
|
||||||
|
|
@ -1,350 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright 2017 Google Inc. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const {FFOX, CHROMIUM, WEBKIT, CHANNEL} = testOptions;
|
|
||||||
|
|
||||||
registerFixture('sppBrowser', async ({browserType, defaultBrowserOptions}, test) => {
|
|
||||||
const browser = await browserType.launch({
|
|
||||||
...defaultBrowserOptions,
|
|
||||||
args: (defaultBrowserOptions.args || []).concat(['--site-per-process'])
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
await test(browser);
|
|
||||||
} finally {
|
|
||||||
await browser.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
registerFixture('sppContext', async ({sppBrowser}, test) => {
|
|
||||||
const context = await sppBrowser.newContext();
|
|
||||||
try {
|
|
||||||
await test(context);
|
|
||||||
} finally {
|
|
||||||
await context.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
registerFixture('sppPage', async ({sppContext}, test) => {
|
|
||||||
const page = await sppContext.newPage();
|
|
||||||
await test(page);
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
describe.skip(!CHROMIUM)('OOPIF', function() {
|
|
||||||
it('should report oopif frames', async function({sppBrowser, sppPage, server}) {
|
|
||||||
const browser = sppBrowser;
|
|
||||||
const page = sppPage;
|
|
||||||
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
|
||||||
expect(await countOOPIFs(browser)).toBe(1);
|
|
||||||
expect(page.frames().length).toBe(2);
|
|
||||||
expect(await page.frames()[1].evaluate(() => '' + location.href)).toBe(server.CROSS_PROCESS_PREFIX + '/grid.html');
|
|
||||||
});
|
|
||||||
it('should handle oopif detach', async function({sppBrowser, sppPage, server}) {
|
|
||||||
const browser = sppBrowser;
|
|
||||||
const page = sppPage;
|
|
||||||
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
|
||||||
expect(await countOOPIFs(browser)).toBe(1);
|
|
||||||
expect(page.frames().length).toBe(2);
|
|
||||||
const frame = page.frames()[1];
|
|
||||||
expect(await frame.evaluate(() => '' + location.href)).toBe(server.CROSS_PROCESS_PREFIX + '/grid.html');
|
|
||||||
const [detachedFrame] = await Promise.all([
|
|
||||||
page.waitForEvent('framedetached'),
|
|
||||||
page.evaluate(() => document.querySelector('iframe').remove()),
|
|
||||||
]);
|
|
||||||
expect(detachedFrame).toBe(frame);
|
|
||||||
});
|
|
||||||
it('should handle remote -> local -> remote transitions', async function({sppBrowser, sppPage, server}) {
|
|
||||||
const browser = sppBrowser;
|
|
||||||
const page = sppPage;
|
|
||||||
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
|
||||||
expect(page.frames().length).toBe(2);
|
|
||||||
expect(await countOOPIFs(browser)).toBe(1);
|
|
||||||
expect(await page.frames()[1].evaluate(() => '' + location.href)).toBe(server.CROSS_PROCESS_PREFIX + '/grid.html');
|
|
||||||
await Promise.all([
|
|
||||||
page.frames()[1].waitForNavigation(),
|
|
||||||
page.evaluate(() => goLocal()),
|
|
||||||
]);
|
|
||||||
expect(await page.frames()[1].evaluate(() => '' + location.href)).toBe(server.PREFIX + '/grid.html');
|
|
||||||
expect(await countOOPIFs(browser)).toBe(0);
|
|
||||||
await Promise.all([
|
|
||||||
page.frames()[1].waitForNavigation(),
|
|
||||||
page.evaluate(() => goRemote()),
|
|
||||||
]);
|
|
||||||
expect(await page.frames()[1].evaluate(() => '' + location.href)).toBe(server.CROSS_PROCESS_PREFIX + '/grid.html');
|
|
||||||
expect(await countOOPIFs(browser)).toBe(1);
|
|
||||||
});
|
|
||||||
it.fail(true)('should get the proper viewport', async({sppBrowser, sppPage, server}) => {
|
|
||||||
const browser = sppBrowser;
|
|
||||||
const page = sppPage;
|
|
||||||
expect(page.viewportSize()).toEqual({width: 1280, height: 720});
|
|
||||||
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
|
||||||
expect(page.frames().length).toBe(2);
|
|
||||||
expect(await countOOPIFs(browser)).toBe(1);
|
|
||||||
const oopif = page.frames()[1];
|
|
||||||
expect(await oopif.evaluate(() => screen.width)).toBe(1280);
|
|
||||||
expect(await oopif.evaluate(() => screen.height)).toBe(720);
|
|
||||||
expect(await oopif.evaluate(() => matchMedia('(device-width: 1280px)').matches)).toBe(true);
|
|
||||||
expect(await oopif.evaluate(() => matchMedia('(device-height: 720px)').matches)).toBe(true);
|
|
||||||
expect(await oopif.evaluate(() => 'ontouchstart' in window)).toBe(false);
|
|
||||||
await page.setViewportSize({width: 123, height: 456});
|
|
||||||
expect(await oopif.evaluate(() => screen.width)).toBe(123);
|
|
||||||
expect(await oopif.evaluate(() => screen.height)).toBe(456);
|
|
||||||
expect(await oopif.evaluate(() => matchMedia('(device-width: 123px)').matches)).toBe(true);
|
|
||||||
expect(await oopif.evaluate(() => matchMedia('(device-height: 456px)').matches)).toBe(true);
|
|
||||||
expect(await oopif.evaluate(() => 'ontouchstart' in window)).toBe(false);
|
|
||||||
});
|
|
||||||
it('should expose function', async({sppBrowser, sppPage, server}) => {
|
|
||||||
const browser = sppBrowser;
|
|
||||||
const page = sppPage;
|
|
||||||
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
|
||||||
expect(page.frames().length).toBe(2);
|
|
||||||
expect(await countOOPIFs(browser)).toBe(1);
|
|
||||||
const oopif = page.frames()[1];
|
|
||||||
await page.exposeFunction('mul', (a, b) => a * b);
|
|
||||||
const result = await oopif.evaluate(async function() {
|
|
||||||
return await mul(9, 4);
|
|
||||||
});
|
|
||||||
expect(result).toBe(36);
|
|
||||||
});
|
|
||||||
it('should emulate media', async({sppBrowser, sppPage, server}) => {
|
|
||||||
const browser = sppBrowser;
|
|
||||||
const page = sppPage;
|
|
||||||
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
|
||||||
expect(page.frames().length).toBe(2);
|
|
||||||
expect(await countOOPIFs(browser)).toBe(1);
|
|
||||||
const oopif = page.frames()[1];
|
|
||||||
expect(await oopif.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches)).toBe(false);
|
|
||||||
await page.emulateMedia({ colorScheme: 'dark' });
|
|
||||||
expect(await oopif.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches)).toBe(true);
|
|
||||||
});
|
|
||||||
it('should emulate offline', async({sppBrowser, sppPage, sppContext, server}) => {
|
|
||||||
const browser = sppBrowser;
|
|
||||||
const context = sppContext;
|
|
||||||
const page = sppPage;
|
|
||||||
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
|
||||||
expect(page.frames().length).toBe(2);
|
|
||||||
expect(await countOOPIFs(browser)).toBe(1);
|
|
||||||
const oopif = page.frames()[1];
|
|
||||||
expect(await oopif.evaluate(() => navigator.onLine)).toBe(true);
|
|
||||||
await context.setOffline(true);
|
|
||||||
expect(await oopif.evaluate(() => navigator.onLine)).toBe(false);
|
|
||||||
});
|
|
||||||
it('should support context options', async({sppBrowser, server, playwright}) => {
|
|
||||||
const browser = sppBrowser;
|
|
||||||
const iPhone = playwright.devices['iPhone 6']
|
|
||||||
const context = await browser.newContext({ ...iPhone, timezoneId: 'America/Jamaica', locale: 'fr-CH', userAgent: 'UA' });
|
|
||||||
const page = await context.newPage();
|
|
||||||
|
|
||||||
const [request] = await Promise.all([
|
|
||||||
server.waitForRequest('/grid.html'),
|
|
||||||
page.goto(server.PREFIX + '/dynamic-oopif.html'),
|
|
||||||
]);
|
|
||||||
expect(page.frames().length).toBe(2);
|
|
||||||
expect(await countOOPIFs(browser)).toBe(1);
|
|
||||||
const oopif = page.frames()[1];
|
|
||||||
|
|
||||||
expect(await oopif.evaluate(() => 'ontouchstart' in window)).toBe(true);
|
|
||||||
expect(await oopif.evaluate(() => new Date(1479579154987).toString())).toBe('Sat Nov 19 2016 13:12:34 GMT-0500 (heure normale de l’Est nord-américain)');
|
|
||||||
expect(await oopif.evaluate(() => navigator.language)).toBe('fr-CH');
|
|
||||||
expect(await oopif.evaluate(() => navigator.userAgent)).toBe('UA');
|
|
||||||
expect(request.headers['user-agent']).toBe('UA');
|
|
||||||
|
|
||||||
await context.close();
|
|
||||||
});
|
|
||||||
it('should respect route', async({sppBrowser, sppPage, server}) => {
|
|
||||||
const browser = sppBrowser;
|
|
||||||
const page = sppPage;
|
|
||||||
let intercepted = false;
|
|
||||||
await page.route('**/digits/0.png', route => {
|
|
||||||
intercepted = true;
|
|
||||||
route.continue();
|
|
||||||
});
|
|
||||||
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
|
||||||
expect(page.frames().length).toBe(2);
|
|
||||||
expect(await countOOPIFs(browser)).toBe(1);
|
|
||||||
expect(intercepted).toBe(true);
|
|
||||||
});
|
|
||||||
it('should take screenshot', async({sppBrowser, sppPage, server}) => {
|
|
||||||
const browser = sppBrowser;
|
|
||||||
const page = sppPage;
|
|
||||||
await page.setViewportSize({width: 500, height: 500});
|
|
||||||
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
|
||||||
expect(page.frames().length).toBe(2);
|
|
||||||
expect(await countOOPIFs(browser)).toBe(1);
|
|
||||||
expect(await page.screenshot()).toBeGolden('screenshot-oopif.png');
|
|
||||||
});
|
|
||||||
it('should load oopif iframes with subresources and request interception', async function({sppBrowser, sppPage, server, context}) {
|
|
||||||
const browser = sppBrowser;
|
|
||||||
const page = sppPage;
|
|
||||||
await page.route('**/*', route => route.continue());
|
|
||||||
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
|
||||||
expect(await countOOPIFs(browser)).toBe(1);
|
|
||||||
});
|
|
||||||
it('should report main requests', async function({sppBrowser, sppPage, server}) {
|
|
||||||
const browser = sppBrowser;
|
|
||||||
const page = sppPage;
|
|
||||||
const requestFrames = [];
|
|
||||||
page.on('request', r => requestFrames.push(r.frame()));
|
|
||||||
const finishedFrames = [];
|
|
||||||
page.on('requestfinished', r => finishedFrames.push(r.frame()));
|
|
||||||
|
|
||||||
await page.goto(server.PREFIX + '/empty.html');
|
|
||||||
const main = page.mainFrame();
|
|
||||||
|
|
||||||
await main.evaluate(url => {
|
|
||||||
const iframe = document.createElement('iframe');
|
|
||||||
iframe.src = url;
|
|
||||||
document.body.appendChild(iframe);
|
|
||||||
return new Promise(f => iframe.onload = f);
|
|
||||||
}, server.CROSS_PROCESS_PREFIX + '/empty.html');
|
|
||||||
expect(page.frames().length).toBe(2);
|
|
||||||
const child = main.childFrames()[0];
|
|
||||||
await child.waitForLoadState('domcontentloaded');
|
|
||||||
|
|
||||||
await child.evaluate(url => {
|
|
||||||
const iframe = document.createElement('iframe');
|
|
||||||
iframe.src = url;
|
|
||||||
document.body.appendChild(iframe);
|
|
||||||
return new Promise(f => iframe.onload = f);
|
|
||||||
}, server.PREFIX + '/empty.html');
|
|
||||||
expect(page.frames().length).toBe(3);
|
|
||||||
const grandChild = child.childFrames()[0];
|
|
||||||
await grandChild.waitForLoadState('domcontentloaded');
|
|
||||||
|
|
||||||
expect(await countOOPIFs(browser)).toBe(2);
|
|
||||||
expect(requestFrames[0]).toBe(main);
|
|
||||||
expect(finishedFrames[0]).toBe(main);
|
|
||||||
expect(requestFrames[1]).toBe(child);
|
|
||||||
expect(finishedFrames[1]).toBe(child);
|
|
||||||
expect(requestFrames[2]).toBe(grandChild);
|
|
||||||
expect(finishedFrames[2]).toBe(grandChild);
|
|
||||||
});
|
|
||||||
it('should support exposeFunction', async function({sppBrowser, sppContext, sppPage, server}) {
|
|
||||||
const browser = sppBrowser;
|
|
||||||
const context = sppContext;
|
|
||||||
const page = sppPage;
|
|
||||||
await context.exposeFunction('dec', a => a - 1);
|
|
||||||
await page.exposeFunction('inc', a => a + 1);
|
|
||||||
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
|
||||||
expect(await countOOPIFs(browser)).toBe(1);
|
|
||||||
expect(page.frames().length).toBe(2);
|
|
||||||
expect(await page.frames()[0].evaluate(() => inc(3))).toBe(4);
|
|
||||||
expect(await page.frames()[1].evaluate(() => inc(4))).toBe(5);
|
|
||||||
expect(await page.frames()[0].evaluate(() => dec(3))).toBe(2);
|
|
||||||
expect(await page.frames()[1].evaluate(() => dec(4))).toBe(3);
|
|
||||||
});
|
|
||||||
it('should support addInitScript', async function({sppBrowser, sppContext, sppPage, server}) {
|
|
||||||
const browser = sppBrowser;
|
|
||||||
const context = sppContext;
|
|
||||||
const page = sppPage;
|
|
||||||
await context.addInitScript(() => window.bar = 17);
|
|
||||||
await page.addInitScript(() => window.foo = 42);
|
|
||||||
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
|
||||||
expect(await countOOPIFs(browser)).toBe(1);
|
|
||||||
expect(page.frames().length).toBe(2);
|
|
||||||
expect(await page.frames()[0].evaluate(() => window.foo)).toBe(42);
|
|
||||||
expect(await page.frames()[1].evaluate(() => window.foo)).toBe(42);
|
|
||||||
expect(await page.frames()[0].evaluate(() => window.bar)).toBe(17);
|
|
||||||
expect(await page.frames()[1].evaluate(() => window.bar)).toBe(17);
|
|
||||||
});
|
|
||||||
// @see https://github.com/microsoft/playwright/issues/1240
|
|
||||||
it('should click a button when it overlays oopif', async function({sppBrowser, sppPage, server}) {
|
|
||||||
const browser = sppBrowser;
|
|
||||||
const page = sppPage;
|
|
||||||
await page.goto(server.PREFIX + '/button-overlay-oopif.html');
|
|
||||||
expect(await countOOPIFs(browser)).toBe(1);
|
|
||||||
await page.click('button');
|
|
||||||
expect(await page.evaluate(() => window.BUTTON_CLICKED)).toBe(true);
|
|
||||||
});
|
|
||||||
it('should report google.com frame with headful', async({browserType, defaultBrowserOptions, server}) => {
|
|
||||||
// @see https://github.com/GoogleChrome/puppeteer/issues/2548
|
|
||||||
// https://google.com is isolated by default in Chromium embedder.
|
|
||||||
const browser = await browserType.launch({...defaultBrowserOptions, headless: false});
|
|
||||||
const page = await browser.newPage();
|
|
||||||
await page.goto(server.EMPTY_PAGE);
|
|
||||||
await page.route('**/*', route => {
|
|
||||||
route.fulfill({body: 'YO, GOOGLE.COM'});
|
|
||||||
});
|
|
||||||
await page.evaluate(() => {
|
|
||||||
const frame = document.createElement('iframe');
|
|
||||||
frame.setAttribute('src', 'https://google.com/');
|
|
||||||
document.body.appendChild(frame);
|
|
||||||
return new Promise(x => frame.onload = x);
|
|
||||||
});
|
|
||||||
await page.waitForSelector('iframe[src="https://google.com/"]');
|
|
||||||
expect(await countOOPIFs(browser)).toBe(1);
|
|
||||||
const urls = page.frames().map(frame => frame.url());
|
|
||||||
expect(urls).toEqual([
|
|
||||||
server.EMPTY_PAGE,
|
|
||||||
'https://google.com/'
|
|
||||||
]);
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
it('ElementHandle.boundingBox() should work', async function({sppBrowser, sppPage, server}) {
|
|
||||||
const browser = sppBrowser;
|
|
||||||
const page = sppPage;
|
|
||||||
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
|
||||||
await page.$eval('iframe', iframe => {
|
|
||||||
iframe.style.width = '500px';
|
|
||||||
iframe.style.height = '500px';
|
|
||||||
iframe.style.marginLeft = '42px';
|
|
||||||
iframe.style.marginTop = '17px';
|
|
||||||
});
|
|
||||||
await page.frames()[1].goto(page.frames()[1].url());
|
|
||||||
|
|
||||||
expect(await countOOPIFs(browser)).toBe(1);
|
|
||||||
const handle1 = await page.frames()[1].$('.box:nth-of-type(13)');
|
|
||||||
expect(await handle1.boundingBox()).toEqual({ x: 100 + 42, y: 50 + 17, width: 50, height: 50 });
|
|
||||||
|
|
||||||
await Promise.all([
|
|
||||||
page.frames()[1].waitForNavigation(),
|
|
||||||
page.evaluate(() => goLocal()),
|
|
||||||
]);
|
|
||||||
expect(await countOOPIFs(browser)).toBe(0);
|
|
||||||
const handle2 = await page.frames()[1].$('.box:nth-of-type(13)');
|
|
||||||
expect(await handle2.boundingBox()).toEqual({ x: 100 + 42, y: 50 + 17, width: 50, height: 50 });
|
|
||||||
});
|
|
||||||
it('should click', async function({sppBrowser, sppPage, server}) {
|
|
||||||
const browser = sppBrowser;
|
|
||||||
const page = sppPage;
|
|
||||||
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
|
||||||
await page.$eval('iframe', iframe => {
|
|
||||||
iframe.style.width = '500px';
|
|
||||||
iframe.style.height = '500px';
|
|
||||||
iframe.style.marginLeft = '102px';
|
|
||||||
iframe.style.marginTop = '117px';
|
|
||||||
});
|
|
||||||
await page.frames()[1].goto(page.frames()[1].url());
|
|
||||||
|
|
||||||
expect(await countOOPIFs(browser)).toBe(1);
|
|
||||||
const handle1 = await page.frames()[1].$('.box:nth-of-type(13)');
|
|
||||||
await handle1.evaluate(div => div.addEventListener('click', () => window._clicked = true, false));
|
|
||||||
await handle1.click();
|
|
||||||
expect(await handle1.evaluate(() => window._clicked)).toBe(true);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
async function countOOPIFs(browser) {
|
|
||||||
const browserSession = await browser.newBrowserCDPSession();
|
|
||||||
const oopifs = [];
|
|
||||||
browserSession.on('Target.targetCreated', async ({targetInfo}) => {
|
|
||||||
if (targetInfo.type === 'iframe')
|
|
||||||
oopifs.push(targetInfo);
|
|
||||||
});
|
|
||||||
await browserSession.send('Target.setDiscoverTargets', { discover: true });
|
|
||||||
await browserSession.detach();
|
|
||||||
return oopifs.length;
|
|
||||||
}
|
|
||||||
364
test/chromium/oopif.spec.js
Normal file
364
test/chromium/oopif.spec.js
Normal file
|
|
@ -0,0 +1,364 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2017 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const {FFOX, CHROMIUM, WEBKIT, CHANNEL} = testOptions;
|
||||||
|
|
||||||
|
registerFixture('sppBrowser', async ({browserType, defaultBrowserOptions}, test) => {
|
||||||
|
const browser = await browserType.launch({
|
||||||
|
...defaultBrowserOptions,
|
||||||
|
args: (defaultBrowserOptions.args || []).concat(['--site-per-process'])
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await test(browser);
|
||||||
|
} finally {
|
||||||
|
await browser.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
registerFixture('sppContext', async ({sppBrowser}, test) => {
|
||||||
|
const context = await sppBrowser.newContext();
|
||||||
|
try {
|
||||||
|
await test(context);
|
||||||
|
} finally {
|
||||||
|
await context.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
registerFixture('sppPage', async ({sppContext}, test) => {
|
||||||
|
const page = await sppContext.newPage();
|
||||||
|
await test(page);
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should report oopif frames', async function({sppBrowser, sppPage, server}) {
|
||||||
|
const browser = sppBrowser;
|
||||||
|
const page = sppPage;
|
||||||
|
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
||||||
|
expect(await countOOPIFs(browser)).toBe(1);
|
||||||
|
expect(page.frames().length).toBe(2);
|
||||||
|
expect(await page.frames()[1].evaluate(() => '' + location.href)).toBe(server.CROSS_PROCESS_PREFIX + '/grid.html');
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should handle oopif detach', async function({sppBrowser, sppPage, server}) {
|
||||||
|
const browser = sppBrowser;
|
||||||
|
const page = sppPage;
|
||||||
|
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
||||||
|
expect(await countOOPIFs(browser)).toBe(1);
|
||||||
|
expect(page.frames().length).toBe(2);
|
||||||
|
const frame = page.frames()[1];
|
||||||
|
expect(await frame.evaluate(() => '' + location.href)).toBe(server.CROSS_PROCESS_PREFIX + '/grid.html');
|
||||||
|
const [detachedFrame] = await Promise.all([
|
||||||
|
page.waitForEvent('framedetached'),
|
||||||
|
page.evaluate(() => document.querySelector('iframe').remove()),
|
||||||
|
]);
|
||||||
|
expect(detachedFrame).toBe(frame);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should handle remote -> local -> remote transitions', async function({sppBrowser, sppPage, server}) {
|
||||||
|
const browser = sppBrowser;
|
||||||
|
const page = sppPage;
|
||||||
|
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
||||||
|
expect(page.frames().length).toBe(2);
|
||||||
|
expect(await countOOPIFs(browser)).toBe(1);
|
||||||
|
expect(await page.frames()[1].evaluate(() => '' + location.href)).toBe(server.CROSS_PROCESS_PREFIX + '/grid.html');
|
||||||
|
await Promise.all([
|
||||||
|
page.frames()[1].waitForNavigation(),
|
||||||
|
page.evaluate(() => goLocal()),
|
||||||
|
]);
|
||||||
|
expect(await page.frames()[1].evaluate(() => '' + location.href)).toBe(server.PREFIX + '/grid.html');
|
||||||
|
expect(await countOOPIFs(browser)).toBe(0);
|
||||||
|
await Promise.all([
|
||||||
|
page.frames()[1].waitForNavigation(),
|
||||||
|
page.evaluate(() => goRemote()),
|
||||||
|
]);
|
||||||
|
expect(await page.frames()[1].evaluate(() => '' + location.href)).toBe(server.CROSS_PROCESS_PREFIX + '/grid.html');
|
||||||
|
expect(await countOOPIFs(browser)).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.fail(true)('should get the proper viewport', async({sppBrowser, sppPage, server}) => {
|
||||||
|
const browser = sppBrowser;
|
||||||
|
const page = sppPage;
|
||||||
|
expect(page.viewportSize()).toEqual({width: 1280, height: 720});
|
||||||
|
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
||||||
|
expect(page.frames().length).toBe(2);
|
||||||
|
expect(await countOOPIFs(browser)).toBe(1);
|
||||||
|
const oopif = page.frames()[1];
|
||||||
|
expect(await oopif.evaluate(() => screen.width)).toBe(1280);
|
||||||
|
expect(await oopif.evaluate(() => screen.height)).toBe(720);
|
||||||
|
expect(await oopif.evaluate(() => matchMedia('(device-width: 1280px)').matches)).toBe(true);
|
||||||
|
expect(await oopif.evaluate(() => matchMedia('(device-height: 720px)').matches)).toBe(true);
|
||||||
|
expect(await oopif.evaluate(() => 'ontouchstart' in window)).toBe(false);
|
||||||
|
await page.setViewportSize({width: 123, height: 456});
|
||||||
|
expect(await oopif.evaluate(() => screen.width)).toBe(123);
|
||||||
|
expect(await oopif.evaluate(() => screen.height)).toBe(456);
|
||||||
|
expect(await oopif.evaluate(() => matchMedia('(device-width: 123px)').matches)).toBe(true);
|
||||||
|
expect(await oopif.evaluate(() => matchMedia('(device-height: 456px)').matches)).toBe(true);
|
||||||
|
expect(await oopif.evaluate(() => 'ontouchstart' in window)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should expose function', async({sppBrowser, sppPage, server}) => {
|
||||||
|
const browser = sppBrowser;
|
||||||
|
const page = sppPage;
|
||||||
|
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
||||||
|
expect(page.frames().length).toBe(2);
|
||||||
|
expect(await countOOPIFs(browser)).toBe(1);
|
||||||
|
const oopif = page.frames()[1];
|
||||||
|
await page.exposeFunction('mul', (a, b) => a * b);
|
||||||
|
const result = await oopif.evaluate(async function() {
|
||||||
|
return await mul(9, 4);
|
||||||
|
});
|
||||||
|
expect(result).toBe(36);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should emulate media', async({sppBrowser, sppPage, server}) => {
|
||||||
|
const browser = sppBrowser;
|
||||||
|
const page = sppPage;
|
||||||
|
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
||||||
|
expect(page.frames().length).toBe(2);
|
||||||
|
expect(await countOOPIFs(browser)).toBe(1);
|
||||||
|
const oopif = page.frames()[1];
|
||||||
|
expect(await oopif.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches)).toBe(false);
|
||||||
|
await page.emulateMedia({ colorScheme: 'dark' });
|
||||||
|
expect(await oopif.evaluate(() => matchMedia('(prefers-color-scheme: dark)').matches)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should emulate offline', async({sppBrowser, sppPage, sppContext, server}) => {
|
||||||
|
const browser = sppBrowser;
|
||||||
|
const context = sppContext;
|
||||||
|
const page = sppPage;
|
||||||
|
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
||||||
|
expect(page.frames().length).toBe(2);
|
||||||
|
expect(await countOOPIFs(browser)).toBe(1);
|
||||||
|
const oopif = page.frames()[1];
|
||||||
|
expect(await oopif.evaluate(() => navigator.onLine)).toBe(true);
|
||||||
|
await context.setOffline(true);
|
||||||
|
expect(await oopif.evaluate(() => navigator.onLine)).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should support context options', async({sppBrowser, server, playwright}) => {
|
||||||
|
const browser = sppBrowser;
|
||||||
|
const iPhone = playwright.devices['iPhone 6']
|
||||||
|
const context = await browser.newContext({ ...iPhone, timezoneId: 'America/Jamaica', locale: 'fr-CH', userAgent: 'UA' });
|
||||||
|
const page = await context.newPage();
|
||||||
|
|
||||||
|
const [request] = await Promise.all([
|
||||||
|
server.waitForRequest('/grid.html'),
|
||||||
|
page.goto(server.PREFIX + '/dynamic-oopif.html'),
|
||||||
|
]);
|
||||||
|
expect(page.frames().length).toBe(2);
|
||||||
|
expect(await countOOPIFs(browser)).toBe(1);
|
||||||
|
const oopif = page.frames()[1];
|
||||||
|
|
||||||
|
expect(await oopif.evaluate(() => 'ontouchstart' in window)).toBe(true);
|
||||||
|
expect(await oopif.evaluate(() => new Date(1479579154987).toString())).toBe('Sat Nov 19 2016 13:12:34 GMT-0500 (heure normale de l’Est nord-américain)');
|
||||||
|
expect(await oopif.evaluate(() => navigator.language)).toBe('fr-CH');
|
||||||
|
expect(await oopif.evaluate(() => navigator.userAgent)).toBe('UA');
|
||||||
|
expect(request.headers['user-agent']).toBe('UA');
|
||||||
|
|
||||||
|
await context.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should respect route', async({sppBrowser, sppPage, server}) => {
|
||||||
|
const browser = sppBrowser;
|
||||||
|
const page = sppPage;
|
||||||
|
let intercepted = false;
|
||||||
|
await page.route('**/digits/0.png', route => {
|
||||||
|
intercepted = true;
|
||||||
|
route.continue();
|
||||||
|
});
|
||||||
|
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
||||||
|
expect(page.frames().length).toBe(2);
|
||||||
|
expect(await countOOPIFs(browser)).toBe(1);
|
||||||
|
expect(intercepted).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should take screenshot', async({sppBrowser, sppPage, server}) => {
|
||||||
|
const browser = sppBrowser;
|
||||||
|
const page = sppPage;
|
||||||
|
await page.setViewportSize({width: 500, height: 500});
|
||||||
|
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
||||||
|
expect(page.frames().length).toBe(2);
|
||||||
|
expect(await countOOPIFs(browser)).toBe(1);
|
||||||
|
expect(await page.screenshot()).toBeGolden('screenshot-oopif.png');
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should load oopif iframes with subresources and request interception', async function({sppBrowser, sppPage, server, context}) {
|
||||||
|
const browser = sppBrowser;
|
||||||
|
const page = sppPage;
|
||||||
|
await page.route('**/*', route => route.continue());
|
||||||
|
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
||||||
|
expect(await countOOPIFs(browser)).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should report main requests', async function({sppBrowser, sppPage, server}) {
|
||||||
|
const browser = sppBrowser;
|
||||||
|
const page = sppPage;
|
||||||
|
const requestFrames = [];
|
||||||
|
page.on('request', r => requestFrames.push(r.frame()));
|
||||||
|
const finishedFrames = [];
|
||||||
|
page.on('requestfinished', r => finishedFrames.push(r.frame()));
|
||||||
|
|
||||||
|
await page.goto(server.PREFIX + '/empty.html');
|
||||||
|
const main = page.mainFrame();
|
||||||
|
|
||||||
|
await main.evaluate(url => {
|
||||||
|
const iframe = document.createElement('iframe');
|
||||||
|
iframe.src = url;
|
||||||
|
document.body.appendChild(iframe);
|
||||||
|
return new Promise(f => iframe.onload = f);
|
||||||
|
}, server.CROSS_PROCESS_PREFIX + '/empty.html');
|
||||||
|
expect(page.frames().length).toBe(2);
|
||||||
|
const child = main.childFrames()[0];
|
||||||
|
await child.waitForLoadState('domcontentloaded');
|
||||||
|
|
||||||
|
await child.evaluate(url => {
|
||||||
|
const iframe = document.createElement('iframe');
|
||||||
|
iframe.src = url;
|
||||||
|
document.body.appendChild(iframe);
|
||||||
|
return new Promise(f => iframe.onload = f);
|
||||||
|
}, server.PREFIX + '/empty.html');
|
||||||
|
expect(page.frames().length).toBe(3);
|
||||||
|
const grandChild = child.childFrames()[0];
|
||||||
|
await grandChild.waitForLoadState('domcontentloaded');
|
||||||
|
|
||||||
|
expect(await countOOPIFs(browser)).toBe(2);
|
||||||
|
expect(requestFrames[0]).toBe(main);
|
||||||
|
expect(finishedFrames[0]).toBe(main);
|
||||||
|
expect(requestFrames[1]).toBe(child);
|
||||||
|
expect(finishedFrames[1]).toBe(child);
|
||||||
|
expect(requestFrames[2]).toBe(grandChild);
|
||||||
|
expect(finishedFrames[2]).toBe(grandChild);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should support exposeFunction', async function({sppBrowser, sppContext, sppPage, server}) {
|
||||||
|
const browser = sppBrowser;
|
||||||
|
const context = sppContext;
|
||||||
|
const page = sppPage;
|
||||||
|
await context.exposeFunction('dec', a => a - 1);
|
||||||
|
await page.exposeFunction('inc', a => a + 1);
|
||||||
|
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
||||||
|
expect(await countOOPIFs(browser)).toBe(1);
|
||||||
|
expect(page.frames().length).toBe(2);
|
||||||
|
expect(await page.frames()[0].evaluate(() => inc(3))).toBe(4);
|
||||||
|
expect(await page.frames()[1].evaluate(() => inc(4))).toBe(5);
|
||||||
|
expect(await page.frames()[0].evaluate(() => dec(3))).toBe(2);
|
||||||
|
expect(await page.frames()[1].evaluate(() => dec(4))).toBe(3);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should support addInitScript', async function({sppBrowser, sppContext, sppPage, server}) {
|
||||||
|
const browser = sppBrowser;
|
||||||
|
const context = sppContext;
|
||||||
|
const page = sppPage;
|
||||||
|
await context.addInitScript(() => window.bar = 17);
|
||||||
|
await page.addInitScript(() => window.foo = 42);
|
||||||
|
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
||||||
|
expect(await countOOPIFs(browser)).toBe(1);
|
||||||
|
expect(page.frames().length).toBe(2);
|
||||||
|
expect(await page.frames()[0].evaluate(() => window.foo)).toBe(42);
|
||||||
|
expect(await page.frames()[1].evaluate(() => window.foo)).toBe(42);
|
||||||
|
expect(await page.frames()[0].evaluate(() => window.bar)).toBe(17);
|
||||||
|
expect(await page.frames()[1].evaluate(() => window.bar)).toBe(17);
|
||||||
|
});
|
||||||
|
// @see https://github.com/microsoft/playwright/issues/1240
|
||||||
|
it.skip(!CHROMIUM)('should click a button when it overlays oopif', async function({sppBrowser, sppPage, server}) {
|
||||||
|
const browser = sppBrowser;
|
||||||
|
const page = sppPage;
|
||||||
|
await page.goto(server.PREFIX + '/button-overlay-oopif.html');
|
||||||
|
expect(await countOOPIFs(browser)).toBe(1);
|
||||||
|
await page.click('button');
|
||||||
|
expect(await page.evaluate(() => window.BUTTON_CLICKED)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should report google.com frame with headful', async({browserType, defaultBrowserOptions, server}) => {
|
||||||
|
// @see https://github.com/GoogleChrome/puppeteer/issues/2548
|
||||||
|
// https://google.com is isolated by default in Chromium embedder.
|
||||||
|
const browser = await browserType.launch({...defaultBrowserOptions, headless: false});
|
||||||
|
const page = await browser.newPage();
|
||||||
|
await page.goto(server.EMPTY_PAGE);
|
||||||
|
await page.route('**/*', route => {
|
||||||
|
route.fulfill({body: 'YO, GOOGLE.COM'});
|
||||||
|
});
|
||||||
|
await page.evaluate(() => {
|
||||||
|
const frame = document.createElement('iframe');
|
||||||
|
frame.setAttribute('src', 'https://google.com/');
|
||||||
|
document.body.appendChild(frame);
|
||||||
|
return new Promise(x => frame.onload = x);
|
||||||
|
});
|
||||||
|
await page.waitForSelector('iframe[src="https://google.com/"]');
|
||||||
|
expect(await countOOPIFs(browser)).toBe(1);
|
||||||
|
const urls = page.frames().map(frame => frame.url());
|
||||||
|
expect(urls).toEqual([
|
||||||
|
server.EMPTY_PAGE,
|
||||||
|
'https://google.com/'
|
||||||
|
]);
|
||||||
|
await browser.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('ElementHandle.boundingBox() should work', async function({sppBrowser, sppPage, server}) {
|
||||||
|
const browser = sppBrowser;
|
||||||
|
const page = sppPage;
|
||||||
|
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
||||||
|
await page.$eval('iframe', iframe => {
|
||||||
|
iframe.style.width = '500px';
|
||||||
|
iframe.style.height = '500px';
|
||||||
|
iframe.style.marginLeft = '42px';
|
||||||
|
iframe.style.marginTop = '17px';
|
||||||
|
});
|
||||||
|
await page.frames()[1].goto(page.frames()[1].url());
|
||||||
|
|
||||||
|
expect(await countOOPIFs(browser)).toBe(1);
|
||||||
|
const handle1 = await page.frames()[1].$('.box:nth-of-type(13)');
|
||||||
|
expect(await handle1.boundingBox()).toEqual({ x: 100 + 42, y: 50 + 17, width: 50, height: 50 });
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
page.frames()[1].waitForNavigation(),
|
||||||
|
page.evaluate(() => goLocal()),
|
||||||
|
]);
|
||||||
|
expect(await countOOPIFs(browser)).toBe(0);
|
||||||
|
const handle2 = await page.frames()[1].$('.box:nth-of-type(13)');
|
||||||
|
expect(await handle2.boundingBox()).toEqual({ x: 100 + 42, y: 50 + 17, width: 50, height: 50 });
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should click', async function({sppBrowser, sppPage, server}) {
|
||||||
|
const browser = sppBrowser;
|
||||||
|
const page = sppPage;
|
||||||
|
await page.goto(server.PREFIX + '/dynamic-oopif.html');
|
||||||
|
await page.$eval('iframe', iframe => {
|
||||||
|
iframe.style.width = '500px';
|
||||||
|
iframe.style.height = '500px';
|
||||||
|
iframe.style.marginLeft = '102px';
|
||||||
|
iframe.style.marginTop = '117px';
|
||||||
|
});
|
||||||
|
await page.frames()[1].goto(page.frames()[1].url());
|
||||||
|
|
||||||
|
expect(await countOOPIFs(browser)).toBe(1);
|
||||||
|
const handle1 = await page.frames()[1].$('.box:nth-of-type(13)');
|
||||||
|
await handle1.evaluate(div => div.addEventListener('click', () => window._clicked = true, false));
|
||||||
|
await handle1.click();
|
||||||
|
expect(await handle1.evaluate(() => window._clicked)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
async function countOOPIFs(browser) {
|
||||||
|
const browserSession = await browser.newBrowserCDPSession();
|
||||||
|
const oopifs = [];
|
||||||
|
browserSession.on('Target.targetCreated', async ({targetInfo}) => {
|
||||||
|
if (targetInfo.type === 'iframe')
|
||||||
|
oopifs.push(targetInfo);
|
||||||
|
});
|
||||||
|
await browserSession.send('Target.setDiscoverTargets', { discover: true });
|
||||||
|
await browserSession.detach();
|
||||||
|
return oopifs.length;
|
||||||
|
}
|
||||||
|
|
@ -1,112 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright 2018 Google Inc. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const {FFOX, CHROMIUM, WEBKIT, CHANNEL, USES_HOOKS} = testOptions;
|
|
||||||
|
|
||||||
describe.skip(!CHROMIUM)('ChromiumBrowserContext.createSession', function() {
|
|
||||||
it('should work', async function({page}) {
|
|
||||||
const client = await page.context().newCDPSession(page);
|
|
||||||
|
|
||||||
await Promise.all([
|
|
||||||
client.send('Runtime.enable'),
|
|
||||||
client.send('Runtime.evaluate', { expression: 'window.foo = "bar"' })
|
|
||||||
]);
|
|
||||||
const foo = await page.evaluate(() => window.foo);
|
|
||||||
expect(foo).toBe('bar');
|
|
||||||
});
|
|
||||||
it('should send events', async function({page, server}) {
|
|
||||||
const client = await page.context().newCDPSession(page);
|
|
||||||
await client.send('Network.enable');
|
|
||||||
const events = [];
|
|
||||||
client.on('Network.requestWillBeSent', event => events.push(event));
|
|
||||||
await page.goto(server.EMPTY_PAGE);
|
|
||||||
expect(events.length).toBe(1);
|
|
||||||
});
|
|
||||||
it('should enable and disable domains independently', async function({page}) {
|
|
||||||
const client = await page.context().newCDPSession(page);
|
|
||||||
await client.send('Runtime.enable');
|
|
||||||
await client.send('Debugger.enable');
|
|
||||||
// JS coverage enables and then disables Debugger domain.
|
|
||||||
await page.coverage.startJSCoverage();
|
|
||||||
await page.coverage.stopJSCoverage();
|
|
||||||
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 => {
|
|
||||||
if (event.url === 'foo.js')
|
|
||||||
f();
|
|
||||||
})),
|
|
||||||
page.evaluate('//# sourceURL=foo.js')
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
it('should be able to detach session', async function({page}) {
|
|
||||||
const client = await page.context().newCDPSession(page);
|
|
||||||
await client.send('Runtime.enable');
|
|
||||||
const evalResponse = await client.send('Runtime.evaluate', {expression: '1 + 2', returnByValue: true});
|
|
||||||
expect(evalResponse.result.value).toBe(3);
|
|
||||||
await client.detach();
|
|
||||||
let error = null;
|
|
||||||
try {
|
|
||||||
await client.send('Runtime.evaluate', {expression: '3 + 1', returnByValue: true});
|
|
||||||
} catch (e) {
|
|
||||||
error = e;
|
|
||||||
}
|
|
||||||
expect(error.message).toContain(CHANNEL ? 'Target browser or context has been closed' : 'Session closed.');
|
|
||||||
});
|
|
||||||
it('should throw nice errors', async function({page}) {
|
|
||||||
const client = await page.context().newCDPSession(page);
|
|
||||||
const error = await theSourceOfTheProblems().catch(error => error);
|
|
||||||
expect(error.stack).toContain('theSourceOfTheProblems');
|
|
||||||
expect(error.message).toContain('ThisCommand.DoesNotExist');
|
|
||||||
|
|
||||||
async function theSourceOfTheProblems() {
|
|
||||||
await client.send('ThisCommand.DoesNotExist');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
it('should not break page.close()', async function({browser}) {
|
|
||||||
const context = await browser.newContext();
|
|
||||||
const page = await context.newPage();
|
|
||||||
const session = await page.context().newCDPSession(page);
|
|
||||||
await session.detach();
|
|
||||||
await page.close();
|
|
||||||
await context.close();
|
|
||||||
});
|
|
||||||
it('should detach when page closes', async function({browser}) {
|
|
||||||
const context = await browser.newContext();
|
|
||||||
const page = await context.newPage();
|
|
||||||
const session = await context.newCDPSession(page);
|
|
||||||
await page.close();
|
|
||||||
let error;
|
|
||||||
await session.detach().catch(e => error = e);
|
|
||||||
expect(error).toBeTruthy();
|
|
||||||
await context.close();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
describe.skip(!CHROMIUM)('ChromiumBrowser.newBrowserCDPSession', function() {
|
|
||||||
it('should work', async function({browser}) {
|
|
||||||
const session = await browser.newBrowserCDPSession();
|
|
||||||
|
|
||||||
const version = await session.send('Browser.getVersion');
|
|
||||||
expect(version.userAgent).toBeTruthy();
|
|
||||||
|
|
||||||
let gotEvent = false;
|
|
||||||
session.on('Target.targetCreated', () => gotEvent = true);
|
|
||||||
await session.send('Target.setDiscoverTargets', { discover: true });
|
|
||||||
expect(gotEvent).toBe(true);
|
|
||||||
|
|
||||||
await session.detach();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
115
test/chromium/session.spec.js
Normal file
115
test/chromium/session.spec.js
Normal file
|
|
@ -0,0 +1,115 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2018 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const {FFOX, CHROMIUM, WEBKIT, CHANNEL, USES_HOOKS} = testOptions;
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should work', async function({page}) {
|
||||||
|
const client = await page.context().newCDPSession(page);
|
||||||
|
|
||||||
|
await Promise.all([
|
||||||
|
client.send('Runtime.enable'),
|
||||||
|
client.send('Runtime.evaluate', { expression: 'window.foo = "bar"' })
|
||||||
|
]);
|
||||||
|
const foo = await page.evaluate(() => window.foo);
|
||||||
|
expect(foo).toBe('bar');
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should send events', async function({page, server}) {
|
||||||
|
const client = await page.context().newCDPSession(page);
|
||||||
|
await client.send('Network.enable');
|
||||||
|
const events = [];
|
||||||
|
client.on('Network.requestWillBeSent', event => events.push(event));
|
||||||
|
await page.goto(server.EMPTY_PAGE);
|
||||||
|
expect(events.length).toBe(1);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should enable and disable domains independently', async function({page}) {
|
||||||
|
const client = await page.context().newCDPSession(page);
|
||||||
|
await client.send('Runtime.enable');
|
||||||
|
await client.send('Debugger.enable');
|
||||||
|
// JS coverage enables and then disables Debugger domain.
|
||||||
|
await page.coverage.startJSCoverage();
|
||||||
|
await page.coverage.stopJSCoverage();
|
||||||
|
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 => {
|
||||||
|
if (event.url === 'foo.js')
|
||||||
|
f();
|
||||||
|
})),
|
||||||
|
page.evaluate('//# sourceURL=foo.js')
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should be able to detach session', async function({page}) {
|
||||||
|
const client = await page.context().newCDPSession(page);
|
||||||
|
await client.send('Runtime.enable');
|
||||||
|
const evalResponse = await client.send('Runtime.evaluate', {expression: '1 + 2', returnByValue: true});
|
||||||
|
expect(evalResponse.result.value).toBe(3);
|
||||||
|
await client.detach();
|
||||||
|
let error = null;
|
||||||
|
try {
|
||||||
|
await client.send('Runtime.evaluate', {expression: '3 + 1', returnByValue: true});
|
||||||
|
} catch (e) {
|
||||||
|
error = e;
|
||||||
|
}
|
||||||
|
expect(error.message).toContain(CHANNEL ? 'Target browser or context has been closed' : 'Session closed.');
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should throw nice errors', async function({page}) {
|
||||||
|
const client = await page.context().newCDPSession(page);
|
||||||
|
const error = await theSourceOfTheProblems().catch(error => error);
|
||||||
|
expect(error.stack).toContain('theSourceOfTheProblems');
|
||||||
|
expect(error.message).toContain('ThisCommand.DoesNotExist');
|
||||||
|
|
||||||
|
async function theSourceOfTheProblems() {
|
||||||
|
await client.send('ThisCommand.DoesNotExist');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should not break page.close()', async function({browser}) {
|
||||||
|
const context = await browser.newContext();
|
||||||
|
const page = await context.newPage();
|
||||||
|
const session = await page.context().newCDPSession(page);
|
||||||
|
await session.detach();
|
||||||
|
await page.close();
|
||||||
|
await context.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should detach when page closes', async function({browser}) {
|
||||||
|
const context = await browser.newContext();
|
||||||
|
const page = await context.newPage();
|
||||||
|
const session = await context.newCDPSession(page);
|
||||||
|
await page.close();
|
||||||
|
let error;
|
||||||
|
await session.detach().catch(e => error = e);
|
||||||
|
expect(error).toBeTruthy();
|
||||||
|
await context.close();
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should work', async function({browser}) {
|
||||||
|
const session = await browser.newBrowserCDPSession();
|
||||||
|
|
||||||
|
const version = await session.send('Browser.getVersion');
|
||||||
|
expect(version.userAgent).toBeTruthy();
|
||||||
|
|
||||||
|
let gotEvent = false;
|
||||||
|
session.on('Target.targetCreated', () => gotEvent = true);
|
||||||
|
await session.send('Target.setDiscoverTargets', { discover: true });
|
||||||
|
expect(gotEvent).toBe(true);
|
||||||
|
|
||||||
|
await session.detach();
|
||||||
|
});
|
||||||
|
|
@ -1,70 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright 2017 Google Inc. All rights reserved.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
const {FFOX, CHROMIUM, WEBKIT, OUTPUT_DIR, CHANNEL} = testOptions;
|
|
||||||
|
|
||||||
registerFixture('outputFile', async ({parallelIndex}, test) => {
|
|
||||||
const outputFile = path.join(OUTPUT_DIR, `trace-${parallelIndex}.json`);
|
|
||||||
await test(outputFile);
|
|
||||||
if (fs.existsSync(outputFile))
|
|
||||||
fs.unlinkSync(outputFile);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe.skip(!CHROMIUM)('Chromium.startTracing', function() {
|
|
||||||
it('should output a trace', async({browser, page, server, outputFile}) => {
|
|
||||||
await browser.startTracing(page, {screenshots: true, path: outputFile});
|
|
||||||
await page.goto(server.PREFIX + '/grid.html');
|
|
||||||
await browser.stopTracing();
|
|
||||||
expect(fs.existsSync(outputFile)).toBe(true);
|
|
||||||
});
|
|
||||||
it('should run with custom categories if provided', async({browser, page, outputFile}) => {
|
|
||||||
await browser.startTracing(page, {path: outputFile, categories: ['disabled-by-default-v8.cpu_profiler.hires']});
|
|
||||||
await browser.stopTracing();
|
|
||||||
|
|
||||||
const traceJson = JSON.parse(fs.readFileSync(outputFile).toString());
|
|
||||||
expect(traceJson.metadata['trace-config']).toContain('disabled-by-default-v8.cpu_profiler.hires', 'Does not contain expected category');
|
|
||||||
});
|
|
||||||
it('should throw if tracing on two pages', async({browser, page, outputFile}) => {
|
|
||||||
await browser.startTracing(page, {path: outputFile});
|
|
||||||
const newPage = await browser.newPage();
|
|
||||||
let error = null;
|
|
||||||
await browser.startTracing(newPage, {path: outputFile}).catch(e => error = e);
|
|
||||||
await newPage.close();
|
|
||||||
expect(error).toBeTruthy();
|
|
||||||
await browser.stopTracing();
|
|
||||||
});
|
|
||||||
it('should return a buffer', async({browser, page, server, outputFile}) => {
|
|
||||||
await browser.startTracing(page, {screenshots: true, path: outputFile});
|
|
||||||
await page.goto(server.PREFIX + '/grid.html');
|
|
||||||
const trace = await browser.stopTracing();
|
|
||||||
const buf = fs.readFileSync(outputFile);
|
|
||||||
expect(trace.toString()).toEqual(buf.toString(), 'Tracing buffer mismatch');
|
|
||||||
});
|
|
||||||
it('should work without options', async({browser, page, server}) => {
|
|
||||||
await browser.startTracing(page);
|
|
||||||
await page.goto(server.PREFIX + '/grid.html');
|
|
||||||
const trace = await browser.stopTracing();
|
|
||||||
expect(trace).toBeTruthy();
|
|
||||||
});
|
|
||||||
it('should support a buffer without a path', async({browser, page, server}) => {
|
|
||||||
await browser.startTracing(page, {screenshots: true});
|
|
||||||
await page.goto(server.PREFIX + '/grid.html');
|
|
||||||
const trace = await browser.stopTracing();
|
|
||||||
expect(trace.toString()).toContain('screenshot', 'Does not contain screenshot');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
73
test/chromium/tracing.spec.js
Normal file
73
test/chromium/tracing.spec.js
Normal file
|
|
@ -0,0 +1,73 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2017 Google Inc. All rights reserved.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const fs = require('fs');
|
||||||
|
const path = require('path');
|
||||||
|
const {FFOX, CHROMIUM, WEBKIT, OUTPUT_DIR, CHANNEL} = testOptions;
|
||||||
|
|
||||||
|
registerFixture('outputFile', async ({parallelIndex}, test) => {
|
||||||
|
const outputFile = path.join(OUTPUT_DIR, `trace-${parallelIndex}.json`);
|
||||||
|
await test(outputFile);
|
||||||
|
if (fs.existsSync(outputFile))
|
||||||
|
fs.unlinkSync(outputFile);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should output a trace', async({browser, page, server, outputFile}) => {
|
||||||
|
await browser.startTracing(page, {screenshots: true, path: outputFile});
|
||||||
|
await page.goto(server.PREFIX + '/grid.html');
|
||||||
|
await browser.stopTracing();
|
||||||
|
expect(fs.existsSync(outputFile)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should run with custom categories if provided', async({browser, page, outputFile}) => {
|
||||||
|
await browser.startTracing(page, {path: outputFile, categories: ['disabled-by-default-v8.cpu_profiler.hires']});
|
||||||
|
await browser.stopTracing();
|
||||||
|
|
||||||
|
const traceJson = JSON.parse(fs.readFileSync(outputFile).toString());
|
||||||
|
expect(traceJson.metadata['trace-config']).toContain('disabled-by-default-v8.cpu_profiler.hires', 'Does not contain expected category');
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should throw if tracing on two pages', async({browser, page, outputFile}) => {
|
||||||
|
await browser.startTracing(page, {path: outputFile});
|
||||||
|
const newPage = await browser.newPage();
|
||||||
|
let error = null;
|
||||||
|
await browser.startTracing(newPage, {path: outputFile}).catch(e => error = e);
|
||||||
|
await newPage.close();
|
||||||
|
expect(error).toBeTruthy();
|
||||||
|
await browser.stopTracing();
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should return a buffer', async({browser, page, server, outputFile}) => {
|
||||||
|
await browser.startTracing(page, {screenshots: true, path: outputFile});
|
||||||
|
await page.goto(server.PREFIX + '/grid.html');
|
||||||
|
const trace = await browser.stopTracing();
|
||||||
|
const buf = fs.readFileSync(outputFile);
|
||||||
|
expect(trace.toString()).toEqual(buf.toString(), 'Tracing buffer mismatch');
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should work without options', async({browser, page, server}) => {
|
||||||
|
await browser.startTracing(page);
|
||||||
|
await page.goto(server.PREFIX + '/grid.html');
|
||||||
|
const trace = await browser.stopTracing();
|
||||||
|
expect(trace).toBeTruthy();
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should support a buffer without a path', async({browser, page, server}) => {
|
||||||
|
await browser.startTracing(page, {screenshots: true});
|
||||||
|
await page.goto(server.PREFIX + '/grid.html');
|
||||||
|
const trace = await browser.stopTracing();
|
||||||
|
expect(trace.toString()).toContain('screenshot', 'Does not contain screenshot');
|
||||||
|
});
|
||||||
136
test/electron/electron-app.spec.js
Normal file
136
test/electron/electron-app.spec.js
Normal file
|
|
@ -0,0 +1,136 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
const electronName = process.platform === 'win32' ? 'electron.cmd' : 'electron';
|
||||||
|
|
||||||
|
const { CHROMIUM } = testOptions;
|
||||||
|
|
||||||
|
registerFixture('application', async ({playwright}, test) => {
|
||||||
|
const electronPath = path.join(__dirname, '..', '..', 'node_modules', '.bin', electronName);
|
||||||
|
const application = await playwright.electron.launch(electronPath, {
|
||||||
|
args: [path.join(__dirname, 'testApp.js')],
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await test(application);
|
||||||
|
} finally {
|
||||||
|
await application.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should fire close event', async ({ playwright }) => {
|
||||||
|
const electronPath = path.join(__dirname, '..', '..', 'node_modules', '.bin', electronName);
|
||||||
|
const application = await playwright.electron.launch(electronPath, {
|
||||||
|
args: [path.join(__dirname, 'testApp.js')],
|
||||||
|
});
|
||||||
|
const events = [];
|
||||||
|
application.on('close', () => events.push('application'));
|
||||||
|
application.context().on('close', () => events.push('context'));
|
||||||
|
await application.close();
|
||||||
|
expect(events.join('|')).toBe('context|application');
|
||||||
|
// Give it some time to fire more events - there should not be any.
|
||||||
|
await new Promise(f => setTimeout(f, 1000));
|
||||||
|
expect(events.join('|')).toBe('context|application');
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should script application', async ({ application }) => {
|
||||||
|
const appPath = await application.evaluate(async ({ app }) => app.getAppPath());
|
||||||
|
expect(appPath).toContain('electron');
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should create window', async ({ application }) => {
|
||||||
|
const [ page ] = await Promise.all([
|
||||||
|
application.waitForEvent('window'),
|
||||||
|
application.evaluate(({ BrowserWindow }) => {
|
||||||
|
const window = new BrowserWindow({ width: 800, height: 600 });
|
||||||
|
window.loadURL('data:text/html,<title>Hello World 1</title>');
|
||||||
|
})
|
||||||
|
]);
|
||||||
|
await page.waitForLoadState('domcontentloaded');
|
||||||
|
expect(await page.title()).toBe('Hello World 1');
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should create window 2', async ({ application }) => {
|
||||||
|
const page = await application.newBrowserWindow({ width: 800, height: 600 });
|
||||||
|
await page.goto('data:text/html,<title>Hello World 2</title>');
|
||||||
|
expect(await page.title()).toBe('Hello World 2');
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should create multiple windows', async ({ application }) => {
|
||||||
|
const createPage = async ordinal => {
|
||||||
|
const page = await application.newBrowserWindow({ width: 800, height: 600 });
|
||||||
|
await Promise.all([
|
||||||
|
page.waitForNavigation(),
|
||||||
|
page.browserWindow.evaluate((window, ordinal) => window.loadURL(`data:text/html,<title>Hello World ${ordinal}</title>`), ordinal)
|
||||||
|
]);
|
||||||
|
return page;
|
||||||
|
};
|
||||||
|
|
||||||
|
const page1 = await createPage(1);
|
||||||
|
const page2 = await createPage(2);
|
||||||
|
const page3 = await createPage(3);
|
||||||
|
await page1.close();
|
||||||
|
const page4 = await createPage(4);
|
||||||
|
const titles = [];
|
||||||
|
for (const window of application.windows())
|
||||||
|
titles.push(await window.title());
|
||||||
|
expect(titles).toEqual(['Hello World 2', 'Hello World 3', 'Hello World 4']);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should route network', async ({ application }) => {
|
||||||
|
await application.context().route('**/empty.html', (route, request) => {
|
||||||
|
route.fulfill({
|
||||||
|
status: 200,
|
||||||
|
contentType: 'text/html',
|
||||||
|
body: '<title>Hello World</title>',
|
||||||
|
})
|
||||||
|
});
|
||||||
|
const page = await application.newBrowserWindow({ width: 800, height: 600 });
|
||||||
|
await page.goto('https://localhost:1000/empty.html');
|
||||||
|
expect(await page.title()).toBe('Hello World');
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should support init script', async ({ application }) => {
|
||||||
|
await application.context().addInitScript('window.magic = 42;')
|
||||||
|
const page = await application.newBrowserWindow({ width: 800, height: 600 });
|
||||||
|
await page.goto('data:text/html,<script>window.copy = magic</script>');
|
||||||
|
expect(await page.evaluate(() => copy)).toBe(42);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should expose function', async ({ application }) => {
|
||||||
|
const result = new Promise(f => callback = f);
|
||||||
|
const t = Date.now();
|
||||||
|
await application.context().exposeFunction('add', (a, b) => a + b);
|
||||||
|
const page = await application.newBrowserWindow({ width: 800, height: 600 });
|
||||||
|
await page.goto('data:text/html,<script>window.result = add(20, 22);</script>');
|
||||||
|
expect(await page.evaluate(() => result)).toBe(42);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should wait for first window', async ({ application }) => {
|
||||||
|
application.evaluate(({ BrowserWindow }) => {
|
||||||
|
const window = new BrowserWindow({ width: 800, height: 600 });
|
||||||
|
window.loadURL('data:text/html,<title>Hello World!</title>');
|
||||||
|
});
|
||||||
|
const window = await application.firstWindow();
|
||||||
|
expect(await window.title()).toBe('Hello World!');
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should have a clipboard instance', async ({ application }) => {
|
||||||
|
const clipboardContentToWrite = 'Hello from Playwright';
|
||||||
|
await application.evaluate(async ({clipboard}, text) => clipboard.writeText(text), clipboardContentToWrite);
|
||||||
|
const clipboardContentRead = await application.evaluate(async ({clipboard}) => clipboard.readText());
|
||||||
|
await expect(clipboardContentRead).toEqual(clipboardContentToWrite);
|
||||||
|
});
|
||||||
70
test/electron/electron-window.spec.js
Normal file
70
test/electron/electron-window.spec.js
Normal file
|
|
@ -0,0 +1,70 @@
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
const electronName = process.platform === 'win32' ? 'electron.cmd' : 'electron';
|
||||||
|
|
||||||
|
const { CHROMIUM } = testOptions;
|
||||||
|
|
||||||
|
registerFixture('application', async ({playwright}, test) => {
|
||||||
|
const electronPath = path.join(__dirname, '..', '..', 'node_modules', '.bin', electronName);
|
||||||
|
const application = await playwright.electron.launch(electronPath, {
|
||||||
|
args: [path.join(__dirname, 'testApp.js')],
|
||||||
|
});
|
||||||
|
try {
|
||||||
|
await test(application);
|
||||||
|
} finally {
|
||||||
|
await application.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
registerFixture('window', async ({application}, test) => {
|
||||||
|
const page = await application.newBrowserWindow({ width: 800, height: 600 });
|
||||||
|
try {
|
||||||
|
await test(page);
|
||||||
|
} finally {
|
||||||
|
await page.close();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should click the button', async({window, server}) => {
|
||||||
|
await window.goto(server.PREFIX + '/input/button.html');
|
||||||
|
await window.click('button');
|
||||||
|
expect(await window.evaluate(() => result)).toBe('Clicked');
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should check the box', async({window}) => {
|
||||||
|
await window.setContent(`<input id='checkbox' type='checkbox'></input>`);
|
||||||
|
await window.check('input');
|
||||||
|
expect(await window.evaluate(() => checkbox.checked)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should not check the checked box', async({window}) => {
|
||||||
|
await window.setContent(`<input id='checkbox' type='checkbox' checked></input>`);
|
||||||
|
await window.check('input');
|
||||||
|
expect(await window.evaluate(() => checkbox.checked)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(!CHROMIUM)('should type into a textarea', async({window, server}) => {
|
||||||
|
await window.evaluate(() => {
|
||||||
|
const textarea = document.createElement('textarea');
|
||||||
|
document.body.appendChild(textarea);
|
||||||
|
textarea.focus();
|
||||||
|
});
|
||||||
|
const text = 'Hello world. I am the text that was typed!';
|
||||||
|
await window.keyboard.type(text);
|
||||||
|
expect(await window.evaluate(() => document.querySelector('textarea').value)).toBe(text);
|
||||||
|
});
|
||||||
|
|
@ -1,166 +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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const path = require('path');
|
|
||||||
const electronName = process.platform === 'win32' ? 'electron.cmd' : 'electron';
|
|
||||||
|
|
||||||
const { CHROMIUM } = testOptions;
|
|
||||||
|
|
||||||
registerFixture('application', async ({playwright}, test) => {
|
|
||||||
const electronPath = path.join(__dirname, '..', '..', 'node_modules', '.bin', electronName);
|
|
||||||
const application = await playwright.electron.launch(electronPath, {
|
|
||||||
args: [path.join(__dirname, 'testApp.js')],
|
|
||||||
});
|
|
||||||
try {
|
|
||||||
await test(application);
|
|
||||||
} finally {
|
|
||||||
await application.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
registerFixture('window', async ({application}, test) => {
|
|
||||||
const page = await application.newBrowserWindow({ width: 800, height: 600 });
|
|
||||||
try {
|
|
||||||
await test(page);
|
|
||||||
} finally {
|
|
||||||
await page.close();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
describe.skip(!CHROMIUM)('Electron', function() {
|
|
||||||
it('should fire close event', async ({ playwright }) => {
|
|
||||||
const electronPath = path.join(__dirname, '..', '..', 'node_modules', '.bin', electronName);
|
|
||||||
const application = await playwright.electron.launch(electronPath, {
|
|
||||||
args: [path.join(__dirname, 'testApp.js')],
|
|
||||||
});
|
|
||||||
const events = [];
|
|
||||||
application.on('close', () => events.push('application'));
|
|
||||||
application.context().on('close', () => events.push('context'));
|
|
||||||
await application.close();
|
|
||||||
expect(events.join('|')).toBe('context|application');
|
|
||||||
// Give it some time to fire more events - there should not be any.
|
|
||||||
await new Promise(f => setTimeout(f, 1000));
|
|
||||||
expect(events.join('|')).toBe('context|application');
|
|
||||||
});
|
|
||||||
it('should script application', async ({ application }) => {
|
|
||||||
const appPath = await application.evaluate(async ({ app }) => app.getAppPath());
|
|
||||||
expect(appPath).toContain('electron');
|
|
||||||
});
|
|
||||||
it('should create window', async ({ application }) => {
|
|
||||||
const [ page ] = await Promise.all([
|
|
||||||
application.waitForEvent('window'),
|
|
||||||
application.evaluate(({ BrowserWindow }) => {
|
|
||||||
const window = new BrowserWindow({ width: 800, height: 600 });
|
|
||||||
window.loadURL('data:text/html,<title>Hello World 1</title>');
|
|
||||||
})
|
|
||||||
]);
|
|
||||||
await page.waitForLoadState('domcontentloaded');
|
|
||||||
expect(await page.title()).toBe('Hello World 1');
|
|
||||||
});
|
|
||||||
it('should create window 2', async ({ application }) => {
|
|
||||||
const page = await application.newBrowserWindow({ width: 800, height: 600 });
|
|
||||||
await page.goto('data:text/html,<title>Hello World 2</title>');
|
|
||||||
expect(await page.title()).toBe('Hello World 2');
|
|
||||||
});
|
|
||||||
it('should create multiple windows', async ({ application }) => {
|
|
||||||
const createPage = async ordinal => {
|
|
||||||
const page = await application.newBrowserWindow({ width: 800, height: 600 });
|
|
||||||
await Promise.all([
|
|
||||||
page.waitForNavigation(),
|
|
||||||
page.browserWindow.evaluate((window, ordinal) => window.loadURL(`data:text/html,<title>Hello World ${ordinal}</title>`), ordinal)
|
|
||||||
]);
|
|
||||||
return page;
|
|
||||||
};
|
|
||||||
|
|
||||||
const page1 = await createPage(1);
|
|
||||||
const page2 = await createPage(2);
|
|
||||||
const page3 = await createPage(3);
|
|
||||||
await page1.close();
|
|
||||||
const page4 = await createPage(4);
|
|
||||||
const titles = [];
|
|
||||||
for (const window of application.windows())
|
|
||||||
titles.push(await window.title());
|
|
||||||
expect(titles).toEqual(['Hello World 2', 'Hello World 3', 'Hello World 4']);
|
|
||||||
});
|
|
||||||
it('should route network', async ({ application }) => {
|
|
||||||
await application.context().route('**/empty.html', (route, request) => {
|
|
||||||
route.fulfill({
|
|
||||||
status: 200,
|
|
||||||
contentType: 'text/html',
|
|
||||||
body: '<title>Hello World</title>',
|
|
||||||
})
|
|
||||||
});
|
|
||||||
const page = await application.newBrowserWindow({ width: 800, height: 600 });
|
|
||||||
await page.goto('https://localhost:1000/empty.html');
|
|
||||||
expect(await page.title()).toBe('Hello World');
|
|
||||||
});
|
|
||||||
it('should support init script', async ({ application }) => {
|
|
||||||
await application.context().addInitScript('window.magic = 42;')
|
|
||||||
const page = await application.newBrowserWindow({ width: 800, height: 600 });
|
|
||||||
await page.goto('data:text/html,<script>window.copy = magic</script>');
|
|
||||||
expect(await page.evaluate(() => copy)).toBe(42);
|
|
||||||
});
|
|
||||||
it('should expose function', async ({ application }) => {
|
|
||||||
const result = new Promise(f => callback = f);
|
|
||||||
const t = Date.now();
|
|
||||||
await application.context().exposeFunction('add', (a, b) => a + b);
|
|
||||||
const page = await application.newBrowserWindow({ width: 800, height: 600 });
|
|
||||||
await page.goto('data:text/html,<script>window.result = add(20, 22);</script>');
|
|
||||||
expect(await page.evaluate(() => result)).toBe(42);
|
|
||||||
});
|
|
||||||
it('should wait for first window', async ({ application }) => {
|
|
||||||
application.evaluate(({ BrowserWindow }) => {
|
|
||||||
const window = new BrowserWindow({ width: 800, height: 600 });
|
|
||||||
window.loadURL('data:text/html,<title>Hello World!</title>');
|
|
||||||
});
|
|
||||||
const window = await application.firstWindow();
|
|
||||||
expect(await window.title()).toBe('Hello World!');
|
|
||||||
});
|
|
||||||
it('should have a clipboard instance', async ({ application }) => {
|
|
||||||
const clipboardContentToWrite = 'Hello from Playwright';
|
|
||||||
await application.evaluate(async ({clipboard}, text) => clipboard.writeText(text), clipboardContentToWrite);
|
|
||||||
const clipboardContentRead = await application.evaluate(async ({clipboard}) => clipboard.readText());
|
|
||||||
await expect(clipboardContentRead).toEqual(clipboardContentToWrite);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe.skip(!CHROMIUM)('Electron per window', function() {
|
|
||||||
it('should click the button', async({window, server}) => {
|
|
||||||
await window.goto(server.PREFIX + '/input/button.html');
|
|
||||||
await window.click('button');
|
|
||||||
expect(await window.evaluate(() => result)).toBe('Clicked');
|
|
||||||
});
|
|
||||||
it('should check the box', async({window}) => {
|
|
||||||
await window.setContent(`<input id='checkbox' type='checkbox'></input>`);
|
|
||||||
await window.check('input');
|
|
||||||
expect(await window.evaluate(() => checkbox.checked)).toBe(true);
|
|
||||||
});
|
|
||||||
it('should not check the checked box', async({window}) => {
|
|
||||||
await window.setContent(`<input id='checkbox' type='checkbox' checked></input>`);
|
|
||||||
await window.check('input');
|
|
||||||
expect(await window.evaluate(() => checkbox.checked)).toBe(true);
|
|
||||||
});
|
|
||||||
it('should type into a textarea', async({window, server}) => {
|
|
||||||
await window.evaluate(() => {
|
|
||||||
const textarea = document.createElement('textarea');
|
|
||||||
document.body.appendChild(textarea);
|
|
||||||
textarea.focus();
|
|
||||||
});
|
|
||||||
const text = 'Hello world. I am the text that was typed!';
|
|
||||||
await window.keyboard.type(text);
|
|
||||||
expect(await window.evaluate(() => document.querySelector('textarea').value)).toBe(text);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
@ -16,19 +16,17 @@
|
||||||
|
|
||||||
const { FFOX } = testOptions;
|
const { FFOX } = testOptions;
|
||||||
|
|
||||||
describe.skip(!FFOX)('launcher', function() {
|
it.skip(!FFOX)('should pass firefox user preferences', async({browserType, defaultBrowserOptions}) => {
|
||||||
it('should pass firefox user preferences', async({browserType, defaultBrowserOptions}) => {
|
const browser = await browserType.launch({
|
||||||
const browser = await browserType.launch({
|
...defaultBrowserOptions,
|
||||||
...defaultBrowserOptions,
|
firefoxUserPrefs: {
|
||||||
firefoxUserPrefs: {
|
'network.proxy.type': 1,
|
||||||
'network.proxy.type': 1,
|
'network.proxy.http': '127.0.0.1',
|
||||||
'network.proxy.http': '127.0.0.1',
|
'network.proxy.http_port': 3333,
|
||||||
'network.proxy.http_port': 3333,
|
}
|
||||||
}
|
|
||||||
});
|
|
||||||
const page = await browser.newPage();
|
|
||||||
const error = await page.goto('http://example.com').catch(e => e);
|
|
||||||
expect(error.message).toContain('NS_ERROR_PROXY_CONNECTION_REFUSED');
|
|
||||||
await browser.close();
|
|
||||||
});
|
});
|
||||||
|
const page = await browser.newPage();
|
||||||
|
const error = await page.goto('http://example.com').catch(e => e);
|
||||||
|
expect(error.message).toContain('NS_ERROR_PROXY_CONNECTION_REFUSED');
|
||||||
|
await browser.close();
|
||||||
});
|
});
|
||||||
|
|
@ -1,192 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright 2019 Google Inc. All rights reserved.
|
|
||||||
* Modifications 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const path = require('path');
|
|
||||||
const {spawn, execSync} = require('child_process');
|
|
||||||
const {FFOX, CHROMIUM, WEBKIT, WIN, LINUX, HEADLESS} = testOptions;
|
|
||||||
|
|
||||||
const playwrightPath = path.join(__dirname, '..');
|
|
||||||
|
|
||||||
class Wrapper {
|
|
||||||
constructor(browserType, defaultBrowserOptions, extraOptions) {
|
|
||||||
this._output = new Map();
|
|
||||||
this._outputCallback = new Map();
|
|
||||||
|
|
||||||
this._browserType = browserType;
|
|
||||||
const launchOptions = {...defaultBrowserOptions,
|
|
||||||
handleSIGINT: true,
|
|
||||||
handleSIGTERM: true,
|
|
||||||
handleSIGHUP: true,
|
|
||||||
executablePath: browserType.executablePath(),
|
|
||||||
logger: undefined,
|
|
||||||
};
|
|
||||||
const options = {
|
|
||||||
playwrightPath,
|
|
||||||
browserTypeName: browserType.name(),
|
|
||||||
launchOptions,
|
|
||||||
...extraOptions,
|
|
||||||
};
|
|
||||||
this._child = spawn('node', [path.join(__dirname, 'fixtures', 'closeme.js'), JSON.stringify(options)]);
|
|
||||||
this._child.on('error', (...args) => console.log("ERROR", ...args));
|
|
||||||
this._exitPromise = new Promise(resolve => this._child.on('exit', resolve));
|
|
||||||
|
|
||||||
let outputString = '';
|
|
||||||
this._child.stdout.on('data', data => {
|
|
||||||
outputString += data.toString();
|
|
||||||
// Uncomment to debug.
|
|
||||||
// console.log(data.toString());
|
|
||||||
let match;
|
|
||||||
while (match = outputString.match(/\(([^()]+)=>([^()]+)\)/)) {
|
|
||||||
const key = match[1];
|
|
||||||
const value = match[2];
|
|
||||||
this._addOutput(key, value);
|
|
||||||
outputString = outputString.substring(match.index + match[0].length);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
_addOutput(key, value) {
|
|
||||||
this._output.set(key, value);
|
|
||||||
const cb = this._outputCallback.get(key);
|
|
||||||
this._outputCallback.delete(key);
|
|
||||||
if (cb)
|
|
||||||
cb();
|
|
||||||
}
|
|
||||||
|
|
||||||
async out(key) {
|
|
||||||
if (!this._output.has(key))
|
|
||||||
await new Promise(f => this._outputCallback.set(key, f));
|
|
||||||
return this._output.get(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
async connect() {
|
|
||||||
const wsEndpoint = await this.out('wsEndpoint');
|
|
||||||
const browser = await this._browserType.connect({ wsEndpoint });
|
|
||||||
this._exitAndDisconnectPromise = Promise.all([
|
|
||||||
this._exitPromise,
|
|
||||||
new Promise(resolve => browser.once('disconnected', resolve)),
|
|
||||||
]).then(([exitCode]) => exitCode);
|
|
||||||
}
|
|
||||||
|
|
||||||
child() {
|
|
||||||
return this._child;
|
|
||||||
}
|
|
||||||
|
|
||||||
async childExitCode() {
|
|
||||||
return await this._exitAndDisconnectPromise;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
registerFixture('wrapper', async ({browserType, defaultBrowserOptions}, test) => {
|
|
||||||
const wrapper = new Wrapper(browserType, defaultBrowserOptions);
|
|
||||||
await wrapper.connect();
|
|
||||||
await test(wrapper);
|
|
||||||
});
|
|
||||||
|
|
||||||
registerFixture('stallingWrapper', async ({browserType, defaultBrowserOptions}, test) => {
|
|
||||||
const wrapper = new Wrapper(browserType, defaultBrowserOptions, { stallOnClose: true });
|
|
||||||
await wrapper.connect();
|
|
||||||
await test(wrapper);
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Fixtures', function() {
|
|
||||||
it.slow()('should close the browser when the node process closes', async ({wrapper}) => {
|
|
||||||
if (WIN)
|
|
||||||
execSync(`taskkill /pid ${wrapper.child().pid} /T /F`);
|
|
||||||
else
|
|
||||||
process.kill(wrapper.child().pid);
|
|
||||||
expect(await wrapper.childExitCode()).toBe(WIN ? 1 : 0);
|
|
||||||
// We might not get browser exitCode in time when killing the parent node process,
|
|
||||||
// so we don't check it here.
|
|
||||||
});
|
|
||||||
|
|
||||||
describe.skip(WIN || !HEADLESS)('signals', () => {
|
|
||||||
// Cannot reliably send signals on Windows.
|
|
||||||
it.slow()('should report browser close signal', async ({wrapper}) => {
|
|
||||||
const pid = await wrapper.out('pid');
|
|
||||||
process.kill(-pid, 'SIGTERM');
|
|
||||||
expect(await wrapper.out('exitCode')).toBe('null');
|
|
||||||
expect(await wrapper.out('signal')).toBe('SIGTERM');
|
|
||||||
process.kill(wrapper.child().pid);
|
|
||||||
await wrapper.childExitCode();
|
|
||||||
});
|
|
||||||
it.slow()('should report browser close signal 2', async ({wrapper}) => {
|
|
||||||
const pid = await wrapper.out('pid');
|
|
||||||
process.kill(-pid, 'SIGKILL');
|
|
||||||
expect(await wrapper.out('exitCode')).toBe('null');
|
|
||||||
expect(await wrapper.out('signal')).toBe('SIGKILL');
|
|
||||||
process.kill(wrapper.child().pid);
|
|
||||||
await wrapper.childExitCode();
|
|
||||||
});
|
|
||||||
it.slow()('should close the browser on SIGINT', async ({wrapper}) => {
|
|
||||||
process.kill(wrapper.child().pid, 'SIGINT');
|
|
||||||
expect(await wrapper.out('exitCode')).toBe('0');
|
|
||||||
expect(await wrapper.out('signal')).toBe('null');
|
|
||||||
expect(await wrapper.childExitCode()).toBe(130);
|
|
||||||
});
|
|
||||||
it.slow()('should close the browser on SIGTERM', async ({wrapper}) => {
|
|
||||||
process.kill(wrapper.child().pid, 'SIGTERM');
|
|
||||||
expect(await wrapper.out('exitCode')).toBe('0');
|
|
||||||
expect(await wrapper.out('signal')).toBe('null');
|
|
||||||
expect(await wrapper.childExitCode()).toBe(0);
|
|
||||||
});
|
|
||||||
it.slow()('should close the browser on SIGHUP', async ({wrapper}) => {
|
|
||||||
process.kill(wrapper.child().pid, 'SIGHUP');
|
|
||||||
expect(await wrapper.out('exitCode')).toBe('0');
|
|
||||||
expect(await wrapper.out('signal')).toBe('null');
|
|
||||||
expect(await wrapper.childExitCode()).toBe(0);
|
|
||||||
});
|
|
||||||
it.slow()('should kill the browser on double SIGINT', async ({stallingWrapper}) => {
|
|
||||||
const wrapper = stallingWrapper;
|
|
||||||
process.kill(wrapper.child().pid, 'SIGINT');
|
|
||||||
await wrapper.out('stalled');
|
|
||||||
process.kill(wrapper.child().pid, 'SIGINT');
|
|
||||||
expect(await wrapper.out('exitCode')).toBe('null');
|
|
||||||
expect(await wrapper.out('signal')).toBe('SIGKILL');
|
|
||||||
expect(await wrapper.childExitCode()).toBe(130);
|
|
||||||
});
|
|
||||||
it.slow()('should kill the browser on SIGINT + SIGTERM', async ({stallingWrapper}) => {
|
|
||||||
const wrapper = stallingWrapper;
|
|
||||||
process.kill(wrapper.child().pid, 'SIGINT');
|
|
||||||
await wrapper.out('stalled');
|
|
||||||
process.kill(wrapper.child().pid, 'SIGTERM');
|
|
||||||
expect(await wrapper.out('exitCode')).toBe('null');
|
|
||||||
expect(await wrapper.out('signal')).toBe('SIGKILL');
|
|
||||||
expect(await wrapper.childExitCode()).toBe(0);
|
|
||||||
});
|
|
||||||
it.slow()('should kill the browser on SIGTERM + SIGINT', async ({stallingWrapper}) => {
|
|
||||||
const wrapper = stallingWrapper;
|
|
||||||
process.kill(wrapper.child().pid, 'SIGTERM');
|
|
||||||
await wrapper.out('stalled');
|
|
||||||
process.kill(wrapper.child().pid, 'SIGINT');
|
|
||||||
expect(await wrapper.out('exitCode')).toBe('null');
|
|
||||||
expect(await wrapper.out('signal')).toBe('SIGKILL');
|
|
||||||
expect(await wrapper.childExitCode()).toBe(130);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('StackTrace', () => {
|
|
||||||
it('caller file path', async ({}) => {
|
|
||||||
const stackTrace = require(path.join(playwrightPath, 'lib', 'utils', 'stackTrace'));
|
|
||||||
const callme = require('./fixtures/callback');
|
|
||||||
const filePath = callme(() => {
|
|
||||||
return stackTrace.getCallerFilePath(path.join(__dirname, 'fixtures') + path.sep);
|
|
||||||
});
|
|
||||||
expect(filePath).toBe(__filename);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
193
test/fixtures.spec.js
Normal file
193
test/fixtures.spec.js
Normal file
|
|
@ -0,0 +1,193 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2019 Google Inc. All rights reserved.
|
||||||
|
* Modifications 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
const {spawn, execSync} = require('child_process');
|
||||||
|
const {FFOX, CHROMIUM, WEBKIT, WIN, LINUX, HEADLESS} = testOptions;
|
||||||
|
|
||||||
|
const playwrightPath = path.join(__dirname, '..');
|
||||||
|
|
||||||
|
class Wrapper {
|
||||||
|
constructor(browserType, defaultBrowserOptions, extraOptions) {
|
||||||
|
this._output = new Map();
|
||||||
|
this._outputCallback = new Map();
|
||||||
|
|
||||||
|
this._browserType = browserType;
|
||||||
|
const launchOptions = {...defaultBrowserOptions,
|
||||||
|
handleSIGINT: true,
|
||||||
|
handleSIGTERM: true,
|
||||||
|
handleSIGHUP: true,
|
||||||
|
executablePath: browserType.executablePath(),
|
||||||
|
logger: undefined,
|
||||||
|
};
|
||||||
|
const options = {
|
||||||
|
playwrightPath,
|
||||||
|
browserTypeName: browserType.name(),
|
||||||
|
launchOptions,
|
||||||
|
...extraOptions,
|
||||||
|
};
|
||||||
|
this._child = spawn('node', [path.join(__dirname, 'fixtures', 'closeme.js'), JSON.stringify(options)]);
|
||||||
|
this._child.on('error', (...args) => console.log("ERROR", ...args));
|
||||||
|
this._exitPromise = new Promise(resolve => this._child.on('exit', resolve));
|
||||||
|
|
||||||
|
let outputString = '';
|
||||||
|
this._child.stdout.on('data', data => {
|
||||||
|
outputString += data.toString();
|
||||||
|
// Uncomment to debug.
|
||||||
|
// console.log(data.toString());
|
||||||
|
let match;
|
||||||
|
while (match = outputString.match(/\(([^()]+)=>([^()]+)\)/)) {
|
||||||
|
const key = match[1];
|
||||||
|
const value = match[2];
|
||||||
|
this._addOutput(key, value);
|
||||||
|
outputString = outputString.substring(match.index + match[0].length);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
_addOutput(key, value) {
|
||||||
|
this._output.set(key, value);
|
||||||
|
const cb = this._outputCallback.get(key);
|
||||||
|
this._outputCallback.delete(key);
|
||||||
|
if (cb)
|
||||||
|
cb();
|
||||||
|
}
|
||||||
|
|
||||||
|
async out(key) {
|
||||||
|
if (!this._output.has(key))
|
||||||
|
await new Promise(f => this._outputCallback.set(key, f));
|
||||||
|
return this._output.get(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
async connect() {
|
||||||
|
const wsEndpoint = await this.out('wsEndpoint');
|
||||||
|
const browser = await this._browserType.connect({ wsEndpoint });
|
||||||
|
this._exitAndDisconnectPromise = Promise.all([
|
||||||
|
this._exitPromise,
|
||||||
|
new Promise(resolve => browser.once('disconnected', resolve)),
|
||||||
|
]).then(([exitCode]) => exitCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
child() {
|
||||||
|
return this._child;
|
||||||
|
}
|
||||||
|
|
||||||
|
async childExitCode() {
|
||||||
|
return await this._exitAndDisconnectPromise;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
registerFixture('wrapper', async ({browserType, defaultBrowserOptions}, test) => {
|
||||||
|
const wrapper = new Wrapper(browserType, defaultBrowserOptions);
|
||||||
|
await wrapper.connect();
|
||||||
|
await test(wrapper);
|
||||||
|
});
|
||||||
|
|
||||||
|
registerFixture('stallingWrapper', async ({browserType, defaultBrowserOptions}, test) => {
|
||||||
|
const wrapper = new Wrapper(browserType, defaultBrowserOptions, { stallOnClose: true });
|
||||||
|
await wrapper.connect();
|
||||||
|
await test(wrapper);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.slow()('should close the browser when the node process closes', async ({wrapper}) => {
|
||||||
|
if (WIN)
|
||||||
|
execSync(`taskkill /pid ${wrapper.child().pid} /T /F`);
|
||||||
|
else
|
||||||
|
process.kill(wrapper.child().pid);
|
||||||
|
expect(await wrapper.childExitCode()).toBe(WIN ? 1 : 0);
|
||||||
|
// We might not get browser exitCode in time when killing the parent node process,
|
||||||
|
// so we don't check it here.
|
||||||
|
});
|
||||||
|
|
||||||
|
// Cannot reliably send signals on Windows.
|
||||||
|
it.skip(WIN || !HEADLESS).slow()('should report browser close signal', async ({wrapper}) => {
|
||||||
|
const pid = await wrapper.out('pid');
|
||||||
|
process.kill(-pid, 'SIGTERM');
|
||||||
|
expect(await wrapper.out('exitCode')).toBe('null');
|
||||||
|
expect(await wrapper.out('signal')).toBe('SIGTERM');
|
||||||
|
process.kill(wrapper.child().pid);
|
||||||
|
await wrapper.childExitCode();
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(WIN || !HEADLESS).slow()('should report browser close signal 2', async ({wrapper}) => {
|
||||||
|
const pid = await wrapper.out('pid');
|
||||||
|
process.kill(-pid, 'SIGKILL');
|
||||||
|
expect(await wrapper.out('exitCode')).toBe('null');
|
||||||
|
expect(await wrapper.out('signal')).toBe('SIGKILL');
|
||||||
|
process.kill(wrapper.child().pid);
|
||||||
|
await wrapper.childExitCode();
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(WIN || !HEADLESS).slow()('should close the browser on SIGINT', async ({wrapper}) => {
|
||||||
|
process.kill(wrapper.child().pid, 'SIGINT');
|
||||||
|
expect(await wrapper.out('exitCode')).toBe('0');
|
||||||
|
expect(await wrapper.out('signal')).toBe('null');
|
||||||
|
expect(await wrapper.childExitCode()).toBe(130);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(WIN || !HEADLESS).slow()('should close the browser on SIGTERM', async ({wrapper}) => {
|
||||||
|
process.kill(wrapper.child().pid, 'SIGTERM');
|
||||||
|
expect(await wrapper.out('exitCode')).toBe('0');
|
||||||
|
expect(await wrapper.out('signal')).toBe('null');
|
||||||
|
expect(await wrapper.childExitCode()).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(WIN || !HEADLESS).slow()('should close the browser on SIGHUP', async ({wrapper}) => {
|
||||||
|
process.kill(wrapper.child().pid, 'SIGHUP');
|
||||||
|
expect(await wrapper.out('exitCode')).toBe('0');
|
||||||
|
expect(await wrapper.out('signal')).toBe('null');
|
||||||
|
expect(await wrapper.childExitCode()).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(WIN || !HEADLESS).slow()('should kill the browser on double SIGINT', async ({stallingWrapper}) => {
|
||||||
|
const wrapper = stallingWrapper;
|
||||||
|
process.kill(wrapper.child().pid, 'SIGINT');
|
||||||
|
await wrapper.out('stalled');
|
||||||
|
process.kill(wrapper.child().pid, 'SIGINT');
|
||||||
|
expect(await wrapper.out('exitCode')).toBe('null');
|
||||||
|
expect(await wrapper.out('signal')).toBe('SIGKILL');
|
||||||
|
expect(await wrapper.childExitCode()).toBe(130);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(WIN || !HEADLESS).slow()('should kill the browser on SIGINT + SIGTERM', async ({stallingWrapper}) => {
|
||||||
|
const wrapper = stallingWrapper;
|
||||||
|
process.kill(wrapper.child().pid, 'SIGINT');
|
||||||
|
await wrapper.out('stalled');
|
||||||
|
process.kill(wrapper.child().pid, 'SIGTERM');
|
||||||
|
expect(await wrapper.out('exitCode')).toBe('null');
|
||||||
|
expect(await wrapper.out('signal')).toBe('SIGKILL');
|
||||||
|
expect(await wrapper.childExitCode()).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.skip(WIN || !HEADLESS).slow()('should kill the browser on SIGTERM + SIGINT', async ({stallingWrapper}) => {
|
||||||
|
const wrapper = stallingWrapper;
|
||||||
|
process.kill(wrapper.child().pid, 'SIGTERM');
|
||||||
|
await wrapper.out('stalled');
|
||||||
|
process.kill(wrapper.child().pid, 'SIGINT');
|
||||||
|
expect(await wrapper.out('exitCode')).toBe('null');
|
||||||
|
expect(await wrapper.out('signal')).toBe('SIGKILL');
|
||||||
|
expect(await wrapper.childExitCode()).toBe(130);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('caller file path', async ({}) => {
|
||||||
|
const stackTrace = require(path.join(playwrightPath, 'lib', 'utils', 'stackTrace'));
|
||||||
|
const callme = require('./fixtures/callback');
|
||||||
|
const filePath = callme(() => {
|
||||||
|
return stackTrace.getCallerFilePath(path.join(__dirname, 'fixtures') + path.sep);
|
||||||
|
});
|
||||||
|
expect(filePath).toBe(__filename);
|
||||||
|
});
|
||||||
|
|
@ -1,314 +0,0 @@
|
||||||
/**
|
|
||||||
* Copyright 2017 Google Inc. All rights reserved.
|
|
||||||
* Modifications 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.
|
|
||||||
*/
|
|
||||||
|
|
||||||
const path = require('path');
|
|
||||||
const fs = require('fs');
|
|
||||||
const utils = require('./utils');
|
|
||||||
const {FFOX, CHROMIUM, WEBKIT, WIN, USES_HOOKS, CHANNEL} = testOptions;
|
|
||||||
|
|
||||||
describe('Playwright', function() {
|
|
||||||
describe('browserType.launch', function() {
|
|
||||||
it('should reject all promises when browser is closed', async({browserType, defaultBrowserOptions}) => {
|
|
||||||
const browser = await browserType.launch(defaultBrowserOptions);
|
|
||||||
const page = await (await browser.newContext()).newPage();
|
|
||||||
let error = null;
|
|
||||||
const neverResolves = page.evaluate(() => new Promise(r => {})).catch(e => error = e);
|
|
||||||
await page.evaluate(() => new Promise(f => setTimeout(f, 0)));
|
|
||||||
await browser.close();
|
|
||||||
await neverResolves;
|
|
||||||
expect(error.message).toContain('Protocol error');
|
|
||||||
});
|
|
||||||
it('should throw if userDataDir option is passed', async({browserType, defaultBrowserOptions}) => {
|
|
||||||
let waitError = null;
|
|
||||||
const options = Object.assign({}, defaultBrowserOptions, {userDataDir: 'random-path'});
|
|
||||||
await browserType.launch(options).catch(e => waitError = e);
|
|
||||||
expect(waitError.message).toContain('launchPersistentContext');
|
|
||||||
});
|
|
||||||
it.skip(FFOX)('should throw if page argument is passed', async({browserType, defaultBrowserOptions}) => {
|
|
||||||
let waitError = null;
|
|
||||||
const options = Object.assign({}, defaultBrowserOptions, { args: ['http://example.com'] });
|
|
||||||
await browserType.launch(options).catch(e => waitError = e);
|
|
||||||
expect(waitError.message).toContain('can not specify page');
|
|
||||||
});
|
|
||||||
it.fail(true)('should reject if launched browser fails immediately', async({browserType, defaultBrowserOptions}) => {
|
|
||||||
// I'm getting ENCONRESET on this one.
|
|
||||||
const options = Object.assign({}, defaultBrowserOptions, {executablePath: path.join(__dirname, 'assets', 'dummy_bad_browser_executable.js')});
|
|
||||||
let waitError = null;
|
|
||||||
await browserType.launch(options).catch(e => waitError = e);
|
|
||||||
expect(waitError.message).toContain('== logs ==');
|
|
||||||
});
|
|
||||||
it('should reject if executable path is invalid', async({browserType, defaultBrowserOptions}) => {
|
|
||||||
let waitError = null;
|
|
||||||
const options = Object.assign({}, defaultBrowserOptions, {executablePath: 'random-invalid-path'});
|
|
||||||
await browserType.launch(options).catch(e => waitError = e);
|
|
||||||
expect(waitError.message).toContain('Failed to launch');
|
|
||||||
});
|
|
||||||
it.skip(USES_HOOKS)('should handle timeout', async({browserType, defaultBrowserOptions}) => {
|
|
||||||
const options = { ...defaultBrowserOptions, timeout: 5000, __testHookBeforeCreateBrowser: () => new Promise(f => setTimeout(f, 6000)) };
|
|
||||||
const error = await browserType.launch(options).catch(e => e);
|
|
||||||
expect(error.message).toContain(`browserType.launch: Timeout 5000ms exceeded.`);
|
|
||||||
expect(error.message).toContain(`[browser] <launching>`);
|
|
||||||
expect(error.message).toContain(`[browser] <launched> pid=`);
|
|
||||||
});
|
|
||||||
it.skip(USES_HOOKS)('should handle exception', async({browserType, defaultBrowserOptions}) => {
|
|
||||||
const e = new Error('Dummy');
|
|
||||||
const options = { ...defaultBrowserOptions, __testHookBeforeCreateBrowser: () => { throw e; }, timeout: 9000 };
|
|
||||||
const error = await browserType.launch(options).catch(e => e);
|
|
||||||
expect(error.message).toContain('Dummy');
|
|
||||||
});
|
|
||||||
it.skip(USES_HOOKS)('should report launch log', async({browserType, defaultBrowserOptions}) => {
|
|
||||||
const e = new Error('Dummy');
|
|
||||||
const options = { ...defaultBrowserOptions, __testHookBeforeCreateBrowser: () => { throw e; }, timeout: 9000 };
|
|
||||||
const error = await browserType.launch(options).catch(e => e);
|
|
||||||
expect(error.message).toContain('<launching>');
|
|
||||||
});
|
|
||||||
it.slow()('should accept objects as options', async({browserType, defaultBrowserOptions}) => {
|
|
||||||
const browser = await browserType.launch({ ...defaultBrowserOptions, process });
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('browserType.executablePath', function() {
|
|
||||||
it('should work', async({browserType}) => {
|
|
||||||
const executablePath = browserType.executablePath();
|
|
||||||
expect(fs.existsSync(executablePath)).toBe(true);
|
|
||||||
expect(fs.realpathSync(executablePath)).toBe(executablePath);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('browserType.name', function() {
|
|
||||||
it('should work', async({browserType}) => {
|
|
||||||
if (WEBKIT)
|
|
||||||
expect(browserType.name()).toBe('webkit');
|
|
||||||
else if (FFOX)
|
|
||||||
expect(browserType.name()).toBe('firefox');
|
|
||||||
else if (CHROMIUM)
|
|
||||||
expect(browserType.name()).toBe('chromium');
|
|
||||||
else
|
|
||||||
throw new Error('Unknown browser');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Top-level requires', function() {
|
|
||||||
it('should require top-level Errors', async({playwright}) => {
|
|
||||||
const Errors = require(path.join(utils.projectRoot(), '/lib/errors.js'));
|
|
||||||
expect(String(Errors.TimeoutError)).toContain('TimeoutError');
|
|
||||||
});
|
|
||||||
it('should require top-level DeviceDescriptors', async({playwright}) => {
|
|
||||||
const Devices = require(path.join(utils.projectRoot(), '/lib/deviceDescriptors.js')).DeviceDescriptors;
|
|
||||||
expect(Devices['iPhone 6']).toBeTruthy();
|
|
||||||
expect(Devices['iPhone 6']).toEqual(playwright.devices['iPhone 6']);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Browser.isConnected', () => {
|
|
||||||
it('should set the browser connected state', async ({browserType, defaultBrowserOptions}) => {
|
|
||||||
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
|
||||||
const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
|
|
||||||
expect(remote.isConnected()).toBe(true);
|
|
||||||
await remote.close();
|
|
||||||
expect(remote.isConnected()).toBe(false);
|
|
||||||
await browserServer._checkLeaks();
|
|
||||||
await browserServer.close();
|
|
||||||
});
|
|
||||||
it('should throw when used after isConnected returns false', async({browserType, defaultBrowserOptions}) => {
|
|
||||||
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
|
||||||
const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
|
|
||||||
const page = await remote.newPage();
|
|
||||||
await Promise.all([
|
|
||||||
browserServer.close(),
|
|
||||||
new Promise(f => remote.once('disconnected', f)),
|
|
||||||
]);
|
|
||||||
expect(remote.isConnected()).toBe(false);
|
|
||||||
const error = await page.evaluate('1 + 1').catch(e => e);
|
|
||||||
expect(error.message).toContain('has been closed');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Browser.disconnect', function() {
|
|
||||||
it('should reject navigation when browser closes', async({browserType, defaultBrowserOptions, server}) => {
|
|
||||||
server.setRoute('/one-style.css', () => {});
|
|
||||||
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
|
||||||
const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
|
|
||||||
const page = await remote.newPage();
|
|
||||||
const navigationPromise = page.goto(server.PREFIX + '/one-style.html', {timeout: 60000}).catch(e => e);
|
|
||||||
await server.waitForRequest('/one-style.css');
|
|
||||||
await remote.close();
|
|
||||||
const error = await navigationPromise;
|
|
||||||
expect(error.message).toContain('Navigation failed because page was closed!');
|
|
||||||
await browserServer._checkLeaks();
|
|
||||||
await browserServer.close();
|
|
||||||
});
|
|
||||||
it('should reject waitForSelector when browser closes', async({browserType, defaultBrowserOptions, server}) => {
|
|
||||||
server.setRoute('/empty.html', () => {});
|
|
||||||
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
|
||||||
const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
|
|
||||||
const page = await remote.newPage();
|
|
||||||
const watchdog = page.waitForSelector('div', { state: 'attached', timeout: 60000 }).catch(e => e);
|
|
||||||
|
|
||||||
// Make sure the previous waitForSelector has time to make it to the browser before we disconnect.
|
|
||||||
await page.waitForSelector('body', { state: 'attached' });
|
|
||||||
|
|
||||||
await remote.close();
|
|
||||||
const error = await watchdog;
|
|
||||||
expect(error.message).toContain('Protocol error');
|
|
||||||
await browserServer._checkLeaks();
|
|
||||||
await browserServer.close();
|
|
||||||
});
|
|
||||||
it('should throw if used after disconnect', async({browserType, defaultBrowserOptions}) => {
|
|
||||||
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
|
||||||
const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
|
|
||||||
const page = await remote.newPage();
|
|
||||||
await remote.close();
|
|
||||||
const error = await page.evaluate('1 + 1').catch(e => e);
|
|
||||||
expect(error.message).toContain('has been closed');
|
|
||||||
await browserServer._checkLeaks();
|
|
||||||
await browserServer.close();
|
|
||||||
});
|
|
||||||
it('should emit close events on pages and contexts', async({browserType, defaultBrowserOptions}) => {
|
|
||||||
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
|
||||||
const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
|
|
||||||
const context = await remote.newContext();
|
|
||||||
const page = await context.newPage();
|
|
||||||
let pageClosed = false;
|
|
||||||
page.on('close', e => pageClosed = true);
|
|
||||||
await Promise.all([
|
|
||||||
new Promise(f => context.on('close', f)),
|
|
||||||
browserServer.close()
|
|
||||||
]);
|
|
||||||
expect(pageClosed).toBeTruthy();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('Browser.close', function() {
|
|
||||||
it('should terminate network waiters', async({browserType, defaultBrowserOptions, server}) => {
|
|
||||||
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
|
||||||
const remote = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
|
|
||||||
const newPage = await remote.newPage();
|
|
||||||
const results = await Promise.all([
|
|
||||||
newPage.waitForRequest(server.EMPTY_PAGE).catch(e => e),
|
|
||||||
newPage.waitForResponse(server.EMPTY_PAGE).catch(e => e),
|
|
||||||
browserServer.close()
|
|
||||||
]);
|
|
||||||
for (let i = 0; i < 2; i++) {
|
|
||||||
const message = results[i].message;
|
|
||||||
expect(message).toContain('Page closed');
|
|
||||||
expect(message).not.toContain('Timeout');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
it('should fire close event for all contexts', async({browserType, defaultBrowserOptions}) => {
|
|
||||||
const browser = await browserType.launch(defaultBrowserOptions);
|
|
||||||
const context = await browser.newContext();
|
|
||||||
let closed = false;
|
|
||||||
context.on('close', () => closed = true);
|
|
||||||
await browser.close();
|
|
||||||
expect(closed).toBe(true);
|
|
||||||
});
|
|
||||||
it('should be callable twice', async({browserType, defaultBrowserOptions}) => {
|
|
||||||
const browser = await browserType.launch(defaultBrowserOptions);
|
|
||||||
await Promise.all([
|
|
||||||
browser.close(),
|
|
||||||
browser.close(),
|
|
||||||
]);
|
|
||||||
await browser.close();
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('browserType.launchServer', function() {
|
|
||||||
it('should work', async({browserType, defaultBrowserOptions}) => {
|
|
||||||
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
|
||||||
const browser = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
|
|
||||||
const browserContext = await browser.newContext();
|
|
||||||
expect(browserContext.pages().length).toBe(0);
|
|
||||||
expect(browserServer.wsEndpoint()).not.toBe(null);
|
|
||||||
const page = await browserContext.newPage();
|
|
||||||
expect(await page.evaluate('11 * 11')).toBe(121);
|
|
||||||
await page.close();
|
|
||||||
await browser.close();
|
|
||||||
await browserServer._checkLeaks();
|
|
||||||
await browserServer.close();
|
|
||||||
});
|
|
||||||
it('should fire "disconnected" when closing the server', async({browserType, defaultBrowserOptions}) => {
|
|
||||||
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
|
||||||
const browser = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
|
|
||||||
const disconnectedEventPromise = new Promise(resolve => browser.once('disconnected', resolve));
|
|
||||||
const closedPromise = new Promise(f => browserServer.on('close', f));
|
|
||||||
browserServer.kill();
|
|
||||||
await Promise.all([
|
|
||||||
disconnectedEventPromise,
|
|
||||||
closedPromise,
|
|
||||||
]);
|
|
||||||
});
|
|
||||||
it('should fire "close" event during kill', async({browserType, defaultBrowserOptions}) => {
|
|
||||||
const order = [];
|
|
||||||
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
|
||||||
const closedPromise = new Promise(f => browserServer.on('close', () => {
|
|
||||||
order.push('closed');
|
|
||||||
f();
|
|
||||||
}));
|
|
||||||
await Promise.all([
|
|
||||||
browserServer.kill().then(() => order.push('killed')),
|
|
||||||
closedPromise,
|
|
||||||
]);
|
|
||||||
expect(order).toEqual(['closed', 'killed']);
|
|
||||||
});
|
|
||||||
it('should return child_process instance', async ({browserType, defaultBrowserOptions}) => {
|
|
||||||
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
|
||||||
expect(browserServer.process().pid).toBeGreaterThan(0);
|
|
||||||
await browserServer.close();
|
|
||||||
});
|
|
||||||
it('should fire close event', async ({browserType, defaultBrowserOptions}) => {
|
|
||||||
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
|
||||||
const [result] = await Promise.all([
|
|
||||||
new Promise(f => browserServer.on('close', (exitCode, signal) => f({ exitCode, signal }))),
|
|
||||||
browserServer.close(),
|
|
||||||
]);
|
|
||||||
expect(result.exitCode).toBe(0);
|
|
||||||
expect(result.signal).toBe(null);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
describe('browserType.connect', function() {
|
|
||||||
it.slow()('should be able to reconnect to a browser', async({browserType, defaultBrowserOptions, server}) => {
|
|
||||||
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
|
||||||
{
|
|
||||||
const browser = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
|
|
||||||
const browserContext = await browser.newContext();
|
|
||||||
const page = await browserContext.newPage();
|
|
||||||
await page.goto(server.EMPTY_PAGE);
|
|
||||||
await browser.close();
|
|
||||||
}
|
|
||||||
{
|
|
||||||
const browser = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint() });
|
|
||||||
const browserContext = await browser.newContext();
|
|
||||||
const page = await browserContext.newPage();
|
|
||||||
await page.goto(server.EMPTY_PAGE);
|
|
||||||
await browser.close();
|
|
||||||
}
|
|
||||||
await browserServer._checkLeaks();
|
|
||||||
await browserServer.close();
|
|
||||||
});
|
|
||||||
it.fail(USES_HOOKS || (CHROMIUM && WIN)).slow()('should handle exceptions during connect', async({browserType, defaultBrowserOptions, server}) => {
|
|
||||||
const browserServer = await browserType.launchServer(defaultBrowserOptions);
|
|
||||||
const __testHookBeforeCreateBrowser = () => { throw new Error('Dummy') };
|
|
||||||
const error = await browserType.connect({ wsEndpoint: browserServer.wsEndpoint(), __testHookBeforeCreateBrowser }).catch(e => e);
|
|
||||||
await browserServer._checkLeaks();
|
|
||||||
await browserServer.close();
|
|
||||||
expect(error.message).toContain('Dummy');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
32
test/launcher.spec.js
Normal file
32
test/launcher.spec.js
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
/**
|
||||||
|
* Copyright 2017 Google Inc. All rights reserved.
|
||||||
|
* Modifications 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
const path = require('path');
|
||||||
|
const fs = require('fs');
|
||||||
|
const utils = require('./utils');
|
||||||
|
const {FFOX, CHROMIUM, WEBKIT, WIN, USES_HOOKS, CHANNEL} = testOptions;
|
||||||
|
|
||||||
|
it('should require top-level Errors', async({playwright}) => {
|
||||||
|
const Errors = require(path.join(utils.projectRoot(), '/lib/errors.js'));
|
||||||
|
expect(String(Errors.TimeoutError)).toContain('TimeoutError');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should require top-level DeviceDescriptors', async({playwright}) => {
|
||||||
|
const Devices = require(path.join(utils.projectRoot(), '/lib/deviceDescriptors.js')).DeviceDescriptors;
|
||||||
|
expect(Devices['iPhone 6']).toBeTruthy();
|
||||||
|
expect(Devices['iPhone 6']).toEqual(playwright.devices['iPhone 6']);
|
||||||
|
});
|
||||||
|
|
@ -98,7 +98,7 @@ it('should trigger correct Log', async({page, server}) => {
|
||||||
expect(message.type()).toEqual('error');
|
expect(message.type()).toEqual('error');
|
||||||
});
|
});
|
||||||
|
|
||||||
it.only('should have location for console API calls', async({page, server}) => {
|
it('should have location for console API calls', async({page, server}) => {
|
||||||
await page.goto(server.EMPTY_PAGE);
|
await page.goto(server.EMPTY_PAGE);
|
||||||
const [message] = await Promise.all([
|
const [message] = await Promise.all([
|
||||||
page.waitForEvent('console', m => m.text() === 'yellow' ),
|
page.waitForEvent('console', m => m.text() === 'yellow' ),
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue