feat(firefox): support WebSockets on Firefox (#4289)

This commit is contained in:
Andrey Lushnikov 2020-10-30 10:34:24 -07:00 committed by GitHub
parent 333916a83d
commit 7fbbd1822e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 73 additions and 17 deletions

View File

@ -8,7 +8,7 @@
},
{
"name": "firefox",
"revision": "1197",
"revision": "1198",
"download": true
},
{

View File

@ -84,6 +84,11 @@ export class FFPage implements PageDelegate {
helper.addEventListener(this._session, 'Page.dispatchMessageFromWorker', this._onDispatchMessageFromWorker.bind(this)),
helper.addEventListener(this._session, 'Page.crashed', this._onCrashed.bind(this)),
helper.addEventListener(this._session, 'Page.screencastStarted', this._onScreencastStarted.bind(this)),
helper.addEventListener(this._session, 'Page.webSocketCreated', this._onWebSocketCreated.bind(this)),
helper.addEventListener(this._session, 'Page.webSocketClosed', this._onWebSocketClosed.bind(this)),
helper.addEventListener(this._session, 'Page.webSocketFrameReceived', this._onWebSocketFrameReceived.bind(this)),
helper.addEventListener(this._session, 'Page.webSocketFrameSent', this._onWebSocketFrameSent.bind(this)),
];
this._pagePromise = new Promise(f => this._pageCallback = f);
session.once(FFSessionEvents.Disconnected, () => this._page._didDisconnect());
@ -100,6 +105,25 @@ export class FFPage implements PageDelegate {
return this._pagePromise;
}
_onWebSocketCreated(event: Protocol.Page.webSocketCreatedPayload) {
this._page._frameManager.onWebSocketCreated(webSocketId(event.frameId, event.wsid), event.requestURL);
this._page._frameManager.onWebSocketRequest(webSocketId(event.frameId, event.wsid));
}
_onWebSocketClosed(event: Protocol.Page.webSocketClosedPayload) {
if (event.error)
this._page._frameManager.webSocketError(webSocketId(event.frameId, event.wsid), event.error);
this._page._frameManager.webSocketClosed(webSocketId(event.frameId, event.wsid));
}
_onWebSocketFrameReceived(event: Protocol.Page.webSocketFrameReceivedPayload) {
this._page._frameManager.webSocketFrameReceived(webSocketId(event.frameId, event.wsid), event.opcode, event.data);
}
_onWebSocketFrameSent(event: Protocol.Page.webSocketFrameSentPayload) {
this._page._frameManager.onWebSocketFrameSent(webSocketId(event.frameId, event.wsid), event.opcode, event.data);
}
_onExecutionContextCreated(payload: Protocol.Runtime.executionContextCreatedPayload) {
const {executionContextId, auxData} = payload;
const frame = this._page._frameManager.frame(auxData ? auxData.frameId : null);
@ -500,3 +524,7 @@ export class FFPage implements PageDelegate {
return result.handle;
}
}
function webSocketId(frameId: string, wsid: string): string {
return `${frameId}---${wsid}`;
}

View File

@ -413,6 +413,34 @@ export module Protocol {
screencastId: string;
file: string;
}
export type webSocketCreatedPayload = {
frameId: string;
wsid: string;
requestURL: string;
}
export type webSocketOpenedPayload = {
frameId: string;
requestId: string;
wsid: string;
effectiveURL: string;
}
export type webSocketClosedPayload = {
frameId: string;
wsid: string;
error: string;
}
export type webSocketFrameSentPayload = {
frameId: string;
wsid: string;
opcode: number;
data: string;
}
export type webSocketFrameReceivedPayload = {
frameId: string;
wsid: string;
opcode: number;
data: string;
}
export type closeParameters = {
runBeforeUnload?: boolean;
};
@ -979,6 +1007,11 @@ export module Protocol {
"Page.workerDestroyed": Page.workerDestroyedPayload;
"Page.dispatchMessageFromWorker": Page.dispatchMessageFromWorkerPayload;
"Page.screencastStarted": Page.screencastStartedPayload;
"Page.webSocketCreated": Page.webSocketCreatedPayload;
"Page.webSocketOpened": Page.webSocketOpenedPayload;
"Page.webSocketClosed": Page.webSocketClosedPayload;
"Page.webSocketFrameSent": Page.webSocketFrameSentPayload;
"Page.webSocketFrameReceived": Page.webSocketFrameReceivedPayload;
"Runtime.executionContextCreated": Runtime.executionContextCreatedPayload;
"Runtime.executionContextDestroyed": Runtime.executionContextDestroyedPayload;
"Runtime.console": Runtime.consolePayload;

View File

@ -34,16 +34,6 @@ if (browserName !== 'chromium') {
api.delete('cDPSession.detach');
}
if (browserName === 'firefox') {
// WebSockets on FF are work in progress.
api.delete('webSocket.url');
api.delete('webSocket.emit("close")');
api.delete('webSocket.emit("socketerror")');
api.delete('webSocket.emit("framereceived")');
api.delete('webSocket.emit("framesent")');
api.delete('page.emit("websocket")');
}
// Some permissions tests are disabled in webkit. See permissions.jest.js
if (browserName === 'webkit')
api.delete('browserContext.clearPermissions');
@ -77,4 +67,4 @@ function * getCoverageFiles(dir) {
else
yield path.join(dir, entry.name);
}
}
}

View File

@ -18,7 +18,6 @@
import { it, describe, expect } from './fixtures';
describe('web socket', (test, { browserName }) => {
test.fixme(browserName === 'firefox');
}, () => {
it('should work', async ({ page, server }) => {
const value = await page.evaluate(port => {
@ -47,7 +46,7 @@ describe('web socket', (test, { browserName }) => {
expect(log.join(':')).toBe(`open<ws://localhost:${server.PORT}/ws>:close`);
});
it('should emit frame events', async ({ page, server }) => {
it('should emit frame events', async ({ page, server, isFirefox }) => {
let socketClosed;
const socketClosePromise = new Promise(f => socketClosed = f);
const log = [];
@ -63,7 +62,10 @@ describe('web socket', (test, { browserName }) => {
ws.addEventListener('message', () => { ws.close(); });
}, server.PORT);
await socketClosePromise;
expect(log.join(':')).toBe('open:sent<outgoing>:received<incoming>:close');
if (isFirefox)
expect(log.join(':')).toBe('open:received<incoming>:sent<outgoing>:close');
else
expect(log.join(':')).toBe('open:sent<outgoing>:received<incoming>:close');
});
it('should emit binary frame events', async ({ page, server }) => {
@ -91,7 +93,7 @@ describe('web socket', (test, { browserName }) => {
expect(sent[1][i]).toBe(i);
});
it('should emit error', async ({page, server}) => {
it('should emit error', async ({page, server, isFirefox}) => {
let callback;
const result = new Promise(f => callback = f);
page.on('websocket', ws => ws.on('socketerror', callback));
@ -99,6 +101,9 @@ describe('web socket', (test, { browserName }) => {
new WebSocket('ws://localhost:' + port + '/bogus-ws');
}, server.PORT);
const message = await result;
expect(message).toContain(': 400');
if (isFirefox)
expect(message).toBe('CLOSE_ABNORMAL');
else
expect(message).toContain(': 400');
});
});