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 .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ jobs:
test-remote:
docker:
- image: cimg/ruby:3.4
- image: mcr.microsoft.com/playwright:v1.63.0-noble
command: /bin/sh -c "cd /home/pwuser && npm install --no-save playwright-core@1.63.0 && ./node_modules/.bin/playwright-core install && ./node_modules/.bin/playwright-core run-server --port 8888 --host 0.0.0.0 --path /ws"
- image: mcr.microsoft.com/playwright:v1.64.0-noble
command: /bin/sh -c "cd /home/pwuser && npm install --no-save playwright-core@1.64.0 && ./node_modules/.bin/playwright-core install && ./node_modules/.bin/playwright-core run-server --port 8888 --host 0.0.0.0 --path /ws"
environment:
DEBUG: "pw:*"
user: pwuser
Expand Down
2 changes: 1 addition & 1 deletion development/CLI_VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.63.0
1.64.0
3,037 changes: 2,638 additions & 399 deletions development/api.json

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions development/generate_api.rb
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
PageAssertions
WebStorage
Credentials
WebMCP
]
EXPERIMENTAL = %w[
]
Expand All @@ -54,6 +55,7 @@
Selectors
WebStorage
Credentials
WebMCP
]

require 'bundler/setup'
Expand Down
35 changes: 34 additions & 1 deletion development/generate_api/example_codes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,20 @@ def example_8b05a1e391492122df853bef56d8d3680ea0911e5ff2afd7e442ce0b1a3a4e10(pla
end
end

# APIRequestContext#add_cookies
def example_c660aff4beb8731b2eae5c6a848c042843281033a3ab48ae30e2d7b3490cb501(request:, cookie_object1:, cookie_object2:)
request.add_cookies([cookie_object1, cookie_object2])
end

# APIRequestContext#clear_cookies
def example_7db940bba7d23476943133061e9d9e696d5afc9489ec6930042db8d76322487d(request:)
request.clear_cookies
request.clear_cookies(name: "session-id")
request.clear_cookies(domain: "my-origin.com")
request.clear_cookies(path: "/api/v1")
request.clear_cookies(name: "session-id", domain: "my-origin.com")
end

# APIRequestContext#fetch
def example_19c86319c1f40a2cae90cfaf7f6471c50b59319e8b08d6e37d9be9d4697de0b8(api_request_context:)
data = {
Expand Down Expand Up @@ -459,7 +473,7 @@ def example_a56dcffc601af859fb6f2992dd574a0d97b9a8e42aeba15d308be51411ede1ce(bro
end

# Credentials
def example_4418a8e24419f983d07a8957cbd2f580f7aced3efc4f94457f8c263bb197c482(browser:)
def example_a1fe8586a14f833a8e191eed7e91e7c4c9ddf1009aa834c9fa1015a6daa1fd90(browser:)
# later test: seed the captured passkey so the app starts already enrolled.
credential = JSON.parse(File.read("playwright/.auth/passkey.json"))
context = browser.new_context
Expand All @@ -469,6 +483,7 @@ def example_4418a8e24419f983d07a8957cbd2f580f7aced3efc4f94457f8c263bb197c482(bro
userHandle: credential["userHandle"],
privateKey: credential["privateKey"],
publicKey: credential["publicKey"],
signCount: credential["signCount"],
)
context.credentials.install

Expand Down Expand Up @@ -1146,6 +1161,13 @@ def example_2e421ea5f306bc8b63fb4a73f9be8b1fffb8d75bbdbf2d14a565673268fb41da(pag
banana = page.get_by_role("listitem").last
end

# Locator#normalize
def example_0b5dea0e2d1d1b1d0133349b0ba0cd8991468a9586d00b97a6af0384236f46a2(page:)
normalized = page.get_by_ref("e2").normalize
puts normalized.to_s
# get_by_role("button", name="Submit")
end

# Locator#nth
def example_d6cc7c4a653d7139137c582ad853bebd92e3b97893fb6d5f88919553404c57e4(page:)
banana = page.get_by_role("listitem").nth(2)
Expand Down Expand Up @@ -1242,6 +1264,12 @@ def example_fe6f0a646d9e680807072ce223c7fdf83033490839c9a04e94ac48c278cb5568(pag
order_sent.wait_for
end

# Locator#within
def example_622cccefcda0bf4d35e338d1bf0c045f64815fc8b81a4792506a912e3e1abf3c(page:)
third_column = page.get_by_role("cell").nth(2).within(page.get_by_role("row"))
expect(third_column).to have_text(["Apple", "Banana", "Cherry"])
end

# LocatorAssertions
def example_eff0600f575bf375d7372280ca8e6dfc51d927ced49fbcb75408c894b9e0564e(page:)
page.content = <<~HTML
Expand Down Expand Up @@ -1711,6 +1739,11 @@ def example_baa3371b838c7b85056072b30bb30405debbc593119cd8cb214052f338aca062(pag
locator.click
end

# Page#get_by_ref
def example_aedd4380b0c218a8c79f80ea43f5b0180044f3d501c7282f1cadfb050e25124a(page:)
page.get_by_ref("e2").click
end

# Page#pdf
def example_e079fbec8ee0607ee45cdca94df61dea36f7fd3840986d5f4ac24918569a5f5e(page:)
# generates a pdf with "screen" media type.
Expand Down
233 changes: 233 additions & 0 deletions development/upgrades/1.64.md

Large diffs are not rendered by default.

47 changes: 47 additions & 0 deletions documentation/docs/api/api_request_context.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,53 @@ playwright.chromium.launch do |browser|
end
```

## add_cookies

```
def add_cookies(cookies)
```


Adds cookies into this request context. They will be sent with matching subsequent requests. For [BrowserContext#request](./browser_context#request)
and [Page#request](./page#request), this is equivalent to calling [BrowserContext#add_cookies](./browser_context#add_cookies) on the corresponding browser context.

**Usage**

```ruby
request.add_cookies([cookie_object1, cookie_object2])
```

## clear_cookies

```
def clear_cookies(domain: nil, name: nil, path: nil)
```


Removes cookies from this request context. Accepts optional filter. For [BrowserContext#request](./browser_context#request)
and [Page#request](./page#request), this is equivalent to calling [BrowserContext#clear_cookies](./browser_context#clear_cookies) on the corresponding browser context.

**Usage**

```ruby
request.clear_cookies
request.clear_cookies(name: "session-id")
request.clear_cookies(domain: "my-origin.com")
request.clear_cookies(path: "/api/v1")
request.clear_cookies(name: "session-id", domain: "my-origin.com")
```

## cookies

```
def cookies(urls: nil)
```


If no URLs are specified, this method returns all cookies. If URLs are specified, only cookies that affect those URLs
are returned. For [BrowserContext#request](./browser_context#request) and [Page#request](./page#request), this is equivalent to calling
[BrowserContext#cookies](./browser_context#cookies) on the corresponding browser context.

## delete

```
Expand Down
2 changes: 2 additions & 0 deletions documentation/docs/api/browser.md
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ def new_context(
record_har_path: nil,
record_har_url_filter: nil,
record_video_dir: nil,
record_video_fps: nil,
record_video_size: nil,
reducedMotion: nil,
screen: nil,
Expand Down Expand Up @@ -174,6 +175,7 @@ def new_page(
record_har_path: nil,
record_har_url_filter: nil,
record_video_dir: nil,
record_video_fps: nil,
record_video_size: nil,
reducedMotion: nil,
screen: nil,
Expand Down
1 change: 1 addition & 0 deletions documentation/docs/api/browser_type.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,6 +177,7 @@ def launch_persistent_context(
record_har_path: nil,
record_har_url_filter: nil,
record_video_dir: nil,
record_video_fps: nil,
record_video_size: nil,
reducedMotion: nil,
screen: nil,
Expand Down
1 change: 1 addition & 0 deletions documentation/docs/api/clock.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ def install(time: nil)

Install fake implementations for the following time-related functions:
- `Date`
- `Temporal.Now`
- `setTimeout`
- `clearTimeout`
- `setInterval`
Expand Down
9 changes: 6 additions & 3 deletions documentation/docs/api/credentials.md
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ context.credentials.create(
userHandle: credential["userHandle"],
privateKey: credential["privateKey"],
publicKey: credential["publicKey"],
signCount: credential["signCount"],
)
context.credentials.install

Expand All @@ -67,7 +68,7 @@ page.goto("https://example.com/login")

**Usage: save credentials in the storage state, restore later**

See [authentication guide](https://playwright.dev/python/docs/auth) for examples of using saving and resotring the storage state.
See [authentication guide](https://playwright.dev/python/docs/auth) for examples of using saving and restoring the storage state.

**Defaults**

Expand Down Expand Up @@ -95,6 +96,7 @@ def create(
id: nil,
privateKey: nil,
publicKey: nil,
signCount: nil,
userHandle: nil)
```

Expand All @@ -106,7 +108,8 @@ seeded credential is discoverable (resident), so the page can resolve it from bo
username-then-passkey and usernameless passkey flows. The returned object carries the private and public keys, so it can be persisted to disk and re-seeded in a later test.

To **import a known credential**, supply all four of `id`, `userHandle`, `privateKey` and
`publicKey` together.
`publicKey` together. Pass `signCount` as well to continue from the
signature counter the relying party has already seen.

Call [Credentials#install](./credentials#install) before navigating to a page that uses WebAuthn.

Expand All @@ -132,5 +135,5 @@ Returns every credential currently held by the authenticator, optionally filtere
`id`. This includes both credentials seeded with [Credentials#create](./credentials#create) and credentials
the page registered itself by calling `navigator.credentials.create()`.

Each returned credential includes its private and public keys, so a passkey the app just
Each returned credential includes its private and public keys and the current signature counter, so a passkey the app just
registered can be saved and re-seeded into a later test with [Credentials#create](./credentials#create) — see the second example in the class overview.
7 changes: 6 additions & 1 deletion documentation/docs/api/frame.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ When all steps combined have not finished during the specified `timeout`, this m
## content

```
def content
def content(includeShadow: nil)
```


Expand Down Expand Up @@ -1236,3 +1236,8 @@ Waits for the frame to navigate to the given URL.
frame.click("a.delayed-navigation") # clicking the link will indirectly cause a navigation
frame.wait_for_url("**/target.html")
```

## webmcp


Tools that the frame registers through the experimental [WebMCP](./web_mcp) browser API. See [WebMCP](./web_mcp) for details.
38 changes: 38 additions & 0 deletions documentation/docs/api/locator.md
Original file line number Diff line number Diff line change
Expand Up @@ -1135,6 +1135,26 @@ def normalize
Returns a new locator that uses best practices for referencing the matched element, prioritizing test ids,
aria roles, and other user-facing attributes over CSS selectors. This is useful for converting implementation-detail selectors into more resilient, human-readable locators.

**Usage**

An agent can pick an element by its ref from an [Page#aria_snapshot](./page#aria_snapshot) taken in the `"ai"` mode. Refs only
work for the latest snapshot. Normalize the ref locator and convert it to a string to get resilient locator code
in your language, the same way `codegen` does.

Consider the following aria snapshot.

```yaml
- button "Submit" [ref=e2]
```

You can turn the ref into locator code:

```ruby
normalized = page.get_by_ref("e2").normalize
puts normalized.to_s
# get_by_role("button", name="Submit")
```

## nth

```
Expand Down Expand Up @@ -1598,3 +1618,21 @@ If `expression` throws or rejects, this method throws.
Wait for an attribute to appear:

Passing argument to `expression`:

## within

```
def within(locator)
```


Returns a locator that matches this locator's elements inside each element matched by `locator`.

Note that relative locators, such as [Locator#nth](./locator#nth) or [Locator#first](./locator#first), are resolved separately inside each matched parent. In the example below, `page.getByRole('cell').nth(2)` picks the third cell of every row, not the third cell in the whole table.

**Usage**

```ruby
third_column = page.get_by_role("cell").nth(2).within(page.get_by_role("row"))
expect(third_column).to have_text(["Apple", "Banana", "Cherry"])
```
33 changes: 32 additions & 1 deletion documentation/docs/api/page.md
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ manually via [`event: Page.dialog`] event.
## content

```
def content
def content(includeShadow: nil)
```


Expand Down Expand Up @@ -699,6 +699,30 @@ You can fill the input after locating it by the placeholder text:
page.get_by_placeholder("name@example.com").fill("playwright@microsoft.com")
```

## get_by_ref

```
def get_by_ref(ref)
```


Locate element by its aria ref. Refs like `[ref=e2]` are reported by [Page#aria_snapshot](./page#aria_snapshot) when called with
the `"ai"` mode, and resolve against the latest snapshot taken in the element's frame.

**Usage**

Consider the following aria snapshot.

```yaml
- button "Submit" [ref=e2]
```

You can locate the button by its ref:

```ruby
page.get_by_ref("e2").click
```

## get_by_role

```
Expand Down Expand Up @@ -2052,3 +2076,10 @@ API testing helper associated with this page. This method returns the same insta
**Usage**

## touchscreen

## webmcp


Tools that the main frame registers through the experimental [WebMCP](./web_mcp) browser API. Shortcut for [Frame#webmcp](./frame#webmcp) of [Page#main_frame](./page#main_frame), see [WebMCP](./web_mcp) for details.

**Usage**
2 changes: 1 addition & 1 deletion documentation/docs/api/request.md
Original file line number Diff line number Diff line change
Expand Up @@ -205,7 +205,7 @@ def resource_type

Contains the request's resource type as it was perceived by the rendering engine. ResourceType will be one of the
following: `document`, `stylesheet`, `image`, `media`, `font`, `script`, `texttrack`, `xhr`, `fetch`, `eventsource`,
`websocket`, `manifest`, `other`.
`websocket`, `manifest`, `beacon`, `ping`, `cspreport`, `other`.

## response

Expand Down
3 changes: 2 additions & 1 deletion documentation/docs/api/response.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,9 @@ def headers_array
```


An array with all the request HTTP headers associated with this response. Unlike [Response#all_headers](./response#all_headers), header names are NOT lower-cased.
An array with all the response HTTP headers associated with this response. Unlike [Response#all_headers](./response#all_headers), header names are NOT lower-cased.
Headers with multiple entries, such as `Set-Cookie`, appear in the array multiple times.
Some browser network stacks combine multiple field values before reporting them, so separate entries are not always available.

## header_value

Expand Down
4 changes: 2 additions & 2 deletions documentation/docs/api/tracing.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def start(
```


Start tracing.
Start tracing. Disposing the returned `Disposable` stops tracing without saving the trace, similarly to calling [Tracing#stop](./tracing#stop) without a path.

**NOTE**: You probably want to [enable tracing in your config file](https://playwright.dev/docs/api/class-testoptions#test-options-trace) instead of using `Tracing.start`.

Expand All @@ -59,7 +59,7 @@ def start_chunk(name: nil, title: nil)
```


Start a new trace chunk. If you'd like to record multiple traces on the same [BrowserContext](./browser_context), use [Tracing#start](./tracing#start) once, and then create multiple trace chunks with [Tracing#start_chunk](./tracing#start_chunk) and [Tracing#stop_chunk](./tracing#stop_chunk).
Start a new trace chunk. Disposing the returned `Disposable` stops the chunk without saving it, similarly to calling [Tracing#stop_chunk](./tracing#stop_chunk) without a path. If you'd like to record multiple traces on the same [BrowserContext](./browser_context), use [Tracing#start](./tracing#start) once, and then create multiple trace chunks with [Tracing#start_chunk](./tracing#start_chunk) and [Tracing#stop_chunk](./tracing#stop_chunk).

**Usage**

Expand Down
Loading
Loading