parent
1489fbdbff
commit
25f2a32af3
|
|
@ -467,6 +467,7 @@ page.removeListener('request', logRequest);
|
||||||
- [page.keyboard](#pagekeyboard)
|
- [page.keyboard](#pagekeyboard)
|
||||||
- [page.mainFrame()](#pagemainframe)
|
- [page.mainFrame()](#pagemainframe)
|
||||||
- [page.mouse](#pagemouse)
|
- [page.mouse](#pagemouse)
|
||||||
|
- [page.opener()](#pageopener)
|
||||||
- [page.pdf([options])](#pagepdfoptions)
|
- [page.pdf([options])](#pagepdfoptions)
|
||||||
- [page.reload([options])](#pagereloadoptions)
|
- [page.reload([options])](#pagereloadoptions)
|
||||||
- [page.screenshot([options])](#pagescreenshotoptions)
|
- [page.screenshot([options])](#pagescreenshotoptions)
|
||||||
|
|
@ -1098,6 +1099,10 @@ Page is guaranteed to have a main frame which persists during navigations.
|
||||||
|
|
||||||
- returns: <[Mouse]>
|
- returns: <[Mouse]>
|
||||||
|
|
||||||
|
#### page.opener()
|
||||||
|
|
||||||
|
- returns: <[Promise]<?[Page]>> Promise which resolves to the opener for popup pages and `null` for others. If the opener has been closed already the promise may resolve to `null`.
|
||||||
|
|
||||||
#### page.pdf([options])
|
#### page.pdf([options])
|
||||||
- `options` <[Object]> Options object which might have the following properties:
|
- `options` <[Object]> Options object which might have the following properties:
|
||||||
- `path` <[string]> The file path to save the PDF to. If `path` is a relative path, then it is resolved relative to [current working directory](https://nodejs.org/api/process.html#process_process_cwd). If no path is provided, the PDF won't be saved to the disk.
|
- `path` <[string]> The file path to save the PDF to. If `path` is a relative path, then it is resolved relative to [current working directory](https://nodejs.org/api/process.html#process_process_cwd). If no path is provided, the PDF won't be saved to the disk.
|
||||||
|
|
|
||||||
|
|
@ -38,6 +38,7 @@ import { BrowserContext } from '../browserContext';
|
||||||
import * as types from '../types';
|
import * as types from '../types';
|
||||||
import { ConsoleMessage } from '../console';
|
import { ConsoleMessage } from '../console';
|
||||||
import * as platform from '../platform';
|
import * as platform from '../platform';
|
||||||
|
import { CRTarget } from './crTarget';
|
||||||
|
|
||||||
const UTILITY_WORLD_NAME = '__playwright_utility_world__';
|
const UTILITY_WORLD_NAME = '__playwright_utility_world__';
|
||||||
|
|
||||||
|
|
@ -349,6 +350,13 @@ export class CRPage implements PageDelegate {
|
||||||
await this._client.send('Page.setInterceptFileChooserDialog', { enabled }).catch(e => {}); // target can be closed.
|
await this._client.send('Page.setInterceptFileChooserDialog', { enabled }).catch(e => {}); // target can be closed.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async opener() : Promise<Page | null> {
|
||||||
|
const openerTarget = CRTarget.fromPage(this._page).opener();
|
||||||
|
if (!openerTarget)
|
||||||
|
return null;
|
||||||
|
return await openerTarget.page();
|
||||||
|
}
|
||||||
|
|
||||||
async reload(): Promise<void> {
|
async reload(): Promise<void> {
|
||||||
await this._client.send('Page.reload');
|
await this._client.send('Page.reload');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -280,7 +280,12 @@ class Target {
|
||||||
if (!this._pagePromise) {
|
if (!this._pagePromise) {
|
||||||
this._pagePromise = new Promise(async f => {
|
this._pagePromise = new Promise(async f => {
|
||||||
const session = await this._connection.createSession(this._targetId);
|
const session = await this._connection.createSession(this._targetId);
|
||||||
this._ffPage = new FFPage(session, this._context);
|
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;
|
const page = this._ffPage._page;
|
||||||
session.once(FFSessionEvents.Disconnected, () => page._didDisconnect());
|
session.once(FFSessionEvents.Disconnected, () => page._didDisconnect());
|
||||||
await this._ffPage._initialize();
|
await this._ffPage._initialize();
|
||||||
|
|
|
||||||
|
|
@ -41,12 +41,14 @@ export class FFPage implements PageDelegate {
|
||||||
readonly _session: FFSession;
|
readonly _session: FFSession;
|
||||||
readonly _page: Page;
|
readonly _page: Page;
|
||||||
readonly _networkManager: FFNetworkManager;
|
readonly _networkManager: FFNetworkManager;
|
||||||
|
private readonly _openerResolver: () => Promise<Page | null>;
|
||||||
private readonly _contextIdToContext: Map<string, dom.FrameExecutionContext>;
|
private readonly _contextIdToContext: Map<string, dom.FrameExecutionContext>;
|
||||||
private _eventListeners: RegisteredListener[];
|
private _eventListeners: RegisteredListener[];
|
||||||
private _workers = new Map<string, { frameId: string, session: FFSession }>();
|
private _workers = new Map<string, { frameId: string, session: FFSession }>();
|
||||||
|
|
||||||
constructor(session: FFSession, browserContext: BrowserContext) {
|
constructor(session: FFSession, browserContext: BrowserContext, openerResolver: () => Promise<Page | null>) {
|
||||||
this._session = session;
|
this._session = session;
|
||||||
|
this._openerResolver = openerResolver;
|
||||||
this.rawKeyboard = new RawKeyboardImpl(session);
|
this.rawKeyboard = new RawKeyboardImpl(session);
|
||||||
this.rawMouse = new RawMouseImpl(session);
|
this.rawMouse = new RawMouseImpl(session);
|
||||||
this._contextIdToContext = new Map();
|
this._contextIdToContext = new Map();
|
||||||
|
|
@ -305,6 +307,10 @@ export class FFPage implements PageDelegate {
|
||||||
await this._session.send('Page.setInterceptFileChooserDialog', { enabled }).catch(e => {}); // target can be closed.
|
await this._session.send('Page.setInterceptFileChooserDialog', { enabled }).catch(e => {}); // target can be closed.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async opener() : Promise<Page | null> {
|
||||||
|
return await this._openerResolver();
|
||||||
|
}
|
||||||
|
|
||||||
async reload(): Promise<void> {
|
async reload(): Promise<void> {
|
||||||
await this._session.send('Page.reload', { frameId: this._page.mainFrame()._id });
|
await this._session.send('Page.reload', { frameId: this._page.mainFrame()._id });
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,6 +34,8 @@ export interface PageDelegate {
|
||||||
readonly rawMouse: input.RawMouse;
|
readonly rawMouse: input.RawMouse;
|
||||||
readonly rawKeyboard: input.RawKeyboard;
|
readonly rawKeyboard: input.RawKeyboard;
|
||||||
|
|
||||||
|
opener(): Promise<Page | null>;
|
||||||
|
|
||||||
reload(): Promise<void>;
|
reload(): Promise<void>;
|
||||||
goBack(): Promise<boolean>;
|
goBack(): Promise<boolean>;
|
||||||
goForward(): Promise<boolean>;
|
goForward(): Promise<boolean>;
|
||||||
|
|
@ -173,6 +175,10 @@ export class Page extends platform.EventEmitter {
|
||||||
return this._browserContext;
|
return this._browserContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async opener(): Promise<Page | null> {
|
||||||
|
return await this._delegate.opener();
|
||||||
|
}
|
||||||
|
|
||||||
mainFrame(): frames.Frame {
|
mainFrame(): frames.Frame {
|
||||||
return this._frameManager.mainFrame();
|
return this._frameManager.mainFrame();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -113,7 +113,14 @@ export class WKBrowser extends platform.EventEmitter implements Browser {
|
||||||
const pageProxySession = new WKSession(this._connection, pageProxyId, `The page has been closed.`, (message: any) => {
|
const pageProxySession = new WKSession(this._connection, pageProxyId, `The page has been closed.`, (message: any) => {
|
||||||
this._connection.rawSend({ ...message, pageProxyId });
|
this._connection.rawSend({ ...message, pageProxyId });
|
||||||
});
|
});
|
||||||
const pageProxy = new WKPageProxy(pageProxySession, context);
|
const pageProxy = new WKPageProxy(pageProxySession, context, () => {
|
||||||
|
if (!pageProxyInfo.openerId)
|
||||||
|
return null;
|
||||||
|
const opener = this._pageProxies.get(pageProxyInfo.openerId);
|
||||||
|
if (!opener)
|
||||||
|
return null;
|
||||||
|
return opener;
|
||||||
|
});
|
||||||
this._pageProxies.set(pageProxyId, pageProxy);
|
this._pageProxies.set(pageProxyId, pageProxy);
|
||||||
|
|
||||||
if (pageProxyInfo.openerId) {
|
if (pageProxyInfo.openerId) {
|
||||||
|
|
|
||||||
|
|
@ -45,6 +45,7 @@ export class WKPage implements PageDelegate {
|
||||||
private _provisionalPage: WKProvisionalPage | null = null;
|
private _provisionalPage: WKProvisionalPage | null = null;
|
||||||
readonly _page: Page;
|
readonly _page: Page;
|
||||||
private readonly _pageProxySession: WKSession;
|
private readonly _pageProxySession: WKSession;
|
||||||
|
private readonly _openerResolver: () => Promise<Page | null>;
|
||||||
private readonly _requestIdToRequest = new Map<string, WKInterceptableRequest>();
|
private readonly _requestIdToRequest = new Map<string, WKInterceptableRequest>();
|
||||||
private readonly _workers: WKWorkers;
|
private readonly _workers: WKWorkers;
|
||||||
private readonly _contextIdToContext: Map<number, dom.FrameExecutionContext>;
|
private readonly _contextIdToContext: Map<number, dom.FrameExecutionContext>;
|
||||||
|
|
@ -52,8 +53,9 @@ export class WKPage implements PageDelegate {
|
||||||
private _sessionListeners: RegisteredListener[] = [];
|
private _sessionListeners: RegisteredListener[] = [];
|
||||||
private readonly _bootstrapScripts: string[] = [];
|
private readonly _bootstrapScripts: string[] = [];
|
||||||
|
|
||||||
constructor(browserContext: BrowserContext, pageProxySession: WKSession) {
|
constructor(browserContext: BrowserContext, pageProxySession: WKSession, openerResolver: () => Promise<Page | null>) {
|
||||||
this._pageProxySession = pageProxySession;
|
this._pageProxySession = pageProxySession;
|
||||||
|
this._openerResolver = openerResolver;
|
||||||
this.rawKeyboard = new RawKeyboardImpl(pageProxySession);
|
this.rawKeyboard = new RawKeyboardImpl(pageProxySession);
|
||||||
this.rawMouse = new RawMouseImpl(pageProxySession);
|
this.rawMouse = new RawMouseImpl(pageProxySession);
|
||||||
this._contextIdToContext = new Map();
|
this._contextIdToContext = new Map();
|
||||||
|
|
@ -415,6 +417,10 @@ export class WKPage implements PageDelegate {
|
||||||
await this._session.send('Page.setInterceptFileChooserDialog', { enabled }).catch(e => {}); // target can be closed.
|
await this._session.send('Page.setInterceptFileChooserDialog', { enabled }).catch(e => {}); // target can be closed.
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async opener() {
|
||||||
|
return await this._openerResolver();
|
||||||
|
}
|
||||||
|
|
||||||
async reload(): Promise<void> {
|
async reload(): Promise<void> {
|
||||||
await this._session.send('Page.reload');
|
await this._session.send('Page.reload');
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ const isPovisionalSymbol = Symbol('isPovisional');
|
||||||
export class WKPageProxy {
|
export class WKPageProxy {
|
||||||
private readonly _pageProxySession: WKSession;
|
private readonly _pageProxySession: WKSession;
|
||||||
readonly _browserContext: BrowserContext;
|
readonly _browserContext: BrowserContext;
|
||||||
|
private readonly _openerResolver: () => WKPageProxy | null;
|
||||||
private _pagePromise: Promise<Page> | null = null;
|
private _pagePromise: Promise<Page> | null = null;
|
||||||
private _wkPage: WKPage | null = null;
|
private _wkPage: WKPage | null = null;
|
||||||
private readonly _firstTargetPromise: Promise<void>;
|
private readonly _firstTargetPromise: Promise<void>;
|
||||||
|
|
@ -36,9 +37,10 @@ export class WKPageProxy {
|
||||||
private readonly _sessions = new Map<string, WKSession>();
|
private readonly _sessions = new Map<string, WKSession>();
|
||||||
private readonly _eventListeners: RegisteredListener[];
|
private readonly _eventListeners: RegisteredListener[];
|
||||||
|
|
||||||
constructor(pageProxySession: WKSession, browserContext: BrowserContext) {
|
constructor(pageProxySession: WKSession, browserContext: BrowserContext, openerResolver: () => (WKPageProxy | null)) {
|
||||||
this._pageProxySession = pageProxySession;
|
this._pageProxySession = pageProxySession;
|
||||||
this._browserContext = browserContext;
|
this._browserContext = browserContext;
|
||||||
|
this._openerResolver = openerResolver;
|
||||||
this._firstTargetPromise = new Promise(r => this._firstTargetCallback = r);
|
this._firstTargetPromise = new Promise(r => this._firstTargetCallback = r);
|
||||||
this._eventListeners = [
|
this._eventListeners = [
|
||||||
helper.addEventListener(this._pageProxySession, 'Target.targetCreated', this._onTargetCreated.bind(this)),
|
helper.addEventListener(this._pageProxySession, 'Target.targetCreated', this._onTargetCreated.bind(this)),
|
||||||
|
|
@ -111,7 +113,12 @@ export class WKPageProxy {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
assert(session, 'One non-provisional target session must exist');
|
assert(session, 'One non-provisional target session must exist');
|
||||||
this._wkPage = new WKPage(this._browserContext, this._pageProxySession);
|
this._wkPage = new WKPage(this._browserContext, this._pageProxySession, async () => {
|
||||||
|
const pageProxy = this._openerResolver();
|
||||||
|
if (!pageProxy)
|
||||||
|
return null;
|
||||||
|
return await pageProxy.page();
|
||||||
|
});
|
||||||
await this._wkPage.initialize(session!);
|
await this._wkPage.initialize(session!);
|
||||||
if (this._pagePausedOnStart) {
|
if (this._pagePausedOnStart) {
|
||||||
this._resumeTarget(session!.sessionId);
|
this._resumeTarget(session!.sessionId);
|
||||||
|
|
|
||||||
|
|
@ -186,6 +186,26 @@ module.exports.describe = function({testRunner, expect, headless, playwright, FF
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('Page.opener', function() {
|
||||||
|
it('should provide access to the opener page', async({page}) => {
|
||||||
|
const [popup] = await Promise.all([
|
||||||
|
new Promise(x => page.once('popup', x)),
|
||||||
|
page.evaluate(() => window.open('about:blank')),
|
||||||
|
]);
|
||||||
|
const opener = await popup.opener();
|
||||||
|
expect(opener).toBe(page);
|
||||||
|
});
|
||||||
|
it('should return null if parent page has been closed', async({page}) => {
|
||||||
|
const [popup] = await Promise.all([
|
||||||
|
new Promise(x => page.once('popup', x)),
|
||||||
|
page.evaluate(() => window.open('about:blank')),
|
||||||
|
]);
|
||||||
|
await page.close();
|
||||||
|
const opener = await popup.opener();
|
||||||
|
expect(opener).toBe(null);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
describe('Page.Events.Console', function() {
|
describe('Page.Events.Console', function() {
|
||||||
it('should work', async({page, server}) => {
|
it('should work', async({page, server}) => {
|
||||||
let message = null;
|
let message = null;
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue