在我的测试中,我必须等待事件触发才能继续测试断言,但我不知道如何让 Playwright 等待该事件。看来剧作家看不到该事件。
django 页面的简单示例:单击按钮会触发一个事件
boop
,该事件会更改文档的背景颜色。
模板
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>
网址配置:
urlpatterns = [
path('', TemplateView.as_view(template_name="event.html"))
]
测试:
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)
在 Head 模式下运行测试时,您可以看到背景颜色发生变化 - 这意味着事件
boop
已被触发。但测试仍然失败,因为expect_event
超时:playwright._impl._api_types.TimeoutError: Timeout 1000ms exceeded while waiting for event "boop"
我一定做错了什么,但我不知道是什么。
发现这个类似的post,但它不是关于 playwright-python 和 django 的。
在文档中没有那么明确,但事件指的是剧作家事件,而不是 HTML 事件。
目前不支持您描述的功能,您可以按如下方式模拟它:
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