Issue
In my tests, I have to wait for an event to trigger before continuing with test assertions, but I can't figure out how to make Playwright wait for that event. It seems like Playwright can't see the event.
Simple example with a django page: clicking the button fires an event boop
that changes the background color of the document.
Template event.html
:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Playwright Events</title>
</head>
<body>
<button>Click me</button>
<script>
const btn = document.querySelector("button");
btn.addEventListener("click", (e) => document.dispatchEvent(new Event("boop")));
document.addEventListener("boop", (e) => { document.body.style.backgroundColor = "darkcyan"; });
</script>
</body>
</html>
URL conf:
urlpatterns = [
path('', TemplateView.as_view(template_name="event.html"))
]
The test:
def test(page, live_server):
page.goto(live_server.url)
page.wait_for_timeout(500)
btn = page.get_by_text('Click me')
with page.expect_event("boop", timeout=1000):
btn.click()
page.wait_for_timeout(500)
When running the test in headed mode, you can see the background color changing - meaning that the event boop
was fired. But the test still fails because expect_event
times out:
playwright._impl._api_types.TimeoutError: Timeout 1000ms exceeded while waiting for event "boop"
I must be doing something wrong, but I can't figure out what.
Found this similar post, but it is not about playwright-python with django.
Solution
It's not that explicit in the documentation but events refer to playwright events, not HTML events.
There is no support at the moment for the functionality you describe, you could emulate it as follows though:
class ExpectedHTMLEvent:
def __init__(self, page: sync_api.Page, html_event: str, timeout_ms: float):
self.page = page
self.html_event = html_event
self.timeout_ms = timeout_ms
self.fn_name = f"setFlag{''.join(random.choices(string.ascii_lowercase, k=6))}"
self._flag = False
self._end = None
def _flag_setter(self):
self._flag = True
def __enter__(self) -> None:
self.page.expose_function(self.fn_name, self._flag_setter)
opts = "{once: true}"
self.page.evaluate(
f"document.addEventListener('{self.html_event}', async () => await window.{self.fn_name}(), {opts})"
)
self._end = datetime.now() + timedelta(milliseconds=self.timeout_ms)
def __exit__(self, __exc_type, __exc_value, __traceback) -> None:
while datetime.now() < self._end:
if self._flag:
return
time.sleep(0.1)
raise TimeoutError(f"'{self.html_event}' was never observed")
with sync_playwright() as p:
browser = p.chromium.launch()
page = browser.new_page()
page.goto('http://example.com/')
with ExpectedHTMLEvent(page, "boop", 2_000):
page.evaluate("() => document.dispatchEvent(new Event('boop'))")
with ExpectedHTMLEvent(page, "not boop", 2_000):
page.evaluate("() => document.dispatchEvent(new Event('boop'))")
TimeoutError: 'not boop' was never observed
Answered By - Mattwmaster58
0 comments:
Post a Comment
Note: Only a member of this blog may post a comment.