Playwright + Django:如何等待事件

问题描述 投票:0回答:1

在我的测试中,我必须等待事件触发才能继续测试断言,但我不知道如何让 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 的。

django pytest-django playwright-python
1个回答
3
投票

文档中没有那么明确,但事件指的是剧作家事件,而不是 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
© www.soinside.com 2019 - 2024. All rights reserved.