| 
									
										
										
										
											2020-10-26 22:20:43 -07:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Copyright 2018 Google Inc. All rights reserved. | 
					
						
							|  |  |  |  * Modifications copyright (c) Microsoft Corporation. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
					
						
							|  |  |  |  * you may not use this file except in compliance with the License. | 
					
						
							|  |  |  |  * You may obtain a copy of the License at | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *     http://www.apache.org/licenses/LICENSE-2.0
 | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * Unless required by applicable law or agreed to in writing, software | 
					
						
							|  |  |  |  * distributed under the License is distributed on an "AS IS" BASIS, | 
					
						
							|  |  |  |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
					
						
							|  |  |  |  * See the License for the specific language governing permissions and | 
					
						
							|  |  |  |  * limitations under the License. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-05 09:18:56 -07:00
										 |  |  | import { test as it, expect } from './config/pageTest'; | 
					
						
							|  |  |  | import { Server as WebSocketServer } from 'ws'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-09 07:59:09 -07:00
										 |  |  | it.beforeEach(async ({ isAndroid }) => { | 
					
						
							|  |  |  |   it.skip(isAndroid); | 
					
						
							| 
									
										
										
										
											2021-04-05 09:18:56 -07:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2020-10-26 22:20:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-30 13:38:54 -07:00
										 |  |  | it('should work', async ({ page, server }) => { | 
					
						
							|  |  |  |   const value = await page.evaluate(port => { | 
					
						
							|  |  |  |     let cb; | 
					
						
							|  |  |  |     const result = new Promise(f => cb = f); | 
					
						
							|  |  |  |     const ws = new WebSocket('ws://localhost:' + port + '/ws'); | 
					
						
							|  |  |  |     ws.addEventListener('message', data => { ws.close(); cb(data.data); }); | 
					
						
							|  |  |  |     return result; | 
					
						
							|  |  |  |   }, server.PORT); | 
					
						
							|  |  |  |   expect(value).toBe('incoming'); | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2020-10-26 22:20:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-30 13:38:54 -07:00
										 |  |  | it('should emit close events', async ({ page, server }) => { | 
					
						
							|  |  |  |   let socketClosed; | 
					
						
							|  |  |  |   const socketClosePromise = new Promise(f => socketClosed = f); | 
					
						
							|  |  |  |   const log = []; | 
					
						
							| 
									
										
										
										
											2020-11-02 14:09:58 -08:00
										 |  |  |   let webSocket; | 
					
						
							| 
									
										
										
										
											2020-10-30 13:38:54 -07:00
										 |  |  |   page.on('websocket', ws => { | 
					
						
							|  |  |  |     log.push(`open<${ws.url()}>`); | 
					
						
							| 
									
										
										
										
											2020-11-02 14:09:58 -08:00
										 |  |  |     webSocket = ws; | 
					
						
							| 
									
										
										
										
											2020-10-30 13:38:54 -07:00
										 |  |  |     ws.on('close', () => { log.push('close'); socketClosed(); }); | 
					
						
							| 
									
										
										
										
											2020-10-26 22:20:43 -07:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2020-10-30 13:38:54 -07:00
										 |  |  |   await page.evaluate(port => { | 
					
						
							|  |  |  |     const ws = new WebSocket('ws://localhost:' + port + '/ws'); | 
					
						
							|  |  |  |     ws.addEventListener('open', () => ws.close()); | 
					
						
							|  |  |  |   }, server.PORT); | 
					
						
							|  |  |  |   await socketClosePromise; | 
					
						
							|  |  |  |   expect(log.join(':')).toBe(`open<ws://localhost:${server.PORT}/ws>:close`); | 
					
						
							| 
									
										
										
										
											2020-11-02 14:09:58 -08:00
										 |  |  |   expect(webSocket.isClosed()).toBeTruthy(); | 
					
						
							| 
									
										
										
										
											2020-10-30 13:38:54 -07:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2020-10-26 22:20:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-05 09:18:56 -07:00
										 |  |  | it('should emit frame events', async ({ page, server }) => { | 
					
						
							| 
									
										
										
										
											2020-10-30 13:38:54 -07:00
										 |  |  |   let socketClosed; | 
					
						
							|  |  |  |   const socketClosePromise = new Promise(f => socketClosed = f); | 
					
						
							|  |  |  |   const log = []; | 
					
						
							|  |  |  |   page.on('websocket', ws => { | 
					
						
							|  |  |  |     log.push('open'); | 
					
						
							|  |  |  |     ws.on('framesent', d => log.push('sent<' + d.payload + '>')); | 
					
						
							|  |  |  |     ws.on('framereceived', d => log.push('received<' + d.payload + '>')); | 
					
						
							|  |  |  |     ws.on('close', () => { log.push('close'); socketClosed(); }); | 
					
						
							| 
									
										
										
										
											2020-10-26 22:20:43 -07:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2020-10-30 13:38:54 -07:00
										 |  |  |   await page.evaluate(port => { | 
					
						
							|  |  |  |     const ws = new WebSocket('ws://localhost:' + port + '/ws'); | 
					
						
							|  |  |  |     ws.addEventListener('open', () => ws.send('outgoing')); | 
					
						
							|  |  |  |     ws.addEventListener('message', () => { ws.close(); }); | 
					
						
							|  |  |  |   }, server.PORT); | 
					
						
							|  |  |  |   await socketClosePromise; | 
					
						
							|  |  |  |   expect(log[0]).toBe('open'); | 
					
						
							|  |  |  |   expect(log[3]).toBe('close'); | 
					
						
							|  |  |  |   log.sort(); | 
					
						
							|  |  |  |   expect(log.join(':')).toBe('close:open:received<incoming>:sent<outgoing>'); | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2020-10-26 22:20:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-05 09:18:56 -07:00
										 |  |  | it('should pass self as argument to close event', async ({ page, server }) => { | 
					
						
							| 
									
										
										
										
											2021-01-22 09:58:31 -08:00
										 |  |  |   let socketClosed; | 
					
						
							|  |  |  |   const socketClosePromise = new Promise(f => socketClosed = f); | 
					
						
							|  |  |  |   let webSocket; | 
					
						
							|  |  |  |   page.on('websocket', ws => { | 
					
						
							|  |  |  |     webSocket = ws; | 
					
						
							|  |  |  |     ws.on('close', socketClosed); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   await page.evaluate(port => { | 
					
						
							|  |  |  |     const ws = new WebSocket('ws://localhost:' + port + '/ws'); | 
					
						
							|  |  |  |     ws.addEventListener('open', () => ws.close()); | 
					
						
							|  |  |  |   }, server.PORT); | 
					
						
							|  |  |  |   const eventArg = await socketClosePromise; | 
					
						
							|  |  |  |   expect(eventArg).toBe(webSocket); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-30 13:38:54 -07:00
										 |  |  | it('should emit binary frame events', async ({ page, server }) => { | 
					
						
							|  |  |  |   let doneCallback; | 
					
						
							|  |  |  |   const donePromise = new Promise(f => doneCallback = f); | 
					
						
							|  |  |  |   const sent = []; | 
					
						
							|  |  |  |   page.on('websocket', ws => { | 
					
						
							|  |  |  |     ws.on('close', doneCallback); | 
					
						
							|  |  |  |     ws.on('framesent', d => sent.push(d.payload)); | 
					
						
							| 
									
										
										
										
											2020-10-26 22:20:43 -07:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2020-10-30 13:38:54 -07:00
										 |  |  |   await page.evaluate(port => { | 
					
						
							|  |  |  |     const ws = new WebSocket('ws://localhost:' + port + '/ws'); | 
					
						
							|  |  |  |     ws.addEventListener('open', () => { | 
					
						
							|  |  |  |       const binary = new Uint8Array(5); | 
					
						
							|  |  |  |       for (let i = 0; i < 5; ++i) | 
					
						
							|  |  |  |         binary[i] = i; | 
					
						
							|  |  |  |       ws.send('text'); | 
					
						
							|  |  |  |       ws.send(binary); | 
					
						
							|  |  |  |       ws.close(); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |   }, server.PORT); | 
					
						
							|  |  |  |   await donePromise; | 
					
						
							|  |  |  |   expect(sent[0]).toBe('text'); | 
					
						
							|  |  |  |   for (let i = 0; i < 5; ++i) | 
					
						
							|  |  |  |     expect(sent[1][i]).toBe(i); | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2020-10-26 22:20:43 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-30 13:38:54 -07:00
										 |  |  | 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)); | 
					
						
							|  |  |  |   page.evaluate(port => { | 
					
						
							|  |  |  |     new WebSocket('ws://localhost:' + port + '/bogus-ws'); | 
					
						
							|  |  |  |   }, server.PORT); | 
					
						
							|  |  |  |   const message = await result; | 
					
						
							|  |  |  |   if (isFirefox) | 
					
						
							|  |  |  |     expect(message).toBe('CLOSE_ABNORMAL'); | 
					
						
							|  |  |  |   else | 
					
						
							|  |  |  |     expect(message).toContain(': 400'); | 
					
						
							| 
									
										
										
										
											2020-10-26 22:20:43 -07:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2020-11-02 14:09:58 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-10 15:01:30 -08:00
										 |  |  | it('should not have stray error events', async ({page, server}) => { | 
					
						
							|  |  |  |   let error; | 
					
						
							|  |  |  |   page.on('websocket', ws => ws.on('socketerror', e => error = e)); | 
					
						
							|  |  |  |   await Promise.all([ | 
					
						
							|  |  |  |     page.waitForEvent('websocket').then(async ws => { | 
					
						
							|  |  |  |       await ws.waitForEvent('framereceived'); | 
					
						
							|  |  |  |       return ws; | 
					
						
							|  |  |  |     }), | 
					
						
							| 
									
										
										
										
											2020-11-02 14:09:58 -08:00
										 |  |  |     page.evaluate(port => { | 
					
						
							|  |  |  |       (window as any).ws = new WebSocket('ws://localhost:' + port + '/ws'); | 
					
						
							|  |  |  |     }, server.PORT) | 
					
						
							|  |  |  |   ]); | 
					
						
							|  |  |  |   await page.evaluate('window.ws.close()'); | 
					
						
							|  |  |  |   expect(error).toBeFalsy(); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-10 15:01:30 -08:00
										 |  |  | it('should reject waitForEvent on socket close', async ({page, server}) => { | 
					
						
							| 
									
										
										
										
											2020-11-02 14:09:58 -08:00
										 |  |  |   const [ws] = await Promise.all([ | 
					
						
							| 
									
										
										
										
											2020-12-10 15:01:30 -08:00
										 |  |  |     page.waitForEvent('websocket').then(async ws => { | 
					
						
							|  |  |  |       await ws.waitForEvent('framereceived'); | 
					
						
							|  |  |  |       return ws; | 
					
						
							|  |  |  |     }), | 
					
						
							| 
									
										
										
										
											2020-11-02 14:09:58 -08:00
										 |  |  |     page.evaluate(port => { | 
					
						
							|  |  |  |       (window as any).ws = new WebSocket('ws://localhost:' + port + '/ws'); | 
					
						
							|  |  |  |     }, server.PORT) | 
					
						
							|  |  |  |   ]); | 
					
						
							|  |  |  |   const error = ws.waitForEvent('framesent').catch(e => e); | 
					
						
							|  |  |  |   await page.evaluate('window.ws.close()'); | 
					
						
							|  |  |  |   expect((await error).message).toContain('Socket closed'); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-10 15:01:30 -08:00
										 |  |  | it('should reject waitForEvent on page close', async ({page, server}) => { | 
					
						
							| 
									
										
										
										
											2020-11-02 14:09:58 -08:00
										 |  |  |   const [ws] = await Promise.all([ | 
					
						
							| 
									
										
										
										
											2020-12-10 15:01:30 -08:00
										 |  |  |     page.waitForEvent('websocket').then(async ws => { | 
					
						
							|  |  |  |       await ws.waitForEvent('framereceived'); | 
					
						
							|  |  |  |       return ws; | 
					
						
							|  |  |  |     }), | 
					
						
							| 
									
										
										
										
											2020-11-02 14:09:58 -08:00
										 |  |  |     page.evaluate(port => { | 
					
						
							|  |  |  |       (window as any).ws = new WebSocket('ws://localhost:' + port + '/ws'); | 
					
						
							|  |  |  |     }, server.PORT) | 
					
						
							|  |  |  |   ]); | 
					
						
							|  |  |  |   const error = ws.waitForEvent('framesent').catch(e => e); | 
					
						
							|  |  |  |   await page.close(); | 
					
						
							|  |  |  |   expect((await error).message).toContain('Page closed'); | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2021-03-29 20:24:12 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-04-05 09:18:56 -07:00
										 |  |  | it('should turn off when offline', async ({page}) => { | 
					
						
							|  |  |  |   it.fixme(); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const webSocketServer = new WebSocketServer(); | 
					
						
							| 
									
										
										
										
											2021-03-29 20:24:12 -07:00
										 |  |  |   const address = webSocketServer.address(); | 
					
						
							|  |  |  |   const [socket, wsHandle] = await Promise.all([ | 
					
						
							|  |  |  |     new Promise<import('ws')>(x => webSocketServer.once('connection', x)), | 
					
						
							|  |  |  |     page.evaluateHandle(async address => { | 
					
						
							|  |  |  |       const ws = new WebSocket(`ws://${address}/`); | 
					
						
							|  |  |  |       await new Promise(x => ws.onopen = x); | 
					
						
							|  |  |  |       return ws; | 
					
						
							|  |  |  |     }, typeof address === 'string' ? address : 'localhost:' + address.port), | 
					
						
							|  |  |  |   ]); | 
					
						
							|  |  |  |   const failurePromise = new Promise(x => socket.on('message', data => x(data))); | 
					
						
							|  |  |  |   const closePromise = wsHandle.evaluate(async ws => { | 
					
						
							|  |  |  |     if (ws.readyState !== WebSocket.CLOSED) | 
					
						
							|  |  |  |       await new Promise(x => ws.onclose = x); | 
					
						
							|  |  |  |     return 'successfully closed'; | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   const result = Promise.race([ | 
					
						
							|  |  |  |     failurePromise, | 
					
						
							|  |  |  |     closePromise | 
					
						
							|  |  |  |   ]); | 
					
						
							|  |  |  |   await page.context().setOffline(true); | 
					
						
							|  |  |  |   await wsHandle.evaluate(ws => ws.send('if this arrives it failed')); | 
					
						
							|  |  |  |   expect(await result).toBe('successfully closed'); | 
					
						
							| 
									
										
										
										
											2021-04-05 09:18:56 -07:00
										 |  |  |   await new Promise(x => webSocketServer.close(x)); | 
					
						
							| 
									
										
										
										
											2021-03-29 20:24:12 -07:00
										 |  |  | }); |