| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Copyright 2017 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. | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2020-08-19 21:32:12 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-06 07:08:22 -07:00
										 |  |  | import { test as it, expect } from './pageTest'; | 
					
						
							| 
									
										
										
										
											2021-05-05 19:10:28 -07:00
										 |  |  | import type { ElementHandle } from '../../index'; | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('exposeBinding should work', async ({ page }) => { | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |   let bindingSource; | 
					
						
							|  |  |  |   await page.exposeBinding('add', (source, a, b) => { | 
					
						
							|  |  |  |     bindingSource = source; | 
					
						
							|  |  |  |     return a + b; | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   const result = await page.evaluate(async function() { | 
					
						
							| 
									
										
										
										
											2020-08-11 15:50:53 -07:00
										 |  |  |     return window['add'](5, 6); | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2020-12-16 16:28:44 +01:00
										 |  |  |   expect(bindingSource.context).toBe(page.context()); | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |   expect(bindingSource.page).toBe(page); | 
					
						
							|  |  |  |   expect(bindingSource.frame).toBe(page.mainFrame()); | 
					
						
							|  |  |  |   expect(result).toEqual(11); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('should work', async ({ page, server }) => { | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |   await page.exposeFunction('compute', function(a, b) { | 
					
						
							|  |  |  |     return a * b; | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   const result = await page.evaluate(async function() { | 
					
						
							| 
									
										
										
										
											2020-08-11 15:50:53 -07:00
										 |  |  |     return await window['compute'](9, 4); | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |   }); | 
					
						
							|  |  |  |   expect(result).toBe(36); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('should work with handles and complex objects', async ({ page, server }) => { | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |   const fooHandle = await page.evaluateHandle(() => { | 
					
						
							| 
									
										
										
										
											2020-08-11 15:50:53 -07:00
										 |  |  |     window['fooValue'] = { bar: 2 }; | 
					
						
							|  |  |  |     return window['fooValue']; | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |   }); | 
					
						
							|  |  |  |   await page.exposeFunction('handle', () => { | 
					
						
							|  |  |  |     return [{ foo: fooHandle }]; | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   const equals = await page.evaluate(async function() { | 
					
						
							| 
									
										
										
										
											2020-08-11 15:50:53 -07:00
										 |  |  |     const value = await window['handle'](); | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |     const [{ foo }] = value; | 
					
						
							| 
									
										
										
										
											2020-08-11 15:50:53 -07:00
										 |  |  |     return foo === window['fooValue']; | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |   }); | 
					
						
							|  |  |  |   expect(equals).toBe(true); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('should throw exception in page context', async ({ page, server }) => { | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |   await page.exposeFunction('woof', function() { | 
					
						
							|  |  |  |     throw new Error('WOOF WOOF'); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  |   const { message, stack } = await page.evaluate(async () => { | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |     try { | 
					
						
							| 
									
										
										
										
											2020-08-28 04:20:29 -07:00
										 |  |  |       await window['woof'](); | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |     } catch (e) { | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  |       return { message: e.message, stack: e.stack }; | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |     } | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   expect(message).toBe('WOOF WOOF'); | 
					
						
							|  |  |  |   expect(stack).toContain(__filename); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('should support throwing "null"', async ({ page, server }) => { | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |   await page.exposeFunction('woof', function() { | 
					
						
							|  |  |  |     throw null; | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2020-08-28 04:20:29 -07:00
										 |  |  |   const thrown = await page.evaluate(async () => { | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |     try { | 
					
						
							| 
									
										
										
										
											2020-08-28 04:20:29 -07:00
										 |  |  |       await window['woof'](); | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |     } catch (e) { | 
					
						
							|  |  |  |       return e; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   expect(thrown).toBe(null); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('should be callable from-inside addInitScript', async ({ page, server }) => { | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |   let called = false; | 
					
						
							|  |  |  |   await page.exposeFunction('woof', function() { | 
					
						
							|  |  |  |     called = true; | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2020-08-28 04:20:29 -07:00
										 |  |  |   await page.addInitScript(() => window['woof']()); | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |   await page.reload(); | 
					
						
							|  |  |  |   expect(called).toBe(true); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('should survive navigation', async ({ page, server }) => { | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |   await page.exposeFunction('compute', function(a, b) { | 
					
						
							|  |  |  |     return a * b; | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   await page.goto(server.EMPTY_PAGE); | 
					
						
							|  |  |  |   const result = await page.evaluate(async function() { | 
					
						
							| 
									
										
										
										
											2020-08-11 15:50:53 -07:00
										 |  |  |     return await window['compute'](9, 4); | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |   }); | 
					
						
							|  |  |  |   expect(result).toBe(36); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('should await returned promise', async ({ page, server }) => { | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |   await page.exposeFunction('compute', function(a, b) { | 
					
						
							|  |  |  |     return Promise.resolve(a * b); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const result = await page.evaluate(async function() { | 
					
						
							| 
									
										
										
										
											2020-08-11 15:50:53 -07:00
										 |  |  |     return await window['compute'](3, 5); | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |   }); | 
					
						
							|  |  |  |   expect(result).toBe(15); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('should work on frames', async ({ page, server }) => { | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |   await page.exposeFunction('compute', function(a, b) { | 
					
						
							|  |  |  |     return Promise.resolve(a * b); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   await page.goto(server.PREFIX + '/frames/nested-frames.html'); | 
					
						
							|  |  |  |   const frame = page.frames()[1]; | 
					
						
							|  |  |  |   const result = await frame.evaluate(async function() { | 
					
						
							| 
									
										
										
										
											2020-08-11 15:50:53 -07:00
										 |  |  |     return await window['compute'](3, 5); | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |   }); | 
					
						
							|  |  |  |   expect(result).toBe(15); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('should work on frames before navigation', async ({ page, server }) => { | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |   await page.goto(server.PREFIX + '/frames/nested-frames.html'); | 
					
						
							|  |  |  |   await page.exposeFunction('compute', function(a, b) { | 
					
						
							|  |  |  |     return Promise.resolve(a * b); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const frame = page.frames()[1]; | 
					
						
							|  |  |  |   const result = await frame.evaluate(async function() { | 
					
						
							| 
									
										
										
										
											2020-08-11 15:50:53 -07:00
										 |  |  |     return await window['compute'](3, 5); | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |   }); | 
					
						
							|  |  |  |   expect(result).toBe(15); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('should work after cross origin navigation', async ({ page, server }) => { | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |   await page.goto(server.EMPTY_PAGE); | 
					
						
							|  |  |  |   await page.exposeFunction('compute', function(a, b) { | 
					
						
							|  |  |  |     return a * b; | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   await page.goto(server.CROSS_PROCESS_PREFIX + '/empty.html'); | 
					
						
							|  |  |  |   const result = await page.evaluate(async function() { | 
					
						
							| 
									
										
										
										
											2020-08-11 15:50:53 -07:00
										 |  |  |     return await window['compute'](9, 4); | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |   }); | 
					
						
							|  |  |  |   expect(result).toBe(36); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('should work with complex objects', async ({ page, server }) => { | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |   await page.exposeFunction('complexObject', function(a, b) { | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  |     return { x: a.x + b.x }; | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  |   const result = await page.evaluate(async () => window['complexObject']({ x: 5 }, { x: 2 })); | 
					
						
							| 
									
										
										
										
											2020-08-04 15:09:24 -07:00
										 |  |  |   expect(result.x).toBe(7); | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2020-10-01 22:47:31 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('exposeBindingHandle should work', async ({ page }) => { | 
					
						
							| 
									
										
										
										
											2020-10-01 22:47:31 -07:00
										 |  |  |   let target; | 
					
						
							|  |  |  |   await page.exposeBinding('logme', (source, t) => { | 
					
						
							|  |  |  |     target = t; | 
					
						
							|  |  |  |     return 17; | 
					
						
							|  |  |  |   }, { handle: true }); | 
					
						
							|  |  |  |   const result = await page.evaluate(async function() { | 
					
						
							|  |  |  |     return window['logme']({ foo: 42 }); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   expect(await target.evaluate(x => x.foo)).toBe(42); | 
					
						
							|  |  |  |   expect(result).toEqual(17); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('exposeBindingHandle should not throw during navigation', async ({ page, server }) => { | 
					
						
							| 
									
										
										
										
											2020-10-01 22:47:31 -07:00
										 |  |  |   await page.exposeBinding('logme', (source, t) => { | 
					
						
							|  |  |  |     return 17; | 
					
						
							|  |  |  |   }, { handle: true }); | 
					
						
							|  |  |  |   await page.goto(server.EMPTY_PAGE); | 
					
						
							|  |  |  |   await Promise.all([ | 
					
						
							|  |  |  |     page.evaluate(async url => { | 
					
						
							|  |  |  |       window['logme']({ foo: 42 }); | 
					
						
							|  |  |  |       window.location.href = url; | 
					
						
							|  |  |  |     }, server.PREFIX + '/one-style.html'), | 
					
						
							|  |  |  |     page.waitForNavigation({ waitUntil: 'load' }), | 
					
						
							|  |  |  |   ]); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('should throw for duplicate registrations', async ({ page }) => { | 
					
						
							| 
									
										
										
										
											2020-10-01 22:47:31 -07:00
										 |  |  |   await page.exposeFunction('foo', () => {}); | 
					
						
							|  |  |  |   const error = await page.exposeFunction('foo', () => {}).catch(e => e); | 
					
						
							|  |  |  |   expect(error.message).toContain('page.exposeFunction: Function "foo" has been already registered'); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('exposeBindingHandle should throw for multiple arguments', async ({ page }) => { | 
					
						
							| 
									
										
										
										
											2020-10-01 22:47:31 -07:00
										 |  |  |   await page.exposeBinding('logme', (source, t) => { | 
					
						
							|  |  |  |     return 17; | 
					
						
							|  |  |  |   }, { handle: true }); | 
					
						
							|  |  |  |   expect(await page.evaluate(async function() { | 
					
						
							|  |  |  |     return window['logme']({ foo: 42 }); | 
					
						
							|  |  |  |   })).toBe(17); | 
					
						
							|  |  |  |   expect(await page.evaluate(async function() { | 
					
						
							|  |  |  |     return window['logme']({ foo: 42 }, undefined, undefined); | 
					
						
							|  |  |  |   })).toBe(17); | 
					
						
							|  |  |  |   expect(await page.evaluate(async function() { | 
					
						
							|  |  |  |     return window['logme'](undefined, undefined, undefined); | 
					
						
							|  |  |  |   })).toBe(17); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   const error = await page.evaluate(async function() { | 
					
						
							|  |  |  |     return window['logme'](1, 2); | 
					
						
							|  |  |  |   }).catch(e => e); | 
					
						
							|  |  |  |   expect(error.message).toContain('exposeBindingHandle supports a single argument, 2 received'); | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2020-12-03 10:51:59 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('should not result in unhandled rejection', async ({ page, isAndroid }) => { | 
					
						
							| 
									
										
										
										
											2021-04-09 07:59:09 -07:00
										 |  |  |   it.fixme(isAndroid); | 
					
						
							| 
									
										
										
										
											2021-04-04 19:32:14 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-12-04 14:48:20 -08:00
										 |  |  |   const closedPromise = page.waitForEvent('close'); | 
					
						
							| 
									
										
										
										
											2020-12-03 10:51:59 -08:00
										 |  |  |   await page.exposeFunction('foo', async () => { | 
					
						
							|  |  |  |     await page.close(); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   await page.evaluate(() => { | 
					
						
							| 
									
										
										
										
											2020-12-04 14:48:20 -08:00
										 |  |  |     setTimeout(() => (window as any).foo(), 0); | 
					
						
							|  |  |  |     return undefined; | 
					
						
							| 
									
										
										
										
											2020-12-03 10:51:59 -08:00
										 |  |  |   }); | 
					
						
							| 
									
										
										
										
											2020-12-04 14:48:20 -08:00
										 |  |  |   await closedPromise; | 
					
						
							|  |  |  |   // Make a round-trip to be sure we did not throw immediately after closing.
 | 
					
						
							|  |  |  |   expect(await page.evaluate('1 + 1').catch(e => e)).toBeInstanceOf(Error); | 
					
						
							| 
									
										
										
										
											2020-12-03 10:51:59 -08:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2020-12-08 08:38:29 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('exposeBinding(handle) should work with element handles', async ({ page }) => { | 
					
						
							| 
									
										
										
										
											2021-01-04 13:54:55 -08:00
										 |  |  |   let cb; | 
					
						
							|  |  |  |   const promise = new Promise(f => cb = f); | 
					
						
							|  |  |  |   await page.exposeBinding('clicked', async (source, element: ElementHandle) => { | 
					
						
							|  |  |  |     cb(await element.innerText().catch(e => e)); | 
					
						
							|  |  |  |   }, { handle: true }); | 
					
						
							|  |  |  |   await page.goto('about:blank'); | 
					
						
							|  |  |  |   await page.setContent(`
 | 
					
						
							|  |  |  |     <script> | 
					
						
							|  |  |  |       document.addEventListener('click', event => window.clicked(event.target)); | 
					
						
							|  |  |  |     </script> | 
					
						
							|  |  |  |     <div id="a1">Click me</div> | 
					
						
							|  |  |  |   `);
 | 
					
						
							|  |  |  |   await page.click('#a1'); | 
					
						
							|  |  |  |   expect(await promise).toBe('Click me'); | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2021-02-26 14:16:32 -08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('should work with setContent', async ({ page, server }) => { | 
					
						
							| 
									
										
										
										
											2021-02-26 14:16:32 -08:00
										 |  |  |   await page.exposeFunction('compute', function(a, b) { | 
					
						
							|  |  |  |     return Promise.resolve(a * b); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   await page.setContent('<script>window.result = compute(3, 2)</script>'); | 
					
						
							|  |  |  |   expect(await page.evaluate('window.result')).toBe(6); | 
					
						
							|  |  |  | }); |