playwright-ruby-client 0.0.4 → 0.0.9

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 (68) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +120 -6
  3. data/docs/api_coverage.md +351 -0
  4. data/lib/playwright.rb +9 -0
  5. data/lib/playwright/channel_owner.rb +16 -2
  6. data/lib/playwright/channel_owners/android.rb +10 -1
  7. data/lib/playwright/channel_owners/android_device.rb +163 -0
  8. data/lib/playwright/channel_owners/browser.rb +20 -27
  9. data/lib/playwright/channel_owners/browser_context.rb +51 -0
  10. data/lib/playwright/channel_owners/console_message.rb +0 -4
  11. data/lib/playwright/channel_owners/element_handle.rb +306 -0
  12. data/lib/playwright/channel_owners/frame.rb +473 -7
  13. data/lib/playwright/channel_owners/js_handle.rb +51 -0
  14. data/lib/playwright/channel_owners/page.rb +589 -4
  15. data/lib/playwright/channel_owners/request.rb +98 -0
  16. data/lib/playwright/channel_owners/webkit_browser.rb +1 -1
  17. data/lib/playwright/connection.rb +15 -14
  18. data/lib/playwright/errors.rb +1 -1
  19. data/lib/playwright/event_emitter.rb +17 -1
  20. data/lib/playwright/http_headers.rb +20 -0
  21. data/lib/playwright/input_files.rb +42 -0
  22. data/lib/playwright/input_type.rb +19 -0
  23. data/lib/playwright/input_types/android_input.rb +19 -0
  24. data/lib/playwright/input_types/keyboard.rb +32 -0
  25. data/lib/playwright/input_types/mouse.rb +4 -0
  26. data/lib/playwright/input_types/touchscreen.rb +4 -0
  27. data/lib/playwright/javascript.rb +13 -0
  28. data/lib/playwright/javascript/expression.rb +67 -0
  29. data/lib/playwright/javascript/function.rb +67 -0
  30. data/lib/playwright/javascript/value_parser.rb +75 -0
  31. data/lib/playwright/javascript/value_serializer.rb +54 -0
  32. data/lib/playwright/playwright_api.rb +45 -25
  33. data/lib/playwright/select_option_values.rb +32 -0
  34. data/lib/playwright/timeout_settings.rb +19 -0
  35. data/lib/playwright/url_matcher.rb +19 -0
  36. data/lib/playwright/utils.rb +37 -0
  37. data/lib/playwright/version.rb +1 -1
  38. data/lib/playwright/wait_helper.rb +73 -0
  39. data/lib/playwright_api/accessibility.rb +46 -6
  40. data/lib/playwright_api/android.rb +33 -0
  41. data/lib/playwright_api/android_device.rb +78 -0
  42. data/lib/playwright_api/android_input.rb +25 -0
  43. data/lib/playwright_api/binding_call.rb +18 -0
  44. data/lib/playwright_api/browser.rb +93 -12
  45. data/lib/playwright_api/browser_context.rb +279 -28
  46. data/lib/playwright_api/browser_type.rb +68 -5
  47. data/lib/playwright_api/cdp_session.rb +23 -1
  48. data/lib/playwright_api/chromium_browser_context.rb +26 -0
  49. data/lib/playwright_api/console_message.rb +20 -7
  50. data/lib/playwright_api/dialog.rb +48 -2
  51. data/lib/playwright_api/download.rb +19 -4
  52. data/lib/playwright_api/element_handle.rb +278 -104
  53. data/lib/playwright_api/file_chooser.rb +20 -3
  54. data/lib/playwright_api/frame.rb +452 -147
  55. data/lib/playwright_api/js_handle.rb +78 -19
  56. data/lib/playwright_api/keyboard.rb +99 -9
  57. data/lib/playwright_api/mouse.rb +22 -0
  58. data/lib/playwright_api/page.rb +864 -222
  59. data/lib/playwright_api/playwright.rb +116 -14
  60. data/lib/playwright_api/request.rb +86 -24
  61. data/lib/playwright_api/response.rb +18 -7
  62. data/lib/playwright_api/route.rb +49 -0
  63. data/lib/playwright_api/selectors.rb +28 -2
  64. data/lib/playwright_api/video.rb +8 -0
  65. data/lib/playwright_api/web_socket.rb +0 -8
  66. data/lib/playwright_api/worker.rb +25 -13
  67. data/playwright.gemspec +3 -0
  68. metadata +66 -2
@@ -14,6 +14,39 @@ module Playwright
14
14
  # await browser.close();
15
15
  # })();
16
16
  # ```
17
+ #
18
+ # ```python async
19
+ # import asyncio
20
+ # from playwright.async_api import async_playwright
21
+ #
22
+ # async def run(playwright):
23
+ # chromium = playwright.chromium
24
+ # browser = await chromium.launch()
25
+ # page = await browser.new_page()
26
+ # await page.goto("https://example.com")
27
+ # # other actions...
28
+ # await browser.close()
29
+ #
30
+ # async def main():
31
+ # async with async_playwright() as playwright:
32
+ # await run(playwright)
33
+ # asyncio.run(main())
34
+ # ```
35
+ #
36
+ # ```python sync
37
+ # from playwright.sync_api import sync_playwright
38
+ #
39
+ # def run(playwright):
40
+ # chromium = playwright.chromium
41
+ # browser = chromium.launch()
42
+ # page = browser.new_page()
43
+ # page.goto("https://example.com")
44
+ # # other actions...
45
+ # browser.close()
46
+ #
47
+ # with sync_playwright() as playwright:
48
+ # run(playwright)
49
+ # ```
17
50
  class BrowserType < PlaywrightApi
18
51
 
19
52
  # This methods attaches Playwright to an existing browser instance.
@@ -23,7 +56,7 @@ module Playwright
23
56
 
24
57
  # A path where Playwright expects to find a bundled browser executable.
25
58
  def executable_path
26
- wrap_channel_owner(@channel_owner.executable_path)
59
+ wrap_impl(@impl.executable_path)
27
60
  end
28
61
 
29
62
  # Returns the browser instance.
@@ -37,6 +70,18 @@ module Playwright
37
70
  # });
38
71
  # ```
39
72
  #
73
+ # ```python async
74
+ # browser = await playwright.chromium.launch( # or "firefox" or "webkit".
75
+ # ignore_default_args=["--mute-audio"]
76
+ # )
77
+ # ```
78
+ #
79
+ # ```python sync
80
+ # browser = playwright.chromium.launch( # or "firefox" or "webkit".
81
+ # ignore_default_args=["--mute-audio"]
82
+ # )
83
+ # ```
84
+ #
40
85
  # > **Chromium-only** Playwright can also be used to control the Chrome browser, but it works best with the version of
41
86
  # Chromium it is bundled with. There is no guarantee it will work with any other version. Use `executablePath` option with
42
87
  # extreme caution.
@@ -63,13 +108,14 @@ module Playwright
63
108
  handleSIGINT: nil,
64
109
  handleSIGTERM: nil,
65
110
  headless: nil,
111
+ ignoreAllDefaultArgs: nil,
66
112
  ignoreDefaultArgs: nil,
67
113
  logger: nil,
68
114
  proxy: nil,
69
115
  slowMo: nil,
70
116
  timeout: nil,
71
117
  &block)
72
- wrap_channel_owner(@channel_owner.launch(args: args, chromiumSandbox: chromiumSandbox, devtools: devtools, downloadsPath: downloadsPath, env: env, executablePath: executablePath, firefoxUserPrefs: firefoxUserPrefs, handleSIGHUP: handleSIGHUP, handleSIGINT: handleSIGINT, handleSIGTERM: handleSIGTERM, headless: headless, ignoreDefaultArgs: ignoreDefaultArgs, logger: logger, proxy: proxy, slowMo: slowMo, timeout: timeout, &wrap_block_call(block)))
118
+ wrap_impl(@impl.launch(args: unwrap_impl(args), chromiumSandbox: unwrap_impl(chromiumSandbox), devtools: unwrap_impl(devtools), downloadsPath: unwrap_impl(downloadsPath), env: unwrap_impl(env), executablePath: unwrap_impl(executablePath), firefoxUserPrefs: unwrap_impl(firefoxUserPrefs), handleSIGHUP: unwrap_impl(handleSIGHUP), handleSIGINT: unwrap_impl(handleSIGINT), handleSIGTERM: unwrap_impl(handleSIGTERM), headless: unwrap_impl(headless), ignoreAllDefaultArgs: unwrap_impl(ignoreAllDefaultArgs), ignoreDefaultArgs: unwrap_impl(ignoreDefaultArgs), logger: unwrap_impl(logger), proxy: unwrap_impl(proxy), slowMo: unwrap_impl(slowMo), timeout: unwrap_impl(timeout), &wrap_block_call(block)))
73
119
  end
74
120
 
75
121
  # Returns the persistent browser context instance.
@@ -96,6 +142,7 @@ module Playwright
96
142
  hasTouch: nil,
97
143
  headless: nil,
98
144
  httpCredentials: nil,
145
+ ignoreAllDefaultArgs: nil,
99
146
  ignoreDefaultArgs: nil,
100
147
  ignoreHTTPSErrors: nil,
101
148
  isMobile: nil,
@@ -140,14 +187,12 @@ module Playwright
140
187
  chromiumSandbox: nil,
141
188
  devtools: nil,
142
189
  downloadsPath: nil,
143
- env: nil,
144
190
  executablePath: nil,
145
191
  firefoxUserPrefs: nil,
146
192
  handleSIGHUP: nil,
147
193
  handleSIGINT: nil,
148
194
  handleSIGTERM: nil,
149
195
  headless: nil,
150
- ignoreDefaultArgs: nil,
151
196
  logger: nil,
152
197
  port: nil,
153
198
  proxy: nil,
@@ -157,7 +202,25 @@ module Playwright
157
202
 
158
203
  # Returns browser name. For example: `'chromium'`, `'webkit'` or `'firefox'`.
159
204
  def name
160
- wrap_channel_owner(@channel_owner.name)
205
+ wrap_impl(@impl.name)
206
+ end
207
+
208
+ # -- inherited from EventEmitter --
209
+ # @nodoc
210
+ def on(event, callback)
211
+ wrap_impl(@impl.on(unwrap_impl(event), unwrap_impl(callback)))
212
+ end
213
+
214
+ # -- inherited from EventEmitter --
215
+ # @nodoc
216
+ def off(event, callback)
217
+ wrap_impl(@impl.off(unwrap_impl(event), unwrap_impl(callback)))
218
+ end
219
+
220
+ # -- inherited from EventEmitter --
221
+ # @nodoc
222
+ def once(event, callback)
223
+ wrap_impl(@impl.once(unwrap_impl(event), unwrap_impl(callback)))
161
224
  end
162
225
  end
163
226
  end
@@ -1,5 +1,5 @@
1
1
  module Playwright
2
- # - extends: [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter)
2
+ # - extends: [EventEmitter]
3
3
  #
4
4
  # The `CDPSession` instances are used to talk raw Chrome Devtools Protocol:
5
5
  # - protocol methods can be called with `session.send` method.
@@ -22,6 +22,28 @@ module Playwright
22
22
  # playbackRate: response.playbackRate / 2
23
23
  # });
24
24
  # ```
25
+ #
26
+ # ```python async
27
+ # client = await page.context().new_cdp_session(page)
28
+ # await client.send("animation.enable")
29
+ # client.on("animation.animation_created", lambda: print("animation created!"))
30
+ # response = await client.send("animation.get_playback_rate")
31
+ # print("playback rate is " + response["playback_rate"])
32
+ # await client.send("animation.set_playback_rate", {
33
+ # playback_rate: response["playback_rate"] / 2
34
+ # })
35
+ # ```
36
+ #
37
+ # ```python sync
38
+ # client = page.context().new_cdp_session(page)
39
+ # client.send("animation.enable")
40
+ # client.on("animation.animation_created", lambda: print("animation created!"))
41
+ # response = client.send("animation.get_playback_rate")
42
+ # print("playback rate is " + response["playback_rate"])
43
+ # client.send("animation.set_playback_rate", {
44
+ # playback_rate: response["playback_rate"] / 2
45
+ # })
46
+ # ```
25
47
  class CDPSession < PlaywrightApi
26
48
 
27
49
  # Detaches the CDPSession from the target. Once detached, the CDPSession object won't emit any events and can't be used to
@@ -9,6 +9,14 @@ module Playwright
9
9
  # ```js
10
10
  # const backgroundPage = await context.waitForEvent('backgroundpage');
11
11
  # ```
12
+ #
13
+ # ```python async
14
+ # background_page = await context.wait_for_event("backgroundpage")
15
+ # ```
16
+ #
17
+ # ```python sync
18
+ # background_page = context.wait_for_event("backgroundpage")
19
+ # ```
12
20
  class ChromiumBrowserContext < BrowserContext
13
21
 
14
22
  # All existing background pages in the context.
@@ -25,5 +33,23 @@ module Playwright
25
33
  def service_workers
26
34
  raise NotImplementedError.new('service_workers is not implemented yet.')
27
35
  end
36
+
37
+ # -- inherited from EventEmitter --
38
+ # @nodoc
39
+ def on(event, callback)
40
+ wrap_impl(@impl.on(unwrap_impl(event), unwrap_impl(callback)))
41
+ end
42
+
43
+ # -- inherited from EventEmitter --
44
+ # @nodoc
45
+ def off(event, callback)
46
+ wrap_impl(@impl.off(unwrap_impl(event), unwrap_impl(callback)))
47
+ end
48
+
49
+ # -- inherited from EventEmitter --
50
+ # @nodoc
51
+ def once(event, callback)
52
+ wrap_impl(@impl.once(unwrap_impl(event), unwrap_impl(callback)))
53
+ end
28
54
  end
29
55
  end
@@ -3,27 +3,40 @@ module Playwright
3
3
  class ConsoleMessage < PlaywrightApi
4
4
 
5
5
  def args
6
- wrap_channel_owner(@channel_owner.args)
6
+ wrap_impl(@impl.args)
7
7
  end
8
8
 
9
9
  def location
10
- wrap_channel_owner(@channel_owner.location)
10
+ wrap_impl(@impl.location)
11
11
  end
12
12
 
13
13
  def text
14
- wrap_channel_owner(@channel_owner.text)
14
+ wrap_impl(@impl.text)
15
15
  end
16
16
 
17
17
  # One of the following values: `'log'`, `'debug'`, `'info'`, `'error'`, `'warning'`, `'dir'`, `'dirxml'`, `'table'`,
18
18
  # `'trace'`, `'clear'`, `'startGroup'`, `'startGroupCollapsed'`, `'endGroup'`, `'assert'`, `'profile'`, `'profileEnd'`,
19
19
  # `'count'`, `'timeEnd'`.
20
- def type_text
21
- raise NotImplementedError.new('type_text is not implemented yet.')
20
+ def type
21
+ wrap_impl(@impl.type)
22
22
  end
23
23
 
24
+ # -- inherited from EventEmitter --
24
25
  # @nodoc
25
- def type
26
- wrap_channel_owner(@channel_owner.type)
26
+ def on(event, callback)
27
+ wrap_impl(@impl.on(unwrap_impl(event), unwrap_impl(callback)))
28
+ end
29
+
30
+ # -- inherited from EventEmitter --
31
+ # @nodoc
32
+ def off(event, callback)
33
+ wrap_impl(@impl.off(unwrap_impl(event), unwrap_impl(callback)))
34
+ end
35
+
36
+ # -- inherited from EventEmitter --
37
+ # @nodoc
38
+ def once(event, callback)
39
+ wrap_impl(@impl.once(unwrap_impl(event), unwrap_impl(callback)))
27
40
  end
28
41
  end
29
42
  end
@@ -18,6 +18,52 @@ module Playwright
18
18
  # page.evaluate(() => alert('1'));
19
19
  # })();
20
20
  # ```
21
+ #
22
+ # ```python async
23
+ # import asyncio
24
+ # from playwright.async_api import async_playwright
25
+ #
26
+ # async def handle_dialog(dialog):
27
+ # print(dialog.message)
28
+ # await dialog.dismiss()
29
+ #
30
+ # async def run(playwright):
31
+ # chromium = playwright.chromium
32
+ # browser = await chromium.launch()
33
+ # page = await browser.new_page()
34
+ # page.on("dialog", handle_dialog)
35
+ # page.evaluate("alert('1')")
36
+ # await browser.close()
37
+ #
38
+ # async def main():
39
+ # async with async_playwright() as playwright:
40
+ # await run(playwright)
41
+ # asyncio.run(main())
42
+ # ```
43
+ #
44
+ # ```python sync
45
+ # from playwright.sync_api import sync_playwright
46
+ #
47
+ # def handle_dialog(dialog):
48
+ # print(dialog.message)
49
+ # dialog.dismiss()
50
+ #
51
+ # def run(playwright):
52
+ # chromium = playwright.chromium
53
+ # browser = chromium.launch()
54
+ # page = browser.new_page()
55
+ # page.on("dialog", handle_dialog)
56
+ # page.evaluate("alert('1')")
57
+ # browser.close()
58
+ #
59
+ # with sync_playwright() as playwright:
60
+ # run(playwright)
61
+ # ```
62
+ #
63
+ # > NOTE: Dialogs are dismissed automatically, unless there is a [`event: Page.dialog`] listener. When listener is
64
+ # present, it **must** either [`method: Dialog.accept`] or [`method: Dialog.dismiss`] the dialog - otherwise the page will
65
+ # [freeze](https://developer.mozilla.org/en-US/docs/Web/JavaScript/EventLoop#never_blocking) waiting for the dialog, and
66
+ # actions like click will never finish.
21
67
  class Dialog < PlaywrightApi
22
68
 
23
69
  # Returns when the dialog has been accepted.
@@ -41,8 +87,8 @@ module Playwright
41
87
  end
42
88
 
43
89
  # Returns dialog's type, can be one of `alert`, `beforeunload`, `confirm` or `prompt`.
44
- def type_text
45
- raise NotImplementedError.new('type_text is not implemented yet.')
90
+ def type
91
+ raise NotImplementedError.new('type is not implemented yet.')
46
92
  end
47
93
  end
48
94
  end
@@ -14,12 +14,27 @@ module Playwright
14
14
  # ]);
15
15
  # // wait for download to complete
16
16
  # const path = await download.path();
17
- # ...
18
17
  # ```
19
18
  #
20
- # > **NOTE** Browser context **must** be created with the `acceptDownloads` set to `true` when user needs access to the
21
- # downloaded content. If `acceptDownloads` is not set or set to `false`, download events are emitted, but the actual
22
- # download is not performed and user has no access to the downloaded files.
19
+ # ```python async
20
+ # async with page.expect_download() as download_info:
21
+ # await page.click("a")
22
+ # download = await download_info.value
23
+ # # waits for download to complete
24
+ # path = await download.path()
25
+ # ```
26
+ #
27
+ # ```python sync
28
+ # with page.expect_download() as download_info:
29
+ # page.click("a")
30
+ # download = download_info.value
31
+ # # wait for download to complete
32
+ # path = download.path()
33
+ # ```
34
+ #
35
+ # > NOTE: Browser context **must** be created with the `acceptDownloads` set to `true` when user needs access to the
36
+ # downloaded content. If `acceptDownloads` is not set, download events are emitted, but the actual download is not
37
+ # performed and user has no access to the downloaded files.
23
38
  class Download < PlaywrightApi
24
39
 
25
40
  # Returns readable stream for current download or `null` if download failed.
@@ -3,7 +3,8 @@ require_relative './js_handle.rb'
3
3
  module Playwright
4
4
  # - extends: `JSHandle`
5
5
  #
6
- # ElementHandle represents an in-page DOM element. ElementHandles can be created with the [`method: Page.$`] method.
6
+ # ElementHandle represents an in-page DOM element. ElementHandles can be created with the [`method: Page.querySelector`]
7
+ # method.
7
8
  #
8
9
  #
9
10
  # ```js
@@ -19,72 +20,48 @@ module Playwright
19
20
  # })();
20
21
  # ```
21
22
  #
23
+ # ```python async
24
+ # import asyncio
25
+ # from playwright.async_api import async_playwright
26
+ #
27
+ # async def run(playwright):
28
+ # chromium = playwright.chromium
29
+ # browser = await chromium.launch()
30
+ # page = await browser.new_page()
31
+ # await page.goto("https://example.com")
32
+ # href_element = await page.query_selector("a")
33
+ # await href_element.click()
34
+ # # ...
35
+ #
36
+ # async def main():
37
+ # async with async_playwright() as playwright:
38
+ # await run(playwright)
39
+ # asyncio.run(main())
40
+ # ```
41
+ #
42
+ # ```python sync
43
+ # from playwright.sync_api import sync_playwright
44
+ #
45
+ # def run(playwright):
46
+ # chromium = playwright.chromium
47
+ # browser = chromium.launch()
48
+ # page = browser.new_page()
49
+ # page.goto("https://example.com")
50
+ # href_element = page.query_selector("a")
51
+ # href_element.click()
52
+ # # ...
53
+ #
54
+ # with sync_playwright() as playwright:
55
+ # run(playwright)
56
+ # ```
57
+ #
22
58
  # ElementHandle prevents DOM element from garbage collection unless the handle is disposed with
23
59
  # [`method: JSHandle.dispose`]. ElementHandles are auto-disposed when their origin frame gets navigated.
24
60
  #
25
- # ElementHandle instances can be used as an argument in [`method: Page.$eval`] and [`method: Page.evaluate`] methods.
61
+ # ElementHandle instances can be used as an argument in [`method: Page.evalOnSelector`] and [`method: Page.evaluate`]
62
+ # methods.
26
63
  class ElementHandle < JSHandle
27
64
 
28
- # The method finds an element matching the specified selector in the `ElementHandle`'s subtree. See
29
- # [Working with selectors](./selectors.md#working-with-selectors) for more details. If no elements match the selector,
30
- # returns `null`.
31
- def query_selector(selector)
32
- raise NotImplementedError.new('query_selector is not implemented yet.')
33
- end
34
-
35
- # The method finds all elements matching the specified selector in the `ElementHandle`s subtree. See
36
- # [Working with selectors](./selectors.md#working-with-selectors) for more details. If no elements match the selector,
37
- # returns empty array.
38
- def query_selector_all(selector)
39
- raise NotImplementedError.new('query_selector_all is not implemented yet.')
40
- end
41
-
42
- # Returns the return value of `pageFunction`
43
- #
44
- # The method finds an element matching the specified selector in the `ElementHandle`s subtree and passes it as a first
45
- # argument to `pageFunction`. See [Working with selectors](./selectors.md#working-with-selectors) for more details. If no
46
- # elements match the selector, the method throws an error.
47
- #
48
- # If `pageFunction` returns a [Promise], then `frame.$eval` would wait for the promise to resolve and return its value.
49
- #
50
- # Examples:
51
- #
52
- #
53
- # ```js
54
- # const tweetHandle = await page.$('.tweet');
55
- # expect(await tweetHandle.$eval('.like', node => node.innerText)).toBe('100');
56
- # expect(await tweetHandle.$eval('.retweets', node => node.innerText)).toBe('10');
57
- # ```
58
- def eval_on_selector(selector, pageFunction, arg: nil)
59
- raise NotImplementedError.new('eval_on_selector is not implemented yet.')
60
- end
61
-
62
- # Returns the return value of `pageFunction`
63
- #
64
- # The method finds all elements matching the specified selector in the `ElementHandle`'s subtree and passes an array of
65
- # matched elements as a first argument to `pageFunction`. See
66
- # [Working with selectors](./selectors.md#working-with-selectors) for more details.
67
- #
68
- # If `pageFunction` returns a [Promise], then `frame.$$eval` would wait for the promise to resolve and return its value.
69
- #
70
- # Examples:
71
- #
72
- # ```html
73
- # <div class="feed">
74
- # <div class="tweet">Hello!</div>
75
- # <div class="tweet">Hi!</div>
76
- # </div>
77
- # ```
78
- #
79
- #
80
- # ```js
81
- # const feedHandle = await page.$('.feed');
82
- # expect(await feedHandle.$$eval('.tweet', nodes => nodes.map(n => n.innerText))).toEqual(['Hello!', 'Hi!']);
83
- # ```
84
- def eval_on_selector_all(selector, pageFunction, arg: nil)
85
- raise NotImplementedError.new('eval_on_selector_all is not implemented yet.')
86
- end
87
-
88
65
  # This method returns the bounding box of the element, or `null` if the element is not visible. The bounding box is
89
66
  # calculated relative to the main frame viewport - which is usually the same as the browser window.
90
67
  #
@@ -103,8 +80,18 @@ module Playwright
103
80
  # const box = await elementHandle.boundingBox();
104
81
  # await page.mouse.click(box.x + box.width / 2, box.y + box.height / 2);
105
82
  # ```
83
+ #
84
+ # ```python async
85
+ # box = await element_handle.bounding_box()
86
+ # await page.mouse.click(box["x"] + box["width"] / 2, box["y"] + box["height"] / 2)
87
+ # ```
88
+ #
89
+ # ```python sync
90
+ # box = element_handle.bounding_box()
91
+ # page.mouse.click(box["x"] + box["width"] / 2, box["y"] + box["height"] / 2)
92
+ # ```
106
93
  def bounding_box
107
- raise NotImplementedError.new('bounding_box is not implemented yet.')
94
+ wrap_impl(@impl.bounding_box)
108
95
  end
109
96
 
110
97
  # This method checks the element by performing the following steps:
@@ -121,7 +108,7 @@ module Playwright
121
108
  # When all steps combined have not finished during the specified `timeout`, this method rejects with a `TimeoutError`.
122
109
  # Passing zero timeout disables this.
123
110
  def check(force: nil, noWaitAfter: nil, timeout: nil)
124
- raise NotImplementedError.new('check is not implemented yet.')
111
+ wrap_impl(@impl.check(force: unwrap_impl(force), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
125
112
  end
126
113
 
127
114
  # This method clicks the element by performing the following steps:
@@ -143,12 +130,12 @@ module Playwright
143
130
  noWaitAfter: nil,
144
131
  position: nil,
145
132
  timeout: nil)
146
- raise NotImplementedError.new('click is not implemented yet.')
133
+ wrap_impl(@impl.click(button: unwrap_impl(button), clickCount: unwrap_impl(clickCount), delay: unwrap_impl(delay), force: unwrap_impl(force), modifiers: unwrap_impl(modifiers), noWaitAfter: unwrap_impl(noWaitAfter), position: unwrap_impl(position), timeout: unwrap_impl(timeout)))
147
134
  end
148
135
 
149
136
  # Returns the content frame for element handles referencing iframe nodes, or `null` otherwise
150
137
  def content_frame
151
- raise NotImplementedError.new('content_frame is not implemented yet.')
138
+ wrap_impl(@impl.content_frame)
152
139
  end
153
140
 
154
141
  # This method double clicks the element by performing the following steps:
@@ -163,7 +150,7 @@ module Playwright
163
150
  # When all steps combined have not finished during the specified `timeout`, this method rejects with a `TimeoutError`.
164
151
  # Passing zero timeout disables this.
165
152
  #
166
- # > **NOTE** `elementHandle.dblclick()` dispatches two `click` events and a single `dblclick` event.
153
+ # > NOTE: `elementHandle.dblclick()` dispatches two `click` events and a single `dblclick` event.
167
154
  def dblclick(
168
155
  button: nil,
169
156
  delay: nil,
@@ -172,7 +159,7 @@ module Playwright
172
159
  noWaitAfter: nil,
173
160
  position: nil,
174
161
  timeout: nil)
175
- raise NotImplementedError.new('dblclick is not implemented yet.')
162
+ wrap_impl(@impl.dblclick(button: unwrap_impl(button), delay: unwrap_impl(delay), force: unwrap_impl(force), modifiers: unwrap_impl(modifiers), noWaitAfter: unwrap_impl(noWaitAfter), position: unwrap_impl(position), timeout: unwrap_impl(timeout)))
176
163
  end
177
164
 
178
165
  # The snippet below dispatches the `click` event on the element. Regardless of the visibility state of the elment, `click`
@@ -184,6 +171,14 @@ module Playwright
184
171
  # await elementHandle.dispatchEvent('click');
185
172
  # ```
186
173
  #
174
+ # ```python async
175
+ # await element_handle.dispatch_event("click")
176
+ # ```
177
+ #
178
+ # ```python sync
179
+ # element_handle.dispatch_event("click")
180
+ # ```
181
+ #
187
182
  # Under the hood, it creates an instance of an event based on the given `type`, initializes it with `eventInit` properties
188
183
  # and dispatches it on the element. Events are `composed`, `cancelable` and bubble by default.
189
184
  #
@@ -204,26 +199,110 @@ module Playwright
204
199
  # const dataTransfer = await page.evaluateHandle(() => new DataTransfer());
205
200
  # await elementHandle.dispatchEvent('dragstart', { dataTransfer });
206
201
  # ```
202
+ #
203
+ # ```python async
204
+ # # note you can only create data_transfer in chromium and firefox
205
+ # data_transfer = await page.evaluate_handle("new DataTransfer()")
206
+ # await element_handle.dispatch_event("#source", "dragstart", {"dataTransfer": data_transfer})
207
+ # ```
208
+ #
209
+ # ```python sync
210
+ # # note you can only create data_transfer in chromium and firefox
211
+ # data_transfer = page.evaluate_handle("new DataTransfer()")
212
+ # element_handle.dispatch_event("#source", "dragstart", {"dataTransfer": data_transfer})
213
+ # ```
207
214
  def dispatch_event(type, eventInit: nil)
208
- raise NotImplementedError.new('dispatch_event is not implemented yet.')
215
+ wrap_impl(@impl.dispatch_event(unwrap_impl(type), eventInit: unwrap_impl(eventInit)))
216
+ end
217
+
218
+ # Returns the return value of `expression`.
219
+ #
220
+ # The method finds an element matching the specified selector in the `ElementHandle`s subtree and passes it as a first
221
+ # argument to `expression`. See [Working with selectors](./selectors.md) for more details. If no elements match the
222
+ # selector, the method throws an error.
223
+ #
224
+ # If `expression` returns a [Promise], then [`method: ElementHandle.evalOnSelector`] would wait for the promise to resolve
225
+ # and return its value.
226
+ #
227
+ # Examples:
228
+ #
229
+ #
230
+ # ```js
231
+ # const tweetHandle = await page.$('.tweet');
232
+ # expect(await tweetHandle.$eval('.like', node => node.innerText)).toBe('100');
233
+ # expect(await tweetHandle.$eval('.retweets', node => node.innerText)).toBe('10');
234
+ # ```
235
+ #
236
+ # ```python async
237
+ # tweet_handle = await page.query_selector(".tweet")
238
+ # assert await tweet_handle.eval_on_selector(".like", "node => node.innerText") == "100"
239
+ # assert await tweet_handle.eval_on_selector(".retweets", "node => node.innerText") = "10"
240
+ # ```
241
+ #
242
+ # ```python sync
243
+ # tweet_handle = page.query_selector(".tweet")
244
+ # assert tweet_handle.eval_on_selector(".like", "node => node.innerText") == "100"
245
+ # assert tweet_handle.eval_on_selector(".retweets", "node => node.innerText") = "10"
246
+ # ```
247
+ def eval_on_selector(selector, expression, arg: nil)
248
+ wrap_impl(@impl.eval_on_selector(unwrap_impl(selector), unwrap_impl(expression), arg: unwrap_impl(arg)))
249
+ end
250
+
251
+ # Returns the return value of `expression`.
252
+ #
253
+ # The method finds all elements matching the specified selector in the `ElementHandle`'s subtree and passes an array of
254
+ # matched elements as a first argument to `expression`. See [Working with selectors](./selectors.md) for more details.
255
+ #
256
+ # If `expression` returns a [Promise], then [`method: ElementHandle.evalOnSelectorAll`] would wait for the promise to
257
+ # resolve and return its value.
258
+ #
259
+ # Examples:
260
+ #
261
+ # ```html
262
+ # <div class="feed">
263
+ # <div class="tweet">Hello!</div>
264
+ # <div class="tweet">Hi!</div>
265
+ # </div>
266
+ # ```
267
+ #
268
+ #
269
+ # ```js
270
+ # const feedHandle = await page.$('.feed');
271
+ # expect(await feedHandle.$$eval('.tweet', nodes => nodes.map(n => n.innerText))).toEqual(['Hello!', 'Hi!']);
272
+ # ```
273
+ #
274
+ # ```python async
275
+ # feed_handle = await page.query_selector(".feed")
276
+ # assert await feed_handle.eval_on_selector_all(".tweet", "nodes => nodes.map(n => n.innerText)") == ["hello!", "hi!"]
277
+ # ```
278
+ #
279
+ # ```python sync
280
+ # feed_handle = page.query_selector(".feed")
281
+ # assert feed_handle.eval_on_selector_all(".tweet", "nodes => nodes.map(n => n.innerText)") == ["hello!", "hi!"]
282
+ # ```
283
+ def eval_on_selector_all(selector, expression, arg: nil)
284
+ wrap_impl(@impl.eval_on_selector_all(unwrap_impl(selector), unwrap_impl(expression), arg: unwrap_impl(arg)))
209
285
  end
210
286
 
211
287
  # This method waits for [actionability](./actionability.md) checks, focuses the element, fills it and triggers an `input`
212
- # event after filling. If the element is not an `<input>`, `<textarea>` or `[contenteditable]` element, this method throws
213
- # an error. Note that you can pass an empty string to clear the input field.
288
+ # event after filling. If the element is inside the `<label>` element that has associated
289
+ # [control](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control), that control will be filled
290
+ # instead. If the element to be filled is not an `<input>`, `<textarea>` or `[contenteditable]` element, this method
291
+ # throws an error. Note that you can pass an empty string to clear the input field.
214
292
  def fill(value, noWaitAfter: nil, timeout: nil)
215
- raise NotImplementedError.new('fill is not implemented yet.')
293
+ wrap_impl(@impl.fill(unwrap_impl(value), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
216
294
  end
217
295
 
218
296
  # Calls [focus](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus) on the element.
219
297
  def focus
220
- raise NotImplementedError.new('focus is not implemented yet.')
298
+ wrap_impl(@impl.focus)
221
299
  end
222
300
 
223
301
  # Returns element attribute value.
224
302
  def get_attribute(name)
225
- raise NotImplementedError.new('get_attribute is not implemented yet.')
303
+ wrap_impl(@impl.get_attribute(unwrap_impl(name)))
226
304
  end
305
+ alias_method :[], :get_attribute
227
306
 
228
307
  # This method hovers over the element by performing the following steps:
229
308
  # 1. Wait for [actionability](./actionability.md) checks on the element, unless `force` option is set.
@@ -236,52 +315,52 @@ module Playwright
236
315
  # When all steps combined have not finished during the specified `timeout`, this method rejects with a `TimeoutError`.
237
316
  # Passing zero timeout disables this.
238
317
  def hover(force: nil, modifiers: nil, position: nil, timeout: nil)
239
- raise NotImplementedError.new('hover is not implemented yet.')
318
+ wrap_impl(@impl.hover(force: unwrap_impl(force), modifiers: unwrap_impl(modifiers), position: unwrap_impl(position), timeout: unwrap_impl(timeout)))
240
319
  end
241
320
 
242
321
  # Returns the `element.innerHTML`.
243
322
  def inner_html
244
- raise NotImplementedError.new('inner_html is not implemented yet.')
323
+ wrap_impl(@impl.inner_html)
245
324
  end
246
325
 
247
326
  # Returns the `element.innerText`.
248
327
  def inner_text
249
- raise NotImplementedError.new('inner_text is not implemented yet.')
328
+ wrap_impl(@impl.inner_text)
250
329
  end
251
330
 
252
331
  # Returns whether the element is checked. Throws if the element is not a checkbox or radio input.
253
332
  def checked?
254
- raise NotImplementedError.new('checked? is not implemented yet.')
333
+ wrap_impl(@impl.checked?)
255
334
  end
256
335
 
257
336
  # Returns whether the element is disabled, the opposite of [enabled](./actionability.md#enabled).
258
337
  def disabled?
259
- raise NotImplementedError.new('disabled? is not implemented yet.')
338
+ wrap_impl(@impl.disabled?)
260
339
  end
261
340
 
262
341
  # Returns whether the element is [editable](./actionability.md#editable).
263
342
  def editable?
264
- raise NotImplementedError.new('editable? is not implemented yet.')
343
+ wrap_impl(@impl.editable?)
265
344
  end
266
345
 
267
346
  # Returns whether the element is [enabled](./actionability.md#enabled).
268
347
  def enabled?
269
- raise NotImplementedError.new('enabled? is not implemented yet.')
348
+ wrap_impl(@impl.enabled?)
270
349
  end
271
350
 
272
351
  # Returns whether the element is hidden, the opposite of [visible](./actionability.md#visible).
273
352
  def hidden?
274
- raise NotImplementedError.new('hidden? is not implemented yet.')
353
+ wrap_impl(@impl.hidden?)
275
354
  end
276
355
 
277
356
  # Returns whether the element is [visible](./actionability.md#visible).
278
357
  def visible?
279
- raise NotImplementedError.new('visible? is not implemented yet.')
358
+ wrap_impl(@impl.visible?)
280
359
  end
281
360
 
282
361
  # Returns the frame containing the given element.
283
362
  def owner_frame
284
- raise NotImplementedError.new('owner_frame is not implemented yet.')
363
+ wrap_impl(@impl.owner_frame)
285
364
  end
286
365
 
287
366
  # Focuses the element, and then uses [`method: Keyboard.down`] and [`method: Keyboard.up`].
@@ -303,7 +382,19 @@ module Playwright
303
382
  # Shortcuts such as `key: "Control+o"` or `key: "Control+Shift+T"` are supported as well. When speficied with the
304
383
  # modifier, modifier is pressed and being held while the subsequent key is being pressed.
305
384
  def press(key, delay: nil, noWaitAfter: nil, timeout: nil)
306
- raise NotImplementedError.new('press is not implemented yet.')
385
+ wrap_impl(@impl.press(unwrap_impl(key), delay: unwrap_impl(delay), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
386
+ end
387
+
388
+ # The method finds an element matching the specified selector in the `ElementHandle`'s subtree. See
389
+ # [Working with selectors](./selectors.md) for more details. If no elements match the selector, returns `null`.
390
+ def query_selector(selector)
391
+ wrap_impl(@impl.query_selector(unwrap_impl(selector)))
392
+ end
393
+
394
+ # The method finds all elements matching the specified selector in the `ElementHandle`s subtree. See
395
+ # [Working with selectors](./selectors.md) for more details. If no elements match the selector, returns empty array.
396
+ def query_selector_all(selector)
397
+ wrap_impl(@impl.query_selector_all(unwrap_impl(selector)))
307
398
  end
308
399
 
309
400
  # Returns the buffer with the captured screenshot.
@@ -316,17 +407,17 @@ module Playwright
316
407
  quality: nil,
317
408
  timeout: nil,
318
409
  type: nil)
319
- raise NotImplementedError.new('screenshot is not implemented yet.')
410
+ wrap_impl(@impl.screenshot(omitBackground: unwrap_impl(omitBackground), path: unwrap_impl(path), quality: unwrap_impl(quality), timeout: unwrap_impl(timeout), type: unwrap_impl(type)))
320
411
  end
321
412
 
322
413
  # This method waits for [actionability](./actionability.md) checks, then tries to scroll element into view, unless it is
323
414
  # completely visible as defined by
324
- # [IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API)'s ```ratio```.
415
+ # [IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API)'s `ratio`.
325
416
  #
326
417
  # Throws when `elementHandle` does not point to an element
327
418
  # [connected](https://developer.mozilla.org/en-US/docs/Web/API/Node/isConnected) to a Document or a ShadowRoot.
328
419
  def scroll_into_view_if_needed(timeout: nil)
329
- raise NotImplementedError.new('scroll_into_view_if_needed is not implemented yet.')
420
+ wrap_impl(@impl.scroll_into_view_if_needed(timeout: unwrap_impl(timeout)))
330
421
  end
331
422
 
332
423
  # Returns the array of option values that have been successfully selected.
@@ -334,28 +425,56 @@ module Playwright
334
425
  # Triggers a `change` and `input` event once all the provided options have been selected. If element is not a `<select>`
335
426
  # element, the method throws an error.
336
427
  #
428
+ # Will wait until all specified options are present in the `<select>` element.
429
+ #
337
430
  #
338
431
  # ```js
339
432
  # // single selection matching the value
340
433
  # handle.selectOption('blue');
341
434
  #
342
- # // single selection matching both the value and the label
435
+ # // single selection matching the label
343
436
  # handle.selectOption({ label: 'Blue' });
344
437
  #
345
438
  # // multiple selection
346
- # handle.selectOption('red', 'green', 'blue');
439
+ # handle.selectOption(['red', 'green', 'blue']);
440
+ # ```
441
+ #
442
+ # ```python async
443
+ # # single selection matching the value
444
+ # await handle.select_option("blue")
445
+ # # single selection matching the label
446
+ # await handle.select_option(label="blue")
447
+ # # multiple selection
448
+ # await handle.select_option(value=["red", "green", "blue"])
449
+ # ```
450
+ #
451
+ # ```python sync
452
+ # # single selection matching the value
453
+ # handle.select_option("blue")
454
+ # # single selection matching both the label
455
+ # handle.select_option(label="blue")
456
+ # # multiple selection
457
+ # handle.select_option(value=["red", "green", "blue"])
458
+ # ```
347
459
  #
348
- # // multiple selection for blue, red and second option
349
- # handle.selectOption({ value: 'blue' }, { index: 2 }, 'red');
460
+ # ```python sync
461
+ # # single selection matching the value
462
+ # handle.select_option("blue")
463
+ # # single selection matching both the value and the label
464
+ # handle.select_option(label="blue")
465
+ # # multiple selection
466
+ # handle.select_option("red", "green", "blue")
467
+ # # multiple selection for blue, red and second option
468
+ # handle.select_option(value="blue", { index: 2 }, "red")
350
469
  # ```
351
470
  def select_option(values, noWaitAfter: nil, timeout: nil)
352
- raise NotImplementedError.new('select_option is not implemented yet.')
471
+ wrap_impl(@impl.select_option(unwrap_impl(values), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
353
472
  end
354
473
 
355
474
  # This method waits for [actionability](./actionability.md) checks, then focuses the element and selects all its text
356
475
  # content.
357
476
  def select_text(timeout: nil)
358
- raise NotImplementedError.new('select_text is not implemented yet.')
477
+ wrap_impl(@impl.select_text(timeout: unwrap_impl(timeout)))
359
478
  end
360
479
 
361
480
  # This method expects `elementHandle` to point to an
@@ -364,8 +483,9 @@ module Playwright
364
483
  # Sets the value of the file input to these file paths or files. If some of the `filePaths` are relative paths, then they
365
484
  # are resolved relative to the the current working directory. For empty array, clears the selected files.
366
485
  def set_input_files(files, noWaitAfter: nil, timeout: nil)
367
- raise NotImplementedError.new('set_input_files is not implemented yet.')
486
+ wrap_impl(@impl.set_input_files(unwrap_impl(files), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
368
487
  end
488
+ alias_method :input_files=, :set_input_files
369
489
 
370
490
  # This method taps the element by performing the following steps:
371
491
  # 1. Wait for [actionability](./actionability.md) checks on the element, unless `force` option is set.
@@ -378,19 +498,19 @@ module Playwright
378
498
  # When all steps combined have not finished during the specified `timeout`, this method rejects with a `TimeoutError`.
379
499
  # Passing zero timeout disables this.
380
500
  #
381
- # > **NOTE** `elementHandle.tap()` requires that the `hasTouch` option of the browser context be set to true.
501
+ # > NOTE: `elementHandle.tap()` requires that the `hasTouch` option of the browser context be set to true.
382
502
  def tap_point(
383
503
  force: nil,
384
504
  modifiers: nil,
385
505
  noWaitAfter: nil,
386
506
  position: nil,
387
507
  timeout: nil)
388
- raise NotImplementedError.new('tap_point is not implemented yet.')
508
+ wrap_impl(@impl.tap_point(force: unwrap_impl(force), modifiers: unwrap_impl(modifiers), noWaitAfter: unwrap_impl(noWaitAfter), position: unwrap_impl(position), timeout: unwrap_impl(timeout)))
389
509
  end
390
510
 
391
511
  # Returns the `node.textContent`.
392
512
  def text_content
393
- raise NotImplementedError.new('text_content is not implemented yet.')
513
+ wrap_impl(@impl.text_content)
394
514
  end
395
515
 
396
516
  # Focuses the element, and then sends a `keydown`, `keypress`/`input`, and `keyup` event for each character in the text.
@@ -403,6 +523,16 @@ module Playwright
403
523
  # await elementHandle.type('World', {delay: 100}); // Types slower, like a user
404
524
  # ```
405
525
  #
526
+ # ```python async
527
+ # await element_handle.type("hello") # types instantly
528
+ # await element_handle.type("world", delay=100) # types slower, like a user
529
+ # ```
530
+ #
531
+ # ```python sync
532
+ # element_handle.type("hello") # types instantly
533
+ # element_handle.type("world", delay=100) # types slower, like a user
534
+ # ```
535
+ #
406
536
  # An example of typing into a text field and then submitting the form:
407
537
  #
408
538
  #
@@ -411,8 +541,20 @@ module Playwright
411
541
  # await elementHandle.type('some text');
412
542
  # await elementHandle.press('Enter');
413
543
  # ```
414
- def type_text(text, delay: nil, noWaitAfter: nil, timeout: nil)
415
- raise NotImplementedError.new('type_text is not implemented yet.')
544
+ #
545
+ # ```python async
546
+ # element_handle = await page.query_selector("input")
547
+ # await element_handle.type("some text")
548
+ # await element_handle.press("Enter")
549
+ # ```
550
+ #
551
+ # ```python sync
552
+ # element_handle = page.query_selector("input")
553
+ # element_handle.type("some text")
554
+ # element_handle.press("Enter")
555
+ # ```
556
+ def type(text, delay: nil, noWaitAfter: nil, timeout: nil)
557
+ wrap_impl(@impl.type(unwrap_impl(text), delay: unwrap_impl(delay), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
416
558
  end
417
559
 
418
560
  # This method checks the element by performing the following steps:
@@ -429,7 +571,7 @@ module Playwright
429
571
  # When all steps combined have not finished during the specified `timeout`, this method rejects with a `TimeoutError`.
430
572
  # Passing zero timeout disables this.
431
573
  def uncheck(force: nil, noWaitAfter: nil, timeout: nil)
432
- raise NotImplementedError.new('uncheck is not implemented yet.')
574
+ wrap_impl(@impl.uncheck(force: unwrap_impl(force), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
433
575
  end
434
576
 
435
577
  # Returns when the element satisfies the `state`.
@@ -447,7 +589,7 @@ module Playwright
447
589
  #
448
590
  # If the element does not satisfy the condition for the `timeout` milliseconds, this method will throw.
449
591
  def wait_for_element_state(state, timeout: nil)
450
- raise NotImplementedError.new('wait_for_element_state is not implemented yet.')
592
+ wrap_impl(@impl.wait_for_element_state(unwrap_impl(state), timeout: unwrap_impl(timeout)))
451
593
  end
452
594
 
453
595
  # Returns element specified by selector when it satisfies `state` option. Returns `null` if waiting for `hidden` or
@@ -466,9 +608,41 @@ module Playwright
466
608
  # const span = await div.waitForSelector('span', { state: 'attached' });
467
609
  # ```
468
610
  #
469
- # > **NOTE** This method does not work across navigations, use [`method: Page.waitForSelector`] instead.
611
+ # ```python async
612
+ # await page.set_content("<div><span></span></div>")
613
+ # div = await page.query_selector("div")
614
+ # # waiting for the "span" selector relative to the div.
615
+ # span = await div.wait_for_selector("span", state="attached")
616
+ # ```
617
+ #
618
+ # ```python sync
619
+ # page.set_content("<div><span></span></div>")
620
+ # div = page.query_selector("div")
621
+ # # waiting for the "span" selector relative to the div.
622
+ # span = div.wait_for_selector("span", state="attached")
623
+ # ```
624
+ #
625
+ # > NOTE: This method does not work across navigations, use [`method: Page.waitForSelector`] instead.
470
626
  def wait_for_selector(selector, state: nil, timeout: nil)
471
- raise NotImplementedError.new('wait_for_selector is not implemented yet.')
627
+ wrap_impl(@impl.wait_for_selector(unwrap_impl(selector), state: unwrap_impl(state), timeout: unwrap_impl(timeout)))
628
+ end
629
+
630
+ # -- inherited from EventEmitter --
631
+ # @nodoc
632
+ def on(event, callback)
633
+ wrap_impl(@impl.on(unwrap_impl(event), unwrap_impl(callback)))
634
+ end
635
+
636
+ # -- inherited from EventEmitter --
637
+ # @nodoc
638
+ def off(event, callback)
639
+ wrap_impl(@impl.off(unwrap_impl(event), unwrap_impl(callback)))
640
+ end
641
+
642
+ # -- inherited from EventEmitter --
643
+ # @nodoc
644
+ def once(event, callback)
645
+ wrap_impl(@impl.once(unwrap_impl(event), unwrap_impl(callback)))
472
646
  end
473
647
  end
474
648
  end