feat(firefox): support Browser.target() (#4028)
Support browser target. Drive-by: switch over to a more devtools'ish protocol: - use `targetId` instead of `pageId` everywhere - use target events instead of tab events
This commit is contained in:
parent
ea482c4751
commit
4a4793a5e1
@ -31,8 +31,8 @@ class Browser extends EventEmitter {
|
||||
this._process = process;
|
||||
this._closeCallback = closeCallback;
|
||||
|
||||
/** @type {!Map<string, ?Target>} */
|
||||
this._pageTargets = new Map();
|
||||
/** @type {!Map<string, !Target>} */
|
||||
this._targets = new Map();
|
||||
|
||||
this._defaultContext = new BrowserContext(this._connection, this, null);
|
||||
/** @type {!Map<string, !BrowserContext>} */
|
||||
@ -43,9 +43,9 @@ class Browser extends EventEmitter {
|
||||
this._connection.on(Events.Connection.Disconnected, () => this.emit(Events.Browser.Disconnected));
|
||||
|
||||
this._eventListeners = [
|
||||
helper.addEventListener(this._connection, 'Browser.tabOpened', this._onTabOpened.bind(this)),
|
||||
helper.addEventListener(this._connection, 'Browser.tabClosed', this._onTabClosed.bind(this)),
|
||||
helper.addEventListener(this._connection, 'Browser.tabNavigated', this._onTabNavigated.bind(this)),
|
||||
helper.addEventListener(this._connection, 'Browser.targetCreated', this._onTargetCreated.bind(this)),
|
||||
helper.addEventListener(this._connection, 'Browser.targetDestroyed', this._onTargetDestroyed.bind(this)),
|
||||
helper.addEventListener(this._connection, 'Browser.targetInfoChanged', this._onTargetInfoChanged.bind(this)),
|
||||
];
|
||||
}
|
||||
|
||||
@ -152,29 +152,32 @@ class Browser extends EventEmitter {
|
||||
* @return {Promise<Page>}
|
||||
*/
|
||||
async _createPageInContext(browserContextId) {
|
||||
const {pageId} = await this._connection.send('Browser.newPage', {
|
||||
const {targetId} = await this._connection.send('Browser.newPage', {
|
||||
browserContextId: browserContextId || undefined
|
||||
});
|
||||
const target = this._pageTargets.get(pageId);
|
||||
const target = this._targets.get(targetId);
|
||||
return await target.page();
|
||||
}
|
||||
|
||||
async pages() {
|
||||
const pageTargets = Array.from(this._pageTargets.values());
|
||||
const pageTargets = Array.from(this._targets.values()).filter(target => target.type() === 'page');
|
||||
return await Promise.all(pageTargets.map(target => target.page()));
|
||||
}
|
||||
|
||||
targets() {
|
||||
return Array.from(this._pageTargets.values());
|
||||
return Array.from(this._targets.values());
|
||||
}
|
||||
|
||||
async _onTabOpened({pageId, url, browserContextId, openerId}) {
|
||||
target() {
|
||||
return this.targets().find(target => target.type() === 'browser');
|
||||
}
|
||||
|
||||
async _onTargetCreated({targetId, url, browserContextId, openerId, type}) {
|
||||
const context = browserContextId ? this._contexts.get(browserContextId) : this._defaultContext;
|
||||
const opener = openerId ? this._pageTargets.get(openerId) : null;
|
||||
const target = new Target(this._connection, this, context, pageId, url, opener);
|
||||
this._pageTargets.set(pageId, target);
|
||||
if (opener && opener._pagePromise) {
|
||||
const openerPage = await opener._pagePromise;
|
||||
const target = new Target(this._connection, this, context, targetId, type, url, openerId);
|
||||
this._targets.set(targetId, target);
|
||||
if (target.opener() && target.opener()._pagePromise) {
|
||||
const openerPage = await target.opener()._pagePromise;
|
||||
if (openerPage.listenerCount(Events.Page.Popup)) {
|
||||
const popupPage = await target.page();
|
||||
openerPage.emit(Events.Page.Popup, popupPage);
|
||||
@ -184,15 +187,15 @@ class Browser extends EventEmitter {
|
||||
context.emit(Events.BrowserContext.TargetCreated, target);
|
||||
}
|
||||
|
||||
_onTabClosed({pageId}) {
|
||||
const target = this._pageTargets.get(pageId);
|
||||
this._pageTargets.delete(pageId);
|
||||
_onTargetDestroyed({targetId}) {
|
||||
const target = this._targets.get(targetId);
|
||||
this._targets.delete(targetId);
|
||||
this.emit(Events.Browser.TargetDestroyed, target);
|
||||
target.browserContext().emit(Events.BrowserContext.TargetDestroyed, target);
|
||||
}
|
||||
|
||||
_onTabNavigated({pageId, url}) {
|
||||
const target = this._pageTargets.get(pageId);
|
||||
_onTargetInfoChanged({targetId, url}) {
|
||||
const target = this._targets.get(targetId);
|
||||
target._url = url;
|
||||
this.emit(Events.Browser.TargetChanged, target);
|
||||
target.browserContext().emit(Events.BrowserContext.TargetChanged, target);
|
||||
@ -210,33 +213,35 @@ class Target {
|
||||
* @param {*} connection
|
||||
* @param {!Browser} browser
|
||||
* @param {!BrowserContext} context
|
||||
* @param {string} pageId
|
||||
* @param {string} targetId
|
||||
* @param {string} type
|
||||
* @param {string} url
|
||||
* @param {?Target} opener
|
||||
* @param {string=} openerId
|
||||
*/
|
||||
constructor(connection, browser, context, pageId, url, opener) {
|
||||
constructor(connection, browser, context, targetId, type, url, openerId) {
|
||||
this._browser = browser;
|
||||
this._context = context;
|
||||
this._connection = connection;
|
||||
this._pageId = pageId;
|
||||
this._targetId = targetId;
|
||||
this._type = type;
|
||||
/** @type {?Promise<!Page>} */
|
||||
this._pagePromise = null;
|
||||
this._url = url;
|
||||
this._opener = opener;
|
||||
this._openerId = openerId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {?Target}
|
||||
*/
|
||||
opener() {
|
||||
return this._opener;
|
||||
return this._openerId ? this._browser._targets.get(this._openerId) : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return {"page"|"background_page"|"service_worker"|"other"|"browser"}
|
||||
* @return {"page"|"browser"}
|
||||
*/
|
||||
type() {
|
||||
return 'page';
|
||||
return this._type;
|
||||
}
|
||||
|
||||
url() {
|
||||
@ -251,8 +256,8 @@ class Target {
|
||||
}
|
||||
|
||||
async page() {
|
||||
if (!this._pagePromise)
|
||||
this._pagePromise = Page.create(this._connection, this, this._pageId, this._browser._defaultViewport);
|
||||
if (this._type === 'page' && !this._pagePromise)
|
||||
this._pagePromise = Page.create(this._connection, this, this._targetId, this._browser._defaultViewport);
|
||||
return this._pagePromise;
|
||||
}
|
||||
|
||||
|
@ -19,14 +19,14 @@ const writeFileAsync = util.promisify(fs.writeFile);
|
||||
* @internal
|
||||
*/
|
||||
class PageSession extends EventEmitter {
|
||||
constructor(connection, pageId) {
|
||||
constructor(connection, targetId) {
|
||||
super();
|
||||
this._connection = connection;
|
||||
this._pageId = pageId;
|
||||
this._targetId = targetId;
|
||||
const wrapperSymbol = Symbol('listenerWrapper');
|
||||
|
||||
function wrapperListener(listener, params) {
|
||||
if (params.pageId === pageId)
|
||||
if (params.targetId === targetId)
|
||||
listener.call(null, params);
|
||||
}
|
||||
|
||||
@ -41,7 +41,7 @@ class PageSession extends EventEmitter {
|
||||
}
|
||||
|
||||
async send(method, params = {}) {
|
||||
params = Object.assign({}, params, {pageId: this._pageId});
|
||||
params = Object.assign({}, params, {targetId: this._targetId});
|
||||
return await this._connection.send(method, params);
|
||||
}
|
||||
}
|
||||
@ -51,11 +51,11 @@ class Page extends EventEmitter {
|
||||
*
|
||||
* @param {!Puppeteer.Connection} connection
|
||||
* @param {!Puppeteer.Target} target
|
||||
* @param {string} pageId
|
||||
* @param {string} targetId
|
||||
* @param {?Puppeteer.Viewport} defaultViewport
|
||||
*/
|
||||
static async create(connection, target, pageId, defaultViewport) {
|
||||
const session = new PageSession(connection, pageId);
|
||||
static async create(connection, target, targetId, defaultViewport) {
|
||||
const session = new PageSession(connection, targetId);
|
||||
const page = new Page(session, target);
|
||||
await session.send('Page.enable');
|
||||
if (defaultViewport)
|
||||
@ -82,7 +82,7 @@ class Page extends EventEmitter {
|
||||
helper.addEventListener(this._session, 'Page.uncaughtError', this._onUncaughtError.bind(this)),
|
||||
helper.addEventListener(this._session, 'Page.console', this._onConsole.bind(this)),
|
||||
helper.addEventListener(this._session, 'Page.dialogOpened', this._onDialogOpened.bind(this)),
|
||||
helper.addEventListener(this._session, 'Browser.tabClosed', this._onClosed.bind(this)),
|
||||
helper.addEventListener(this._session, 'Browser.targetDestroyed', this._onClosed.bind(this)),
|
||||
helper.addEventListener(this._frameManager, Events.FrameManager.Load, () => this.emit(Events.Page.Load)),
|
||||
helper.addEventListener(this._frameManager, Events.FrameManager.DOMContentLoaded, () => this.emit(Events.Page.DOMContentLoaded)),
|
||||
helper.addEventListener(this._frameManager, Events.FrameManager.FrameAttached, frame => this.emit(Events.Page.FrameAttached, frame)),
|
||||
|
@ -9,7 +9,7 @@
|
||||
"node": ">=8.9.4"
|
||||
},
|
||||
"puppeteer": {
|
||||
"firefox_revision": "10282bfac697c69a6fdfeec4cddae7caf98e1969"
|
||||
"firefox_revision": "2ede4ae19f39ec7a1b73162a6004235908260dfe"
|
||||
},
|
||||
"scripts": {
|
||||
"install": "node install.js",
|
||||
|
@ -20,7 +20,7 @@ module.exports.addTests = function({testRunner, expect, headless, puppeteer}) {
|
||||
const {beforeAll, beforeEach, afterAll, afterEach} = testRunner;
|
||||
|
||||
describe('Browser.target', function() {
|
||||
it_fails_ffox('should return browser target', async({browser}) => {
|
||||
it('should return browser target', async({browser}) => {
|
||||
const target = browser.target();
|
||||
expect(target.type()).toBe('browser');
|
||||
});
|
||||
|
@ -24,7 +24,7 @@ module.exports.addTests = function({testRunner, expect, puppeteer, Errors}) {
|
||||
const {TimeoutError} = Errors;
|
||||
|
||||
describe('Target', function() {
|
||||
it_fails_ffox('Browser.targets should return all of the targets', async({page, server, browser}) => {
|
||||
it('Browser.targets should return all of the targets', async({page, server, browser}) => {
|
||||
// The pages will be the testing page and the original newtab page
|
||||
const targets = browser.targets();
|
||||
expect(targets.some(target => target.type() === 'page' &&
|
||||
@ -38,7 +38,7 @@ module.exports.addTests = function({testRunner, expect, puppeteer, Errors}) {
|
||||
expect(allPages).toContain(page);
|
||||
expect(allPages[0]).not.toBe(allPages[1]);
|
||||
});
|
||||
it_fails_ffox('should contain browser target', async({browser}) => {
|
||||
it('should contain browser target', async({browser}) => {
|
||||
const targets = browser.targets();
|
||||
const browserTarget = targets.find(target => target.type() === 'browser');
|
||||
expect(browserTarget).toBeTruthy();
|
||||
|
Loading…
Reference in New Issue
Block a user