Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/src/api/class-request.md
Original file line number Diff line number Diff line change
Expand Up @@ -287,7 +287,7 @@ Returns the matching [Response] object, or `null` if the response was not receiv

## method: Request.serviceWorker
* since: v1.24
* langs: js
* langs: js, python
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be implemented in 1.57 python.

- returns: <[null]|[Worker]>

The Service [Worker] that is performing the request.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ They can act as a **network proxy** between the page and the external network to
Many sites that use Service Workers simply use them as a transparent optimization technique. While users might notice a faster experience, the app's implementation is unaware of their existence. Running the app with or without Service Workers enabled appears functionally equivalent.

## How to Disable Service Workers
* langs: js

Playwright allows to disable Service Workers during testing. This makes tests more predictable and performant. However, if your actual page uses a Service Worker, the behavior might be different.

Expand All @@ -36,6 +37,24 @@ export default defineConfig({
});
```

## How to Disable Service Workers
* langs: python

Playwright allows to disable Service Workers during testing. This makes tests more predictable and performant. However, if your actual page uses a Service Worker, the behavior might be different.

To disable service workers, set `service_workers` context option to `"block"`.

```python title="conftest.py"
import pytest

@pytest.fixture(scope="session")
def browser_context_args(browser_context_args):
return {
**browser_context_args,
"service_workers": "block"
}
```

## Accessing Service Workers and Waiting for Activation

You can use [`method: BrowserContext.serviceWorkers`] to list the Service [Worker]s, or specifically watch for the Service [Worker] if you anticipate a page will trigger its [registration](https://developer.mozilla.org/en-US/docs/Web/API/ServiceWorkerContainer/register):
Expand All @@ -46,6 +65,18 @@ await page.goto('/example-with-a-service-worker.html');
const serviceworker = await serviceWorkerPromise;
```

```python sync
with context.expect_event("serviceworker") as worker_info:
page.goto("/example-with-a-service-worker.html")
service_worker = worker_info.value
```

```python async
async with context.expect_event("serviceworker") as worker_info:
await page.goto("/example-with-a-service-worker.html")
service_worker = await worker_info.value
```

[`event: BrowserContext.serviceWorker`] event is fired ***before*** the Service Worker has taken control over the page, so ***before*** evaluating in the worker with [`method: Worker.evaluate`] you should wait on its activation.

There are more idiomatic methods of waiting for a Service Worker to be activated, but the following is an implementation agnostic method:
Expand All @@ -61,6 +92,28 @@ await page.evaluate(async () => {
});
```

```python sync
page.evaluate("""async () => {
const registration = await window.navigator.serviceWorker.getRegistration();
if (registration.active?.state === 'activated')
return;
await new Promise(resolve => {
window.navigator.serviceWorker.addEventListener('controllerchange', resolve);
});
}""")
```

```python async
await page.evaluate("""async () => {
const registration = await window.navigator.serviceWorker.getRegistration();
if (registration.active?.state === 'activated')
return;
await new Promise(resolve => {
window.navigator.serviceWorker.addEventListener('controllerchange', resolve);
});
}""")
```

## Network Events and Routing

Any network request made by the **Service Worker** is reported through the [BrowserContext] object:
Expand Down Expand Up @@ -126,6 +179,28 @@ await context.route('**', async route => {
});
```

```python sync
def handle_route(route: Route):
if route.request.service_worker:
# NB: accessing route.request.frame here would THROW
route.fulfill(content_type="text/plain", status=200, body="from sw")
else:
route.continue_()

context.route("**", handle_route)
```

```python async
async def handle_route(route: Route):
if route.request.service_worker:
# NB: accessing route.request.frame here would THROW
await route.fulfill(content_type="text/plain", status=200, body="from sw")
else:
await route.continue_()

await context.route("**", handle_route)
```

## Known Limitations

Requests for updated Service Worker main script code currently cannot be routed (https://github.com/microsoft/playwright/issues/14711).
Expand Down