playwright-ruby-client 1.63.0 → 1.64.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/documentation/docs/api/api_request_context.md +47 -0
  3. data/documentation/docs/api/browser.md +2 -0
  4. data/documentation/docs/api/browser_type.md +1 -0
  5. data/documentation/docs/api/clock.md +1 -0
  6. data/documentation/docs/api/credentials.md +6 -3
  7. data/documentation/docs/api/frame.md +6 -1
  8. data/documentation/docs/api/locator.md +38 -0
  9. data/documentation/docs/api/page.md +32 -1
  10. data/documentation/docs/api/request.md +1 -1
  11. data/documentation/docs/api/response.md +2 -1
  12. data/documentation/docs/api/tracing.md +2 -2
  13. data/documentation/docs/api/web_mcp.md +34 -0
  14. data/documentation/docs/article/guides/playwright_on_alpine_linux.md +1 -1
  15. data/documentation/docs/include/api_coverage.md +12 -0
  16. data/lib/playwright/channel_owners/api_request_context.rb +16 -0
  17. data/lib/playwright/channel_owners/browser_context.rb +4 -31
  18. data/lib/playwright/channel_owners/frame.rb +4 -3
  19. data/lib/playwright/channel_owners/local_utils.rb +5 -0
  20. data/lib/playwright/channel_owners/page.rb +10 -2
  21. data/lib/playwright/channel_owners/tracing.rb +2 -0
  22. data/lib/playwright/connection.rb +6 -2
  23. data/lib/playwright/credentials_impl.rb +2 -1
  24. data/lib/playwright/errors.rb +4 -1
  25. data/lib/playwright/locator_impl.rb +22 -8
  26. data/lib/playwright/screencast.rb +4 -2
  27. data/lib/playwright/transport.rb +21 -5
  28. data/lib/playwright/utils.rb +20 -0
  29. data/lib/playwright/version.rb +2 -2
  30. data/lib/playwright/web_mcp_impl.rb +21 -0
  31. data/lib/playwright_api/api_request_context.rb +38 -0
  32. data/lib/playwright_api/browser.rb +4 -2
  33. data/lib/playwright_api/browser_context.rb +4 -4
  34. data/lib/playwright_api/browser_type.rb +2 -1
  35. data/lib/playwright_api/clock.rb +1 -0
  36. data/lib/playwright_api/credentials.rb +7 -4
  37. data/lib/playwright_api/frame.rb +8 -2
  38. data/lib/playwright_api/locator.rb +38 -3
  39. data/lib/playwright_api/page.rb +40 -11
  40. data/lib/playwright_api/request.rb +5 -5
  41. data/lib/playwright_api/response.rb +2 -1
  42. data/lib/playwright_api/tracing.rb +2 -2
  43. data/lib/playwright_api/web_mcp.rb +26 -0
  44. data/lib/playwright_api/worker.rb +4 -4
  45. data/sig/playwright.rbs +21 -8
  46. metadata +5 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 275e62d0e3c798dd08cdb59a52299af990f93b7fd5fe1cf2a1f9b1c5441a1680
4
- data.tar.gz: 1711ed5665344b5c52b6f45c2621e03e2ac8983d698e6717303cad3bbb80659b
3
+ metadata.gz: 3d790738449c6398b19249ce438000db7f00a06a46b8db59307f2595d849781b
4
+ data.tar.gz: 7010d04e7614128ad40443dae1f3745b0588915c5af4e1d8c81c21f962b9d4c5
5
5
  SHA512:
6
- metadata.gz: 9180d7ceb51f46c828e8a08aaffdd1e813bc57b842f268556990030a9003686841842cd8d3f5c98ea8b5c2ea3e6fdb63a4ff45afb6e44adb2b2a9a6c7c6ef861
7
- data.tar.gz: 5efd8cd40f2e8b5d2cf2e22943ae6df4e3791b66874ca3cb0f72bbb66a1bd50442e8e481c990eed9fe958f4bfe82102e58634c5bfd2bc1823a0ff25b16036bbf
6
+ metadata.gz: c1ff297b16ee61f37ece9c223280dc7ea31c1ecbe5aab4ec130348e6c0c74ca5ab86769328c2810daee6166bb4153a7a703d3bcac99472cdc43920089a60a37c
7
+ data.tar.gz: 9a899659118c9b797a368c956538496fad57df2bb6b33d282af420095eecea459a323d2f046ba61d67e6c7d0bed9cb181fdcc4d2b7e57ac1d7bd8a05f0215e71
@@ -57,6 +57,53 @@ playwright.chromium.launch do |browser|
57
57
  end
58
58
  ```
59
59
 
60
+ ## add_cookies
61
+
62
+ ```
63
+ def add_cookies(cookies)
64
+ ```
65
+
66
+
67
+ Adds cookies into this request context. They will be sent with matching subsequent requests. For [BrowserContext#request](./browser_context#request)
68
+ and [Page#request](./page#request), this is equivalent to calling [BrowserContext#add_cookies](./browser_context#add_cookies) on the corresponding browser context.
69
+
70
+ **Usage**
71
+
72
+ ```ruby
73
+ request.add_cookies([cookie_object1, cookie_object2])
74
+ ```
75
+
76
+ ## clear_cookies
77
+
78
+ ```
79
+ def clear_cookies(domain: nil, name: nil, path: nil)
80
+ ```
81
+
82
+
83
+ Removes cookies from this request context. Accepts optional filter. For [BrowserContext#request](./browser_context#request)
84
+ and [Page#request](./page#request), this is equivalent to calling [BrowserContext#clear_cookies](./browser_context#clear_cookies) on the corresponding browser context.
85
+
86
+ **Usage**
87
+
88
+ ```ruby
89
+ request.clear_cookies
90
+ request.clear_cookies(name: "session-id")
91
+ request.clear_cookies(domain: "my-origin.com")
92
+ request.clear_cookies(path: "/api/v1")
93
+ request.clear_cookies(name: "session-id", domain: "my-origin.com")
94
+ ```
95
+
96
+ ## cookies
97
+
98
+ ```
99
+ def cookies(urls: nil)
100
+ ```
101
+
102
+
103
+ If no URLs are specified, this method returns all cookies. If URLs are specified, only cookies that affect those URLs
104
+ are returned. For [BrowserContext#request](./browser_context#request) and [Page#request](./page#request), this is equivalent to calling
105
+ [BrowserContext#cookies](./browser_context#cookies) on the corresponding browser context.
106
+
60
107
  ## delete
61
108
 
62
109
  ```
@@ -113,6 +113,7 @@ def new_context(
113
113
  record_har_path: nil,
114
114
  record_har_url_filter: nil,
115
115
  record_video_dir: nil,
116
+ record_video_fps: nil,
116
117
  record_video_size: nil,
117
118
  reducedMotion: nil,
118
119
  screen: nil,
@@ -174,6 +175,7 @@ def new_page(
174
175
  record_har_path: nil,
175
176
  record_har_url_filter: nil,
176
177
  record_video_dir: nil,
178
+ record_video_fps: nil,
177
179
  record_video_size: nil,
178
180
  reducedMotion: nil,
179
181
  screen: nil,
@@ -177,6 +177,7 @@ def launch_persistent_context(
177
177
  record_har_path: nil,
178
178
  record_har_url_filter: nil,
179
179
  record_video_dir: nil,
180
+ record_video_fps: nil,
180
181
  record_video_size: nil,
181
182
  reducedMotion: nil,
182
183
  screen: nil,
@@ -36,6 +36,7 @@ def install(time: nil)
36
36
 
37
37
  Install fake implementations for the following time-related functions:
38
38
  - `Date`
39
+ - `Temporal.Now`
39
40
  - `setTimeout`
40
41
  - `clearTimeout`
41
42
  - `setInterval`
@@ -57,6 +57,7 @@ context.credentials.create(
57
57
  userHandle: credential["userHandle"],
58
58
  privateKey: credential["privateKey"],
59
59
  publicKey: credential["publicKey"],
60
+ signCount: credential["signCount"],
60
61
  )
61
62
  context.credentials.install
62
63
 
@@ -67,7 +68,7 @@ page.goto("https://example.com/login")
67
68
 
68
69
  **Usage: save credentials in the storage state, restore later**
69
70
 
70
- See [authentication guide](https://playwright.dev/python/docs/auth) for examples of using saving and resotring the storage state.
71
+ See [authentication guide](https://playwright.dev/python/docs/auth) for examples of using saving and restoring the storage state.
71
72
 
72
73
  **Defaults**
73
74
 
@@ -95,6 +96,7 @@ def create(
95
96
  id: nil,
96
97
  privateKey: nil,
97
98
  publicKey: nil,
99
+ signCount: nil,
98
100
  userHandle: nil)
99
101
  ```
100
102
 
@@ -106,7 +108,8 @@ seeded credential is discoverable (resident), so the page can resolve it from bo
106
108
  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.
107
109
 
108
110
  To **import a known credential**, supply all four of `id`, `userHandle`, `privateKey` and
109
- `publicKey` together.
111
+ `publicKey` together. Pass `signCount` as well to continue from the
112
+ signature counter the relying party has already seen.
110
113
 
111
114
  Call [Credentials#install](./credentials#install) before navigating to a page that uses WebAuthn.
112
115
 
@@ -132,5 +135,5 @@ Returns every credential currently held by the authenticator, optionally filtere
132
135
  `id`. This includes both credentials seeded with [Credentials#create](./credentials#create) and credentials
133
136
  the page registered itself by calling `navigator.credentials.create()`.
134
137
 
135
- Each returned credential includes its private and public keys, so a passkey the app just
138
+ Each returned credential includes its private and public keys and the current signature counter, so a passkey the app just
136
139
  registered can be saved and re-seeded into a later test with [Credentials#create](./credentials#create) — see the second example in the class overview.
@@ -116,7 +116,7 @@ When all steps combined have not finished during the specified `timeout`, this m
116
116
  ## content
117
117
 
118
118
  ```
119
- def content
119
+ def content(includeShadow: nil)
120
120
  ```
121
121
 
122
122
 
@@ -1236,3 +1236,8 @@ Waits for the frame to navigate to the given URL.
1236
1236
  frame.click("a.delayed-navigation") # clicking the link will indirectly cause a navigation
1237
1237
  frame.wait_for_url("**/target.html")
1238
1238
  ```
1239
+
1240
+ ## webmcp
1241
+
1242
+
1243
+ Tools that the frame registers through the experimental [WebMCP](./web_mcp) browser API. See [WebMCP](./web_mcp) for details.
@@ -1135,6 +1135,26 @@ def normalize
1135
1135
  Returns a new locator that uses best practices for referencing the matched element, prioritizing test ids,
1136
1136
  aria roles, and other user-facing attributes over CSS selectors. This is useful for converting implementation-detail selectors into more resilient, human-readable locators.
1137
1137
 
1138
+ **Usage**
1139
+
1140
+ An agent can pick an element by its ref from an [Page#aria_snapshot](./page#aria_snapshot) taken in the `"ai"` mode. Refs only
1141
+ work for the latest snapshot. Normalize the ref locator and convert it to a string to get resilient locator code
1142
+ in your language, the same way `codegen` does.
1143
+
1144
+ Consider the following aria snapshot.
1145
+
1146
+ ```yaml
1147
+ - button "Submit" [ref=e2]
1148
+ ```
1149
+
1150
+ You can turn the ref into locator code:
1151
+
1152
+ ```ruby
1153
+ normalized = page.get_by_ref("e2").normalize
1154
+ puts normalized.to_s
1155
+ # get_by_role("button", name="Submit")
1156
+ ```
1157
+
1138
1158
  ## nth
1139
1159
 
1140
1160
  ```
@@ -1598,3 +1618,21 @@ If `expression` throws or rejects, this method throws.
1598
1618
  Wait for an attribute to appear:
1599
1619
 
1600
1620
  Passing argument to `expression`:
1621
+
1622
+ ## within
1623
+
1624
+ ```
1625
+ def within(locator)
1626
+ ```
1627
+
1628
+
1629
+ Returns a locator that matches this locator's elements inside each element matched by `locator`.
1630
+
1631
+ 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.
1632
+
1633
+ **Usage**
1634
+
1635
+ ```ruby
1636
+ third_column = page.get_by_role("cell").nth(2).within(page.get_by_role("row"))
1637
+ expect(third_column).to have_text(["Apple", "Banana", "Cherry"])
1638
+ ```
@@ -177,7 +177,7 @@ manually via [`event: Page.dialog`] event.
177
177
  ## content
178
178
 
179
179
  ```
180
- def content
180
+ def content(includeShadow: nil)
181
181
  ```
182
182
 
183
183
 
@@ -699,6 +699,30 @@ You can fill the input after locating it by the placeholder text:
699
699
  page.get_by_placeholder("name@example.com").fill("playwright@microsoft.com")
700
700
  ```
701
701
 
702
+ ## get_by_ref
703
+
704
+ ```
705
+ def get_by_ref(ref)
706
+ ```
707
+
708
+
709
+ Locate element by its aria ref. Refs like `[ref=e2]` are reported by [Page#aria_snapshot](./page#aria_snapshot) when called with
710
+ the `"ai"` mode, and resolve against the latest snapshot taken in the element's frame.
711
+
712
+ **Usage**
713
+
714
+ Consider the following aria snapshot.
715
+
716
+ ```yaml
717
+ - button "Submit" [ref=e2]
718
+ ```
719
+
720
+ You can locate the button by its ref:
721
+
722
+ ```ruby
723
+ page.get_by_ref("e2").click
724
+ ```
725
+
702
726
  ## get_by_role
703
727
 
704
728
  ```
@@ -2052,3 +2076,10 @@ API testing helper associated with this page. This method returns the same insta
2052
2076
  **Usage**
2053
2077
 
2054
2078
  ## touchscreen
2079
+
2080
+ ## webmcp
2081
+
2082
+
2083
+ 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.
2084
+
2085
+ **Usage**
@@ -205,7 +205,7 @@ def resource_type
205
205
 
206
206
  Contains the request's resource type as it was perceived by the rendering engine. ResourceType will be one of the
207
207
  following: `document`, `stylesheet`, `image`, `media`, `font`, `script`, `texttrack`, `xhr`, `fetch`, `eventsource`,
208
- `websocket`, `manifest`, `other`.
208
+ `websocket`, `manifest`, `beacon`, `ping`, `cspreport`, `other`.
209
209
 
210
210
  ## response
211
211
 
@@ -70,8 +70,9 @@ def headers_array
70
70
  ```
71
71
 
72
72
 
73
- 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.
73
+ 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.
74
74
  Headers with multiple entries, such as `Set-Cookie`, appear in the array multiple times.
75
+ Some browser network stacks combine multiple field values before reporting them, so separate entries are not always available.
75
76
 
76
77
  ## header_value
77
78
 
@@ -37,7 +37,7 @@ def start(
37
37
  ```
38
38
 
39
39
 
40
- Start tracing.
40
+ Start tracing. Disposing the returned `Disposable` stops tracing without saving the trace, similarly to calling [Tracing#stop](./tracing#stop) without a path.
41
41
 
42
42
  **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`.
43
43
 
@@ -59,7 +59,7 @@ def start_chunk(name: nil, title: nil)
59
59
  ```
60
60
 
61
61
 
62
- 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).
62
+ 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).
63
63
 
64
64
  **Usage**
65
65
 
@@ -0,0 +1,34 @@
1
+ ---
2
+ sidebar_position: 10
3
+ ---
4
+
5
+ # WebMCP
6
+
7
+
8
+ [WebMCP](./web_mcp) exposes the tools that a frame registers through the experimental [WebMCP](./web_mcp) browser API, `navigator.modelContext`. It lists the tools and calls them.
9
+
10
+ Instances are accessed through [Frame#webmcp](./frame#webmcp). [Page#webmcp](./page#webmcp) is the instance of the main frame.
11
+
12
+ **NOTE**: WebMCP is an experimental browser feature. Chromium enables it with the `--enable-features=WebMCP` launch argument, Firefox with the `dom.modelcontext.enabled` and `dom.modelcontext.testing.enabled` preferences. WebKit does not implement it.
13
+
14
+ Tool names, descriptions, input schemas and results are provided by the page, so treat them as untrusted input.
15
+
16
+ ## call_tool
17
+
18
+ ```
19
+ def call_tool(name, input: nil, timeout: nil)
20
+ ```
21
+
22
+
23
+ Calls a tool registered by the frame and returns its result. The result is whatever the tool's `execute` function resolved to, typically an object with a `content` array. A result with `isError: true` is returned as is. The method throws when the tool is not registered or its `execute` function throws.
24
+
25
+ ## tools
26
+
27
+ ```
28
+ def tools(timeout: nil)
29
+ ```
30
+
31
+
32
+ Returns the tools currently registered by the frame. Throws if the browser was launched without WebMCP support, see the note above for the launch options that enable it.
33
+
34
+ [Page#webmcp](./page#webmcp) covers the main frame only, child frames list their tools through their own [Frame#webmcp](./frame#webmcp).
@@ -83,7 +83,7 @@ If custom Docker image is preferred, build it as follows:
83
83
  FROM mcr.microsoft.com/playwright
84
84
 
85
85
  WORKDIR /root
86
- ARG PLAYWRIGHT_CORE_VERSION=1.63.0
86
+ ARG PLAYWRIGHT_CORE_VERSION=1.64.0
87
87
  RUN npm install "playwright-core@$PLAYWRIGHT_CORE_VERSION" && ./node_modules/.bin/playwright-core install
88
88
 
89
89
  ENV PORT 8888
@@ -201,6 +201,7 @@
201
201
  * wait_for_selector
202
202
  * wait_for_timeout
203
203
  * wait_for_url
204
+ * webmcp
204
205
 
205
206
  ## Worker
206
207
 
@@ -285,6 +286,7 @@
285
286
  * get_by_alt_text
286
287
  * get_by_label
287
288
  * get_by_placeholder
289
+ * get_by_ref
288
290
  * get_by_role
289
291
  * get_by_test_id
290
292
  * get_by_text
@@ -371,6 +373,7 @@
371
373
  * request
372
374
  * screencast
373
375
  * touchscreen
376
+ * webmcp
374
377
 
375
378
  ## BrowserContext
376
379
 
@@ -533,6 +536,7 @@
533
536
  * visible
534
537
  * wait_for
535
538
  * wait_for_function
539
+ * within
536
540
 
537
541
  ## FrameLocator
538
542
 
@@ -568,6 +572,9 @@
568
572
 
569
573
  ## APIRequestContext
570
574
 
575
+ * add_cookies
576
+ * clear_cookies
577
+ * cookies
571
578
  * delete
572
579
  * dispose
573
580
  * fetch
@@ -661,3 +668,8 @@
661
668
  * create
662
669
  * delete
663
670
  * get
671
+
672
+ ## WebMCP
673
+
674
+ * call_tool
675
+ * tools
@@ -3,6 +3,8 @@ require 'cgi/escape'
3
3
 
4
4
  module Playwright
5
5
  define_channel_owner :APIRequestContext do
6
+ include Utils::ClearCookiesParameters
7
+
6
8
  private def after_initialize
7
9
  @tracing = ChannelOwners::Tracing.from(@initializer['tracing'])
8
10
  @timeout_settings = TimeoutSettings.new
@@ -10,6 +12,20 @@ module Playwright
10
12
 
11
13
  attr_reader :tracing
12
14
 
15
+ def cookies(urls: nil)
16
+ @channel.send_message_to_server('cookies', urls: urls.nil? ? [] : Array(urls))
17
+ end
18
+
19
+ def add_cookies(cookies)
20
+ @channel.send_message_to_server('addCookies', cookies: cookies)
21
+ nil
22
+ end
23
+
24
+ def clear_cookies(domain: nil, name: nil, path: nil)
25
+ @channel.send_message_to_server('clearCookies', clear_cookies_params(domain: domain, name: name, path: path))
26
+ nil
27
+ end
28
+
13
29
  private def _update_timeout_settings(timeout_settings)
14
30
  @timeout_settings = timeout_settings
15
31
  end
@@ -1,6 +1,8 @@
1
1
  module Playwright
2
2
  # @ref https://github.com/microsoft/playwright-python/blob/master/playwright/_impl/_browser_context.py
3
3
  define_channel_owner :BrowserContext do
4
+ include Utils::ClearCookiesParameters
5
+
4
6
  include Utils::PrepareBrowserContextOptions
5
7
 
6
8
  attr_accessor :browser
@@ -274,36 +276,7 @@ module Playwright
274
276
  end
275
277
 
276
278
  def clear_cookies(domain: nil, name: nil, path: nil)
277
- params = {}
278
-
279
- case name
280
- when String
281
- params[:name] = name
282
- when Regexp
283
- regex = JavaScript::Regex.new(name)
284
- params[:nameRegexSource] = regex.source
285
- params[:nameRegexFlags] = regex.flag
286
- end
287
-
288
- case domain
289
- when String
290
- params[:domain] = domain
291
- when Regexp
292
- regex = JavaScript::Regex.new(domain)
293
- params[:domainRegexSource] = regex.source
294
- params[:domainRegexFlags] = regex.flag
295
- end
296
-
297
- case path
298
- when String
299
- params[:path] = path
300
- when Regexp
301
- regex = JavaScript::Regex.new(path)
302
- params[:pathRegexSource] = regex.source
303
- params[:pathRegexFlags] = regex.flag
304
- end
305
-
306
- @channel.send_message_to_server('clearCookies', params)
279
+ @channel.send_message_to_server('clearCookies', clear_cookies_params(domain: domain, name: name, path: path))
307
280
  end
308
281
 
309
282
  def grant_permissions(permissions, origin: nil)
@@ -459,7 +432,7 @@ module Playwright
459
432
  #
460
433
  # So, launch inspector as Python app.
461
434
  # NOTE: This should be used only for Page#pause at this moment.
462
- @channel.send_message_to_server('enableRecorder', language: :python)
435
+ @channel.send_message_to_server('showRecorder', language: :python)
463
436
  @debug_console_enabled = true
464
437
  end
465
438
 
@@ -17,6 +17,7 @@ module Playwright
17
17
  @child_frames = Set.new
18
18
  @load_states = Set.new(@initializer['loadStates'])
19
19
  @event_emitter = Object.new.extend(EventEmitter)
20
+ @webmcp = WebMCPImpl.new(self)
20
21
 
21
22
  @channel.on('loadstate', ->(params) {
22
23
  on_load_state(add: params['add'], remove: params['remove'])
@@ -24,7 +25,7 @@ module Playwright
24
25
  @channel.on('navigated', method(:on_frame_navigated))
25
26
  end
26
27
 
27
- attr_reader :page, :parent_frame
28
+ attr_reader :page, :parent_frame, :webmcp
28
29
  attr_writer :detached
29
30
 
30
31
  private def _timeout(timeout)
@@ -272,8 +273,8 @@ module Playwright
272
273
  JavaScript::Expression.new(pageFunction, arg).eval_on_selector_all(@channel, selector)
273
274
  end
274
275
 
275
- def content
276
- @channel.send_message_to_server('content')
276
+ def content(includeShadow: nil)
277
+ @channel.send_message_to_server('content', { includeShadow: includeShadow }.compact)
277
278
  end
278
279
 
279
280
  def set_content(html, timeout: nil, waitUntil: nil)
@@ -62,6 +62,11 @@ module Playwright
62
62
  nil
63
63
  end
64
64
 
65
+ def as_locator_description(selector)
66
+ # Ruby uses the Python SDK language for upstream code generation and the inspector.
67
+ @channel.send_message_to_server('asLocatorDescription', selector: selector, sdkLanguage: 'python')
68
+ end
69
+
65
70
  def connect(params)
66
71
  result = @channel.send_message_to_server_result('connect', params)
67
72
  ChannelOwners::JsonPipe.from(result['pipe'])
@@ -338,8 +338,16 @@ module Playwright
338
338
  @main_frame.url
339
339
  end
340
340
 
341
- def content
342
- @main_frame.content
341
+ def content(includeShadow: nil)
342
+ @main_frame.content(includeShadow: includeShadow)
343
+ end
344
+
345
+ def webmcp
346
+ @main_frame.webmcp
347
+ end
348
+
349
+ def get_by_ref(ref)
350
+ locator("aria-ref=#{ref}")
343
351
  end
344
352
 
345
353
  def set_content(html, timeout: nil, waitUntil: nil)
@@ -18,11 +18,13 @@ module Playwright
18
18
  @channel.send_message_to_server('tracingStart', params)
19
19
  trace_name = @channel.send_message_to_server('tracingStartChunk', { title: title, name: name }.compact)
20
20
  start_collecting_stacks(trace_name)
21
+ DisposableStub.new { stop }
21
22
  end
22
23
 
23
24
  def start_chunk(title: nil, name: nil)
24
25
  trace_name = @channel.send_message_to_server('tracingStartChunk', { title: title, name: name }.compact)
25
26
  start_collecting_stacks(trace_name)
27
+ DisposableStub.new { stop_chunk }
26
28
  end
27
29
 
28
30
  private def start_collecting_stacks(trace_name)
@@ -24,6 +24,7 @@ module Playwright
24
24
  @waiting_for_object = {} # Hash[ guid => Promise<ChannelOwner> ]
25
25
  @callbacks = {} # Hash [ guid => Promise<ChannelOwner> ]
26
26
  @callbacks_mutex = Mutex.new
27
+ @call_id_prefix = Array.new(4) { ('a'..'z').to_a.sample }.join
27
28
  @root_object = RootChannelOwner.new(self)
28
29
  @remote = false
29
30
  @tracing_count = 0
@@ -77,7 +78,10 @@ module Playwright
77
78
  if method == '__waitInfo__' && @closed_error
78
79
  return Concurrent::Promises.fulfilled_future(nil)
79
80
  end
80
- return if @closed_error
81
+ # After the driver is gone, fail fast with the close error instead of
82
+ # returning nil (which would blow up with NoMethodError on .value!).
83
+ # ref: https://github.com/YusukeIwaki/playwright-ruby-client/issues/392
84
+ return Concurrent::Promises.rejected_future(@closed_error) if @closed_error
81
85
 
82
86
  callback = Concurrent::Promises.resolvable_future
83
87
  fire_and_forget = method == '__waitInfo__'
@@ -150,7 +154,7 @@ module Playwright
150
154
  @last_id ||= 0
151
155
  @last_id += 1
152
156
  end
153
- block.call(id)
157
+ block.call("#{@call_id_prefix}@#{id}")
154
158
  end
155
159
 
156
160
  # @param guid [String]
@@ -11,13 +11,14 @@ module Playwright
11
11
  nil
12
12
  end
13
13
 
14
- def create(rpId, id: nil, userHandle: nil, privateKey: nil, publicKey: nil)
14
+ def create(rpId, id: nil, userHandle: nil, privateKey: nil, publicKey: nil, signCount: nil)
15
15
  params = {
16
16
  rpId: rpId,
17
17
  id: id,
18
18
  userHandle: userHandle,
19
19
  privateKey: privateKey,
20
20
  publicKey: publicKey,
21
+ signCount: signCount,
21
22
  }.compact
22
23
  @browser_context.channel.send_message_to_server('credentialsCreate', params)
23
24
  end
@@ -2,7 +2,7 @@ module Playwright
2
2
  class Error < StandardError
3
3
  # ref: https://github.com/microsoft/playwright-python/blob/0b4a980fed366c4c1dee9bfcdd72662d629fdc8d/playwright/_impl/_helper.py#L155
4
4
  def self.parse(error_payload)
5
- if error_payload['name'] == 'TimeoutError'
5
+ error = if error_payload['name'] == 'TimeoutError'
6
6
  TimeoutError.new(
7
7
  message: error_payload['message'],
8
8
  stack: error_payload['stack'],
@@ -19,6 +19,8 @@ module Playwright
19
19
  stack: error_payload['stack'],
20
20
  )
21
21
  end
22
+ error.code = error_payload['code']
23
+ error
22
24
  end
23
25
 
24
26
  # @param name [String]
@@ -34,6 +36,7 @@ module Playwright
34
36
  attr_reader :name, :message, :stack, :raw_log
35
37
  # Error details for `expect` failures (received value, timedOut, customErrorMessage).
36
38
  attr_accessor :details
39
+ attr_accessor :code
37
40
 
38
41
  def log=(log)
39
42
  return unless log