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