From 187081766da44f0f5a5fb8ad6a24e6312f7021c4 Mon Sep 17 00:00:00 2001 From: Ross Wollman Date: Tue, 4 Aug 2020 12:51:09 -0700 Subject: [PATCH] test: add async dispatch event tests (#130) --- playwright/element_handle.py | 4 +- playwright/frame.py | 3 +- tests/assets/drag-n-drop.html | 41 +++++++ tests/async/test_dispatch_event.py | 172 +++++++++++++++++++++++++++++ 4 files changed, 218 insertions(+), 2 deletions(-) create mode 100644 tests/assets/drag-n-drop.html create mode 100644 tests/async/test_dispatch_event.py diff --git a/playwright/element_handle.py b/playwright/element_handle.py index a53c44808..17a7e39d9 100644 --- a/playwright/element_handle.py +++ b/playwright/element_handle.py @@ -66,7 +66,9 @@ async def innerHTML(self) -> str: return await self._channel.send("innerHTML") async def dispatchEvent(self, type: str, eventInit: Dict = None) -> None: - await self._channel.send("dispatchEvent", dict(type=type, eventInit=eventInit)) + await self._channel.send( + "dispatchEvent", dict(type=type, eventInit=serialize_argument(eventInit)) + ) async def scrollIntoViewIfNeeded(self, timeout: int = None) -> None: await self._channel.send("scrollIntoViewIfNeeded", locals_to_params(locals())) diff --git a/playwright/frame.py b/playwright/frame.py index 58a5e7f18..ad08fc91d 100644 --- a/playwright/frame.py +++ b/playwright/frame.py @@ -238,7 +238,8 @@ async def dispatchEvent( self, selector: str, type: str, eventInit: Dict = None, timeout: int = None ) -> None: await self._channel.send( - "dispatchEvent", dict(selector=selector, type=type, eventInit=eventInit) + "dispatchEvent", + dict(selector=selector, type=type, eventInit=serialize_argument(eventInit)), ) async def evalOnSelector( diff --git a/tests/assets/drag-n-drop.html b/tests/assets/drag-n-drop.html new file mode 100644 index 000000000..8189c4925 --- /dev/null +++ b/tests/assets/drag-n-drop.html @@ -0,0 +1,41 @@ + + + + + +
+

+ Select this element, drag it to the Drop Zone and then release the selection to move the element.

+
+
Drop Zone
+ diff --git a/tests/async/test_dispatch_event.py b/tests/async/test_dispatch_event.py new file mode 100644 index 000000000..7c07e176e --- /dev/null +++ b/tests/async/test_dispatch_event.py @@ -0,0 +1,172 @@ +# 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. + +import pytest + + +async def test_should_dispatch_click_event(page, server): + await page.goto(server.PREFIX + "/input/button.html") + await page.dispatchEvent("button", "click") + assert await page.evaluate("() => result") == "Clicked" + + +async def test_should_dispatch_click_event_properties(page, server): + await page.goto(server.PREFIX + "/input/button.html") + await page.dispatchEvent("button", "click") + assert await page.evaluate("() => bubbles") + assert await page.evaluate("() => cancelable") + assert await page.evaluate("() => composed") + + +async def test_should_dispatch_click_svg(page): + await page.setContent( + """ + + + + """ + ) + await page.dispatchEvent("circle", "click") + assert await page.evaluate("() => window.__CLICKED") == 42 + + +async def test_should_dispatch_click_on_a_span_with_an_inline_element_inside(page): + await page.setContent( + """ + + + """ + ) + await page.dispatchEvent("span", "click") + assert await page.evaluate("() => window.CLICKED") == 42 + + +async def test_should_dispatch_click_after_navigation(page, server): + 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") + assert await page.evaluate("() => result") == "Clicked" + + +async def test_should_dispatch_click_after_a_cross_origin_navigation(page, server): + 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") + assert await page.evaluate("() => result") == "Clicked" + + +async def test_should_not_fail_when_element_is_blocked_on_hover(page, server): + await page.setContent( + """ + + +
+
""" + ) + await page.dispatchEvent("button", "click") + assert await page.evaluate("() => window.clicked") + + +async def test_should_dispatch_click_when_node_is_added_in_shadow_dom(page, server): + await page.goto(server.EMPTY_PAGE) + watchdog = page.dispatchEvent("span", "click") + await page.evaluate( + """() => { + const div = document.createElement('div'); + div.attachShadow({mode: 'open'}); + document.body.appendChild(div); + }""" + ) + await page.evaluate("() => new Promise(f => setTimeout(f, 100))") + await page.evaluate( + """() => { + const span = document.createElement('span'); + span.textContent = 'Hello from shadow'; + span.addEventListener('click', () => window.clicked = true); + document.querySelector('div').shadowRoot.appendChild(span); + }""" + ) + await watchdog + assert await page.evaluate("() => window.clicked") + + +async def test_should_be_atomic(selectors, page, utils): + await utils.register_selector_engine( + selectors, + "dispatchEvent", + """{ + create(root, target) { }, + query(root, selector) { + const result = root.querySelector(selector); + if (result) + Promise.resolve().then(() => result.onclick = ""); + return result; + }, + queryAll(root, selector) { + const result = Array.from(root.querySelectorAll(selector)); + for (const e of result) + Promise.resolve().then(() => result.onclick = ""); + return result; + } + }""", + ) + await page.setContent('
Hello
') + await page.dispatchEvent("dispatchEvent=div", "click") + assert await page.evaluate("() => window._clicked") + + +@pytest.mark.skip_browser("webkit") +async def test_should_dispatch_drag_drop_events(page, server): + await page.goto(server.PREFIX + "/drag-n-drop.html") + dataTransfer = await page.evaluateHandle("() => new DataTransfer()") + await page.dispatchEvent("#source", "dragstart", {"dataTransfer": dataTransfer}) + await page.dispatchEvent("#target", "drop", {"dataTransfer": dataTransfer}) + assert await page.evaluate( + """() => { + return source.parentElement === target; + }""" + ) + + +@pytest.mark.skip_browser("webkit") +async def test_should_dispatch_drag_and_drop_events_element_handle(page, server): + await page.goto(server.PREFIX + "/drag-n-drop.html") + dataTransfer = await page.evaluateHandle("() => new DataTransfer()") + source = await page.querySelector("#source") + await source.dispatchEvent("dragstart", {"dataTransfer": dataTransfer}) + target = await page.querySelector("#target") + await target.dispatchEvent("drop", {"dataTransfer": dataTransfer}) + assert await page.evaluate( + """() => { + return source.parentElement === target; + }""" + ) + + +async def test_should_dispatch_click_event_element_handle(page, server): + await page.goto(server.PREFIX + "/input/button.html") + button = await page.querySelector("button") + await button.dispatchEvent("click") + assert await page.evaluate("() => result") == "Clicked"