From 3e6bb76fc960c53a1472d9ba296831269b751a38 Mon Sep 17 00:00:00 2001 From: Simon Knott Date: Fri, 5 Dec 2025 15:51:35 +0100 Subject: [PATCH] chore: implement Request.service_worker --- playwright/_impl/_network.py | 9 ++++++++- playwright/async_api/_generated.py | 18 ++++++++++++++++++ playwright/sync_api/_generated.py | 18 ++++++++++++++++++ setup.py | 2 +- tests/sync/test_network.py | 14 +++++++++++++- 5 files changed, 58 insertions(+), 3 deletions(-) diff --git a/playwright/_impl/_network.py b/playwright/_impl/_network.py index a999ce73c..9f2c29f6e 100644 --- a/playwright/_impl/_network.py +++ b/playwright/_impl/_network.py @@ -66,7 +66,7 @@ from playwright._impl._browser_context import BrowserContext from playwright._impl._fetch import APIResponse from playwright._impl._frame import Frame - from playwright._impl._page import Page + from playwright._impl._page import Page, Worker class FallbackOverrideParameters(TypedDict, total=False): @@ -184,6 +184,13 @@ def url(self) -> str: def resource_type(self) -> str: return self._initializer["resourceType"] + @property + def service_worker(self) -> Optional["Worker"]: + return cast( + Optional["Worker"], + from_nullable_channel(self._initializer.get("serviceWorker")), + ) + @property def method(self) -> str: return cast(str, self._fallback_overrides.method or self._initializer["method"]) diff --git a/playwright/async_api/_generated.py b/playwright/async_api/_generated.py index 79210603c..469046b21 100644 --- a/playwright/async_api/_generated.py +++ b/playwright/async_api/_generated.py @@ -113,6 +113,24 @@ def resource_type(self) -> str: """ return mapping.from_maybe_impl(self._impl_obj.resource_type) + @property + def service_worker(self) -> typing.Optional["Worker"]: + """Request.service_worker + + The Service `Worker` that is performing the request. + + **Details** + + This method is Chromium only. It's safe to call when using other browsers, but it will always be `null`. + + Requests originated in a Service Worker do not have a `request.frame()` available. + + Returns + ------- + Union[Worker, None] + """ + return mapping.from_impl_nullable(self._impl_obj.service_worker) + @property def method(self) -> str: """Request.method diff --git a/playwright/sync_api/_generated.py b/playwright/sync_api/_generated.py index 0d892a0c9..82c7b983f 100644 --- a/playwright/sync_api/_generated.py +++ b/playwright/sync_api/_generated.py @@ -113,6 +113,24 @@ def resource_type(self) -> str: """ return mapping.from_maybe_impl(self._impl_obj.resource_type) + @property + def service_worker(self) -> typing.Optional["Worker"]: + """Request.service_worker + + The Service `Worker` that is performing the request. + + **Details** + + This method is Chromium only. It's safe to call when using other browsers, but it will always be `null`. + + Requests originated in a Service Worker do not have a `request.frame()` available. + + Returns + ------- + Union[Worker, None] + """ + return mapping.from_impl_nullable(self._impl_obj.service_worker) + @property def method(self) -> str: """Request.method diff --git a/setup.py b/setup.py index a0a51c3e4..fa81e5e85 100644 --- a/setup.py +++ b/setup.py @@ -21,7 +21,7 @@ import zipfile from typing import Dict -driver_version = "1.57.0" +driver_version = "1.57.0-beta-1764944708000" base_wheel_bundles = [ { diff --git a/tests/sync/test_network.py b/tests/sync/test_network.py index 9ba91c431..8c196affb 100644 --- a/tests/sync/test_network.py +++ b/tests/sync/test_network.py @@ -92,7 +92,7 @@ def handle_request(route: Route) -> None: assert response.json() == {"foo": "bar"} -def test_should_report_if_request_was_from_service_worker( +def test_should_report_if_response_was_from_service_worker( page: Page, server: Server ) -> None: response = page.goto(server.PREFIX + "/serviceworkers/fetch/sw.html") @@ -102,3 +102,15 @@ def test_should_report_if_request_was_from_service_worker( with page.expect_response("**/example.txt") as response_info: page.evaluate("() => fetch('/example.txt')") assert response_info.value.from_service_worker + + +@pytest.mark.only_browser("chromium") +def test_should_report_service_worker_request(page: Page, server: Server) -> None: + with page.context.expect_event("serviceworker") as worker_info: + page.goto(server.PREFIX + "/serviceworkers/fetch/sw.html") + page.evaluate("() => window.activationPromise") + with page.context.expect_event( + "request", lambda r: r.service_worker is not None + ) as request_info: + page.evaluate("() => fetch('/example.txt')") + assert request_info.value.service_worker == worker_info.value