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
@@ -5,8 +5,9 @@ module Playwright
5
5
  define_api_implementation :LocatorImpl do
6
6
  include LocatorUtils
7
7
 
8
- def initialize(frame:, selector:, has: nil, hasNot: nil, hasNotText: nil, hasText: nil, visible: nil)
8
+ def initialize(frame:, selector:, has: nil, hasNot: nil, hasNotText: nil, hasText: nil, visible: nil, locator_code: nil)
9
9
  @frame = frame
10
+ @locator_code = locator_code
10
11
  selector_scopes = [selector]
11
12
 
12
13
  if hasText
@@ -39,11 +40,18 @@ module Playwright
39
40
  end
40
41
 
41
42
  def to_s
42
- if @description
43
- "Locator@#{@selector} (#{@description})"
44
- else
45
- "Locator@#{@selector}"
46
- end
43
+ custom_description = description
44
+ return custom_description if custom_description
45
+ return @locator_code if @locator_code
46
+
47
+ local_utils = @frame.instance_variable_get(:@connection).local_utils
48
+ return "Locator@#{@selector}" unless local_utils
49
+
50
+ local_utils.as_locator_description(@selector)
51
+ end
52
+
53
+ def within(locator)
54
+ locator.locator(self)
47
55
  end
48
56
 
49
57
  private def to_protocol
@@ -232,6 +240,11 @@ module Playwright
232
240
  hasNot: nil,
233
241
  hasNotText: nil,
234
242
  hasText: nil)
243
+ if selector.is_a?(LocatorImpl)
244
+ raise ArgumentError, 'Locators must belong to the same frame.' unless same_frame?(selector)
245
+
246
+ selector = "internal:chain=#{selector.send(:selector_json)}"
247
+ end
235
248
  LocatorImpl.new(
236
249
  frame: @frame,
237
250
  selector: "#{@selector} >> #{selector}",
@@ -453,10 +466,11 @@ module Playwright
453
466
  end
454
467
 
455
468
  def normalize
456
- resolved_selector = @frame.channel.send_message_to_server('resolveSelector', { selector: @selector })
469
+ result = @frame.channel.send_message_to_server_result('resolveSelector', { selector: @selector, sdkLanguage: 'python' })
457
470
  LocatorImpl.new(
458
471
  frame: @frame,
459
- selector: resolved_selector,
472
+ selector: result['resolvedSelector'],
473
+ locator_code: result['locatorCode'],
460
474
  )
461
475
  end
462
476
 
@@ -11,7 +11,7 @@ module Playwright
11
11
  @page.send(:channel).on('screencastFrame', method(:handle_screencast_frame))
12
12
  end
13
13
 
14
- def start(path: nil, size: nil, quality: nil, &on_frame)
14
+ def start(path: nil, size: nil, quality: nil, fps: nil, &on_frame)
15
15
  raise 'Screencast is already started' if @started
16
16
 
17
17
  @started = true
@@ -21,6 +21,7 @@ module Playwright
21
21
  params[:record] = true if path
22
22
  params[:size] = size if size
23
23
  params[:quality] = quality if quality
24
+ params[:fps] = fps unless fps.nil?
24
25
  params[:sendFrames] = true if on_frame
25
26
 
26
27
  result = @page.send(:channel).send_message_to_server_result('screencastStart', params)
@@ -63,12 +64,13 @@ module Playwright
63
64
  @page.send(:channel).send_message_to_server('screencastChapter', params)
64
65
  end
65
66
 
66
- def show_actions(duration: nil, fontSize: nil, position: nil, cursor: nil)
67
+ def show_actions(duration: nil, fontSize: nil, position: nil, cursor: nil, style: nil)
67
68
  params = {}
68
69
  params[:duration] = duration if duration
69
70
  params[:fontSize] = fontSize if fontSize
70
71
  params[:position] = position if position
71
72
  params[:cursor] = cursor if cursor
73
+ params[:style] = style if style
72
74
  @page.send(:channel).send_message_to_server('screencastShowActions', params)
73
75
  DisposableStub.new { hide_actions }
74
76
  end
@@ -32,10 +32,15 @@ module Playwright
32
32
  def send_message(message)
33
33
  debug_send_message(message) if @debug
34
34
  msg = JSON.dump(message)
35
- @mutex.synchronize {
36
- @stdin.write([msg.bytes.length].pack('V')) # unsigned 32bit, little endian, real byte size instead of chars
37
- @stdin.write(msg) # write UTF-8 in binary mode as byte stream
38
- }
35
+ # Build the whole frame (4-byte little-endian length header + JSON payload) in a
36
+ # single buffer, and write it at once. Two separate writes can be torn by an
37
+ # asynchronous exception (e.g. Timeout::Error from Timeout.timeout, delivered via
38
+ # Thread#raise), which crashes the driver with a JSON parse error.
39
+ # ref: https://github.com/YusukeIwaki/playwright-ruby-client/issues/392
40
+ frame = [msg.bytesize].pack('V') + msg.b # unsigned 32bit, little endian, real byte size instead of chars
41
+ Thread.handle_interrupt(Object => :never) do
42
+ @mutex.synchronize { @stdin.write(frame) } # write UTF-8 in binary mode as byte stream
43
+ end
39
44
  rescue Errno::EPIPE, IOError
40
45
  raise AlreadyDisconnectedError.new('send_message failed')
41
46
  end
@@ -85,6 +90,10 @@ module Playwright
85
90
  debug_recv_message(obj) if @debug
86
91
  @on_message&.call(obj)
87
92
  end
93
+ # exited the loop on clean EOF. The driver is gone, so reject pending
94
+ # callbacks instead of hanging forever on promises that will never resolve.
95
+ # ref: https://github.com/YusukeIwaki/playwright-ruby-client/issues/392
96
+ @on_driver_closed&.call
88
97
  rescue IOError
89
98
  # disconnected by remote.
90
99
  @on_driver_closed&.call
@@ -92,6 +101,9 @@ module Playwright
92
101
 
93
102
  def handle_stderr
94
103
  while err = @stderr.read
104
+ # IO#read without length on a pipe returns "" (not nil) at EOF.
105
+ # Bail out instead of spinning forever on empty reads.
106
+ break if err.empty?
95
107
  # sometimed driver crashes with the error below.
96
108
  # --------
97
109
  # undefined:1
@@ -103,7 +115,11 @@ module Playwright
103
115
  # at Transport.transport.onmessage (/home/runner/work/playwright-ruby-client/playwright-ruby-client/node_modules/playwright/lib/cli/driver.js:42:73)
104
116
  # at Immediate.<anonymous> (/home/runner/work/playwright-ruby-client/playwright-ruby-client/node_modules/playwright/lib/protocol/transport.js:74:26)
105
117
  # at processImmediate (internal/timers.js:461:21)
106
- if err.include?('undefined:1')
118
+ #
119
+ # Node >= 16 prints '<anonymous_script>:1' instead of 'undefined:1'.
120
+ # ref: https://github.com/YusukeIwaki/playwright-ruby-client/issues/392
121
+ if err.include?('undefined:1') || err.include?('<anonymous_script>:1') ||
122
+ err.include?('is not valid JSON')
107
123
  @on_driver_crashed&.call
108
124
  break
109
125
  end
@@ -18,6 +18,23 @@ module Playwright
18
18
  end
19
19
 
20
20
  module Utils
21
+ module ClearCookiesParameters
22
+ private def clear_cookies_params(domain:, name:, path:)
23
+ params = {}
24
+ { domain: domain, name: name, path: path }.each do |key, value|
25
+ case value
26
+ when String
27
+ params[key] = value
28
+ when Regexp
29
+ regex = JavaScript::Regex.new(value)
30
+ params["#{key}RegexSource".to_sym] = regex.source
31
+ params["#{key}RegexFlags".to_sym] = regex.flag
32
+ end
33
+ end
34
+ params
35
+ end
36
+ end
37
+
21
38
  module PrepareHttpCredentials
22
39
  private def prepare_http_credentials(credentials)
23
40
  return nil unless credentials
@@ -47,6 +64,9 @@ module Playwright
47
64
  if params[:record_video_size]
48
65
  params[:recordVideo][:size] = params.delete(:record_video_size)
49
66
  end
67
+ unless params[:record_video_fps].nil?
68
+ params[:recordVideo][:fps] = params.delete(:record_video_fps)
69
+ end
50
70
  if params[:record_video_show_actions]
51
71
  params[:recordVideo][:showActions] = params.delete(:record_video_show_actions)
52
72
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Playwright
4
- VERSION = '1.63.0'
5
- COMPATIBLE_PLAYWRIGHT_VERSION = '1.63.0'
4
+ VERSION = '1.64.0'
5
+ COMPATIBLE_PLAYWRIGHT_VERSION = '1.64.0'
6
6
  end
@@ -0,0 +1,21 @@
1
+ module Playwright
2
+ # https://github.com/microsoft/playwright/blob/v1.64.0/packages/playwright-core/src/client/webmcp.ts
3
+ define_api_implementation :WebMCPImpl do
4
+ def initialize(frame)
5
+ @frame = frame
6
+ end
7
+
8
+ def tools(timeout: nil)
9
+ @frame.channel.send_message_to_server('webmcpTools', timeout: @frame.send(:_timeout, timeout))
10
+ end
11
+
12
+ def call_tool(name, input: nil, timeout: nil)
13
+ result = @frame.channel.send_message_to_server('webmcpCallTool',
14
+ name: name,
15
+ input: JavaScript::ValueSerializer.new(input).serialize,
16
+ timeout: @frame.send(:_timeout, timeout),
17
+ )
18
+ JavaScript::ValueParser.new(result).parse
19
+ end
20
+ end
21
+ end
@@ -73,6 +73,44 @@ module Playwright
73
73
  wrap_impl(@impl.tracing)
74
74
  end
75
75
 
76
+ #
77
+ # Adds cookies into this request context. They will be sent with matching subsequent requests. For [`property: BrowserContext.request`]
78
+ # and [`property: Page.request`], this is equivalent to calling [`method: BrowserContext.addCookies`] on the corresponding browser context.
79
+ #
80
+ # **Usage**
81
+ #
82
+ # ```python sync
83
+ # request.add_cookies([cookie_object1, cookie_object2])
84
+ # ```
85
+ def add_cookies(cookies)
86
+ wrap_impl(@impl.add_cookies(unwrap_impl(cookies)))
87
+ end
88
+
89
+ #
90
+ # Removes cookies from this request context. Accepts optional filter. For [`property: BrowserContext.request`]
91
+ # and [`property: Page.request`], this is equivalent to calling [`method: BrowserContext.clearCookies`] on the corresponding browser context.
92
+ #
93
+ # **Usage**
94
+ #
95
+ # ```python sync
96
+ # request.clear_cookies()
97
+ # request.clear_cookies(name="session-id")
98
+ # request.clear_cookies(domain="my-origin.com")
99
+ # request.clear_cookies(path="/api/v1")
100
+ # request.clear_cookies(name="session-id", domain="my-origin.com")
101
+ # ```
102
+ def clear_cookies(domain: nil, name: nil, path: nil)
103
+ wrap_impl(@impl.clear_cookies(domain: unwrap_impl(domain), name: unwrap_impl(name), path: unwrap_impl(path)))
104
+ end
105
+
106
+ #
107
+ # If no URLs are specified, this method returns all cookies. If URLs are specified, only cookies that affect those URLs
108
+ # are returned. For [`property: BrowserContext.request`] and [`property: Page.request`], this is equivalent to calling
109
+ # [`method: BrowserContext.cookies`] on the corresponding browser context.
110
+ def cookies(urls: nil)
111
+ wrap_impl(@impl.cookies(urls: unwrap_impl(urls)))
112
+ end
113
+
76
114
  #
77
115
  # Sends HTTP(S) [DELETE](https://developer.mozilla.org/en-US/docs/Web/HTTP/Methods/DELETE) request and returns its response.
78
116
  # The method will populate request cookies from the context and update
@@ -113,6 +113,7 @@ module Playwright
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,
@@ -123,7 +124,7 @@ module Playwright
123
124
  userAgent: nil,
124
125
  viewport: nil,
125
126
  &block)
126
- wrap_impl(@impl.new_context(acceptDownloads: unwrap_impl(acceptDownloads), baseURL: unwrap_impl(baseURL), bypassCSP: unwrap_impl(bypassCSP), clientCertificates: unwrap_impl(clientCertificates), colorScheme: unwrap_impl(colorScheme), contrast: unwrap_impl(contrast), deviceScaleFactor: unwrap_impl(deviceScaleFactor), extraHTTPHeaders: unwrap_impl(extraHTTPHeaders), forcedColors: unwrap_impl(forcedColors), geolocation: unwrap_impl(geolocation), hasTouch: unwrap_impl(hasTouch), httpCredentials: unwrap_impl(httpCredentials), ignoreHTTPSErrors: unwrap_impl(ignoreHTTPSErrors), isMobile: unwrap_impl(isMobile), javaScriptEnabled: unwrap_impl(javaScriptEnabled), locale: unwrap_impl(locale), noViewport: unwrap_impl(noViewport), offline: unwrap_impl(offline), permissions: unwrap_impl(permissions), proxy: unwrap_impl(proxy), record_har_content: unwrap_impl(record_har_content), record_har_mode: unwrap_impl(record_har_mode), record_har_omit_content: unwrap_impl(record_har_omit_content), record_har_path: unwrap_impl(record_har_path), record_har_url_filter: unwrap_impl(record_har_url_filter), record_video_dir: unwrap_impl(record_video_dir), record_video_size: unwrap_impl(record_video_size), reducedMotion: unwrap_impl(reducedMotion), screen: unwrap_impl(screen), serviceWorkers: unwrap_impl(serviceWorkers), storageState: unwrap_impl(storageState), strictSelectors: unwrap_impl(strictSelectors), timezoneId: unwrap_impl(timezoneId), userAgent: unwrap_impl(userAgent), viewport: unwrap_impl(viewport), &wrap_block_call(block)))
127
+ wrap_impl(@impl.new_context(acceptDownloads: unwrap_impl(acceptDownloads), baseURL: unwrap_impl(baseURL), bypassCSP: unwrap_impl(bypassCSP), clientCertificates: unwrap_impl(clientCertificates), colorScheme: unwrap_impl(colorScheme), contrast: unwrap_impl(contrast), deviceScaleFactor: unwrap_impl(deviceScaleFactor), extraHTTPHeaders: unwrap_impl(extraHTTPHeaders), forcedColors: unwrap_impl(forcedColors), geolocation: unwrap_impl(geolocation), hasTouch: unwrap_impl(hasTouch), httpCredentials: unwrap_impl(httpCredentials), ignoreHTTPSErrors: unwrap_impl(ignoreHTTPSErrors), isMobile: unwrap_impl(isMobile), javaScriptEnabled: unwrap_impl(javaScriptEnabled), locale: unwrap_impl(locale), noViewport: unwrap_impl(noViewport), offline: unwrap_impl(offline), permissions: unwrap_impl(permissions), proxy: unwrap_impl(proxy), record_har_content: unwrap_impl(record_har_content), record_har_mode: unwrap_impl(record_har_mode), record_har_omit_content: unwrap_impl(record_har_omit_content), record_har_path: unwrap_impl(record_har_path), record_har_url_filter: unwrap_impl(record_har_url_filter), record_video_dir: unwrap_impl(record_video_dir), record_video_fps: unwrap_impl(record_video_fps), record_video_size: unwrap_impl(record_video_size), reducedMotion: unwrap_impl(reducedMotion), screen: unwrap_impl(screen), serviceWorkers: unwrap_impl(serviceWorkers), storageState: unwrap_impl(storageState), strictSelectors: unwrap_impl(strictSelectors), timezoneId: unwrap_impl(timezoneId), userAgent: unwrap_impl(userAgent), viewport: unwrap_impl(viewport), &wrap_block_call(block)))
127
128
  end
128
129
 
129
130
  #
@@ -159,6 +160,7 @@ module Playwright
159
160
  record_har_path: nil,
160
161
  record_har_url_filter: nil,
161
162
  record_video_dir: nil,
163
+ record_video_fps: nil,
162
164
  record_video_size: nil,
163
165
  reducedMotion: nil,
164
166
  screen: nil,
@@ -169,7 +171,7 @@ module Playwright
169
171
  userAgent: nil,
170
172
  viewport: nil,
171
173
  &block)
172
- wrap_impl(@impl.new_page(acceptDownloads: unwrap_impl(acceptDownloads), baseURL: unwrap_impl(baseURL), bypassCSP: unwrap_impl(bypassCSP), clientCertificates: unwrap_impl(clientCertificates), colorScheme: unwrap_impl(colorScheme), contrast: unwrap_impl(contrast), deviceScaleFactor: unwrap_impl(deviceScaleFactor), extraHTTPHeaders: unwrap_impl(extraHTTPHeaders), forcedColors: unwrap_impl(forcedColors), geolocation: unwrap_impl(geolocation), hasTouch: unwrap_impl(hasTouch), httpCredentials: unwrap_impl(httpCredentials), ignoreHTTPSErrors: unwrap_impl(ignoreHTTPSErrors), isMobile: unwrap_impl(isMobile), javaScriptEnabled: unwrap_impl(javaScriptEnabled), locale: unwrap_impl(locale), noViewport: unwrap_impl(noViewport), offline: unwrap_impl(offline), permissions: unwrap_impl(permissions), proxy: unwrap_impl(proxy), record_har_content: unwrap_impl(record_har_content), record_har_mode: unwrap_impl(record_har_mode), record_har_omit_content: unwrap_impl(record_har_omit_content), record_har_path: unwrap_impl(record_har_path), record_har_url_filter: unwrap_impl(record_har_url_filter), record_video_dir: unwrap_impl(record_video_dir), record_video_size: unwrap_impl(record_video_size), reducedMotion: unwrap_impl(reducedMotion), screen: unwrap_impl(screen), serviceWorkers: unwrap_impl(serviceWorkers), storageState: unwrap_impl(storageState), strictSelectors: unwrap_impl(strictSelectors), timezoneId: unwrap_impl(timezoneId), userAgent: unwrap_impl(userAgent), viewport: unwrap_impl(viewport), &wrap_block_call(block)))
174
+ wrap_impl(@impl.new_page(acceptDownloads: unwrap_impl(acceptDownloads), baseURL: unwrap_impl(baseURL), bypassCSP: unwrap_impl(bypassCSP), clientCertificates: unwrap_impl(clientCertificates), colorScheme: unwrap_impl(colorScheme), contrast: unwrap_impl(contrast), deviceScaleFactor: unwrap_impl(deviceScaleFactor), extraHTTPHeaders: unwrap_impl(extraHTTPHeaders), forcedColors: unwrap_impl(forcedColors), geolocation: unwrap_impl(geolocation), hasTouch: unwrap_impl(hasTouch), httpCredentials: unwrap_impl(httpCredentials), ignoreHTTPSErrors: unwrap_impl(ignoreHTTPSErrors), isMobile: unwrap_impl(isMobile), javaScriptEnabled: unwrap_impl(javaScriptEnabled), locale: unwrap_impl(locale), noViewport: unwrap_impl(noViewport), offline: unwrap_impl(offline), permissions: unwrap_impl(permissions), proxy: unwrap_impl(proxy), record_har_content: unwrap_impl(record_har_content), record_har_mode: unwrap_impl(record_har_mode), record_har_omit_content: unwrap_impl(record_har_omit_content), record_har_path: unwrap_impl(record_har_path), record_har_url_filter: unwrap_impl(record_har_url_filter), record_video_dir: unwrap_impl(record_video_dir), record_video_fps: unwrap_impl(record_video_fps), record_video_size: unwrap_impl(record_video_size), reducedMotion: unwrap_impl(reducedMotion), screen: unwrap_impl(screen), serviceWorkers: unwrap_impl(serviceWorkers), storageState: unwrap_impl(storageState), strictSelectors: unwrap_impl(strictSelectors), timezoneId: unwrap_impl(timezoneId), userAgent: unwrap_impl(userAgent), viewport: unwrap_impl(viewport), &wrap_block_call(block)))
173
175
  end
174
176
 
175
177
  #
@@ -504,13 +504,13 @@ module Playwright
504
504
  end
505
505
 
506
506
  # @nodoc
507
- def browser=(req)
508
- wrap_impl(@impl.browser=(unwrap_impl(req)))
507
+ def options=(req)
508
+ wrap_impl(@impl.options=(unwrap_impl(req)))
509
509
  end
510
510
 
511
511
  # @nodoc
512
- def options=(req)
513
- wrap_impl(@impl.options=(unwrap_impl(req)))
512
+ def browser=(req)
513
+ wrap_impl(@impl.browser=(unwrap_impl(req)))
514
514
  end
515
515
 
516
516
  # @nodoc
@@ -165,6 +165,7 @@ module Playwright
165
165
  record_har_path: nil,
166
166
  record_har_url_filter: nil,
167
167
  record_video_dir: nil,
168
+ record_video_fps: nil,
168
169
  record_video_size: nil,
169
170
  reducedMotion: nil,
170
171
  screen: nil,
@@ -177,7 +178,7 @@ module Playwright
177
178
  userAgent: nil,
178
179
  viewport: nil,
179
180
  &block)
180
- wrap_impl(@impl.launch_persistent_context(unwrap_impl(userDataDir), acceptDownloads: unwrap_impl(acceptDownloads), args: unwrap_impl(args), artifactsDir: unwrap_impl(artifactsDir), baseURL: unwrap_impl(baseURL), bypassCSP: unwrap_impl(bypassCSP), channel: unwrap_impl(channel), chromiumSandbox: unwrap_impl(chromiumSandbox), clientCertificates: unwrap_impl(clientCertificates), colorScheme: unwrap_impl(colorScheme), contrast: unwrap_impl(contrast), deviceScaleFactor: unwrap_impl(deviceScaleFactor), downloadsPath: unwrap_impl(downloadsPath), env: unwrap_impl(env), executablePath: unwrap_impl(executablePath), extraHTTPHeaders: unwrap_impl(extraHTTPHeaders), firefoxUserPrefs: unwrap_impl(firefoxUserPrefs), forcedColors: unwrap_impl(forcedColors), geolocation: unwrap_impl(geolocation), handleSIGHUP: unwrap_impl(handleSIGHUP), handleSIGINT: unwrap_impl(handleSIGINT), handleSIGTERM: unwrap_impl(handleSIGTERM), hasTouch: unwrap_impl(hasTouch), headless: unwrap_impl(headless), httpCredentials: unwrap_impl(httpCredentials), ignoreDefaultArgs: unwrap_impl(ignoreDefaultArgs), ignoreHTTPSErrors: unwrap_impl(ignoreHTTPSErrors), isMobile: unwrap_impl(isMobile), javaScriptEnabled: unwrap_impl(javaScriptEnabled), locale: unwrap_impl(locale), noViewport: unwrap_impl(noViewport), offline: unwrap_impl(offline), permissions: unwrap_impl(permissions), proxy: unwrap_impl(proxy), record_har_content: unwrap_impl(record_har_content), record_har_mode: unwrap_impl(record_har_mode), record_har_omit_content: unwrap_impl(record_har_omit_content), record_har_path: unwrap_impl(record_har_path), record_har_url_filter: unwrap_impl(record_har_url_filter), record_video_dir: unwrap_impl(record_video_dir), record_video_size: unwrap_impl(record_video_size), reducedMotion: unwrap_impl(reducedMotion), screen: unwrap_impl(screen), serviceWorkers: unwrap_impl(serviceWorkers), slowMo: unwrap_impl(slowMo), strictSelectors: unwrap_impl(strictSelectors), timeout: unwrap_impl(timeout), timezoneId: unwrap_impl(timezoneId), tracesDir: unwrap_impl(tracesDir), userAgent: unwrap_impl(userAgent), viewport: unwrap_impl(viewport), &wrap_block_call(block)))
181
+ wrap_impl(@impl.launch_persistent_context(unwrap_impl(userDataDir), acceptDownloads: unwrap_impl(acceptDownloads), args: unwrap_impl(args), artifactsDir: unwrap_impl(artifactsDir), baseURL: unwrap_impl(baseURL), bypassCSP: unwrap_impl(bypassCSP), channel: unwrap_impl(channel), chromiumSandbox: unwrap_impl(chromiumSandbox), clientCertificates: unwrap_impl(clientCertificates), colorScheme: unwrap_impl(colorScheme), contrast: unwrap_impl(contrast), deviceScaleFactor: unwrap_impl(deviceScaleFactor), downloadsPath: unwrap_impl(downloadsPath), env: unwrap_impl(env), executablePath: unwrap_impl(executablePath), extraHTTPHeaders: unwrap_impl(extraHTTPHeaders), firefoxUserPrefs: unwrap_impl(firefoxUserPrefs), forcedColors: unwrap_impl(forcedColors), geolocation: unwrap_impl(geolocation), handleSIGHUP: unwrap_impl(handleSIGHUP), handleSIGINT: unwrap_impl(handleSIGINT), handleSIGTERM: unwrap_impl(handleSIGTERM), hasTouch: unwrap_impl(hasTouch), headless: unwrap_impl(headless), httpCredentials: unwrap_impl(httpCredentials), ignoreDefaultArgs: unwrap_impl(ignoreDefaultArgs), ignoreHTTPSErrors: unwrap_impl(ignoreHTTPSErrors), isMobile: unwrap_impl(isMobile), javaScriptEnabled: unwrap_impl(javaScriptEnabled), locale: unwrap_impl(locale), noViewport: unwrap_impl(noViewport), offline: unwrap_impl(offline), permissions: unwrap_impl(permissions), proxy: unwrap_impl(proxy), record_har_content: unwrap_impl(record_har_content), record_har_mode: unwrap_impl(record_har_mode), record_har_omit_content: unwrap_impl(record_har_omit_content), record_har_path: unwrap_impl(record_har_path), record_har_url_filter: unwrap_impl(record_har_url_filter), record_video_dir: unwrap_impl(record_video_dir), record_video_fps: unwrap_impl(record_video_fps), record_video_size: unwrap_impl(record_video_size), reducedMotion: unwrap_impl(reducedMotion), screen: unwrap_impl(screen), serviceWorkers: unwrap_impl(serviceWorkers), slowMo: unwrap_impl(slowMo), strictSelectors: unwrap_impl(strictSelectors), timeout: unwrap_impl(timeout), timezoneId: unwrap_impl(timezoneId), tracesDir: unwrap_impl(tracesDir), userAgent: unwrap_impl(userAgent), viewport: unwrap_impl(viewport), &wrap_block_call(block)))
181
182
  end
182
183
 
183
184
  #
@@ -23,6 +23,7 @@ module Playwright
23
23
  #
24
24
  # Install fake implementations for the following time-related functions:
25
25
  # - `Date`
26
+ # - `Temporal.Now`
26
27
  # - `setTimeout`
27
28
  # - `clearTimeout`
28
29
  # - `setInterval`
@@ -54,6 +54,7 @@ module Playwright
54
54
  # user_handle=credential["userHandle"],
55
55
  # private_key=credential["privateKey"],
56
56
  # public_key=credential["publicKey"],
57
+ # sign_count=credential["signCount"],
57
58
  # )
58
59
  # context.credentials.install()
59
60
  #
@@ -64,7 +65,7 @@ module Playwright
64
65
  #
65
66
  # **Usage: save credentials in the storage state, restore later**
66
67
  #
67
- # See [authentication guide](../auth.md) for examples of using saving and resotring the storage state.
68
+ # See [authentication guide](../auth.md) for examples of using saving and restoring the storage state.
68
69
  #
69
70
  # **Defaults**
70
71
  class Credentials < PlaywrightApi
@@ -90,7 +91,8 @@ module Playwright
90
91
  # 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.
91
92
  #
92
93
  # To **import a known credential**, supply all four of `id`, `userHandle`, `privateKey` and
93
- # `publicKey` together.
94
+ # `publicKey` together. Pass `signCount` as well to continue from the
95
+ # signature counter the relying party has already seen.
94
96
  #
95
97
  # Call [`method: Credentials.install`] before navigating to a page that uses WebAuthn.
96
98
  def create(
@@ -98,8 +100,9 @@ module Playwright
98
100
  id: nil,
99
101
  privateKey: nil,
100
102
  publicKey: nil,
103
+ signCount: nil,
101
104
  userHandle: nil)
102
- wrap_impl(@impl.create(unwrap_impl(rpId), id: unwrap_impl(id), privateKey: unwrap_impl(privateKey), publicKey: unwrap_impl(publicKey), userHandle: unwrap_impl(userHandle)))
105
+ wrap_impl(@impl.create(unwrap_impl(rpId), id: unwrap_impl(id), privateKey: unwrap_impl(privateKey), publicKey: unwrap_impl(publicKey), signCount: unwrap_impl(signCount), userHandle: unwrap_impl(userHandle)))
103
106
  end
104
107
 
105
108
  #
@@ -115,7 +118,7 @@ module Playwright
115
118
  # `id`. This includes both credentials seeded with [`method: Credentials.create`] and credentials
116
119
  # the page registered itself by calling `navigator.credentials.create()`.
117
120
  #
118
- # Each returned credential includes its private and public keys, so a passkey the app just
121
+ # Each returned credential includes its private and public keys and the current signature counter, so a passkey the app just
119
122
  # registered can be saved and re-seeded into a later test with [`method: Credentials.create`] — see the second example in the class overview.
120
123
  def get(id: nil, rpId: nil)
121
124
  wrap_impl(@impl.get(id: unwrap_impl(id), rpId: unwrap_impl(rpId)))
@@ -31,6 +31,12 @@ module Playwright
31
31
  # ```
32
32
  class Frame < PlaywrightApi
33
33
 
34
+ #
35
+ # Tools that the frame registers through the experimental `WebMCP` browser API. See `WebMCP` for details.
36
+ def webmcp # property
37
+ wrap_impl(@impl.webmcp)
38
+ end
39
+
34
40
  #
35
41
  # Returns the added tag when the script's onload fires or when the script content was injected into frame.
36
42
  #
@@ -103,8 +109,8 @@ module Playwright
103
109
 
104
110
  #
105
111
  # Gets the full HTML contents of the frame, including the doctype.
106
- def content
107
- wrap_impl(@impl.content)
112
+ def content(includeShadow: nil)
113
+ wrap_impl(@impl.content(includeShadow: unwrap_impl(includeShadow)))
108
114
  end
109
115
 
110
116
  #
@@ -961,6 +961,26 @@ module Playwright
961
961
  #
962
962
  # Returns a new locator that uses best practices for referencing the matched element, prioritizing test ids,
963
963
  # aria roles, and other user-facing attributes over CSS selectors. This is useful for converting implementation-detail selectors into more resilient, human-readable locators.
964
+ #
965
+ # **Usage**
966
+ #
967
+ # An agent can pick an element by its ref from an [`method: Page.ariaSnapshot`] taken in the `"ai"` mode. Refs only
968
+ # work for the latest snapshot. Normalize the ref locator and convert it to a string to get resilient locator code
969
+ # in your language, the same way `codegen` does.
970
+ #
971
+ # Consider the following aria snapshot.
972
+ #
973
+ # ```yaml
974
+ # - button "Submit" [ref=e2]
975
+ # ```
976
+ #
977
+ # You can turn the ref into locator code:
978
+ #
979
+ # ```python sync
980
+ # normalized = page.get_by_ref("e2").normalize()
981
+ # print(str(normalized))
982
+ # # get_by_role("button", name="Submit")
983
+ # ```
964
984
  def normalize
965
985
  wrap_impl(@impl.normalize)
966
986
  end
@@ -1376,9 +1396,19 @@ module Playwright
1376
1396
  wrap_impl(@impl.wait_for_function(unwrap_impl(expression), arg: unwrap_impl(arg), timeout: unwrap_impl(timeout)))
1377
1397
  end
1378
1398
 
1379
- # @nodoc
1380
- def expect(expression, options, title)
1381
- wrap_impl(@impl.expect(unwrap_impl(expression), unwrap_impl(options), unwrap_impl(title)))
1399
+ #
1400
+ # Returns a locator that matches this locator's elements inside each element matched by `locator`.
1401
+ #
1402
+ # Note that relative locators, such as [`method: Locator.nth`] or [`method: 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.
1403
+ #
1404
+ # **Usage**
1405
+ #
1406
+ # ```python sync
1407
+ # third_column = page.get_by_role("cell").nth(2).within(page.get_by_role("row"))
1408
+ # expect(third_column).to_have_text(["Apple", "Banana", "Cherry"])
1409
+ # ```
1410
+ def within(locator)
1411
+ wrap_impl(@impl.within(unwrap_impl(locator)))
1382
1412
  end
1383
1413
 
1384
1414
  # @nodoc
@@ -1391,6 +1421,11 @@ module Playwright
1391
1421
  wrap_impl(@impl.resolve_selector)
1392
1422
  end
1393
1423
 
1424
+ # @nodoc
1425
+ def expect(expression, options, title)
1426
+ wrap_impl(@impl.expect(unwrap_impl(expression), unwrap_impl(options), unwrap_impl(title)))
1427
+ end
1428
+
1394
1429
  # @nodoc
1395
1430
  def to_s
1396
1431
  wrap_impl(@impl.to_s)
@@ -88,6 +88,14 @@ module Playwright
88
88
  wrap_impl(@impl.touchscreen)
89
89
  end
90
90
 
91
+ #
92
+ # Tools that the main frame registers through the experimental `WebMCP` browser API. Shortcut for [`property: Frame.webmcp`] of [`method: Page.mainFrame`], see `WebMCP` for details.
93
+ #
94
+ # **Usage**
95
+ def webmcp # property
96
+ wrap_impl(@impl.webmcp)
97
+ end
98
+
91
99
  #
92
100
  # Adds a script which would be evaluated in one of the following scenarios:
93
101
  # - Whenever the page is navigated.
@@ -201,8 +209,8 @@ module Playwright
201
209
 
202
210
  #
203
211
  # Gets the full HTML contents of the page, including the doctype.
204
- def content
205
- wrap_impl(@impl.content)
212
+ def content(includeShadow: nil)
213
+ wrap_impl(@impl.content(includeShadow: unwrap_impl(includeShadow)))
206
214
  end
207
215
 
208
216
  #
@@ -687,6 +695,27 @@ module Playwright
687
695
  wrap_impl(@impl.get_by_placeholder(unwrap_impl(text), exact: unwrap_impl(exact)))
688
696
  end
689
697
 
698
+ #
699
+ # Locate element by its aria ref. Refs like `[ref=e2]` are reported by [`method: Page.ariaSnapshot`] when called with
700
+ # the `"ai"` mode, and resolve against the latest snapshot taken in the element's frame.
701
+ #
702
+ # **Usage**
703
+ #
704
+ # Consider the following aria snapshot.
705
+ #
706
+ # ```yaml
707
+ # - button "Submit" [ref=e2]
708
+ # ```
709
+ #
710
+ # You can locate the button by its ref:
711
+ #
712
+ # ```python sync
713
+ # page.get_by_ref("e2").click()
714
+ # ```
715
+ def get_by_ref(ref)
716
+ wrap_impl(@impl.get_by_ref(unwrap_impl(ref)))
717
+ end
718
+
690
719
  #
691
720
  # Allows locating elements by their [ARIA role](https://www.w3.org/TR/wai-aria-1.2/#roles), [ARIA attributes](https://www.w3.org/TR/wai-aria-1.2/#aria-attributes) and [accessible name](https://w3c.github.io/accname/#dfn-accessible-name).
692
721
  #
@@ -1906,8 +1935,8 @@ module Playwright
1906
1935
  end
1907
1936
 
1908
1937
  # @nodoc
1909
- def stop_js_coverage
1910
- wrap_impl(@impl.stop_js_coverage)
1938
+ def snapshot_for_ai(timeout: nil, depth: nil, boxes: nil)
1939
+ wrap_impl(@impl.snapshot_for_ai(timeout: unwrap_impl(timeout), depth: unwrap_impl(depth), boxes: unwrap_impl(boxes)))
1911
1940
  end
1912
1941
 
1913
1942
  # @nodoc
@@ -1916,13 +1945,8 @@ module Playwright
1916
1945
  end
1917
1946
 
1918
1947
  # @nodoc
1919
- def start_css_coverage(resetOnNavigation: nil, reportAnonymousScripts: nil)
1920
- wrap_impl(@impl.start_css_coverage(resetOnNavigation: unwrap_impl(resetOnNavigation), reportAnonymousScripts: unwrap_impl(reportAnonymousScripts)))
1921
- end
1922
-
1923
- # @nodoc
1924
- def snapshot_for_ai(timeout: nil, depth: nil, boxes: nil)
1925
- wrap_impl(@impl.snapshot_for_ai(timeout: unwrap_impl(timeout), depth: unwrap_impl(depth), boxes: unwrap_impl(boxes)))
1948
+ def stop_js_coverage
1949
+ wrap_impl(@impl.stop_js_coverage)
1926
1950
  end
1927
1951
 
1928
1952
  # @nodoc
@@ -1935,6 +1959,11 @@ module Playwright
1935
1959
  wrap_impl(@impl._assertions(unwrap_impl(timeout), unwrap_impl(is_not), unwrap_impl(message)))
1936
1960
  end
1937
1961
 
1962
+ # @nodoc
1963
+ def start_css_coverage(resetOnNavigation: nil, reportAnonymousScripts: nil)
1964
+ wrap_impl(@impl.start_css_coverage(resetOnNavigation: unwrap_impl(resetOnNavigation), reportAnonymousScripts: unwrap_impl(reportAnonymousScripts)))
1965
+ end
1966
+
1938
1967
  # @nodoc
1939
1968
  def guid
1940
1969
  wrap_impl(@impl.guid)
@@ -155,7 +155,7 @@ module Playwright
155
155
  #
156
156
  # Contains the request's resource type as it was perceived by the rendering engine. ResourceType will be one of the
157
157
  # following: `document`, `stylesheet`, `image`, `media`, `font`, `script`, `texttrack`, `xhr`, `fetch`, `eventsource`,
158
- # `websocket`, `manifest`, `other`.
158
+ # `websocket`, `manifest`, `beacon`, `ping`, `cspreport`, `other`.
159
159
  def resource_type
160
160
  wrap_impl(@impl.resource_type)
161
161
  end
@@ -218,13 +218,13 @@ module Playwright
218
218
  end
219
219
 
220
220
  # @nodoc
221
- def header_values(name)
222
- wrap_impl(@impl.header_values(unwrap_impl(name)))
221
+ def apply_fallback_overrides(overrides)
222
+ wrap_impl(@impl.apply_fallback_overrides(unwrap_impl(overrides)))
223
223
  end
224
224
 
225
225
  # @nodoc
226
- def apply_fallback_overrides(overrides)
227
- wrap_impl(@impl.apply_fallback_overrides(unwrap_impl(overrides)))
226
+ def header_values(name)
227
+ wrap_impl(@impl.header_values(unwrap_impl(name)))
228
228
  end
229
229
 
230
230
  # -- inherited from EventEmitter --
@@ -42,8 +42,9 @@ module Playwright
42
42
  end
43
43
 
44
44
  #
45
- # An array with all the request HTTP headers associated with this response. Unlike [`method: Response.allHeaders`], header names are NOT lower-cased.
45
+ # An array with all the response HTTP headers associated with this response. Unlike [`method: Response.allHeaders`], header names are NOT lower-cased.
46
46
  # Headers with multiple entries, such as `Set-Cookie`, appear in the array multiple times.
47
+ # Some browser network stacks combine multiple field values before reporting them, so separate entries are not always available.
47
48
  def headers_array
48
49
  wrap_impl(@impl.headers_array)
49
50
  end
@@ -19,7 +19,7 @@ module Playwright
19
19
  class Tracing < PlaywrightApi
20
20
 
21
21
  #
22
- # Start tracing.
22
+ # Start tracing. Disposing the returned `Disposable` stops tracing without saving the trace, similarly to calling [`method: Tracing.stop`] without a path.
23
23
  #
24
24
  # **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`.
25
25
  #
@@ -46,7 +46,7 @@ module Playwright
46
46
  end
47
47
 
48
48
  #
49
- # Start a new trace chunk. If you'd like to record multiple traces on the same `BrowserContext`, use [`method: Tracing.start`] once, and then create multiple trace chunks with [`method: Tracing.startChunk`] and [`method: Tracing.stopChunk`].
49
+ # Start a new trace chunk. Disposing the returned `Disposable` stops the chunk without saving it, similarly to calling [`method: Tracing.stopChunk`] without a path. If you'd like to record multiple traces on the same `BrowserContext`, use [`method: Tracing.start`] once, and then create multiple trace chunks with [`method: Tracing.startChunk`] and [`method: Tracing.stopChunk`].
50
50
  #
51
51
  # **Usage**
52
52
  #