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
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ Playwright is a Python library to automate [Chromium](https://www.chromium.org/H

| | Linux | macOS | Windows |
| :--- | :---: | :---: | :---: |
| Chromium <!-- GEN:chromium-version -->139.0.7258.5<!-- GEN:stop --> ||||
| Chromium <!-- GEN:chromium-version -->140.0.7339.16<!-- GEN:stop --> ||||
| WebKit <!-- GEN:webkit-version -->26.0<!-- GEN:stop --> ||||
| Firefox <!-- GEN:firefox-version -->140.0.2<!-- GEN:stop --> ||||
| Firefox <!-- GEN:firefox-version -->141.0<!-- GEN:stop --> ||||

## Documentation

Expand Down
26 changes: 24 additions & 2 deletions playwright/_impl/_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
Optional,
Pattern,
Set,
Tuple,
TypedDict,
TypeVar,
Union,
Expand Down Expand Up @@ -221,14 +222,35 @@ def map_token(original: str, replacement: str) -> str:
processed_parts.append(new_prefix + new_suffix)

relative_path = "/".join(processed_parts)
resolved_url = urljoin(base_url if base_url is not None else "", relative_path)
resolved_url, case_insensitive_part = resolve_base_url(base_url, relative_path)

for replacement, original in token_map.items():
resolved_url = resolved_url.replace(replacement, original, 1)
normalize = case_insensitive_part and replacement in case_insensitive_part
resolved_url = resolved_url.replace(
replacement, original.lower() if normalize else original, 1
)

return ensure_trailing_slash(resolved_url)


def resolve_base_url(
base_url: Optional[str], given_url: str
) -> Tuple[str, Optional[str]]:
try:
resolved = urljoin(base_url if base_url is not None else "", given_url)
parsed = urlparse(resolved)
# Schema and domain are case-insensitive.
hostname_port = (
parsed.hostname or ""
) # can't use parsed.netloc because it includes userinfo (username:password)
if parsed.port:
hostname_port += f":{parsed.port}"
case_insensitive_prefix = f"{parsed.scheme}://{hostname_port}"
return resolved, case_insensitive_prefix
except Exception:
return given_url, None


# In Node.js, new URL('http://localhost') returns 'http://localhost/'.
# To ensure the same url matching behavior, do the same.
def ensure_trailing_slash(url: str) -> str:
Expand Down
27 changes: 25 additions & 2 deletions playwright/async_api/_generated.py
Original file line number Diff line number Diff line change
Expand Up @@ -11487,8 +11487,8 @@ async def main():
async def pause(self) -> None:
"""Page.pause

Pauses script execution. Playwright will stop executing the script and wait for the user to either press 'Resume'
button in the page overlay or to call `playwright.resume()` in the DevTools console.
Pauses script execution. Playwright will stop executing the script and wait for the user to either press the
'Resume' button in the page overlay or to call `playwright.resume()` in the DevTools console.

User can inspect selectors or perform manual steps while paused. Resume will continue running the original script
from the place it was paused.
Expand Down Expand Up @@ -13921,6 +13921,10 @@ async def new_context(
`passphrase` property should be provided if the certificate is encrypted. The `origin` property should be provided
with an exact match to the request origin that the certificate is valid for.

Client certificate authentication is only active when at least one client certificate is provided. If you want to
reject all client certificates sent by the server, you need to provide a client certificate with an `origin` that
does not match any of the domains you plan to visit.

**NOTE** When using WebKit on macOS, accessing `localhost` will not pick up client certificates. You can make it
work by replacing `localhost` with `local.playwright`.

Expand Down Expand Up @@ -14152,6 +14156,10 @@ async def new_page(
`passphrase` property should be provided if the certificate is encrypted. The `origin` property should be provided
with an exact match to the request origin that the certificate is valid for.

Client certificate authentication is only active when at least one client certificate is provided. If you want to
reject all client certificates sent by the server, you need to provide a client certificate with an `origin` that
does not match any of the domains you plan to visit.

**NOTE** When using WebKit on macOS, accessing `localhost` will not pick up client certificates. You can make it
work by replacing `localhost` with `local.playwright`.

Expand Down Expand Up @@ -14559,6 +14567,13 @@ async def launch_persistent_context(
**parent** directory of the "Profile Path" seen at `chrome://version`.

Note that browsers do not allow launching multiple instances with the same User Data Directory.

**NOTE** Chromium/Chrome: Due to recent Chrome policy changes, automating the default Chrome user profile is not
supported. Pointing `userDataDir` to Chrome's main "User Data" directory (the profile used for your regular
browsing) may result in pages not loading or the browser exiting. Create and use a separate directory (for example,
an empty folder) as your automation profile instead. See https://developer.chrome.com/blog/remote-debugging-port
for details.

channel : Union[str, None]
Browser distribution channel.

Expand Down Expand Up @@ -14733,6 +14748,10 @@ async def launch_persistent_context(
`passphrase` property should be provided if the certificate is encrypted. The `origin` property should be provided
with an exact match to the request origin that the certificate is valid for.

Client certificate authentication is only active when at least one client certificate is provided. If you want to
reject all client certificates sent by the server, you need to provide a client certificate with an `origin` that
does not match any of the domains you plan to visit.

**NOTE** When using WebKit on macOS, accessing `localhost` will not pick up client certificates. You can make it
work by replacing `localhost` with `local.playwright`.

Expand Down Expand Up @@ -18801,6 +18820,10 @@ async def new_context(
`passphrase` property should be provided if the certificate is encrypted. The `origin` property should be provided
with an exact match to the request origin that the certificate is valid for.

Client certificate authentication is only active when at least one client certificate is provided. If you want to
reject all client certificates sent by the server, you need to provide a client certificate with an `origin` that
does not match any of the domains you plan to visit.

**NOTE** When using WebKit on macOS, accessing `localhost` will not pick up client certificates. You can make it
work by replacing `localhost` with `local.playwright`.

Expand Down
35 changes: 29 additions & 6 deletions playwright/sync_api/_generated.py
Original file line number Diff line number Diff line change
Expand Up @@ -11569,8 +11569,8 @@ def run(playwright: Playwright):
def pause(self) -> None:
"""Page.pause

Pauses script execution. Playwright will stop executing the script and wait for the user to either press 'Resume'
button in the page overlay or to call `playwright.resume()` in the DevTools console.
Pauses script execution. Playwright will stop executing the script and wait for the user to either press the
'Resume' button in the page overlay or to call `playwright.resume()` in the DevTools console.

User can inspect selectors or perform manual steps while paused. Resume will continue running the original script
from the place it was paused.
Expand Down Expand Up @@ -12255,7 +12255,7 @@ def add_locator_handler(

```py
# Setup the handler.
def handler():
async def handler():
await page.get_by_role(\"button\", name=\"No thanks\").click()
await page.add_locator_handler(page.get_by_text(\"Sign up to the newsletter\"), handler)

Expand All @@ -12268,7 +12268,7 @@ def handler():

```py
# Setup the handler.
def handler():
async def handler():
await page.get_by_role(\"button\", name=\"Remind me later\").click()
await page.add_locator_handler(page.get_by_text(\"Confirm your security details\"), handler)

Expand All @@ -12283,7 +12283,7 @@ def handler():

```py
# Setup the handler.
def handler():
async def handler():
await page.evaluate(\"window.removeObstructionsForTestIfNeeded()\")
await page.add_locator_handler(page.locator(\"body\"), handler, no_wait_after=True)

Expand All @@ -12296,7 +12296,7 @@ def handler():
invocations by setting `times`:

```py
def handler(locator):
async def handler(locator):
await locator.click()
await page.add_locator_handler(page.get_by_label(\"Close\"), handler, times=1)
```
Expand Down Expand Up @@ -13952,6 +13952,10 @@ def new_context(
`passphrase` property should be provided if the certificate is encrypted. The `origin` property should be provided
with an exact match to the request origin that the certificate is valid for.

Client certificate authentication is only active when at least one client certificate is provided. If you want to
reject all client certificates sent by the server, you need to provide a client certificate with an `origin` that
does not match any of the domains you plan to visit.

**NOTE** When using WebKit on macOS, accessing `localhost` will not pick up client certificates. You can make it
work by replacing `localhost` with `local.playwright`.

Expand Down Expand Up @@ -14185,6 +14189,10 @@ def new_page(
`passphrase` property should be provided if the certificate is encrypted. The `origin` property should be provided
with an exact match to the request origin that the certificate is valid for.

Client certificate authentication is only active when at least one client certificate is provided. If you want to
reject all client certificates sent by the server, you need to provide a client certificate with an `origin` that
does not match any of the domains you plan to visit.

**NOTE** When using WebKit on macOS, accessing `localhost` will not pick up client certificates. You can make it
work by replacing `localhost` with `local.playwright`.

Expand Down Expand Up @@ -14598,6 +14606,13 @@ def launch_persistent_context(
**parent** directory of the "Profile Path" seen at `chrome://version`.

Note that browsers do not allow launching multiple instances with the same User Data Directory.

**NOTE** Chromium/Chrome: Due to recent Chrome policy changes, automating the default Chrome user profile is not
supported. Pointing `userDataDir` to Chrome's main "User Data" directory (the profile used for your regular
browsing) may result in pages not loading or the browser exiting. Create and use a separate directory (for example,
an empty folder) as your automation profile instead. See https://developer.chrome.com/blog/remote-debugging-port
for details.

channel : Union[str, None]
Browser distribution channel.

Expand Down Expand Up @@ -14772,6 +14787,10 @@ def launch_persistent_context(
`passphrase` property should be provided if the certificate is encrypted. The `origin` property should be provided
with an exact match to the request origin that the certificate is valid for.

Client certificate authentication is only active when at least one client certificate is provided. If you want to
reject all client certificates sent by the server, you need to provide a client certificate with an `origin` that
does not match any of the domains you plan to visit.

**NOTE** When using WebKit on macOS, accessing `localhost` will not pick up client certificates. You can make it
work by replacing `localhost` with `local.playwright`.

Expand Down Expand Up @@ -18922,6 +18941,10 @@ def new_context(
`passphrase` property should be provided if the certificate is encrypted. The `origin` property should be provided
with an exact match to the request origin that the certificate is valid for.

Client certificate authentication is only active when at least one client certificate is provided. If you want to
reject all client certificates sent by the server, you need to provide a client certificate with an `origin` that
does not match any of the domains you plan to visit.

**NOTE** When using WebKit on macOS, accessing `localhost` will not pick up client certificates. You can make it
work by replacing `localhost` with `local.playwright`.

Expand Down
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import zipfile
from typing import Dict

driver_version = "1.54.1"
driver_version = "1.55.0"

base_wheel_bundles = [
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
// Mock script for background extension
window.MAGIC = 42;
globalThis.MAGIC = 42;
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@
"name": "Simple extension",
"version": "0.1",
"background": {
"scripts": ["index.js"]
"service_worker": "index.js"
},
"content_scripts": [{
"matches": ["<all_urls>"],
"css": [],
"js": ["content-script.js"]
}],
"permissions": ["background", "activeTab"],
"manifest_version": 2
"manifest_version": 3
}
5 changes: 5 additions & 0 deletions tests/assets/extension-mv3-with-logging/background.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
console.log("Service worker script loaded");

chrome.runtime.onInstalled.addListener(() => {
console.log("Extension installed");
});
1 change: 1 addition & 0 deletions tests/assets/extension-mv3-with-logging/content.js
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
console.log("Test console log from a third-party execution context");
17 changes: 17 additions & 0 deletions tests/assets/extension-mv3-with-logging/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
{
"manifest_version": 3,
"name": "Console Log Extension",
"version": "1.0",
"background": {
"service_worker": "background.js"
},
"permissions": [
"tabs"
],
"content_scripts": [
{
"matches": ["<all_urls>"],
"js": ["content.js"]
}
]
}
Loading