playwright-python
playwright-python copied to clipboard
[Feature] Document page.route
I am having some trouble using page.route within pytest. I think the issue stems from the way the route functions are run. I believe the routing is run in a background thread, and the routes are eventually run inside a coroutine event loop.
Relevant docs:
https://playwright.dev/python/docs/network
https://playwright.dev/python/docs/api/class-route
https://playwright.dev/python/docs/api/class-page#page-route
I think the documentation needs to call out the expected behavior of the route functions clearly:
What happens when a route function throws an exception?
What happens if the route function returns without calling one of the route methods (eg route.fulfill)?
I have observed that in pytest asserting or calling pytest.fail from a route function does not fail the test reliably. I am also observing some other non deterministic behaviour, but I do not have a simple reproduction yet. I think clarity on the above points may help.
As an example, here are some tests:
import time
from playwright.sync_api import Page, Route
def test_routing_ok(page: Page) -> None:
def handle_err(route: Route):
print("this should not happen", route.request.url)
route.continue_()
def handle_ok(route: Route):
print("this is ok", route.request.url)
route.continue_()
page.route("http://10.42.0.10/**", handle_err)
page.route("http://10.42.0.10/**", handle_ok)
page.goto("http://10.42.0.10/cgi-bin/luci/admin/network/network")
page.wait_for_load_state("networkidle")
def test_routing_no_route(page: Page) -> None:
"""This example times out.
"""
def handle_err(route: Route):
print("this should not happen", route.request.url)
route.continue_()
def handle_ok(route: Route):
print("this is ok", route.request.url)
page.route("http://10.42.0.10/**", handle_err)
page.route("http://10.42.0.10/**", handle_ok)
page.goto("http://10.42.0.10/cgi-bin/luci/admin/network/network")
page.wait_for_load_state("networkidle")
def test_routing_raise_before(page: Page) -> None:
"""This example times out.
How is the exception from the handle_ok function treated?
We also see a message in the logs:
ERROR asyncio:base_events.py:1758 Task exception was never retrieved
"""
def handle_err(route: Route):
print("this should not happen", route.request.url)
route.continue_()
def handle_ok(route: Route):
print("this is ok", route.request.url)
assert False
route.continue_()
page.route("http://10.42.0.10/**", handle_err)
page.route("http://10.42.0.10/**", handle_ok)
page.goto("http://10.42.0.10/cgi-bin/luci/admin/network/network")
page.wait_for_load_state("networkidle")
def test_routing_raise_after(page: Page) -> None:
"""This example passes. The assert? is printed, but the assertion does not fail the test"""
def handle_err(route: Route):
print("this should not happen", route.request.url)
route.continue_()
def handle_ok(route: Route):
print("this is ok", route.request.url)
route.continue_()
print("assert?")
assert False
page.route("http://10.42.0.10/**", handle_err)
page.route("http://10.42.0.10/**", handle_ok)
page.goto("http://10.42.0.10/cgi-bin/luci/admin/network/network")
page.wait_for_load_state("networkidle")
With no route.* call, the playwright times out. Raising before does the same thing, except with a message that indicates a bug in the library. Raising after does nothing, the exception is raised but swallowed somewhere in the library.