playwright-ruby-client 0.6.6 → 0.8.1

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 (57) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +26 -0
  3. data/documentation/docs/api/browser.md +18 -2
  4. data/documentation/docs/api/browser_context.md +10 -0
  5. data/documentation/docs/api/browser_type.md +1 -0
  6. data/documentation/docs/api/cdp_session.md +41 -1
  7. data/documentation/docs/api/element_handle.md +11 -2
  8. data/documentation/docs/api/experimental/android_device.md +1 -0
  9. data/documentation/docs/api/frame.md +29 -1
  10. data/documentation/docs/api/keyboard.md +11 -20
  11. data/documentation/docs/api/page.md +48 -2
  12. data/documentation/docs/api/response.md +16 -0
  13. data/documentation/docs/api/web_socket.md +37 -0
  14. data/documentation/docs/article/guides/launch_browser.md +2 -0
  15. data/documentation/docs/article/guides/playwright_on_alpine_linux.md +91 -0
  16. data/documentation/docs/article/guides/rails_integration.md +1 -1
  17. data/documentation/docs/article/guides/semi_automation.md +71 -0
  18. data/documentation/docs/include/api_coverage.md +18 -11
  19. data/lib/playwright.rb +36 -3
  20. data/lib/playwright/channel_owners/artifact.rb +4 -0
  21. data/lib/playwright/channel_owners/browser.rb +5 -0
  22. data/lib/playwright/channel_owners/browser_context.rb +12 -3
  23. data/lib/playwright/channel_owners/cdp_session.rb +19 -0
  24. data/lib/playwright/channel_owners/element_handle.rb +11 -4
  25. data/lib/playwright/channel_owners/frame.rb +36 -4
  26. data/lib/playwright/channel_owners/page.rb +45 -16
  27. data/lib/playwright/channel_owners/response.rb +9 -1
  28. data/lib/playwright/channel_owners/web_socket.rb +83 -0
  29. data/lib/playwright/connection.rb +2 -4
  30. data/lib/playwright/download.rb +4 -0
  31. data/lib/playwright/route_handler_entry.rb +3 -2
  32. data/lib/playwright/transport.rb +0 -1
  33. data/lib/playwright/url_matcher.rb +12 -2
  34. data/lib/playwright/version.rb +2 -2
  35. data/lib/playwright/web_socket_client.rb +164 -0
  36. data/lib/playwright/web_socket_transport.rb +104 -0
  37. data/lib/playwright_api/android.rb +6 -6
  38. data/lib/playwright_api/android_device.rb +10 -9
  39. data/lib/playwright_api/browser.rb +17 -11
  40. data/lib/playwright_api/browser_context.rb +7 -7
  41. data/lib/playwright_api/browser_type.rb +8 -7
  42. data/lib/playwright_api/cdp_session.rb +30 -8
  43. data/lib/playwright_api/console_message.rb +6 -6
  44. data/lib/playwright_api/dialog.rb +6 -6
  45. data/lib/playwright_api/element_handle.rb +17 -11
  46. data/lib/playwright_api/frame.rb +30 -9
  47. data/lib/playwright_api/js_handle.rb +6 -6
  48. data/lib/playwright_api/page.rb +39 -18
  49. data/lib/playwright_api/playwright.rb +6 -6
  50. data/lib/playwright_api/request.rb +6 -6
  51. data/lib/playwright_api/response.rb +15 -10
  52. data/lib/playwright_api/route.rb +6 -6
  53. data/lib/playwright_api/selectors.rb +6 -6
  54. data/lib/playwright_api/web_socket.rb +12 -12
  55. data/lib/playwright_api/worker.rb +6 -6
  56. data/playwright.gemspec +2 -1
  57. metadata +37 -18
@@ -1,19 +1,29 @@
1
1
  module Playwright
2
2
  class UrlMatcher
3
3
  # @param url [String|Regexp]
4
- def initialize(url)
4
+ # @param base_url [String|nil]
5
+ def initialize(url, base_url:)
5
6
  @url = url
7
+ @base_url = base_url
6
8
  end
7
9
 
8
10
  def match?(target_url)
9
11
  case @url
10
12
  when String
11
- @url == target_url || File.fnmatch?(@url, target_url)
13
+ joined_url == target_url || File.fnmatch?(@url, target_url)
12
14
  when Regexp
13
15
  @url.match?(target_url)
14
16
  else
15
17
  false
16
18
  end
17
19
  end
20
+
21
+ private def joined_url
22
+ if @base_url && !@url.start_with?('*')
23
+ URI.join(@base_url, @url).to_s
24
+ else
25
+ @url
26
+ end
27
+ end
18
28
  end
19
29
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Playwright
4
- VERSION = '0.6.6'
5
- COMPATIBLE_PLAYWRIGHT_VERSION = '1.12.0'
4
+ VERSION = '0.8.1'
5
+ COMPATIBLE_PLAYWRIGHT_VERSION = '1.13.0'
6
6
  end
@@ -0,0 +1,164 @@
1
+ require 'openssl'
2
+ require 'socket'
3
+
4
+ begin
5
+ require 'websocket/driver'
6
+ rescue LoadError
7
+ raise "websocket-driver is required. Add `gem 'websocket-driver'` to your Gemfile"
8
+ end
9
+
10
+ # ref: https://github.com/rails/rails/blob/master/actioncable/lib/action_cable/connection/client_socket.rb
11
+ # ref: https://github.com/cavalle/chrome_remote/blob/master/lib/chrome_remote/web_socket_client.rb
12
+ module Playwright
13
+ class WebSocketClient
14
+ class SecureSocketFactory
15
+ def initialize(host, port)
16
+ @host = host
17
+ @port = port || 443
18
+ end
19
+
20
+ def create
21
+ tcp_socket = TCPSocket.new(@host, @port)
22
+ OpenSSL::SSL::SSLSocket.new(tcp_socket).tap(&:connect)
23
+ end
24
+ end
25
+
26
+ class DriverImpl # providing #url, #write(string)
27
+ def initialize(url)
28
+ @url = url
29
+
30
+ endpoint = URI.parse(url)
31
+ @socket =
32
+ if endpoint.scheme == 'wss'
33
+ SecureSocketFactory.new(endpoint.host, endpoint.port).create
34
+ else
35
+ TCPSocket.new(endpoint.host, endpoint.port)
36
+ end
37
+ end
38
+
39
+ attr_reader :url
40
+
41
+ def write(data)
42
+ @socket.write(data)
43
+ rescue Errno::EPIPE
44
+ raise EOFError.new('already closed')
45
+ rescue Errno::ECONNRESET
46
+ raise EOFError.new('closed by remote')
47
+ end
48
+
49
+ def readpartial(maxlen = 1024)
50
+ @socket.readpartial(maxlen)
51
+ rescue Errno::ECONNRESET
52
+ raise EOFError.new('closed by remote')
53
+ end
54
+
55
+ def disconnect
56
+ @socket.close
57
+ end
58
+ end
59
+
60
+ STATE_CONNECTING = 0
61
+ STATE_OPENED = 1
62
+ STATE_CLOSING = 2
63
+ STATE_CLOSED = 3
64
+
65
+ def initialize(url:, max_payload_size:)
66
+ @impl = DriverImpl.new(url)
67
+ @driver = ::WebSocket::Driver.client(@impl, max_length: max_payload_size)
68
+
69
+ setup
70
+ end
71
+
72
+ class TransportError < StandardError; end
73
+
74
+ private def setup
75
+ @ready_state = STATE_CONNECTING
76
+ @driver.on(:open) do
77
+ @ready_state = STATE_OPENED
78
+ handle_on_open
79
+ end
80
+ @driver.on(:close) do |event|
81
+ @ready_state = STATE_CLOSED
82
+ handle_on_close(reason: event.reason, code: event.code)
83
+ end
84
+ @driver.on(:error) do |event|
85
+ if !handle_on_error(error_message: event.message)
86
+ raise TransportError.new(event.message)
87
+ end
88
+ end
89
+ @driver.on(:message) do |event|
90
+ handle_on_message(event.data)
91
+ end
92
+ end
93
+
94
+ private def wait_for_data
95
+ @driver.parse(@impl.readpartial)
96
+ end
97
+
98
+ def start
99
+ @driver.start
100
+
101
+ Thread.new do
102
+ wait_for_data until @ready_state >= STATE_CLOSING
103
+ rescue EOFError
104
+ # Google Chrome was gone.
105
+ # We have nothing todo. Just finish polling.
106
+ if @ready_state < STATE_CLOSING
107
+ handle_on_close(reason: 'Going Away', code: 1001)
108
+ end
109
+ end
110
+ end
111
+
112
+ # @param message [String]
113
+ def send_text(message)
114
+ return if @ready_state >= STATE_CLOSING
115
+ @driver.text(message)
116
+ end
117
+
118
+ def close(code: 1000, reason: "")
119
+ return if @ready_state >= STATE_CLOSING
120
+ @ready_state = STATE_CLOSING
121
+ @driver.close(reason, code)
122
+ end
123
+
124
+ def on_open(&block)
125
+ @on_open = block
126
+ end
127
+
128
+ # @param block [Proc(reason: String, code: Numeric)]
129
+ def on_close(&block)
130
+ @on_close = block
131
+ end
132
+
133
+ # @param block [Proc(error_message: String)]
134
+ def on_error(&block)
135
+ @on_error = block
136
+ end
137
+
138
+ def on_message(&block)
139
+ @on_message = block
140
+ end
141
+
142
+ private def handle_on_open
143
+ @on_open&.call
144
+ end
145
+
146
+ private def handle_on_close(reason:, code:)
147
+ @on_close&.call(reason, code)
148
+ @impl.disconnect
149
+ end
150
+
151
+ private def handle_on_error(error_message:)
152
+ return false if @on_error.nil?
153
+
154
+ @on_error.call(error_message)
155
+ true
156
+ end
157
+
158
+ private def handle_on_message(data)
159
+ return if @ready_state != STATE_OPENED
160
+
161
+ @on_message&.call(data)
162
+ end
163
+ end
164
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Playwright
6
+ # ref: https://github.com/microsoft/playwright-python/blob/master/playwright/_impl/_transport.py
7
+ class WebSocketTransport
8
+ # @param ws_endpoint [String] EndpointURL of WebSocket
9
+ def initialize(ws_endpoint:)
10
+ @ws_endpoint = ws_endpoint
11
+ @debug = ENV['DEBUG'].to_s == 'true' || ENV['DEBUG'].to_s == '1'
12
+ end
13
+
14
+ def on_message_received(&block)
15
+ @on_message = block
16
+ end
17
+
18
+ def on_driver_crashed(&block)
19
+ @on_driver_crashed = block
20
+ end
21
+
22
+ class AlreadyDisconnectedError < StandardError ; end
23
+
24
+ # @param message [Hash]
25
+ def send_message(message)
26
+ debug_send_message(message) if @debug
27
+ msg = JSON.dump(message)
28
+
29
+ @ws.send_text(msg)
30
+ rescue Errno::EPIPE, IOError
31
+ raise AlreadyDisconnectedError.new('send_message failed')
32
+ end
33
+
34
+ # Terminate playwright-cli driver.
35
+ def stop
36
+ return unless @ws
37
+
38
+ future = Concurrent::Promises.resolvable_future
39
+
40
+ @ws.on_close do
41
+ future.fulfill(nil)
42
+ end
43
+
44
+ begin
45
+ @ws.close
46
+ rescue EOFError => err
47
+ # ignore EOLError. The connection is already closed.
48
+ future.fulfill(err)
49
+ end
50
+
51
+ # Wait for closed actually.
52
+ future.value!
53
+ end
54
+
55
+ # Start `playwright-cli run-driver`
56
+ #
57
+ # @note This method blocks until playwright-cli exited. Consider using Thread or Future.
58
+ def async_run
59
+ ws = WebSocketClient.new(
60
+ url: @ws_endpoint,
61
+ max_payload_size: 256 * 1024 * 1024, # 256MB
62
+ )
63
+ promise = Concurrent::Promises.resolvable_future
64
+ ws.on_open do
65
+ promise.fulfill(ws)
66
+ end
67
+ ws.on_error do |error_message|
68
+ promise.reject(WebSocketClient::TransportError.new(error_message))
69
+ end
70
+
71
+ # Some messages can be sent just after start, before setting @ws.on_message
72
+ # So set this handler before ws.start.
73
+ ws.on_message do |data|
74
+ handle_on_message(data)
75
+ end
76
+
77
+ ws.start
78
+ @ws = promise.value!
79
+ @ws.on_error do |error|
80
+ puts "[WebSocketTransport] error: #{error}"
81
+ @on_driver_crashed&.call
82
+ end
83
+ rescue Errno::ECONNREFUSED => err
84
+ raise WebSocketClient::TransportError.new(err)
85
+ end
86
+
87
+ private
88
+
89
+ def handle_on_message(data)
90
+ obj = JSON.parse(data)
91
+
92
+ debug_recv_message(obj) if @debug
93
+ @on_message&.call(obj)
94
+ end
95
+
96
+ def debug_send_message(message)
97
+ puts "\x1b[33mSEND>\x1b[0m#{message}"
98
+ end
99
+
100
+ def debug_recv_message(message)
101
+ puts "\x1b[33mRECV>\x1b[0m#{message}"
102
+ end
103
+ end
104
+ end
@@ -25,20 +25,20 @@ module Playwright
25
25
 
26
26
  # -- inherited from EventEmitter --
27
27
  # @nodoc
28
- def once(event, callback)
29
- event_emitter_proxy.once(event, callback)
28
+ def off(event, callback)
29
+ event_emitter_proxy.off(event, callback)
30
30
  end
31
31
 
32
32
  # -- inherited from EventEmitter --
33
33
  # @nodoc
34
- def on(event, callback)
35
- event_emitter_proxy.on(event, callback)
34
+ def once(event, callback)
35
+ event_emitter_proxy.once(event, callback)
36
36
  end
37
37
 
38
38
  # -- inherited from EventEmitter --
39
39
  # @nodoc
40
- def off(event, callback)
41
- event_emitter_proxy.off(event, callback)
40
+ def on(event, callback)
41
+ event_emitter_proxy.on(event, callback)
42
42
  end
43
43
 
44
44
  private def event_emitter_proxy
@@ -40,6 +40,7 @@ module Playwright
40
40
  # Launches Chrome browser on the device, and returns its persistent context.
41
41
  def launch_browser(
42
42
  acceptDownloads: nil,
43
+ baseURL: nil,
43
44
  bypassCSP: nil,
44
45
  colorScheme: nil,
45
46
  command: nil,
@@ -65,7 +66,7 @@ module Playwright
65
66
  userAgent: nil,
66
67
  viewport: nil,
67
68
  &block)
68
- wrap_impl(@impl.launch_browser(acceptDownloads: unwrap_impl(acceptDownloads), bypassCSP: unwrap_impl(bypassCSP), colorScheme: unwrap_impl(colorScheme), command: unwrap_impl(command), deviceScaleFactor: unwrap_impl(deviceScaleFactor), extraHTTPHeaders: unwrap_impl(extraHTTPHeaders), 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), record_har_omit_content: unwrap_impl(record_har_omit_content), record_har_path: unwrap_impl(record_har_path), record_video_dir: unwrap_impl(record_video_dir), record_video_size: unwrap_impl(record_video_size), reducedMotion: unwrap_impl(reducedMotion), screen: unwrap_impl(screen), timezoneId: unwrap_impl(timezoneId), userAgent: unwrap_impl(userAgent), viewport: unwrap_impl(viewport), &wrap_block_call(block)))
69
+ wrap_impl(@impl.launch_browser(acceptDownloads: unwrap_impl(acceptDownloads), baseURL: unwrap_impl(baseURL), bypassCSP: unwrap_impl(bypassCSP), colorScheme: unwrap_impl(colorScheme), command: unwrap_impl(command), deviceScaleFactor: unwrap_impl(deviceScaleFactor), extraHTTPHeaders: unwrap_impl(extraHTTPHeaders), 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), record_har_omit_content: unwrap_impl(record_har_omit_content), record_har_path: unwrap_impl(record_har_path), record_video_dir: unwrap_impl(record_video_dir), record_video_size: unwrap_impl(record_video_size), reducedMotion: unwrap_impl(reducedMotion), screen: unwrap_impl(screen), timezoneId: unwrap_impl(timezoneId), userAgent: unwrap_impl(userAgent), viewport: unwrap_impl(viewport), &wrap_block_call(block)))
69
70
  end
70
71
 
71
72
  # Performs a long tap on the widget defined by `selector`.
@@ -161,14 +162,20 @@ module Playwright
161
162
  raise NotImplementedError.new('web_views is not implemented yet.')
162
163
  end
163
164
 
165
+ # @nodoc
166
+ def tap_on(selector, duration: nil, timeout: nil)
167
+ wrap_impl(@impl.tap_on(unwrap_impl(selector), duration: unwrap_impl(duration), timeout: unwrap_impl(timeout)))
168
+ end
169
+
164
170
  # @nodoc
165
171
  def tree
166
172
  wrap_impl(@impl.tree)
167
173
  end
168
174
 
175
+ # -- inherited from EventEmitter --
169
176
  # @nodoc
170
- def tap_on(selector, duration: nil, timeout: nil)
171
- wrap_impl(@impl.tap_on(unwrap_impl(selector), duration: unwrap_impl(duration), timeout: unwrap_impl(timeout)))
177
+ def off(event, callback)
178
+ event_emitter_proxy.off(event, callback)
172
179
  end
173
180
 
174
181
  # -- inherited from EventEmitter --
@@ -183,12 +190,6 @@ module Playwright
183
190
  event_emitter_proxy.on(event, callback)
184
191
  end
185
192
 
186
- # -- inherited from EventEmitter --
187
- # @nodoc
188
- def off(event, callback)
189
- event_emitter_proxy.off(event, callback)
190
- end
191
-
192
193
  private def event_emitter_proxy
193
194
  @event_emitter_proxy ||= EventEmitterProxy.new(self, @impl)
194
195
  end
@@ -50,7 +50,7 @@ module Playwright
50
50
  #
51
51
  # Returns the newly created browser session.
52
52
  def new_browser_cdp_session
53
- raise NotImplementedError.new('new_browser_cdp_session is not implemented yet.')
53
+ wrap_impl(@impl.new_browser_cdp_session)
54
54
  end
55
55
 
56
56
  # Creates a new browser context. It won't share cookies/cache with other browser contexts.
@@ -65,6 +65,7 @@ module Playwright
65
65
  # ```
66
66
  def new_context(
67
67
  acceptDownloads: nil,
68
+ baseURL: nil,
68
69
  bypassCSP: nil,
69
70
  colorScheme: nil,
70
71
  deviceScaleFactor: nil,
@@ -91,7 +92,7 @@ module Playwright
91
92
  userAgent: nil,
92
93
  viewport: nil,
93
94
  &block)
94
- wrap_impl(@impl.new_context(acceptDownloads: unwrap_impl(acceptDownloads), bypassCSP: unwrap_impl(bypassCSP), colorScheme: unwrap_impl(colorScheme), deviceScaleFactor: unwrap_impl(deviceScaleFactor), extraHTTPHeaders: unwrap_impl(extraHTTPHeaders), 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_omit_content: unwrap_impl(record_har_omit_content), record_har_path: unwrap_impl(record_har_path), record_video_dir: unwrap_impl(record_video_dir), record_video_size: unwrap_impl(record_video_size), reducedMotion: unwrap_impl(reducedMotion), screen: unwrap_impl(screen), storageState: unwrap_impl(storageState), timezoneId: unwrap_impl(timezoneId), userAgent: unwrap_impl(userAgent), viewport: unwrap_impl(viewport), &wrap_block_call(block)))
95
+ wrap_impl(@impl.new_context(acceptDownloads: unwrap_impl(acceptDownloads), baseURL: unwrap_impl(baseURL), bypassCSP: unwrap_impl(bypassCSP), colorScheme: unwrap_impl(colorScheme), deviceScaleFactor: unwrap_impl(deviceScaleFactor), extraHTTPHeaders: unwrap_impl(extraHTTPHeaders), 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_omit_content: unwrap_impl(record_har_omit_content), record_har_path: unwrap_impl(record_har_path), record_video_dir: unwrap_impl(record_video_dir), record_video_size: unwrap_impl(record_video_size), reducedMotion: unwrap_impl(reducedMotion), screen: unwrap_impl(screen), storageState: unwrap_impl(storageState), timezoneId: unwrap_impl(timezoneId), userAgent: unwrap_impl(userAgent), viewport: unwrap_impl(viewport), &wrap_block_call(block)))
95
96
  end
96
97
 
97
98
  # Creates a new page in a new browser context. Closing this page will close the context as well.
@@ -101,6 +102,7 @@ module Playwright
101
102
  # [`method: BrowserContext.newPage`] to control their exact life times.
102
103
  def new_page(
103
104
  acceptDownloads: nil,
105
+ baseURL: nil,
104
106
  bypassCSP: nil,
105
107
  colorScheme: nil,
106
108
  deviceScaleFactor: nil,
@@ -127,10 +129,12 @@ module Playwright
127
129
  userAgent: nil,
128
130
  viewport: nil,
129
131
  &block)
130
- wrap_impl(@impl.new_page(acceptDownloads: unwrap_impl(acceptDownloads), bypassCSP: unwrap_impl(bypassCSP), colorScheme: unwrap_impl(colorScheme), deviceScaleFactor: unwrap_impl(deviceScaleFactor), extraHTTPHeaders: unwrap_impl(extraHTTPHeaders), 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_omit_content: unwrap_impl(record_har_omit_content), record_har_path: unwrap_impl(record_har_path), record_video_dir: unwrap_impl(record_video_dir), record_video_size: unwrap_impl(record_video_size), reducedMotion: unwrap_impl(reducedMotion), screen: unwrap_impl(screen), storageState: unwrap_impl(storageState), timezoneId: unwrap_impl(timezoneId), userAgent: unwrap_impl(userAgent), viewport: unwrap_impl(viewport), &wrap_block_call(block)))
132
+ wrap_impl(@impl.new_page(acceptDownloads: unwrap_impl(acceptDownloads), baseURL: unwrap_impl(baseURL), bypassCSP: unwrap_impl(bypassCSP), colorScheme: unwrap_impl(colorScheme), deviceScaleFactor: unwrap_impl(deviceScaleFactor), extraHTTPHeaders: unwrap_impl(extraHTTPHeaders), 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_omit_content: unwrap_impl(record_har_omit_content), record_har_path: unwrap_impl(record_har_path), record_video_dir: unwrap_impl(record_video_dir), record_video_size: unwrap_impl(record_video_size), reducedMotion: unwrap_impl(reducedMotion), screen: unwrap_impl(screen), storageState: unwrap_impl(storageState), timezoneId: unwrap_impl(timezoneId), userAgent: unwrap_impl(userAgent), viewport: unwrap_impl(viewport), &wrap_block_call(block)))
131
133
  end
132
134
 
133
- # > NOTE: Tracing is only supported on Chromium-based browsers.
135
+ # > NOTE: This API controls [Chromium Tracing](https://www.chromium.org/developers/how-tos/trace-event-profiling-tool)
136
+ # which is a low-level chromium-specific debugging tool. API to control [Playwright Tracing](../trace-viewer) could be
137
+ # found [here](./class-tracing).
134
138
  #
135
139
  # You can use [`method: Browser.startTracing`] and [`method: Browser.stopTracing`] to create a trace file that can be
136
140
  # opened in Chrome DevTools performance panel.
@@ -144,7 +148,9 @@ module Playwright
144
148
  wrap_impl(@impl.start_tracing(page: unwrap_impl(page), categories: unwrap_impl(categories), path: unwrap_impl(path), screenshots: unwrap_impl(screenshots)))
145
149
  end
146
150
 
147
- # > NOTE: Tracing is only supported on Chromium-based browsers.
151
+ # > NOTE: This API controls [Chromium Tracing](https://www.chromium.org/developers/how-tos/trace-event-profiling-tool)
152
+ # which is a low-level chromium-specific debugging tool. API to control [Playwright Tracing](../trace-viewer) could be
153
+ # found [here](./class-tracing).
148
154
  #
149
155
  # Returns the buffer with trace data.
150
156
  def stop_tracing
@@ -158,20 +164,20 @@ module Playwright
158
164
 
159
165
  # -- inherited from EventEmitter --
160
166
  # @nodoc
161
- def once(event, callback)
162
- event_emitter_proxy.once(event, callback)
167
+ def off(event, callback)
168
+ event_emitter_proxy.off(event, callback)
163
169
  end
164
170
 
165
171
  # -- inherited from EventEmitter --
166
172
  # @nodoc
167
- def on(event, callback)
168
- event_emitter_proxy.on(event, callback)
173
+ def once(event, callback)
174
+ event_emitter_proxy.once(event, callback)
169
175
  end
170
176
 
171
177
  # -- inherited from EventEmitter --
172
178
  # @nodoc
173
- def off(event, callback)
174
- event_emitter_proxy.off(event, callback)
179
+ def on(event, callback)
180
+ event_emitter_proxy.on(event, callback)
175
181
  end
176
182
 
177
183
  private def event_emitter_proxy