| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  | /** | 
					
						
							|  |  |  |  * Copyright Microsoft Corporation. All rights reserved. | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * 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-09-02 21:43:38 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-05-06 07:08:22 -07:00
										 |  |  | import { test as it, expect } from './pageTest'; | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-03-10 19:42:52 +01:00
										 |  |  | it('should dispatch click event @smoke', async ({ page, server }) => { | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  |   await page.goto(server.PREFIX + '/input/button.html'); | 
					
						
							|  |  |  |   await page.dispatchEvent('button', 'click'); | 
					
						
							| 
									
										
										
										
											2020-08-11 15:50:53 -07:00
										 |  |  |   expect(await page.evaluate(() => window['result'])).toBe('Clicked'); | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('should dispatch click event properties', async ({ page, server }) => { | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  |   await page.goto(server.PREFIX + '/input/button.html'); | 
					
						
							|  |  |  |   await page.dispatchEvent('button', 'click'); | 
					
						
							| 
									
										
										
										
											2020-08-11 15:50:53 -07:00
										 |  |  |   expect(await page.evaluate('bubbles')).toBeTruthy(); | 
					
						
							|  |  |  |   expect(await page.evaluate('cancelable')).toBeTruthy(); | 
					
						
							|  |  |  |   expect(await page.evaluate('composed')).toBeTruthy(); | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('should dispatch click svg', async ({ page }) => { | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  |   await page.setContent(`
 | 
					
						
							|  |  |  |     <svg height="100" width="100"> | 
					
						
							|  |  |  |       <circle onclick="javascript:window.__CLICKED=42" cx="50" cy="50" r="40" stroke="black" stroke-width="3" fill="red" /> | 
					
						
							|  |  |  |     </svg> | 
					
						
							|  |  |  |   `);
 | 
					
						
							|  |  |  |   await page.dispatchEvent('circle', 'click'); | 
					
						
							| 
									
										
										
										
											2020-08-11 15:50:53 -07:00
										 |  |  |   expect(await page.evaluate(() => window['__CLICKED'])).toBe(42); | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('should dispatch click on a span with an inline element inside', async ({ page }) => { | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  |   await page.setContent(`
 | 
					
						
							|  |  |  |     <style> | 
					
						
							|  |  |  |     span::before { | 
					
						
							|  |  |  |       content: 'q'; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     </style> | 
					
						
							|  |  |  |     <span onclick='javascript:window.CLICKED=42'></span> | 
					
						
							|  |  |  |   `);
 | 
					
						
							|  |  |  |   await page.dispatchEvent('span', 'click'); | 
					
						
							| 
									
										
										
										
											2020-08-11 15:50:53 -07:00
										 |  |  |   expect(await page.evaluate(() => window['CLICKED'])).toBe(42); | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('should dispatch click after navigation ', async ({ page, server }) => { | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  |   await page.goto(server.PREFIX + '/input/button.html'); | 
					
						
							|  |  |  |   await page.dispatchEvent('button', 'click'); | 
					
						
							|  |  |  |   await page.goto(server.PREFIX + '/input/button.html'); | 
					
						
							|  |  |  |   await page.dispatchEvent('button', 'click'); | 
					
						
							| 
									
										
										
										
											2020-08-11 15:50:53 -07:00
										 |  |  |   expect(await page.evaluate(() => window['result'])).toBe('Clicked'); | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('should dispatch click after a cross origin navigation ', async ({ page, server }) => { | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  |   await page.goto(server.PREFIX + '/input/button.html'); | 
					
						
							|  |  |  |   await page.dispatchEvent('button', 'click'); | 
					
						
							|  |  |  |   await page.goto(server.CROSS_PROCESS_PREFIX + '/input/button.html'); | 
					
						
							|  |  |  |   await page.dispatchEvent('button', 'click'); | 
					
						
							| 
									
										
										
										
											2020-08-11 15:50:53 -07:00
										 |  |  |   expect(await page.evaluate(() => window['result'])).toBe('Clicked'); | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('should not fail when element is blocked on hover', async ({ page }) => { | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  |   await page.setContent(`<style>
 | 
					
						
							|  |  |  |     container { display: block; position: relative; width: 200px; height: 50px; } | 
					
						
							|  |  |  |     div, button { position: absolute; left: 0; top: 0; bottom: 0; right: 0; } | 
					
						
							|  |  |  |     div { pointer-events: none; } | 
					
						
							|  |  |  |     container:hover div { pointer-events: auto; background: red; } | 
					
						
							|  |  |  |   </style> | 
					
						
							|  |  |  |   <container> | 
					
						
							|  |  |  |     <button onclick="window.clicked=true">Click me</button> | 
					
						
							|  |  |  |     <div></div> | 
					
						
							|  |  |  |   </container>`);
 | 
					
						
							|  |  |  |   await page.dispatchEvent('button', 'click'); | 
					
						
							| 
									
										
										
										
											2020-08-11 15:50:53 -07:00
										 |  |  |   expect(await page.evaluate(() => window['clicked'])).toBeTruthy(); | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('should dispatch click when node is added in shadow dom', async ({ page, server }) => { | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  |   await page.goto(server.EMPTY_PAGE); | 
					
						
							|  |  |  |   const watchdog = page.dispatchEvent('span', 'click'); | 
					
						
							|  |  |  |   await page.evaluate(() => { | 
					
						
							|  |  |  |     const div = document.createElement('div'); | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  |     div.attachShadow({ mode: 'open' }); | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  |     document.body.appendChild(div); | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2024-05-31 14:44:26 -07:00
										 |  |  |   await page.waitForTimeout(100); | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  |   await page.evaluate(() => { | 
					
						
							|  |  |  |     const span = document.createElement('span'); | 
					
						
							|  |  |  |     span.textContent = 'Hello from shadow'; | 
					
						
							| 
									
										
										
										
											2020-08-11 15:50:53 -07:00
										 |  |  |     span.addEventListener('click', () => window['clicked'] = true); | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  |     document.querySelector('div').shadowRoot.appendChild(span); | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   await watchdog; | 
					
						
							| 
									
										
										
										
											2020-08-11 15:50:53 -07:00
										 |  |  |   expect(await page.evaluate(() => window['clicked'])).toBe(true); | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('should be atomic', async ({ playwright, page }) => { | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  |   const createDummySelector = () => ({ | 
					
						
							|  |  |  |     query(root, selector) { | 
					
						
							|  |  |  |       const result = root.querySelector(selector); | 
					
						
							|  |  |  |       if (result) | 
					
						
							| 
									
										
										
										
											2023-06-02 21:59:12 +02:00
										 |  |  |         void Promise.resolve().then(() => result.onclick = ''); | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  |       return result; | 
					
						
							|  |  |  |     }, | 
					
						
							| 
									
										
										
										
											2020-08-11 15:50:53 -07:00
										 |  |  |     queryAll(root: HTMLElement, selector: string) { | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  |       const result = Array.from(root.querySelectorAll(selector)); | 
					
						
							|  |  |  |       for (const e of result) | 
					
						
							| 
									
										
										
										
											2023-06-02 21:59:12 +02:00
										 |  |  |         void Promise.resolve().then(() => (e as HTMLElement).onclick = null); | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  |       return result; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   }); | 
					
						
							| 
									
										
										
										
											2020-09-18 15:52:14 -07:00
										 |  |  |   await playwright.selectors.register('dispatchEvent', createDummySelector); | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  |   await page.setContent(`<div onclick="window._clicked=true">Hello</div>`); | 
					
						
							|  |  |  |   await page.dispatchEvent('dispatchEvent=div', 'click'); | 
					
						
							| 
									
										
										
										
											2020-08-11 15:50:53 -07:00
										 |  |  |   expect(await page.evaluate(() => window['_clicked'])).toBe(true); | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('should dispatch drag drop events', async ({ page, server }) => { | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  |   await page.goto(server.PREFIX + '/drag-n-drop.html'); | 
					
						
							|  |  |  |   const dataTransfer = await page.evaluateHandle(() => new DataTransfer()); | 
					
						
							|  |  |  |   await page.dispatchEvent('#source', 'dragstart', { dataTransfer }); | 
					
						
							|  |  |  |   await page.dispatchEvent('#target', 'drop', { dataTransfer }); | 
					
						
							| 
									
										
										
										
											2020-08-11 15:50:53 -07:00
										 |  |  |   const source = await page.$('#source'); | 
					
						
							|  |  |  |   const target = await page.$('#target'); | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  |   expect(await page.evaluate(({ source, target }) => { | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  |     return source.parentElement === target; | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  |   }, { source, target })).toBeTruthy(); | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('should dispatch drag drop events via ElementHandles', async ({ page, server }) => { | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  |   await page.goto(server.PREFIX + '/drag-n-drop.html'); | 
					
						
							|  |  |  |   const dataTransfer = await page.evaluateHandle(() => new DataTransfer()); | 
					
						
							|  |  |  |   const source = await page.$('#source'); | 
					
						
							|  |  |  |   await source.dispatchEvent('dragstart', { dataTransfer }); | 
					
						
							|  |  |  |   const target = await page.$('#target'); | 
					
						
							|  |  |  |   await target.dispatchEvent('drop', { dataTransfer }); | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  |   expect(await page.evaluate(({ source, target }) => { | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  |     return source.parentElement === target; | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  |   }, { source, target })).toBeTruthy(); | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-27 18:58:08 +02:00
										 |  |  | it('should dispatch click event via ElementHandles', async ({ page, server }) => { | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  |   await page.goto(server.PREFIX + '/input/button.html'); | 
					
						
							|  |  |  |   const button = await page.$('button'); | 
					
						
							|  |  |  |   await button.dispatchEvent('click'); | 
					
						
							| 
									
										
										
										
											2020-08-11 15:50:53 -07:00
										 |  |  |   expect(await page.evaluate(() => window['result'])).toBe('Clicked'); | 
					
						
							| 
									
										
										
										
											2020-08-03 13:41:48 -07:00
										 |  |  | }); | 
					
						
							| 
									
										
										
										
											2022-07-12 17:17:45 -07:00
										 |  |  | 
 | 
					
						
							|  |  |  | it('should dispatch wheel event', async ({ page, server }) => { | 
					
						
							|  |  |  |   it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/15562' }); | 
					
						
							|  |  |  |   await page.goto(server.PREFIX + '/input/scrollable.html'); | 
					
						
							|  |  |  |   const eventsHandle = await page.locator('body').evaluateHandle(e => { | 
					
						
							|  |  |  |     const events = []; | 
					
						
							|  |  |  |     e.addEventListener('wheel', event => { | 
					
						
							|  |  |  |       events.push(event); | 
					
						
							|  |  |  |       console.log(event); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     return events; | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   await page.locator('body').dispatchEvent('wheel', { deltaX: 100, deltaY: 200 }); | 
					
						
							|  |  |  |   expect(await eventsHandle.evaluate(e => e.length)).toBe(1); | 
					
						
							|  |  |  |   expect(await eventsHandle.evaluate(e => e[0] instanceof WheelEvent)).toBeTruthy(); | 
					
						
							|  |  |  |   expect(await eventsHandle.evaluate(e => ({ deltaX: e[0].deltaX, deltaY: e[0].deltaY }))).toEqual({ deltaX: 100, deltaY: 200 }); | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2023-11-08 18:50:25 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-10 16:28:45 +01:00
										 |  |  | it('should dispatch device orientation event', async ({ page, server, isAndroid }) => { | 
					
						
							|  |  |  |   it.skip(isAndroid, 'DeviceOrientationEvent is only available in a secure context. While Androids loopback is not treated as secure.'); | 
					
						
							| 
									
										
										
										
											2023-11-08 18:50:25 +01:00
										 |  |  |   await page.goto(server.PREFIX + '/device-orientation.html'); | 
					
						
							|  |  |  |   await page.locator('html').dispatchEvent('deviceorientation', { alpha: 10, beta: 20, gamma: 30 }); | 
					
						
							|  |  |  |   expect(await page.evaluate('result')).toBe('Oriented'); | 
					
						
							|  |  |  |   expect(await page.evaluate('alpha')).toBe(10); | 
					
						
							|  |  |  |   expect(await page.evaluate('beta')).toBe(20); | 
					
						
							|  |  |  |   expect(await page.evaluate('gamma')).toBe(30); | 
					
						
							|  |  |  |   expect(await page.evaluate('absolute')).toBeFalsy(); | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-10 16:28:45 +01:00
										 |  |  | it('should dispatch absolute device orientation event', async ({ page, server, isAndroid }) => { | 
					
						
							|  |  |  |   it.skip(isAndroid, 'DeviceOrientationEvent is only available in a secure context. While Androids loopback is not treated as secure.'); | 
					
						
							| 
									
										
										
										
											2023-11-08 18:50:25 +01:00
										 |  |  |   await page.goto(server.PREFIX + '/device-orientation.html'); | 
					
						
							|  |  |  |   await page.locator('html').dispatchEvent('deviceorientationabsolute', { alpha: 10, beta: 20, gamma: 30, absolute: true }); | 
					
						
							|  |  |  |   expect(await page.evaluate('result')).toBe('Oriented'); | 
					
						
							|  |  |  |   expect(await page.evaluate('alpha')).toBe(10); | 
					
						
							|  |  |  |   expect(await page.evaluate('beta')).toBe(20); | 
					
						
							|  |  |  |   expect(await page.evaluate('gamma')).toBe(30); | 
					
						
							|  |  |  |   expect(await page.evaluate('absolute')).toBeTruthy(); | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2023-11-13 17:58:46 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | it('should dispatch device motion event', async ({ page, server, isAndroid }) => { | 
					
						
							|  |  |  |   it.skip(isAndroid, 'DeviceOrientationEvent is only available in a secure context. While Androids loopback is not treated as secure.'); | 
					
						
							|  |  |  |   await page.goto(server.PREFIX + '/device-motion.html'); | 
					
						
							|  |  |  |   await page.locator('html').dispatchEvent('devicemotion', { | 
					
						
							|  |  |  |     acceleration: { x: 10, y: 20, z: 30 }, | 
					
						
							|  |  |  |     accelerationIncludingGravity: { x: 15, y: 25, z: 35 }, | 
					
						
							|  |  |  |     rotationRate: { alpha: 5, beta: 10, gamma: 15 }, | 
					
						
							|  |  |  |     interval: 16, | 
					
						
							|  |  |  |   }); | 
					
						
							|  |  |  |   expect(await page.evaluate('result')).toBe('Moved'); | 
					
						
							|  |  |  |   expect(await page.evaluate('acceleration.x')).toBe(10); | 
					
						
							|  |  |  |   expect(await page.evaluate('acceleration.y')).toBe(20); | 
					
						
							|  |  |  |   expect(await page.evaluate('acceleration.z')).toBe(30); | 
					
						
							|  |  |  |   expect(await page.evaluate('accelerationIncludingGravity.x')).toBe(15); | 
					
						
							|  |  |  |   expect(await page.evaluate('accelerationIncludingGravity.y')).toBe(25); | 
					
						
							|  |  |  |   expect(await page.evaluate('accelerationIncludingGravity.z')).toBe(35); | 
					
						
							|  |  |  |   expect(await page.evaluate('rotationRate.alpha')).toBe(5); | 
					
						
							|  |  |  |   expect(await page.evaluate('rotationRate.beta')).toBe(10); | 
					
						
							|  |  |  |   expect(await page.evaluate('rotationRate.gamma')).toBe(15); | 
					
						
							|  |  |  |   expect(await page.evaluate('interval')).toBe(16); | 
					
						
							|  |  |  | }); | 
					
						
							| 
									
										
										
										
											2023-12-19 10:47:43 -08:00
										 |  |  | 
 | 
					
						
							|  |  |  | it('should throw if argument is from different frame', async ({ page, server }) => { | 
					
						
							|  |  |  |   it.info().annotations.push({ type: 'issue', description: 'https://github.com/microsoft/playwright/issues/28690' }); | 
					
						
							|  |  |  |   await page.goto(server.PREFIX + '/frames/one-frame.html'); | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     const dataTransfer = await page.frames()[1].evaluateHandle(() => new DataTransfer()); | 
					
						
							|  |  |  |     await page.frameLocator('iframe').locator('div').dispatchEvent('drop', { dataTransfer }); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  |   { | 
					
						
							|  |  |  |     const dataTransfer = await page.evaluateHandle(() => new DataTransfer()); | 
					
						
							|  |  |  |     await expect(page.frameLocator('iframe').locator('div').dispatchEvent('drop', { dataTransfer })) | 
					
						
							|  |  |  |         .rejects.toThrow('JSHandles can be evaluated only in the context they were created!'); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | }); |