feat(firefox): apply emulation to all pages in the browser context (#931)
This commit is contained in:
parent
90367c1f66
commit
da30847c83
|
|
@ -9,7 +9,7 @@
|
|||
"main": "index.js",
|
||||
"playwright": {
|
||||
"chromium_revision": "740289",
|
||||
"firefox_revision": "1025",
|
||||
"firefox_revision": "1028",
|
||||
"webkit_revision": "1141"
|
||||
},
|
||||
"scripts": {
|
||||
|
|
|
|||
|
|
@ -18,11 +18,11 @@
|
|||
import { Browser, createPageInNewContext } from '../browser';
|
||||
import { BrowserContext, BrowserContextOptions } from '../browserContext';
|
||||
import { Events } from '../events';
|
||||
import { assert, helper, RegisteredListener } from '../helper';
|
||||
import { assert, helper, RegisteredListener, debugError } from '../helper';
|
||||
import * as network from '../network';
|
||||
import * as types from '../types';
|
||||
import { Page } from '../page';
|
||||
import { ConnectionEvents, FFConnection, FFSessionEvents } from './ffConnection';
|
||||
import { ConnectionEvents, FFConnection, FFSessionEvents, FFSession } from './ffConnection';
|
||||
import { FFPage } from './ffPage';
|
||||
import * as platform from '../platform';
|
||||
import { Protocol } from './protocol';
|
||||
|
|
@ -68,8 +68,17 @@ export class FFBrowser extends platform.EventEmitter implements Browser {
|
|||
}
|
||||
|
||||
async newContext(options: BrowserContextOptions = {}): Promise<BrowserContext> {
|
||||
const viewport = options.viewport ? {
|
||||
viewportSize: { width: options.viewport.width, height: options.viewport.height },
|
||||
isMobile: !!options.viewport.isMobile,
|
||||
deviceScaleFactor: options.viewport.deviceScaleFactor || 1,
|
||||
hasTouch: !!options.viewport.isMobile,
|
||||
} : undefined;
|
||||
const {browserContextId} = await this._connection.send('Target.createBrowserContext', {
|
||||
userAgent: options.userAgent
|
||||
userAgent: options.userAgent,
|
||||
bypassCSP: options.bypassCSP,
|
||||
javaScriptDisabled: options.javaScriptEnabled === false ? true : undefined,
|
||||
viewport,
|
||||
});
|
||||
// TODO: move ignoreHTTPSErrors to browser context level.
|
||||
if (options.ignoreHTTPSErrors)
|
||||
|
|
@ -121,14 +130,6 @@ export class FFBrowser extends platform.EventEmitter implements Browser {
|
|||
const context = browserContextId ? this._contexts.get(browserContextId)! : this._defaultContext;
|
||||
const target = new Target(this._connection, this, context, targetId, type, url, openerId);
|
||||
this._targets.set(targetId, target);
|
||||
const opener = target.opener();
|
||||
if (opener && opener._pagePromise) {
|
||||
const openerPage = await opener._pagePromise;
|
||||
if (openerPage.listenerCount(Events.Page.Popup)) {
|
||||
const popupPage = await target.page();
|
||||
openerPage.emit(Events.Page.Popup, popupPage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_onTargetDestroyed(payload: Protocol.Target.targetDestroyedPayload) {
|
||||
|
|
@ -144,11 +145,18 @@ export class FFBrowser extends platform.EventEmitter implements Browser {
|
|||
target._url = url;
|
||||
}
|
||||
|
||||
_onAttachedToTarget(payload: Protocol.Target.attachedToTargetPayload) {
|
||||
const {targetId, type} = payload.targetInfo;
|
||||
async _onAttachedToTarget(payload: Protocol.Target.attachedToTargetPayload) {
|
||||
const {targetId} = payload.targetInfo;
|
||||
const target = this._targets.get(targetId)!;
|
||||
if (type === 'page')
|
||||
target.page();
|
||||
target._initPagePromise(this._connection.getSession(payload.sessionId)!);
|
||||
const opener = target.opener();
|
||||
if (opener && opener._pagePromise) {
|
||||
const openerPage = await opener._pagePromise;
|
||||
if (openerPage.listenerCount(Events.Page.Popup)) {
|
||||
const popupPage = await target.page();
|
||||
openerPage.emit(Events.Page.Popup, popupPage);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async close() {
|
||||
|
|
@ -278,25 +286,27 @@ class Target {
|
|||
return this._context;
|
||||
}
|
||||
|
||||
page(): Promise<Page> {
|
||||
async page(): Promise<Page> {
|
||||
if (this._type !== 'page')
|
||||
throw new Error(`Cannot create page for "${this._type}" target`);
|
||||
if (!this._pagePromise) {
|
||||
this._pagePromise = new Promise(async f => {
|
||||
const session = await this._connection.createSession(this._targetId);
|
||||
this._ffPage = new FFPage(session, this._context, async () => {
|
||||
const openerTarget = this.opener();
|
||||
if (!openerTarget)
|
||||
return null;
|
||||
return await openerTarget.page();
|
||||
});
|
||||
const page = this._ffPage._page;
|
||||
session.once(FFSessionEvents.Disconnected, () => page._didDisconnect());
|
||||
await this._ffPage._initialize();
|
||||
f(page);
|
||||
if (!this._pagePromise)
|
||||
await this._connection.send('Target.attachToTarget', {targetId: this._targetId});
|
||||
return this._pagePromise!;
|
||||
}
|
||||
|
||||
_initPagePromise(session: FFSession) {
|
||||
this._pagePromise = new Promise(async f => {
|
||||
this._ffPage = new FFPage(session, this._context, async () => {
|
||||
const openerTarget = this.opener();
|
||||
if (!openerTarget)
|
||||
return null;
|
||||
return await openerTarget.page();
|
||||
});
|
||||
}
|
||||
return this._pagePromise;
|
||||
const page = this._ffPage._page;
|
||||
session.once(FFSessionEvents.Disconnected, () => page._didDisconnect());
|
||||
await this._ffPage._initialize().catch(debugError);
|
||||
f(page);
|
||||
});
|
||||
}
|
||||
|
||||
browser() {
|
||||
|
|
|
|||
|
|
@ -143,9 +143,8 @@ export class FFConnection extends platform.EventEmitter {
|
|||
this._transport.close();
|
||||
}
|
||||
|
||||
async createSession(targetId: string): Promise<FFSession> {
|
||||
const {sessionId} = await this.send('Target.attachToTarget', {targetId});
|
||||
return this._sessions.get(sessionId)!;
|
||||
getSession(sessionId: string): FFSession | null {
|
||||
return this._sessions.get(sessionId) || null;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -77,26 +77,13 @@ export class FFPage implements PageDelegate {
|
|||
}
|
||||
|
||||
async _initialize() {
|
||||
const promises: Promise<any>[] = [
|
||||
this._session.send('Runtime.enable').then(() => this._ensureIsolatedWorld(UTILITY_WORLD_NAME)),
|
||||
this._session.send('Network.enable'),
|
||||
this._session.send('Page.enable'),
|
||||
];
|
||||
const options = this._page.context()._options;
|
||||
if (options.viewport)
|
||||
promises.push(this._updateViewport());
|
||||
if (options.bypassCSP)
|
||||
promises.push(this._session.send('Page.setBypassCSP', { enabled: true }));
|
||||
if (options.javaScriptEnabled === false)
|
||||
promises.push(this._session.send('Page.setJavascriptEnabled', { enabled: false }));
|
||||
await Promise.all(promises);
|
||||
}
|
||||
|
||||
async _ensureIsolatedWorld(name: string) {
|
||||
await this._session.send('Page.addScriptToEvaluateOnNewDocument', {
|
||||
script: '',
|
||||
worldName: name,
|
||||
});
|
||||
await Promise.all([
|
||||
this._session.send('Page.addScriptToEvaluateOnNewDocument', {
|
||||
script: '',
|
||||
worldName: UTILITY_WORLD_NAME,
|
||||
}),
|
||||
new Promise(f => this._session.once('Page.ready', f)),
|
||||
]);
|
||||
}
|
||||
|
||||
_onExecutionContextCreated(payload: Protocol.Runtime.executionContextCreatedPayload) {
|
||||
|
|
@ -268,22 +255,10 @@ export class FFPage implements PageDelegate {
|
|||
|
||||
async setViewportSize(viewportSize: types.Size): Promise<void> {
|
||||
assert(this._page._state.viewportSize === viewportSize);
|
||||
await this._updateViewport();
|
||||
}
|
||||
|
||||
async _updateViewport() {
|
||||
let viewport = this._page.context()._options.viewport || { width: 0, height: 0 };
|
||||
const viewportSize = this._page._state.viewportSize;
|
||||
if (viewportSize)
|
||||
viewport = { ...viewport, ...viewportSize };
|
||||
await this._session.send('Page.setViewport', {
|
||||
viewport: {
|
||||
width: viewport.width,
|
||||
height: viewport.height,
|
||||
isMobile: !!viewport.isMobile,
|
||||
deviceScaleFactor: viewport.deviceScaleFactor || 1,
|
||||
hasTouch: !!viewport.isMobile,
|
||||
isLandscape: viewport.width > viewport.height
|
||||
await this._session.send('Page.setViewportSize', {
|
||||
viewportSize: {
|
||||
width: viewportSize.width,
|
||||
height: viewportSize.height,
|
||||
},
|
||||
});
|
||||
}
|
||||
|
|
@ -373,7 +348,7 @@ export class FFPage implements PageDelegate {
|
|||
}
|
||||
|
||||
async resetViewport(): Promise<void> {
|
||||
await this._session.send('Page.setViewport', { viewport: null });
|
||||
await this._session.send('Page.setViewportSize', { viewportSize: null });
|
||||
}
|
||||
|
||||
async getContentFrame(handle: dom.ElementHandle): Promise<frames.Frame | null> {
|
||||
|
|
|
|||
|
|
@ -34,19 +34,6 @@ module.exports.describe = function({testRunner, expect, playwright, CHROMIUM, WE
|
|||
await context.close();
|
||||
expect(browser.contexts().length).toBe(0);
|
||||
});
|
||||
it.skip(CHROMIUM)('popup should inherit user agent', async function({newContext, server}) {
|
||||
const context = await newContext({
|
||||
userAgent: 'hey'
|
||||
});
|
||||
const page = await context.newPage();
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const evaluatePromise = page.evaluate(url => window.open(url), server.PREFIX + '/dummy.html');
|
||||
const popupPromise = page.waitForEvent('popup');
|
||||
const request = await server.waitForRequest('/dummy.html');
|
||||
await evaluatePromise;
|
||||
await popupPromise;
|
||||
expect(request.headers['user-agent']).toBe('hey');
|
||||
});
|
||||
it('window.open should use parent tab context', async function({newContext, server}) {
|
||||
const context = await newContext();
|
||||
const page = await context.newPage();
|
||||
|
|
|
|||
|
|
@ -154,7 +154,7 @@ module.exports.describe = function({testRunner, expect, defaultBrowserOptions, p
|
|||
const remote = await playwright.connect({ wsEndpoint: browserServer.wsEndpoint() });
|
||||
const page = await remote.newPage();
|
||||
const watchdog = page.waitForSelector('div', { 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');
|
||||
|
||||
|
|
|
|||
|
|
@ -125,70 +125,6 @@ module.exports.describe = function({testRunner, expect, headless, playwright, FF
|
|||
});
|
||||
});
|
||||
|
||||
describe('Page.Events.Popup', function() {
|
||||
it('should work', async({page}) => {
|
||||
const [popup] = await Promise.all([
|
||||
new Promise(x => page.once('popup', x)),
|
||||
page.evaluate(() => window.open('about:blank')),
|
||||
]);
|
||||
expect(await page.evaluate(() => !!window.opener)).toBe(false);
|
||||
expect(await popup.evaluate(() => !!window.opener)).toBe(true);
|
||||
});
|
||||
it('should work with noopener', async({page}) => {
|
||||
const [popup] = await Promise.all([
|
||||
new Promise(x => page.once('popup', x)),
|
||||
page.evaluate(() => window.open('about:blank', null, 'noopener')),
|
||||
]);
|
||||
expect(await page.evaluate(() => !!window.opener)).toBe(false);
|
||||
expect(await popup.evaluate(() => !!window.opener)).toBe(false);
|
||||
});
|
||||
it.skip(FFOX)('should work with clicking target=_blank', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.setContent('<a target=_blank rel="opener" href="/one-style.html">yo</a>');
|
||||
const [popup] = await Promise.all([
|
||||
page.waitForEvent('popup').then(async popup => { await popup.waitForLoadState(); return popup; }),
|
||||
page.click('a'),
|
||||
]);
|
||||
expect(await page.evaluate(() => !!window.opener)).toBe(false);
|
||||
expect(await popup.evaluate(() => !!window.opener)).toBe(true);
|
||||
});
|
||||
it.skip(FFOX)('should work with fake-clicking target=_blank and rel=noopener', async({page, server}) => {
|
||||
// TODO: FFOX sends events for "one-style.html" request to both pages.
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.setContent('<a target=_blank rel=noopener href="/one-style.html">yo</a>');
|
||||
const [popup] = await Promise.all([
|
||||
page.waitForEvent('popup').then(async popup => { await popup.waitForLoadState(); return popup; }),
|
||||
page.$eval('a', a => a.click()),
|
||||
]);
|
||||
expect(await page.evaluate(() => !!window.opener)).toBe(false);
|
||||
// TODO: At this point popup might still have about:blank as the current document.
|
||||
// FFOX is slow enough to trigger this. We should do something about popups api.
|
||||
expect(await popup.evaluate(() => !!window.opener)).toBe(false);
|
||||
});
|
||||
it.skip(FFOX)('should work with clicking target=_blank and rel=noopener', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.setContent('<a target=_blank rel=noopener href="/one-style.html">yo</a>');
|
||||
const [popup] = await Promise.all([
|
||||
page.waitForEvent('popup').then(async popup => { await popup.waitForLoadState(); return popup; }),
|
||||
page.click('a'),
|
||||
]);
|
||||
expect(await page.evaluate(() => !!window.opener)).toBe(false);
|
||||
expect(await popup.evaluate(() => !!window.opener)).toBe(false);
|
||||
});
|
||||
it.skip(FFOX)('should not treat navigations as new popups', async({page, server}) => {
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.setContent('<a target=_blank rel=noopener href="/one-style.html">yo</a>');
|
||||
const [popup] = await Promise.all([
|
||||
page.waitForEvent('popup').then(async popup => { await popup.waitForLoadState(); return popup; }),
|
||||
page.click('a'),
|
||||
]);
|
||||
let badSecondPopup = false;
|
||||
page.on('popup', () => badSecondPopup = true);
|
||||
await popup.goto(server.CROSS_PROCESS_PREFIX + '/empty.html');
|
||||
expect(badSecondPopup).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('Page.opener', function() {
|
||||
it('should provide access to the opener page', async({page}) => {
|
||||
const [popup] = await Promise.all([
|
||||
|
|
@ -306,8 +242,9 @@ module.exports.describe = function({testRunner, expect, headless, playwright, FF
|
|||
|
||||
describe('Page.Events.DOMContentLoaded', function() {
|
||||
it('should fire when expected', async({page, server}) => {
|
||||
page.goto('about:blank');
|
||||
const navigatedPromise = page.goto('about:blank');
|
||||
await waitEvent(page, 'domcontentloaded');
|
||||
await navigatedPromise;
|
||||
});
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -197,6 +197,7 @@ module.exports.describe = ({testRunner, product, playwrightPath}) => {
|
|||
testRunner.loadTests(require('./browser.spec.js'), testOptions);
|
||||
testRunner.loadTests(require('./browsercontext.spec.js'), testOptions);
|
||||
testRunner.loadTests(require('./ignorehttpserrors.spec.js'), testOptions);
|
||||
testRunner.loadTests(require('./popup.spec.js'), testOptions);
|
||||
});
|
||||
|
||||
// Top-level tests that launch Browser themselves.
|
||||
|
|
|
|||
158
test/popup.spec.js
Normal file
158
test/popup.spec.js
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
/**
|
||||
* 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.
|
||||
*/
|
||||
|
||||
module.exports.describe = function({testRunner, expect, playwright, CHROMIUM, WEBKIT, FFOX}) {
|
||||
const {describe, xdescribe, fdescribe} = testRunner;
|
||||
const {it, fit, xit, dit} = testRunner;
|
||||
const {beforeAll, beforeEach, afterAll, afterEach} = testRunner;
|
||||
|
||||
describe('window.open', function() {
|
||||
it.skip(CHROMIUM)('should inherit user agent from browser context', async function({newContext, server}) {
|
||||
const context = await newContext({
|
||||
userAgent: 'hey'
|
||||
});
|
||||
const page = await context.newPage();
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const evaluatePromise = page.evaluate(url => window.open(url), server.PREFIX + '/dummy.html');
|
||||
const popupPromise = page.waitForEvent('popup');
|
||||
const request = await server.waitForRequest('/dummy.html');
|
||||
await evaluatePromise;
|
||||
await popupPromise;
|
||||
await context.close();
|
||||
expect(request.headers['user-agent']).toBe('hey');
|
||||
});
|
||||
it.skip(CHROMIUM)('should inherit touch support from browser context', async function({newContext, server}) {
|
||||
const context = await newContext({
|
||||
viewport: { width: 400, height: 500, isMobile: true }
|
||||
});
|
||||
const page = await context.newPage();
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const hasTouch = await page.evaluate(() => {
|
||||
const win = window.open('');
|
||||
return 'ontouchstart' in win;
|
||||
});
|
||||
await context.close();
|
||||
expect(hasTouch).toBe(true);
|
||||
});
|
||||
it.skip(CHROMIUM || WEBKIT)('should inherit viewport size from browser context', async function({newContext, server}) {
|
||||
const context = await newContext({
|
||||
viewport: { width: 400, height: 500, isMobile: true }
|
||||
});
|
||||
const page = await context.newPage();
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
const size = await page.evaluate(() => {
|
||||
const win = window.open('about:blank');
|
||||
return { width: win.innerWidth, height: win.innerHeight };
|
||||
});
|
||||
await context.close();
|
||||
expect(size).toEqual({width: 400, height: 500});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Page.Events.Popup', function() {
|
||||
it('should work', async({newContext}) => {
|
||||
const context = await newContext();
|
||||
const page = await context.newPage();
|
||||
const [popup] = await Promise.all([
|
||||
new Promise(x => page.once('popup', x)),
|
||||
page.evaluate(() => window.__popup = window.open('about:blank')),
|
||||
]);
|
||||
expect(await page.evaluate(() => !!window.opener)).toBe(false);
|
||||
expect(await popup.evaluate(() => !!window.opener)).toBe(true);
|
||||
await context.close();
|
||||
});
|
||||
it.skip(CHROMIUM)('should work with empty url', async({newContext}) => {
|
||||
const context = await newContext();
|
||||
const page = await context.newPage();
|
||||
const [popup] = await Promise.all([
|
||||
new Promise(x => page.once('popup', x)),
|
||||
page.evaluate(() => window.__popup = window.open('')),
|
||||
]);
|
||||
expect(await page.evaluate(() => !!window.opener)).toBe(false);
|
||||
expect(await popup.evaluate(() => !!window.opener)).toBe(true);
|
||||
await context.close();
|
||||
});
|
||||
it('should work with noopener', async({newContext}) => {
|
||||
const context = await newContext();
|
||||
const page = await context.newPage();
|
||||
const [popup] = await Promise.all([
|
||||
new Promise(x => page.once('popup', x)),
|
||||
page.evaluate(() => window.__popup = window.open('about:blank', null, 'noopener')),
|
||||
]);
|
||||
expect(await page.evaluate(() => !!window.opener)).toBe(false);
|
||||
expect(await popup.evaluate(() => !!window.opener)).toBe(false);
|
||||
await context.close();
|
||||
});
|
||||
it.skip(FFOX)('should work with clicking target=_blank', async({newContext, server}) => {
|
||||
const context = await newContext();
|
||||
const page = await context.newPage();
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.setContent('<a target=_blank rel="opener" href="/one-style.html">yo</a>');
|
||||
const [popup] = await Promise.all([
|
||||
page.waitForEvent('popup').then(async popup => { await popup.waitForLoadState(); return popup; }),
|
||||
page.click('a'),
|
||||
]);
|
||||
expect(await page.evaluate(() => !!window.opener)).toBe(false);
|
||||
expect(await popup.evaluate(() => !!window.opener)).toBe(true);
|
||||
await context.close();
|
||||
});
|
||||
it.skip(FFOX)('should work with fake-clicking target=_blank and rel=noopener', async({newContext, server}) => {
|
||||
const context = await newContext();
|
||||
const page = await context.newPage();
|
||||
// TODO: FFOX sends events for "one-style.html" request to both pages.
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.setContent('<a target=_blank rel=noopener href="/one-style.html">yo</a>');
|
||||
const [popup] = await Promise.all([
|
||||
page.waitForEvent('popup').then(async popup => { await popup.waitForLoadState(); return popup; }),
|
||||
page.$eval('a', a => a.click()),
|
||||
]);
|
||||
expect(await page.evaluate(() => !!window.opener)).toBe(false);
|
||||
// TODO: At this point popup might still have about:blank as the current document.
|
||||
// FFOX is slow enough to trigger this. We should do something about popups api.
|
||||
expect(await popup.evaluate(() => !!window.opener)).toBe(false);
|
||||
await context.close();
|
||||
});
|
||||
it.skip(FFOX)('should work with clicking target=_blank and rel=noopener', async({newContext, server}) => {
|
||||
const context = await newContext();
|
||||
const page = await context.newPage();
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.setContent('<a target=_blank rel=noopener href="/one-style.html">yo</a>');
|
||||
const [popup] = await Promise.all([
|
||||
page.waitForEvent('popup').then(async popup => { await popup.waitForLoadState(); return popup; }),
|
||||
page.click('a'),
|
||||
]);
|
||||
expect(await page.evaluate(() => !!window.opener)).toBe(false);
|
||||
expect(await popup.evaluate(() => !!window.opener)).toBe(false);
|
||||
await context.close();
|
||||
});
|
||||
it.skip(FFOX)('should not treat navigations as new popups', async({newContext, server}) => {
|
||||
const context = await newContext();
|
||||
const page = await context.newPage();
|
||||
await page.goto(server.EMPTY_PAGE);
|
||||
await page.setContent('<a target=_blank rel=noopener href="/one-style.html">yo</a>');
|
||||
const [popup] = await Promise.all([
|
||||
page.waitForEvent('popup').then(async popup => { await popup.waitForLoadState(); return popup; }),
|
||||
page.click('a'),
|
||||
]);
|
||||
let badSecondPopup = false;
|
||||
page.on('popup', () => badSecondPopup = true);
|
||||
await popup.goto(server.CROSS_PROCESS_PREFIX + '/empty.html');
|
||||
await context.close();
|
||||
expect(badSecondPopup).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
};
|
||||
Loading…
Reference in a new issue