playwright-ruby-client 1.26.0 → 1.28.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 (56) hide show
  1. checksums.yaml +4 -4
  2. data/documentation/docs/api/api_request_context.md +86 -0
  3. data/documentation/docs/api/browser_context.md +3 -3
  4. data/documentation/docs/api/download.md +1 -1
  5. data/documentation/docs/api/element_handle.md +2 -1
  6. data/documentation/docs/api/file_chooser.md +1 -1
  7. data/documentation/docs/api/frame.md +151 -4
  8. data/documentation/docs/api/frame_locator.md +151 -4
  9. data/documentation/docs/api/js_handle.md +5 -3
  10. data/documentation/docs/api/keyboard.md +1 -1
  11. data/documentation/docs/api/locator.md +191 -6
  12. data/documentation/docs/api/page.md +166 -9
  13. data/documentation/docs/api/request.md +1 -1
  14. data/documentation/docs/api/tracing.md +1 -1
  15. data/documentation/docs/article/guides/rails_integration.md +1 -0
  16. data/documentation/docs/article/guides/rails_integration_with_null_driver.md +59 -0
  17. data/documentation/docs/include/api_coverage.md +32 -0
  18. data/lib/playwright/channel_owner.rb +41 -0
  19. data/lib/playwright/channel_owners/browser_context.rb +6 -0
  20. data/lib/playwright/channel_owners/element_handle.rb +8 -1
  21. data/lib/playwright/channel_owners/frame.rb +6 -0
  22. data/lib/playwright/channel_owners/page.rb +25 -28
  23. data/lib/playwright/channel_owners/selectors.rb +4 -0
  24. data/lib/playwright/connection.rb +4 -1
  25. data/lib/playwright/frame_locator_impl.rb +6 -2
  26. data/lib/playwright/locator_impl.rb +21 -31
  27. data/lib/playwright/locator_utils.rb +136 -0
  28. data/lib/playwright/utils.rb +6 -0
  29. data/lib/playwright/version.rb +2 -2
  30. data/lib/playwright_api/android.rb +12 -6
  31. data/lib/playwright_api/android_device.rb +6 -6
  32. data/lib/playwright_api/api_request_context.rb +86 -8
  33. data/lib/playwright_api/browser.rb +6 -6
  34. data/lib/playwright_api/browser_context.rb +9 -9
  35. data/lib/playwright_api/browser_type.rb +6 -6
  36. data/lib/playwright_api/cdp_session.rb +6 -6
  37. data/lib/playwright_api/console_message.rb +6 -6
  38. data/lib/playwright_api/dialog.rb +6 -6
  39. data/lib/playwright_api/download.rb +1 -1
  40. data/lib/playwright_api/element_handle.rb +9 -8
  41. data/lib/playwright_api/file_chooser.rb +1 -1
  42. data/lib/playwright_api/frame.rb +119 -11
  43. data/lib/playwright_api/frame_locator.rb +113 -5
  44. data/lib/playwright_api/js_handle.rb +7 -7
  45. data/lib/playwright_api/keyboard.rb +1 -1
  46. data/lib/playwright_api/locator.rb +145 -6
  47. data/lib/playwright_api/page.rb +133 -16
  48. data/lib/playwright_api/playwright.rb +6 -6
  49. data/lib/playwright_api/request.rb +9 -9
  50. data/lib/playwright_api/response.rb +8 -8
  51. data/lib/playwright_api/route.rb +6 -6
  52. data/lib/playwright_api/selectors.rb +14 -3
  53. data/lib/playwright_api/tracing.rb +7 -7
  54. data/lib/playwright_api/web_socket.rb +6 -6
  55. data/lib/playwright_api/worker.rb +8 -8
  56. metadata +5 -4
@@ -36,6 +36,7 @@ module Playwright
36
36
  @type = type
37
37
  @guid = guid
38
38
  @initializer = initializer
39
+ @event_to_subscription_mapping = {}
39
40
 
40
41
  after_initialize
41
42
  end
@@ -59,6 +60,46 @@ module Playwright
59
60
  @objects.clear
60
61
  end
61
62
 
63
+ private def set_event_to_subscription_mapping(event_to_subscription_mapping)
64
+ @event_to_subscription_mapping = event_to_subscription_mapping
65
+ end
66
+
67
+ private def update_subscription(event, enabled)
68
+ protocol_event = @event_to_subscription_mapping[event]
69
+ if protocol_event
70
+ payload = {
71
+ event: protocol_event,
72
+ enabled: enabled,
73
+ }
74
+ @channel.async_send_message_to_server('updateSubscription', payload)
75
+ end
76
+ end
77
+
78
+ # @override
79
+ def on(event, callback)
80
+ if listener_count(event) == 0
81
+ update_subscription(event, true)
82
+ end
83
+ super
84
+ end
85
+
86
+ # @override
87
+ def once(event, callback)
88
+ if listener_count(event) == 0
89
+ update_subscription(event, true)
90
+ end
91
+ super
92
+ end
93
+
94
+ # @override
95
+ def off(event, callback)
96
+ super
97
+ if listener_count(event) == 0
98
+ update_subscription(event, false)
99
+ end
100
+ end
101
+
102
+
62
103
  # Suppress long long inspect log and avoid RSpec from hanging up...
63
104
  def inspect
64
105
  to_s
@@ -58,6 +58,12 @@ module Playwright
58
58
  ChannelOwners::Page.from_nullable(params['page']),
59
59
  )
60
60
  })
61
+ set_event_to_subscription_mapping({
62
+ Events::BrowserContext::Request => "request",
63
+ Events::BrowserContext::Response => "response",
64
+ Events::BrowserContext::RequestFinished => "requestFinished",
65
+ Events::BrowserContext::RequestFailed => "requestFailed",
66
+ })
61
67
 
62
68
  @closed_promise = Concurrent::Promises.resolvable_future
63
69
  end
@@ -76,10 +76,17 @@ module Playwright
76
76
  nil
77
77
  end
78
78
 
79
- def hover(force: nil, modifiers: nil, position: nil, timeout: nil, trial: nil)
79
+ def hover(
80
+ force: nil,
81
+ modifiers: nil,
82
+ noWaitAfter: nil,
83
+ position: nil,
84
+ timeout: nil,
85
+ trial: nil)
80
86
  params = {
81
87
  force: force,
82
88
  modifiers: modifiers,
89
+ noWaitAfter: noWaitAfter,
83
90
  position: position,
84
91
  timeout: timeout,
85
92
  trial: trial,
@@ -1,6 +1,10 @@
1
+ require_relative '../locator_utils'
2
+
1
3
  module Playwright
2
4
  # @ref https://github.com/microsoft/playwright-python/blob/master/playwright/_impl/_frame.py
3
5
  define_channel_owner :Frame do
6
+ include LocatorUtils
7
+
4
8
  private def after_initialize
5
9
  if @initializer['parentFrame']
6
10
  @parent_frame = ChannelOwners::Frame.from(@initializer['parentFrame'])
@@ -457,6 +461,7 @@ module Playwright
457
461
  selector,
458
462
  force: nil,
459
463
  modifiers: nil,
464
+ noWaitAfter: nil,
460
465
  position: nil,
461
466
  strict: nil,
462
467
  timeout: nil,
@@ -465,6 +470,7 @@ module Playwright
465
470
  selector: selector,
466
471
  force: force,
467
472
  modifiers: modifiers,
473
+ noWaitAfter: noWaitAfter,
468
474
  position: position,
469
475
  strict: strict,
470
476
  timeout: timeout,
@@ -1,11 +1,14 @@
1
1
  require 'base64'
2
+ require_relative '../locator_utils'
2
3
 
3
4
  module Playwright
4
5
  # @ref https://github.com/microsoft/playwright-python/blob/master/playwright/_impl/_page.py
5
6
  define_channel_owner :Page do
6
7
  include Utils::Errors::SafeCloseError
8
+ include LocatorUtils
7
9
  attr_writer :owned_context
8
10
 
11
+
9
12
  private def after_initialize
10
13
  @browser_context = @parent
11
14
  @timeout_settings = TimeoutSettings.new(@browser_context.send(:_timeout_settings))
@@ -71,6 +74,14 @@ module Playwright
71
74
  worker = ChannelOwners::Worker.from(params['worker'])
72
75
  on_worker(worker)
73
76
  })
77
+
78
+ set_event_to_subscription_mapping({
79
+ Events::Page::Request => "request",
80
+ Events::Page::Response => "response",
81
+ Events::Page::RequestFinished => "requestFinished",
82
+ Events::Page::RequestFailed => "requestFailed",
83
+ Events::Page::FileChooser => "fileChooser",
84
+ })
74
85
  end
75
86
 
76
87
  attr_reader \
@@ -167,30 +178,6 @@ module Playwright
167
178
  video.send(:set_artifact, artifact)
168
179
  end
169
180
 
170
- # @override
171
- def on(event, callback)
172
- if event == Events::Page::FileChooser && listener_count(event) == 0
173
- @channel.async_send_message_to_server('setFileChooserInterceptedNoReply', intercepted: true)
174
- end
175
- super
176
- end
177
-
178
- # @override
179
- def once(event, callback)
180
- if event == Events::Page::FileChooser && listener_count(event) == 0
181
- @channel.async_send_message_to_server('setFileChooserInterceptedNoReply', intercepted: true)
182
- end
183
- super
184
- end
185
-
186
- # @override
187
- def off(event, callback)
188
- super
189
- if event == Events::Page::FileChooser && listener_count(event) == 0
190
- @channel.async_send_message_to_server('setFileChooserInterceptedNoReply', intercepted: false)
191
- end
192
- end
193
-
194
181
  def context
195
182
  @browser_context
196
183
  end
@@ -364,16 +351,24 @@ module Playwright
364
351
 
365
352
  def emulate_media(colorScheme: nil, forcedColors: nil, media: nil, reducedMotion: nil)
366
353
  params = {
367
- colorScheme: colorScheme,
368
- forcedColors: forcedColors,
369
- media: media,
370
- reducedMotion: reducedMotion,
354
+ colorScheme: no_override_if_null(colorScheme),
355
+ forcedColors: no_override_if_null(forcedColors),
356
+ media: no_override_if_null(media),
357
+ reducedMotion: no_override_if_null(reducedMotion),
371
358
  }.compact
372
359
  @channel.send_message_to_server('emulateMedia', params)
373
360
 
374
361
  nil
375
362
  end
376
363
 
364
+ private def no_override_if_null(target)
365
+ if target == 'null'
366
+ 'no-override'
367
+ else
368
+ target
369
+ end
370
+ end
371
+
377
372
  def set_viewport_size(viewportSize)
378
373
  @viewport_size = viewportSize
379
374
  @channel.send_message_to_server('setViewportSize', { viewportSize: viewportSize })
@@ -635,6 +630,7 @@ module Playwright
635
630
  selector,
636
631
  force: nil,
637
632
  modifiers: nil,
633
+ noWaitAfter: nil,
638
634
  position: nil,
639
635
  strict: nil,
640
636
  timeout: nil,
@@ -643,6 +639,7 @@ module Playwright
643
639
  selector,
644
640
  force: force,
645
641
  modifiers: modifiers,
642
+ noWaitAfter: noWaitAfter,
646
643
  position: position,
647
644
  strict: strict,
648
645
  timeout: timeout,
@@ -18,5 +18,9 @@ module Playwright
18
18
 
19
19
  nil
20
20
  end
21
+
22
+ def text_id_attribute=(attribute_name)
23
+ ::Playwright::LocatorUtils.instance_variable_set(:@test_id_attribute_name, attribute_name)
24
+ end
21
25
  end
22
26
  end
@@ -43,7 +43,10 @@ module Playwright
43
43
  end
44
44
 
45
45
  def initialize_playwright
46
- result = send_message_to_server('', 'initialize', { sdkLanguage: 'ruby' })
46
+ # Avoid Error: sdkLanguage: expected one of (javascript|python|java|csharp)
47
+ # ref: https://github.com/microsoft/playwright/pull/18308
48
+ # ref: https://github.com/YusukeIwaki/playwright-ruby-client/issues/228
49
+ result = send_message_to_server('', 'initialize', { sdkLanguage: 'python' })
47
50
  ChannelOwners::Playwright.from(result['playwright'])
48
51
  end
49
52
 
@@ -1,5 +1,9 @@
1
+ require_relative './locator_utils'
2
+
1
3
  module Playwright
2
4
  define_api_implementation :FrameLocatorImpl do
5
+ include LocatorUtils
6
+
3
7
  def initialize(frame:, timeout_settings:, frame_selector:)
4
8
  @frame = frame
5
9
  @timeout_settings = timeout_settings
@@ -10,7 +14,7 @@ module Playwright
10
14
  LocatorImpl.new(
11
15
  frame: @frame,
12
16
  timeout_settings: @timeout_settings,
13
- selector: "#{@frame_selector} >> control=enter-frame >> #{selector}",
17
+ selector: "#{@frame_selector} >> internal:control=enter-frame >> #{selector}",
14
18
  hasText: hasText,
15
19
  has: has,
16
20
  )
@@ -20,7 +24,7 @@ module Playwright
20
24
  FrameLocatorImpl.new(
21
25
  frame: @frame,
22
26
  timeout_settings: @timeout_settings,
23
- frame_selector: "#{@frame_selector} >> control=enter-frame >> #{selector}",
27
+ frame_selector: "#{@frame_selector} >> internal:control=enter-frame >> #{selector}",
24
28
  )
25
29
  end
26
30
 
@@ -1,49 +1,24 @@
1
1
  require 'json'
2
+ require_relative './locator_utils'
2
3
 
3
4
  module Playwright
4
- class EscapeWithQuotes
5
- def initialize(text, char = "'")
6
- stringified = text.to_json
7
- escaped_text = stringified[1...-1].gsub(/\\"/, '"')
8
-
9
- case char
10
- when '"'
11
- text = escaped_text.gsub(/["]/, '\\"')
12
- @text = "\"#{text}\""
13
- when "'"
14
- text = escaped_text.gsub(/[']/, '\\\'')
15
- @text = "'#{text}'"
16
- else
17
- raise ArgumentError.new('Invalid escape char')
18
- end
19
- end
20
-
21
- def to_s
22
- @text
23
- end
24
- end
25
-
26
5
  define_api_implementation :LocatorImpl do
6
+ include LocatorUtils
7
+
27
8
  def initialize(frame:, timeout_settings:, selector:, hasText: nil, has: nil)
28
9
  @frame = frame
29
10
  @timeout_settings = timeout_settings
30
11
  selector_scopes = [selector]
31
12
 
32
- case hasText
33
- when Regexp
34
- regex = JavaScript::Regex.new(hasText)
35
- source = EscapeWithQuotes.new(regex.source, '"')
36
- selector_scopes << "has=#{"text=/#{regex.source}/#{regex.flag}".to_json}"
37
- when String
38
- text = EscapeWithQuotes.new(hasText, '"')
39
- selector_scopes << ":scope:has-text(#{text})"
13
+ if hasText
14
+ selector_scopes << "internal:has-text=#{escape_for_text_selector(hasText, false)}"
40
15
  end
41
16
 
42
17
  if has
43
18
  unless same_frame?(has)
44
19
  raise DifferentFrameError.new
45
20
  end
46
- selector_scopes << "has=#{has.send(:selector_json)}"
21
+ selector_scopes << "internal:has=#{has.send(:selector_json)}"
47
22
  end
48
23
 
49
24
  @selector = selector_scopes.join(' >> ')
@@ -211,6 +186,10 @@ module Playwright
211
186
  @frame.fill(@selector, value, strict: true, force: force, noWaitAfter: noWaitAfter, timeout: timeout)
212
187
  end
213
188
 
189
+ def clear(force: nil, noWaitAfter: nil, timeout: nil)
190
+ @frame.fill(@selector, '', strict: true, force: force, noWaitAfter: noWaitAfter, timeout: timeout)
191
+ end
192
+
214
193
  def locator(selector, hasText: nil, has: nil)
215
194
  LocatorImpl.new(
216
195
  frame: @frame,
@@ -275,6 +254,15 @@ module Playwright
275
254
  @frame.focus(@selector, strict: true, timeout: timeout)
276
255
  end
277
256
 
257
+ def blur(timeout: nil)
258
+ params = {
259
+ selector: @selector,
260
+ strict: true,
261
+ timeout: timeout,
262
+ }.compact
263
+ @frame.channel.send_message_to_server('blur', params)
264
+ end
265
+
278
266
  def count
279
267
  @frame.eval_on_selector_all(@selector, 'ee => ee.length')
280
268
  end
@@ -286,6 +274,7 @@ module Playwright
286
274
  def hover(
287
275
  force: nil,
288
276
  modifiers: nil,
277
+ noWaitAfter: nil,
289
278
  position: nil,
290
279
  timeout: nil,
291
280
  trial: nil)
@@ -293,6 +282,7 @@ module Playwright
293
282
  strict: true,
294
283
  force: force,
295
284
  modifiers: modifiers,
285
+ noWaitAfter: noWaitAfter,
296
286
  position: position,
297
287
  timeout: timeout,
298
288
  trial: trial)
@@ -0,0 +1,136 @@
1
+ require 'json'
2
+
3
+ module Playwright
4
+ module LocatorUtils
5
+ def get_by_test_id(test_id)
6
+ test_id_attribute_name = ::Playwright::LocatorUtils.instance_variable_get(:@test_id_attribute_name)
7
+ locator(get_by_test_id_selector(test_id_attribute_name, test_id))
8
+ end
9
+
10
+ def get_by_alt_text(text, exact: false)
11
+ locator(get_by_alt_text_selector(text, exact: exact))
12
+ end
13
+
14
+ def get_by_label(text, exact: false)
15
+ locator(get_by_label_selector(text, exact: exact))
16
+ end
17
+
18
+ def get_by_placeholder(text, exact: false)
19
+ locator(get_by_placeholder_selector(text, exact: exact))
20
+ end
21
+
22
+ def get_by_text(text, exact: false)
23
+ locator(get_by_text_selector(text, exact: exact))
24
+ end
25
+
26
+ def get_by_title(text, exact: false)
27
+ locator(get_by_title_selector(text, exact: exact))
28
+ end
29
+
30
+ def get_by_role(role, **options)
31
+ locator(get_by_role_selector(role, **(options.compact)))
32
+ end
33
+
34
+ # set from Playwright::Selectors#test_id_attribute=
35
+ @test_id_attribute_name = 'data-testid'
36
+
37
+ private def get_by_attribute_text_selector(attr_name, text, exact: false)
38
+ "internal:attr=[#{attr_name}=#{escape_for_attribute_selector_or_regex(text, exact)}]"
39
+ end
40
+
41
+ private def get_by_test_id_selector(test_id_attribute_name, test_id)
42
+ "internal:testid=[#{test_id_attribute_name}=#{escape_for_attribute_selector(test_id, true)}]"
43
+ end
44
+
45
+ private def get_by_label_selector(text, exact:)
46
+ "internal:label=#{escape_for_text_selector(text, exact)}"
47
+ end
48
+
49
+ private def get_by_alt_text_selector(text, exact:)
50
+ get_by_attribute_text_selector('alt', text, exact: exact)
51
+ end
52
+
53
+ private def get_by_title_selector(text, exact:)
54
+ get_by_attribute_text_selector('title', text, exact: exact)
55
+ end
56
+
57
+ private def get_by_placeholder_selector(text, exact:)
58
+ get_by_attribute_text_selector('placeholder', text, exact: exact)
59
+ end
60
+
61
+ private def get_by_text_selector(text, exact:)
62
+ "internal:text=#{escape_for_text_selector(text, exact)}"
63
+ end
64
+
65
+ private def get_by_role_selector(role, **options)
66
+ props = []
67
+
68
+ ex = {
69
+ includeHidden: -> (value) { ['include-hidden', value.to_s] },
70
+ name: -> (value) { ['name', escape_for_attribute_selector_or_regex(value, options[:exact])]},
71
+ }
72
+
73
+ %i[
74
+ checked
75
+ disabled
76
+ selected
77
+ expanded
78
+ includeHidden
79
+ level
80
+ name
81
+ pressed
82
+ ].each do |attr_name|
83
+ if options.key?(attr_name)
84
+ attr_value = options[attr_name]
85
+ props << (ex[attr_name]&.call(attr_value) || [attr_name, attr_value.to_s])
86
+ end
87
+ end
88
+
89
+ opts = props.map { |k, v| "[#{k}=#{v}]"}.join('')
90
+ "internal:role=#{role}#{opts}"
91
+ end
92
+
93
+ # @param text [String]
94
+ private def escape_for_regex(text)
95
+ text.gsub(/[.*+?^>${}()|\[\]\\]/) { "\\#{$&}" }
96
+ end
97
+
98
+ # @param text [Regexp|String]
99
+ private def escape_for_text_selector(text, exact)
100
+ if text.is_a?(Regexp)
101
+ regex = JavaScript::Regex.new(text)
102
+ return "/#{regex.source}/#{regex.flag}"
103
+ end
104
+
105
+ if exact
106
+ "#{text.to_json}s"
107
+ else
108
+ "#{text.to_json}i"
109
+ end
110
+ end
111
+
112
+ # @param text [Regexp|String]
113
+ private def escape_for_attribute_selector_or_regex(text, exact)
114
+ if text.is_a?(Regexp)
115
+ regex = JavaScript::Regex.new(text)
116
+ "/#{regex.source}/#{regex.flag}"
117
+ else
118
+ escape_for_attribute_selector(text, exact)
119
+ end
120
+ end
121
+
122
+ # @param text [String]
123
+ private def escape_for_attribute_selector(text, exact)
124
+ # TODO: this should actually be
125
+ # cssEscape(value).replace(/\\ /g, ' ')
126
+ # However, our attribute selectors do not conform to CSS parsing spec,
127
+ # so we escape them differently.
128
+ _text = text.gsub(/["]/, '\\"')
129
+ if exact
130
+ "\"#{_text}\""
131
+ else
132
+ "\"#{_text}\"i"
133
+ end
134
+ end
135
+ end
136
+ end
@@ -55,6 +55,12 @@ module Playwright
55
55
  params[:storageState] = JSON.parse(File.read(params[:storageState]))
56
56
  end
57
57
 
58
+ %i[colorScheme reducedMotion forcedColors].each do |key|
59
+ if params[key] == 'null'
60
+ params[key] = 'no-override'
61
+ end
62
+ end
63
+
58
64
  params
59
65
  end
60
66
  end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Playwright
4
- VERSION = '1.26.0'
5
- COMPATIBLE_PLAYWRIGHT_VERSION = '1.26.0'
4
+ VERSION = '1.28.0'
5
+ COMPATIBLE_PLAYWRIGHT_VERSION = '1.28.1'
6
6
  end
@@ -25,6 +25,12 @@ module Playwright
25
25
  # ```
26
26
  class Android < PlaywrightApi
27
27
 
28
+ # This methods attaches Playwright to an existing Android device. Use [`method: Android.launchServer`] to launch a new
29
+ # Android server instance.
30
+ def connect(wsEndpoint, headers: nil, slowMo: nil, timeout: nil)
31
+ raise NotImplementedError.new('connect is not implemented yet.')
32
+ end
33
+
28
34
  # Returns the list of detected Android devices.
29
35
  def devices(host: nil, omitDriverInstall: nil, port: nil)
30
36
  wrap_impl(@impl.devices(host: unwrap_impl(host), omitDriverInstall: unwrap_impl(omitDriverInstall), port: unwrap_impl(port)))
@@ -36,12 +42,6 @@ module Playwright
36
42
  end
37
43
  alias_method :default_timeout=, :set_default_timeout
38
44
 
39
- # -- inherited from EventEmitter --
40
- # @nodoc
41
- def off(event, callback)
42
- event_emitter_proxy.off(event, callback)
43
- end
44
-
45
45
  # -- inherited from EventEmitter --
46
46
  # @nodoc
47
47
  def once(event, callback)
@@ -54,6 +54,12 @@ module Playwright
54
54
  event_emitter_proxy.on(event, callback)
55
55
  end
56
56
 
57
+ # -- inherited from EventEmitter --
58
+ # @nodoc
59
+ def off(event, callback)
60
+ event_emitter_proxy.off(event, callback)
61
+ end
62
+
57
63
  private def event_emitter_proxy
58
64
  @event_emitter_proxy ||= EventEmitterProxy.new(self, @impl)
59
65
  end
@@ -173,12 +173,6 @@ module Playwright
173
173
  wrap_impl(@impl.tap_on(unwrap_impl(selector), duration: unwrap_impl(duration), timeout: unwrap_impl(timeout)))
174
174
  end
175
175
 
176
- # -- inherited from EventEmitter --
177
- # @nodoc
178
- def off(event, callback)
179
- event_emitter_proxy.off(event, callback)
180
- end
181
-
182
176
  # -- inherited from EventEmitter --
183
177
  # @nodoc
184
178
  def once(event, callback)
@@ -191,6 +185,12 @@ module Playwright
191
185
  event_emitter_proxy.on(event, callback)
192
186
  end
193
187
 
188
+ # -- inherited from EventEmitter --
189
+ # @nodoc
190
+ def off(event, callback)
191
+ event_emitter_proxy.off(event, callback)
192
+ end
193
+
194
194
  private def event_emitter_proxy
195
195
  @event_emitter_proxy ||= EventEmitterProxy.new(self, @impl)
196
196
  end