Skip to content

Commit aee6324

Browse files
authored
feat(firefox): roll firefox (#1273)
1 parent 3c35d7b commit aee6324

File tree

6 files changed

+38
-66
lines changed

6 files changed

+38
-66
lines changed

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
"main": "index.js",
1010
"playwright": {
1111
"chromium_revision": "747023",
12-
"firefox_revision": "1039",
12+
"firefox_revision": "1040",
1313
"webkit_revision": "1168"
1414
},
1515
"scripts": {

src/firefox/ffBrowser.ts

+24-36
Original file line numberDiff line numberDiff line change
@@ -29,17 +29,19 @@ import { headersArray } from './ffNetworkManager';
2929
import { FFPage } from './ffPage';
3030
import { Protocol } from './protocol';
3131

32+
const kAttachedToTarget = Symbol('kAttachedToTarget');
33+
3234
export class FFBrowser extends platform.EventEmitter implements Browser {
3335
_connection: FFConnection;
3436
_targets: Map<string, Target>;
3537
readonly _defaultContext: FFBrowserContext;
3638
readonly _contexts: Map<string, FFBrowserContext>;
3739
private _eventListeners: RegisteredListener[];
3840

39-
static async connect(transport: ConnectionTransport, slowMo?: number): Promise<FFBrowser> {
41+
static async connect(transport: ConnectionTransport, attachToDefaultContext: boolean, slowMo?: number): Promise<FFBrowser> {
4042
const connection = new FFConnection(SlowMoTransport.wrap(transport, slowMo));
4143
const browser = new FFBrowser(connection);
42-
await connection.send('Target.enable');
44+
await connection.send('Browser.enable', { attachToDefaultContext });
4345
return browser;
4446
}
4547

@@ -56,10 +58,8 @@ export class FFBrowser extends platform.EventEmitter implements Browser {
5658
this.emit(Events.Browser.Disconnected);
5759
});
5860
this._eventListeners = [
59-
helper.addEventListener(this._connection, 'Target.targetCreated', this._onTargetCreated.bind(this)),
60-
helper.addEventListener(this._connection, 'Target.targetDestroyed', this._onTargetDestroyed.bind(this)),
61-
helper.addEventListener(this._connection, 'Target.targetInfoChanged', this._onTargetInfoChanged.bind(this)),
62-
helper.addEventListener(this._connection, 'Target.attachedToTarget', this._onAttachedToTarget.bind(this)),
61+
helper.addEventListener(this._connection, 'Browser.attachedToTarget', this._onAttachedToTarget.bind(this)),
62+
helper.addEventListener(this._connection, 'Browser.detachedFromTarget', this._onDetachedFromTarget.bind(this)),
6363
];
6464
}
6565

@@ -88,7 +88,7 @@ export class FFBrowser extends platform.EventEmitter implements Browser {
8888
hasTouch: false,
8989
};
9090
}
91-
const { browserContextId } = await this._connection.send('Target.createBrowserContext', {
91+
const { browserContextId } = await this._connection.send('Browser.createBrowserContext', {
9292
userAgent: options.userAgent,
9393
bypassCSP: options.bypassCSP,
9494
javaScriptDisabled: options.javaScriptEnabled === false ? true : undefined,
@@ -121,13 +121,13 @@ export class FFBrowser extends platform.EventEmitter implements Browser {
121121
return existingTarget;
122122
let resolve: (t: Target) => void;
123123
const targetPromise = new Promise<Target>(x => resolve = x);
124-
this.on('targetchanged', check);
124+
this.on(kAttachedToTarget, check);
125125
try {
126126
if (!timeout)
127127
return await targetPromise;
128128
return await helper.waitWithTimeout(targetPromise, 'target', timeout);
129129
} finally {
130-
this.removeListener('targetchanged', check);
130+
this.removeListener(kAttachedToTarget, check);
131131
}
132132

133133
function check(target: Target) {
@@ -140,33 +140,23 @@ export class FFBrowser extends platform.EventEmitter implements Browser {
140140
return Array.from(this._targets.values());
141141
}
142142

143-
async _onTargetCreated(payload: Protocol.Target.targetCreatedPayload) {
144-
const {targetId, url, browserContextId, openerId, type} = payload;
145-
const context = browserContextId ? this._contexts.get(browserContextId)! : this._defaultContext;
146-
const target = new Target(this._connection, this, context, targetId, type, url, openerId);
147-
this._targets.set(targetId, target);
148-
}
149-
150-
_onTargetDestroyed(payload: Protocol.Target.targetDestroyedPayload) {
143+
_onDetachedFromTarget(payload: Protocol.Browser.detachedFromTargetPayload) {
151144
const {targetId} = payload;
152145
const target = this._targets.get(targetId)!;
153146
this._targets.delete(targetId);
154147
target._didClose();
155148
}
156149

157-
_onTargetInfoChanged(payload: Protocol.Target.targetInfoChangedPayload) {
158-
const {targetId, url} = payload;
159-
const target = this._targets.get(targetId)!;
160-
target._url = url;
161-
}
162-
163-
async _onAttachedToTarget(payload: Protocol.Target.attachedToTargetPayload) {
164-
const {targetId} = payload.targetInfo;
165-
const target = this._targets.get(targetId)!;
166-
target._initPagePromise(this._connection.getSession(payload.sessionId)!);
150+
async _onAttachedToTarget(payload: Protocol.Browser.attachedToTargetPayload) {
151+
const {targetId, browserContextId, openerId, type} = payload.targetInfo;
152+
const context = browserContextId ? this._contexts.get(browserContextId)! : this._defaultContext;
153+
const target = new Target(this, context, type, '', openerId);
154+
this._targets.set(targetId, target);
155+
target._initPagePromise(this._connection.createSession(payload.sessionId, type));
167156

168157
const pageEvent = new PageEvent(target.pageOrError());
169158
target.context().emit(Events.BrowserContext.Page, pageEvent);
159+
this.emit(kAttachedToTarget, target);
170160

171161
const opener = target.opener();
172162
if (!opener)
@@ -194,23 +184,22 @@ class Target {
194184
_ffPage: FFPage | null = null;
195185
private readonly _browser: FFBrowser;
196186
private readonly _context: FFBrowserContext;
197-
private readonly _connection: FFConnection;
198-
private readonly _targetId: string;
199187
private readonly _type: 'page' | 'browser';
200188
_url: string;
201189
private readonly _openerId: string | undefined;
190+
private _session?: FFSession;
202191

203-
constructor(connection: any, browser: FFBrowser, context: FFBrowserContext, targetId: string, type: 'page' | 'browser', url: string, openerId: string | undefined) {
192+
constructor(browser: FFBrowser, context: FFBrowserContext, type: 'page' | 'browser', url: string, openerId: string | undefined) {
204193
this._browser = browser;
205194
this._context = context;
206-
this._connection = connection;
207-
this._targetId = targetId;
208195
this._type = type;
209196
this._url = url;
210197
this._openerId = openerId;
211198
}
212199

213200
_didClose() {
201+
if (this._session)
202+
this._session.dispose();
214203
if (this._ffPage)
215204
this._ffPage.didClose();
216205
}
@@ -234,12 +223,11 @@ class Target {
234223
async pageOrError(): Promise<Page | Error> {
235224
if (this._type !== 'page')
236225
throw new Error(`Cannot create page for "${this._type}" target`);
237-
if (!this._pagePromise)
238-
await this._connection.send('Target.attachToTarget', {targetId: this._targetId});
239226
return this._pagePromise!;
240227
}
241228

242229
_initPagePromise(session: FFSession) {
230+
this._session = session;
243231
this._pagePromise = new Promise(async f => {
244232
this._ffPage = new FFPage(session, this._context, async () => {
245233
const openerTarget = this.opener();
@@ -318,7 +306,7 @@ export class FFBrowserContext extends BrowserContextBase {
318306

319307
async newPage(): Promise<Page> {
320308
assertBrowserContextIsNotOwned(this);
321-
const {targetId} = await this._browser._connection.send('Target.newPage', {
309+
const {targetId} = await this._browser._connection.send('Browser.newPage', {
322310
browserContextId: this._browserContextId || undefined
323311
});
324312
const target = this._browser._targets.get(targetId)!;
@@ -410,7 +398,7 @@ export class FFBrowserContext extends BrowserContextBase {
410398
if (this._closed)
411399
return;
412400
assert(this._browserContextId, 'Non-incognito profiles cannot be closed!');
413-
await this._browser._connection.send('Target.removeBrowserContext', { browserContextId: this._browserContextId });
401+
await this._browser._connection.send('Browser.removeBrowserContext', { browserContextId: this._browserContextId });
414402
this._browser._contexts.delete(this._browserContextId);
415403
this._didCloseInternal();
416404
}

src/firefox/ffConnection.ts

+8-24
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ export class FFConnection extends platform.EventEmitter {
3232
private _lastId: number;
3333
private _callbacks: Map<number, {resolve: Function, reject: Function, error: Error, method: string}>;
3434
private _transport: ConnectionTransport;
35-
private _sessions: Map<string, FFSession>;
35+
readonly _sessions: Map<string, FFSession>;
3636
_debugProtocol: (message: string) => void = platform.debug('pw:protocol');
3737
_closed: boolean;
3838

@@ -60,14 +60,6 @@ export class FFConnection extends platform.EventEmitter {
6060
this.once = super.once;
6161
}
6262

63-
static fromSession(session: FFSession): FFConnection {
64-
return session._connection;
65-
}
66-
67-
session(sessionId: string): FFSession | null {
68-
return this._sessions.get(sessionId) || null;
69-
}
70-
7163
async send<T extends keyof Protocol.CommandParameters>(
7264
method: T,
7365
params?: Protocol.CommandParameters[T]
@@ -94,17 +86,6 @@ export class FFConnection extends platform.EventEmitter {
9486
const object = JSON.parse(message);
9587
if (object.id === kBrowserCloseMessageId)
9688
return;
97-
if (object.method === 'Target.attachedToTarget') {
98-
const sessionId = object.params.sessionId;
99-
const session = new FFSession(this, object.params.targetInfo.type, sessionId, message => this._rawSend({...message, sessionId}));
100-
this._sessions.set(sessionId, session);
101-
} else if (object.method === 'Target.detachedFromTarget') {
102-
const session = this._sessions.get(object.params.sessionId);
103-
if (session) {
104-
session._onClosed();
105-
this._sessions.delete(object.params.sessionId);
106-
}
107-
}
10889
if (object.sessionId) {
10990
const session = this._sessions.get(object.sessionId);
11091
if (session)
@@ -132,7 +113,7 @@ export class FFConnection extends platform.EventEmitter {
132113
callback.reject(rewriteError(callback.error, `Protocol error (${callback.method}): Target closed.`));
133114
this._callbacks.clear();
134115
for (const session of this._sessions.values())
135-
session._onClosed();
116+
session.dispose();
136117
this._sessions.clear();
137118
Promise.resolve().then(() => this.emit(ConnectionEvents.Disconnected));
138119
}
@@ -142,8 +123,10 @@ export class FFConnection extends platform.EventEmitter {
142123
this._transport.close();
143124
}
144125

145-
getSession(sessionId: string): FFSession | null {
146-
return this._sessions.get(sessionId) || null;
126+
createSession(sessionId: string, type: string): FFSession {
127+
const session = new FFSession(this, type, sessionId, message => this._rawSend({...message, sessionId}));
128+
this._sessions.set(sessionId, session);
129+
return session;
147130
}
148131
}
149132

@@ -206,11 +189,12 @@ export class FFSession extends platform.EventEmitter {
206189
}
207190
}
208191

209-
_onClosed() {
192+
dispose() {
210193
for (const callback of this._callbacks.values())
211194
callback.reject(rewriteError(callback.error, `Protocol error (${callback.method}): Target closed.`));
212195
this._callbacks.clear();
213196
this._disposed = true;
197+
this._connection._sessions.delete(this._sessionId);
214198
Promise.resolve().then(() => this.emit(FFSessionEvents.Disconnected));
215199
}
216200
}

src/firefox/ffPage.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ export class FFPage implements PageDelegate {
226226
const worker = this._workers.get(workerId);
227227
if (!worker)
228228
return;
229-
worker.session._onClosed();
229+
worker.session.dispose();
230230
this._workers.delete(workerId);
231231
this._page._removeWorker(workerId);
232232
}

src/server/firefox.ts

+3-3
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ export class Firefox implements BrowserType {
6565
throw new Error('userDataDir option is not supported in `browserType.launch`. Use `browserType.launchPersistent` instead');
6666
const browserServer = await this._launchServer(options, 'local');
6767
const browser = await platform.connectToWebsocket(browserServer.wsEndpoint()!, transport => {
68-
return FFBrowser.connect(transport, options && options.slowMo);
68+
return FFBrowser.connect(transport, false, options && options.slowMo);
6969
});
7070
// Hack: for typical launch scenario, ensure that close waits for actual process termination.
7171
browser.close = () => browserServer.close();
@@ -81,7 +81,7 @@ export class Firefox implements BrowserType {
8181
const { timeout = 30000 } = options || {};
8282
const browserServer = await this._launchServer(options, 'persistent', userDataDir);
8383
const browser = await platform.connectToWebsocket(browserServer.wsEndpoint()!, transport => {
84-
return FFBrowser.connect(transport);
84+
return FFBrowser.connect(transport, true);
8585
});
8686
await helper.waitWithTimeout(browser._waitForTarget(t => t.type() === 'page'), 'first page', timeout);
8787
// Hack: for typical launch scenario, ensure that close waits for actual process termination.
@@ -166,7 +166,7 @@ export class Firefox implements BrowserType {
166166

167167
async connect(options: ConnectOptions): Promise<FFBrowser> {
168168
return await platform.connectToWebsocket(options.wsEndpoint, transport => {
169-
return FFBrowser.connect(transport, options.slowMo);
169+
return FFBrowser.connect(transport, false, options.slowMo);
170170
});
171171
}
172172

src/web.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -37,7 +37,7 @@ const connect = {
3737
firefox: {
3838
connect: async (url: string) => {
3939
return await platform.connectToWebsocket(url, transport => {
40-
return FirefoxBrowser.connect(transport);
40+
return FirefoxBrowser.connect(transport, false);
4141
});
4242
}
4343
}

0 commit comments

Comments
 (0)