playwright-ruby-client 0.0.3 → 0.0.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +119 -12
  3. data/docs/api_coverage.md +354 -0
  4. data/lib/playwright.rb +8 -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 +22 -29
  9. data/lib/playwright/channel_owners/browser_context.rb +43 -0
  10. data/lib/playwright/channel_owners/console_message.rb +21 -0
  11. data/lib/playwright/channel_owners/element_handle.rb +314 -0
  12. data/lib/playwright/channel_owners/frame.rb +466 -7
  13. data/lib/playwright/channel_owners/js_handle.rb +55 -0
  14. data/lib/playwright/channel_owners/page.rb +353 -5
  15. data/lib/playwright/channel_owners/request.rb +90 -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 +13 -0
  20. data/lib/playwright/input_files.rb +42 -0
  21. data/lib/playwright/input_type.rb +19 -0
  22. data/lib/playwright/input_types/android_input.rb +19 -0
  23. data/lib/playwright/input_types/keyboard.rb +32 -0
  24. data/lib/playwright/input_types/mouse.rb +4 -0
  25. data/lib/playwright/input_types/touchscreen.rb +4 -0
  26. data/lib/playwright/javascript.rb +13 -0
  27. data/lib/playwright/javascript/expression.rb +67 -0
  28. data/lib/playwright/javascript/function.rb +67 -0
  29. data/lib/playwright/javascript/value_parser.rb +75 -0
  30. data/lib/playwright/javascript/value_serializer.rb +54 -0
  31. data/lib/playwright/playwright_api.rb +45 -25
  32. data/lib/playwright/select_option_values.rb +32 -0
  33. data/lib/playwright/timeout_settings.rb +19 -0
  34. data/lib/playwright/url_matcher.rb +19 -0
  35. data/lib/playwright/utils.rb +37 -0
  36. data/lib/playwright/version.rb +1 -1
  37. data/lib/playwright/wait_helper.rb +73 -0
  38. data/lib/playwright_api/accessibility.rb +60 -6
  39. data/lib/playwright_api/android.rb +33 -0
  40. data/lib/playwright_api/android_device.rb +78 -0
  41. data/lib/playwright_api/android_input.rb +25 -0
  42. data/lib/playwright_api/binding_call.rb +18 -0
  43. data/lib/playwright_api/browser.rb +136 -44
  44. data/lib/playwright_api/browser_context.rb +378 -51
  45. data/lib/playwright_api/browser_type.rb +137 -55
  46. data/lib/playwright_api/cdp_session.rb +32 -7
  47. data/lib/playwright_api/chromium_browser_context.rb +31 -0
  48. data/lib/playwright_api/console_message.rb +27 -7
  49. data/lib/playwright_api/dialog.rb +47 -3
  50. data/lib/playwright_api/download.rb +29 -5
  51. data/lib/playwright_api/element_handle.rb +429 -143
  52. data/lib/playwright_api/file_chooser.rb +13 -2
  53. data/lib/playwright_api/frame.rb +633 -179
  54. data/lib/playwright_api/js_handle.rb +97 -17
  55. data/lib/playwright_api/keyboard.rb +152 -24
  56. data/lib/playwright_api/mouse.rb +28 -3
  57. data/lib/playwright_api/page.rb +1183 -317
  58. data/lib/playwright_api/playwright.rb +174 -13
  59. data/lib/playwright_api/request.rb +115 -30
  60. data/lib/playwright_api/response.rb +22 -3
  61. data/lib/playwright_api/route.rb +63 -4
  62. data/lib/playwright_api/selectors.rb +29 -7
  63. data/lib/playwright_api/touchscreen.rb +2 -1
  64. data/lib/playwright_api/video.rb +11 -1
  65. data/lib/playwright_api/web_socket.rb +5 -5
  66. data/lib/playwright_api/worker.rb +29 -5
  67. data/playwright.gemspec +3 -0
  68. metadata +68 -2
@@ -1,7 +1,11 @@
1
1
  module Playwright
2
- # Download objects are dispatched by page via the page.on('download') event.
3
- # All the downloaded files belonging to the browser context are deleted when the browser context is closed. All downloaded files are deleted when the browser closes.
2
+ # `Download` objects are dispatched by page via the [`event: Page.download`] event.
3
+ #
4
+ # All the downloaded files belonging to the browser context are deleted when the browser context is closed. All downloaded
5
+ # files are deleted when the browser closes.
6
+ #
4
7
  # Download event is emitted once the download starts. Download path becomes available once download completes:
8
+ #
5
9
  #
6
10
  # ```js
7
11
  # const [ download ] = await Promise.all([
@@ -10,10 +14,27 @@ module Playwright
10
14
  # ]);
11
15
  # // wait for download to complete
12
16
  # const path = await download.path();
13
- # ...
14
17
  # ```
15
18
  #
16
- # **NOTE** Browser context **must** be created with the `acceptDownloads` set to `true` when user needs access to the downloaded content. If `acceptDownloads` is not set or set to `false`, download events are emitted, but the actual 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.
17
38
  class Download < PlaywrightApi
18
39
 
19
40
  # Returns readable stream for current download or `null` if download failed.
@@ -41,7 +62,10 @@ module Playwright
41
62
  raise NotImplementedError.new('save_as is not implemented yet.')
42
63
  end
43
64
 
44
- # Returns suggested filename for this download. It is typically computed by the browser from the `Content-Disposition` response header or the `download` attribute. See the spec on whatwg. Different browsers can use different logic for computing it.
65
+ # Returns suggested filename for this download. It is typically computed by the browser from the
66
+ # [`Content-Disposition`](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Disposition) response header
67
+ # or the `download` attribute. See the spec on [whatwg](https://html.spec.whatwg.org/#downloading-resources). Different
68
+ # browsers can use different logic for computing it.
45
69
  def suggested_filename
46
70
  raise NotImplementedError.new('suggested_filename is not implemented yet.')
47
71
  end
@@ -1,7 +1,10 @@
1
1
  require_relative './js_handle.rb'
2
2
 
3
3
  module Playwright
4
- # ElementHandle represents an in-page DOM element. ElementHandles can be created with the `page.$(selector)` method.
4
+ # - extends: `JSHandle`
5
+ #
6
+ # ElementHandle represents an in-page DOM element. ElementHandles can be created with the [`method: Page.$`] method.
7
+ #
5
8
  #
6
9
  # ```js
7
10
  # const { chromium } = require('playwright'); // Or 'firefox' or 'webkit'.
@@ -15,336 +18,587 @@ module Playwright
15
18
  # // ...
16
19
  # })();
17
20
  # ```
18
- # ElementHandle prevents DOM element from garbage collection unless the handle is disposed with `jsHandle.dispose()`. ElementHandles are auto-disposed when their origin frame gets navigated.
19
- # ElementHandle instances can be used as an argument in `page.$eval(selector, pageFunction[, arg])` and `page.evaluate(pageFunction[, arg])` methods.
21
+ #
22
+ # ```python async
23
+ # import asyncio
24
+ # from playwright.async_api import async_playwright
25
+ #
26
+ # async def run(playwright):
27
+ # chromium = playwright.chromium
28
+ # browser = await chromium.launch()
29
+ # page = await browser.new_page()
30
+ # await page.goto("https://example.com")
31
+ # href_element = await page.query_selector("a")
32
+ # await href_element.click()
33
+ # # ...
34
+ #
35
+ # async def main():
36
+ # async with async_playwright() as playwright:
37
+ # await run(playwright)
38
+ # asyncio.run(main())
39
+ # ```
40
+ #
41
+ # ```python sync
42
+ # from playwright.sync_api import sync_playwright
43
+ #
44
+ # def run(playwright):
45
+ # chromium = playwright.chromium
46
+ # browser = chromium.launch()
47
+ # page = browser.new_page()
48
+ # page.goto("https://example.com")
49
+ # href_element = page.query_selector("a")
50
+ # href_element.click()
51
+ # # ...
52
+ #
53
+ # with sync_playwright() as playwright:
54
+ # run(playwright)
55
+ # ```
56
+ #
57
+ # ElementHandle prevents DOM element from garbage collection unless the handle is disposed with
58
+ # [`method: JSHandle.dispose`]. ElementHandles are auto-disposed when their origin frame gets navigated.
59
+ #
60
+ # ElementHandle instances can be used as an argument in [`method: Page.$eval`] and [`method: Page.evaluate`] methods.
20
61
  class ElementHandle < JSHandle
21
62
 
22
- # The method finds an element matching the specified selector in the `ElementHandle`'s subtree. See Working with selectors for more details. If no elements match the selector, returns `null`.
23
- def S(selector)
24
- raise NotImplementedError.new('S is not implemented yet.')
63
+ # The method finds an element matching the specified selector in the `ElementHandle`'s subtree. See
64
+ # [Working with selectors](./selectors.md#working-with-selectors) for more details. If no elements match the selector,
65
+ # returns `null`.
66
+ def query_selector(selector)
67
+ wrap_impl(@impl.query_selector(unwrap_impl(selector)))
25
68
  end
26
69
 
27
- # The method finds all elements matching the specified selector in the `ElementHandle`s subtree. See Working with selectors for more details. If no elements match the selector, returns empty array.
28
- def SS(selector)
29
- raise NotImplementedError.new('SS is not implemented yet.')
70
+ # The method finds all elements matching the specified selector in the `ElementHandle`s subtree. See
71
+ # [Working with selectors](./selectors.md#working-with-selectors) for more details. If no elements match the selector,
72
+ # returns empty array.
73
+ def query_selector_all(selector)
74
+ wrap_impl(@impl.query_selector_all(unwrap_impl(selector)))
30
75
  end
31
76
 
32
77
  # Returns the return value of `pageFunction`
33
- # The method finds an element matching the specified selector in the `ElementHandle`s subtree and passes it as a first argument to `pageFunction`. See Working with selectors for more details. If no elements match the selector, the method throws an error.
34
- # If `pageFunction` returns a Promise, then `frame.$eval` would wait for the promise to resolve and return its value.
78
+ #
79
+ # The method finds an element matching the specified selector in the `ElementHandle`s subtree and passes it as a first
80
+ # argument to `pageFunction`. See [Working with selectors](./selectors.md#working-with-selectors) for more details. If no
81
+ # elements match the selector, the method throws an error.
82
+ #
83
+ # If `pageFunction` returns a [Promise], then `frame.$eval` would wait for the promise to resolve and return its value.
84
+ #
35
85
  # Examples:
86
+ #
36
87
  #
37
88
  # ```js
38
89
  # const tweetHandle = await page.$('.tweet');
39
90
  # expect(await tweetHandle.$eval('.like', node => node.innerText)).toBe('100');
40
91
  # expect(await tweetHandle.$eval('.retweets', node => node.innerText)).toBe('10');
41
92
  # ```
42
- def Seval(selector, pageFunction, arg: nil)
43
- raise NotImplementedError.new('Seval is not implemented yet.')
93
+ #
94
+ # ```python async
95
+ # tweet_handle = await page.query_selector(".tweet")
96
+ # assert await tweet_handle.eval_on_selector(".like", "node => node.innerText") == "100"
97
+ # assert await tweet_handle.eval_on_selector(".retweets", "node => node.innerText") = "10"
98
+ # ```
99
+ #
100
+ # ```python sync
101
+ # tweet_handle = page.query_selector(".tweet")
102
+ # assert tweet_handle.eval_on_selector(".like", "node => node.innerText") == "100"
103
+ # assert tweet_handle.eval_on_selector(".retweets", "node => node.innerText") = "10"
104
+ # ```
105
+ def eval_on_selector(selector, pageFunction, arg: nil)
106
+ wrap_impl(@impl.eval_on_selector(unwrap_impl(selector), unwrap_impl(pageFunction), arg: unwrap_impl(arg)))
44
107
  end
45
108
 
46
109
  # Returns the return value of `pageFunction`
47
- # The method finds all elements matching the specified selector in the `ElementHandle`'s subtree and passes an array of matched elements as a first argument to `pageFunction`. See Working with selectors for more details.
48
- # If `pageFunction` returns a Promise, then `frame.$$eval` would wait for the promise to resolve and return its value.
110
+ #
111
+ # The method finds all elements matching the specified selector in the `ElementHandle`'s subtree and passes an array of
112
+ # matched elements as a first argument to `pageFunction`. See
113
+ # [Working with selectors](./selectors.md#working-with-selectors) for more details.
114
+ #
115
+ # If `pageFunction` returns a [Promise], then `frame.$$eval` would wait for the promise to resolve and return its value.
116
+ #
49
117
  # Examples:
118
+ #
50
119
  # ```html
51
120
  # <div class="feed">
52
121
  # <div class="tweet">Hello!</div>
53
122
  # <div class="tweet">Hi!</div>
54
123
  # </div>
55
124
  # ```
125
+ #
56
126
  #
57
127
  # ```js
58
128
  # const feedHandle = await page.$('.feed');
59
129
  # expect(await feedHandle.$$eval('.tweet', nodes => nodes.map(n => n.innerText))).toEqual(['Hello!', 'Hi!']);
60
130
  # ```
61
- def SSeval(selector, pageFunction, arg: nil)
62
- raise NotImplementedError.new('SSeval is not implemented yet.')
131
+ #
132
+ # ```python async
133
+ # # FIXME
134
+ # feed_handle = await page.query_selector(".feed")
135
+ # assert await feed_handle.eval_on_selector_all(".tweet", "nodes => nodes.map(n => n.innerText)") == ["hello!", "hi!"]
136
+ # ```
137
+ #
138
+ # ```python sync
139
+ # feed_handle = page.query_selector(".feed")
140
+ # assert feed_handle.eval_on_selector_all(".tweet", "nodes => nodes.map(n => n.innerText)") == ["hello!", "hi!"]
141
+ # ```
142
+ def eval_on_selector_all(selector, pageFunction, arg: nil)
143
+ wrap_impl(@impl.eval_on_selector_all(unwrap_impl(selector), unwrap_impl(pageFunction), arg: unwrap_impl(arg)))
63
144
  end
64
145
 
65
- # This method returns the bounding box of the element, or `null` if the element is not visible. The bounding box is calculated relative to the main frame viewport - which is usually the same as the browser window.
66
- # Scrolling affects the returned bonding box, similarly to Element.getBoundingClientRect. That means `x` and/or `y` may be negative.
67
- # Elements from child frames return the bounding box relative to the main frame, unlike the Element.getBoundingClientRect.
68
- # Assuming the page is static, it is safe to use bounding box coordinates to perform input. For example, the following snippet should click the center of the element.
146
+ # This method returns the bounding box of the element, or `null` if the element is not visible. The bounding box is
147
+ # calculated relative to the main frame viewport - which is usually the same as the browser window.
148
+ #
149
+ # Scrolling affects the returned bonding box, similarly to
150
+ # [Element.getBoundingClientRect](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect). That
151
+ # means `x` and/or `y` may be negative.
152
+ #
153
+ # Elements from child frames return the bounding box relative to the main frame, unlike the
154
+ # [Element.getBoundingClientRect](https://developer.mozilla.org/en-US/docs/Web/API/Element/getBoundingClientRect).
155
+ #
156
+ # Assuming the page is static, it is safe to use bounding box coordinates to perform input. For example, the following
157
+ # snippet should click the center of the element.
158
+ #
69
159
  #
70
160
  # ```js
71
161
  # const box = await elementHandle.boundingBox();
72
162
  # await page.mouse.click(box.x + box.width / 2, box.y + box.height / 2);
73
163
  # ```
164
+ #
165
+ # ```python async
166
+ # box = await element_handle.bounding_box()
167
+ # await page.mouse.click(box["x"] + box["width"] / 2, box["y"] + box["height"] / 2)
168
+ # ```
169
+ #
170
+ # ```python sync
171
+ # box = element_handle.bounding_box()
172
+ # page.mouse.click(box["x"] + box["width"] / 2, box["y"] + box["height"] / 2)
173
+ # ```
74
174
  def bounding_box
75
- raise NotImplementedError.new('bounding_box is not implemented yet.')
175
+ wrap_impl(@impl.bounding_box)
76
176
  end
77
177
 
78
178
  # This method checks the element by performing the following steps:
79
- #
80
- # Ensure that element is a checkbox or a radio input. If not, this method rejects. If the element is already checked, this method returns immediately.
81
- # Wait for actionability checks on the element, unless `force` option is set.
82
- # Scroll the element into view if needed.
83
- # Use page.mouse to click in the center of the element.
84
- # Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
85
- # Ensure that the element is now checked. If not, this method rejects.
179
+ # 1. Ensure that element is a checkbox or a radio input. If not, this method rejects. If the element is already
180
+ # checked, this method returns immediately.
181
+ # 1. Wait for [actionability](./actionability.md) checks on the element, unless `force` option is set.
182
+ # 1. Scroll the element into view if needed.
183
+ # 1. Use [`property: Page.mouse`] to click in the center of the element.
184
+ # 1. Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
185
+ # 1. Ensure that the element is now checked. If not, this method rejects.
86
186
  #
87
187
  # If the element is detached from the DOM at any moment during the action, this method rejects.
88
- # When all steps combined have not finished during the specified `timeout`, this method rejects with a TimeoutError. Passing zero timeout disables this.
188
+ #
189
+ # When all steps combined have not finished during the specified `timeout`, this method rejects with a `TimeoutError`.
190
+ # Passing zero timeout disables this.
89
191
  def check(force: nil, noWaitAfter: nil, timeout: nil)
90
- raise NotImplementedError.new('check is not implemented yet.')
192
+ wrap_impl(@impl.check(force: unwrap_impl(force), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
91
193
  end
92
194
 
93
195
  # This method clicks the element by performing the following steps:
94
- #
95
- # Wait for actionability checks on the element, unless `force` option is set.
96
- # Scroll the element into view if needed.
97
- # Use page.mouse to click in the center of the element, or the specified `position`.
98
- # Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
196
+ # 1. Wait for [actionability](./actionability.md) checks on the element, unless `force` option is set.
197
+ # 1. Scroll the element into view if needed.
198
+ # 1. Use [`property: Page.mouse`] to click in the center of the element, or the specified `position`.
199
+ # 1. Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
99
200
  #
100
201
  # If the element is detached from the DOM at any moment during the action, this method rejects.
101
- # When all steps combined have not finished during the specified `timeout`, this method rejects with a TimeoutError. Passing zero timeout disables this.
202
+ #
203
+ # When all steps combined have not finished during the specified `timeout`, this method rejects with a `TimeoutError`.
204
+ # Passing zero timeout disables this.
102
205
  def click(
103
206
  button: nil,
104
207
  clickCount: nil,
105
208
  delay: nil,
106
- position: nil,
107
- modifiers: nil,
108
209
  force: nil,
210
+ modifiers: nil,
109
211
  noWaitAfter: nil,
212
+ position: nil,
110
213
  timeout: nil)
111
- raise NotImplementedError.new('click is not implemented yet.')
214
+ 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)))
112
215
  end
113
216
 
114
217
  # Returns the content frame for element handles referencing iframe nodes, or `null` otherwise
115
218
  def content_frame
116
- raise NotImplementedError.new('content_frame is not implemented yet.')
219
+ wrap_impl(@impl.content_frame)
117
220
  end
118
221
 
119
222
  # This method double clicks the element by performing the following steps:
120
- #
121
- # Wait for actionability checks on the element, unless `force` option is set.
122
- # Scroll the element into view if needed.
123
- # Use page.mouse to double click in the center of the element, or the specified `position`.
124
- # Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set. Note that if the first click of the `dblclick()` triggers a navigation event, this method will reject.
223
+ # 1. Wait for [actionability](./actionability.md) checks on the element, unless `force` option is set.
224
+ # 1. Scroll the element into view if needed.
225
+ # 1. Use [`property: Page.mouse`] to double click in the center of the element, or the specified `position`.
226
+ # 1. Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set. Note that if the
227
+ # first click of the `dblclick()` triggers a navigation event, this method will reject.
125
228
  #
126
229
  # If the element is detached from the DOM at any moment during the action, this method rejects.
127
- # When all steps combined have not finished during the specified `timeout`, this method rejects with a TimeoutError. Passing zero timeout disables this.
128
230
  #
129
- # **NOTE** `elementHandle.dblclick()` dispatches two `click` events and a single `dblclick` event.
231
+ # When all steps combined have not finished during the specified `timeout`, this method rejects with a `TimeoutError`.
232
+ # Passing zero timeout disables this.
233
+ #
234
+ # > NOTE: `elementHandle.dblclick()` dispatches two `click` events and a single `dblclick` event.
130
235
  def dblclick(
131
236
  button: nil,
132
237
  delay: nil,
133
- position: nil,
134
- modifiers: nil,
135
238
  force: nil,
239
+ modifiers: nil,
136
240
  noWaitAfter: nil,
241
+ position: nil,
137
242
  timeout: nil)
138
- raise NotImplementedError.new('dblclick is not implemented yet.')
243
+ 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)))
139
244
  end
140
245
 
141
- # The snippet below dispatches the `click` event on the element. Regardless of the visibility state of the elment, `click` is dispatched. This is equivalend to calling element.click().
246
+ # The snippet below dispatches the `click` event on the element. Regardless of the visibility state of the elment, `click`
247
+ # is dispatched. This is equivalend to calling
248
+ # [element.click()](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click).
249
+ #
142
250
  #
143
251
  # ```js
144
252
  # await elementHandle.dispatchEvent('click');
145
253
  # ```
146
- # Under the hood, it creates an instance of an event based on the given `type`, initializes it with `eventInit` properties and dispatches it on the element. Events are `composed`, `cancelable` and bubble by default.
147
- # Since `eventInit` is event-specific, please refer to the events documentation for the lists of initial properties:
148
254
  #
149
- # DragEvent
150
- # FocusEvent
151
- # KeyboardEvent
152
- # MouseEvent
153
- # PointerEvent
154
- # TouchEvent
155
- # Event
255
+ # ```python async
256
+ # await element_handle.dispatch_event("click")
257
+ # ```
258
+ #
259
+ # ```python sync
260
+ # element_handle.dispatch_event("click")
261
+ # ```
262
+ #
263
+ # Under the hood, it creates an instance of an event based on the given `type`, initializes it with `eventInit` properties
264
+ # and dispatches it on the element. Events are `composed`, `cancelable` and bubble by default.
265
+ #
266
+ # Since `eventInit` is event-specific, please refer to the events documentation for the lists of initial properties:
267
+ # - [DragEvent](https://developer.mozilla.org/en-US/docs/Web/API/DragEvent/DragEvent)
268
+ # - [FocusEvent](https://developer.mozilla.org/en-US/docs/Web/API/FocusEvent/FocusEvent)
269
+ # - [KeyboardEvent](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/KeyboardEvent)
270
+ # - [MouseEvent](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/MouseEvent)
271
+ # - [PointerEvent](https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/PointerEvent)
272
+ # - [TouchEvent](https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent/TouchEvent)
273
+ # - [Event](https://developer.mozilla.org/en-US/docs/Web/API/Event/Event)
156
274
  #
157
275
  # You can also specify `JSHandle` as the property value if you want live objects to be passed into the event:
276
+ #
158
277
  #
159
278
  # ```js
160
279
  # // Note you can only create DataTransfer in Chromium and Firefox
161
280
  # const dataTransfer = await page.evaluateHandle(() => new DataTransfer());
162
281
  # await elementHandle.dispatchEvent('dragstart', { dataTransfer });
163
282
  # ```
283
+ #
284
+ # ```python async
285
+ # # note you can only create data_transfer in chromium and firefox
286
+ # data_transfer = await page.evaluate_handle("new DataTransfer()")
287
+ # await element_handle.dispatch_event("#source", "dragstart", {"dataTransfer": data_transfer})
288
+ # ```
289
+ #
290
+ # ```python sync
291
+ # # note you can only create data_transfer in chromium and firefox
292
+ # data_transfer = page.evaluate_handle("new DataTransfer()")
293
+ # element_handle.dispatch_event("#source", "dragstart", {"dataTransfer": data_transfer})
294
+ # ```
164
295
  def dispatch_event(type, eventInit: nil)
165
- raise NotImplementedError.new('dispatch_event is not implemented yet.')
296
+ wrap_impl(@impl.dispatch_event(unwrap_impl(type), eventInit: unwrap_impl(eventInit)))
166
297
  end
167
298
 
168
- # This method waits for actionability checks, focuses the element, fills it and triggers an `input` event after filling. If the element is not an `<input>`, `<textarea>` or `[contenteditable]` element, this method throws an error. Note that you can pass an empty string to clear the input field.
299
+ # This method waits for [actionability](./actionability.md) checks, focuses the element, fills it and triggers an `input`
300
+ # event after filling. If the element is not an `<input>`, `<textarea>` or `[contenteditable]` element, this method throws
301
+ # an error. Note that you can pass an empty string to clear the input field.
169
302
  def fill(value, noWaitAfter: nil, timeout: nil)
170
- raise NotImplementedError.new('fill is not implemented yet.')
303
+ wrap_impl(@impl.fill(unwrap_impl(value), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
171
304
  end
172
305
 
173
- # Calls focus on the element.
306
+ # Calls [focus](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/focus) on the element.
174
307
  def focus
175
- raise NotImplementedError.new('focus is not implemented yet.')
308
+ wrap_impl(@impl.focus)
176
309
  end
177
310
 
178
311
  # Returns element attribute value.
179
312
  def get_attribute(name)
180
- raise NotImplementedError.new('get_attribute is not implemented yet.')
313
+ wrap_impl(@impl.get_attribute(unwrap_impl(name)))
181
314
  end
315
+ alias_method :[], :get_attribute
182
316
 
183
317
  # This method hovers over the element by performing the following steps:
184
- #
185
- # Wait for actionability checks on the element, unless `force` option is set.
186
- # Scroll the element into view if needed.
187
- # Use page.mouse to hover over the center of the element, or the specified `position`.
188
- # Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
318
+ # 1. Wait for [actionability](./actionability.md) checks on the element, unless `force` option is set.
319
+ # 1. Scroll the element into view if needed.
320
+ # 1. Use [`property: Page.mouse`] to hover over the center of the element, or the specified `position`.
321
+ # 1. Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
189
322
  #
190
323
  # If the element is detached from the DOM at any moment during the action, this method rejects.
191
- # When all steps combined have not finished during the specified `timeout`, this method rejects with a TimeoutError. Passing zero timeout disables this.
192
- def hover(position: nil, modifiers: nil, force: nil, timeout: nil)
193
- raise NotImplementedError.new('hover is not implemented yet.')
324
+ #
325
+ # When all steps combined have not finished during the specified `timeout`, this method rejects with a `TimeoutError`.
326
+ # Passing zero timeout disables this.
327
+ def hover(force: nil, modifiers: nil, position: nil, timeout: nil)
328
+ wrap_impl(@impl.hover(force: unwrap_impl(force), modifiers: unwrap_impl(modifiers), position: unwrap_impl(position), timeout: unwrap_impl(timeout)))
194
329
  end
195
330
 
196
331
  # Returns the `element.innerHTML`.
197
332
  def inner_html
198
- raise NotImplementedError.new('inner_html is not implemented yet.')
333
+ wrap_impl(@impl.inner_html)
199
334
  end
200
335
 
201
336
  # Returns the `element.innerText`.
202
337
  def inner_text
203
- raise NotImplementedError.new('inner_text is not implemented yet.')
338
+ wrap_impl(@impl.inner_text)
339
+ end
340
+
341
+ # Returns whether the element is checked. Throws if the element is not a checkbox or radio input.
342
+ def checked?
343
+ wrap_impl(@impl.checked?)
344
+ end
345
+
346
+ # Returns whether the element is disabled, the opposite of [enabled](./actionability.md#enabled).
347
+ def disabled?
348
+ wrap_impl(@impl.disabled?)
349
+ end
350
+
351
+ # Returns whether the element is [editable](./actionability.md#editable).
352
+ def editable?
353
+ wrap_impl(@impl.editable?)
354
+ end
355
+
356
+ # Returns whether the element is [enabled](./actionability.md#enabled).
357
+ def enabled?
358
+ wrap_impl(@impl.enabled?)
359
+ end
360
+
361
+ # Returns whether the element is hidden, the opposite of [visible](./actionability.md#visible).
362
+ def hidden?
363
+ wrap_impl(@impl.hidden?)
364
+ end
365
+
366
+ # Returns whether the element is [visible](./actionability.md#visible).
367
+ def visible?
368
+ wrap_impl(@impl.visible?)
204
369
  end
205
370
 
206
371
  # Returns the frame containing the given element.
207
372
  def owner_frame
208
- raise NotImplementedError.new('owner_frame is not implemented yet.')
373
+ wrap_impl(@impl.owner_frame)
209
374
  end
210
375
 
211
- # Focuses the element, and then uses `keyboard.down(key)` and `keyboard.up(key)`.
212
- # `key` can specify the intended keyboardEvent.key value or a single character to generate the text for. A superset of the `key` values can be found here. Examples of the keys are:
213
- # `F1` - `F12`, `Digit0`- `Digit9`, `KeyA`- `KeyZ`, `Backquote`, `Minus`, `Equal`, `Backslash`, `Backspace`, `Tab`, `Delete`, `Escape`, `ArrowDown`, `End`, `Enter`, `Home`, `Insert`, `PageDown`, `PageUp`, `ArrowRight`, `ArrowUp`, etc.
214
- # Following modification shortcuts are also suported: `Shift`, `Control`, `Alt`, `Meta`, `ShiftLeft`.
376
+ # Focuses the element, and then uses [`method: Keyboard.down`] and [`method: Keyboard.up`].
377
+ #
378
+ # `key` can specify the intended [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key)
379
+ # value or a single character to generate the text for. A superset of the `key` values can be found
380
+ # [here](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values). Examples of the keys are:
381
+ #
382
+ # `F1` - `F12`, `Digit0`- `Digit9`, `KeyA`- `KeyZ`, `Backquote`, `Minus`, `Equal`, `Backslash`, `Backspace`, `Tab`,
383
+ # `Delete`, `Escape`, `ArrowDown`, `End`, `Enter`, `Home`, `Insert`, `PageDown`, `PageUp`, `ArrowRight`, `ArrowUp`, etc.
384
+ #
385
+ # Following modification shortcuts are also supported: `Shift`, `Control`, `Alt`, `Meta`, `ShiftLeft`.
386
+ #
215
387
  # Holding down `Shift` will type the text that corresponds to the `key` in the upper case.
216
- # If `key` is a single character, it is case-sensitive, so the values `a` and `A` will generate different respective texts.
217
- # Shortcuts such as `key: "Control+o"` or `key: "Control+Shift+T"` are supported as well. When speficied with the modifier, modifier is pressed and being held while the subsequent key is being pressed.
388
+ #
389
+ # If `key` is a single character, it is case-sensitive, so the values `a` and `A` will generate different respective
390
+ # texts.
391
+ #
392
+ # Shortcuts such as `key: "Control+o"` or `key: "Control+Shift+T"` are supported as well. When speficied with the
393
+ # modifier, modifier is pressed and being held while the subsequent key is being pressed.
218
394
  def press(key, delay: nil, noWaitAfter: nil, timeout: nil)
219
- raise NotImplementedError.new('press is not implemented yet.')
395
+ wrap_impl(@impl.press(unwrap_impl(key), delay: unwrap_impl(delay), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
220
396
  end
221
397
 
222
398
  # Returns the buffer with the captured screenshot.
223
- # This method waits for the actionability checks, then scrolls element into view before taking a screenshot. If the element is detached from DOM, the method throws an error.
399
+ #
400
+ # This method waits for the [actionability](./actionability.md) checks, then scrolls element into view before taking a
401
+ # screenshot. If the element is detached from DOM, the method throws an error.
224
402
  def screenshot(
403
+ omitBackground: nil,
225
404
  path: nil,
226
- type: nil,
227
405
  quality: nil,
228
- omitBackground: nil,
229
- timeout: nil)
230
- raise NotImplementedError.new('screenshot is not implemented yet.')
406
+ timeout: nil,
407
+ type: nil)
408
+ wrap_impl(@impl.screenshot(omitBackground: unwrap_impl(omitBackground), path: unwrap_impl(path), quality: unwrap_impl(quality), timeout: unwrap_impl(timeout), type: unwrap_impl(type)))
231
409
  end
232
410
 
233
- # This method waits for actionability checks, then tries to scroll element into view, unless it is completely visible as defined by IntersectionObserver's `ratio`.
234
- # Throws when `elementHandle` does not point to an element connected to a Document or a ShadowRoot.
411
+ # This method waits for [actionability](./actionability.md) checks, then tries to scroll element into view, unless it is
412
+ # completely visible as defined by
413
+ # [IntersectionObserver](https://developer.mozilla.org/en-US/docs/Web/API/Intersection_Observer_API)'s `ratio`.
414
+ #
415
+ # Throws when `elementHandle` does not point to an element
416
+ # [connected](https://developer.mozilla.org/en-US/docs/Web/API/Node/isConnected) to a Document or a ShadowRoot.
235
417
  def scroll_into_view_if_needed(timeout: nil)
236
- raise NotImplementedError.new('scroll_into_view_if_needed is not implemented yet.')
418
+ wrap_impl(@impl.scroll_into_view_if_needed(timeout: unwrap_impl(timeout)))
237
419
  end
238
420
 
239
421
  # Returns the array of option values that have been successfully selected.
240
- # Triggers a `change` and `input` event once all the provided options have been selected. If element is not a `<select>` element, the method throws an error.
422
+ #
423
+ # Triggers a `change` and `input` event once all the provided options have been selected. If element is not a `<select>`
424
+ # element, the method throws an error.
425
+ #
426
+ # Will wait until all specified options are present in the `<select>` element.
427
+ #
241
428
  #
242
429
  # ```js
243
430
  # // single selection matching the value
244
431
  # handle.selectOption('blue');
245
432
  #
246
- # // single selection matching both the value and the label
433
+ # // single selection matching the label
247
434
  # handle.selectOption({ label: 'Blue' });
248
435
  #
249
436
  # // multiple selection
250
- # handle.selectOption('red', 'green', 'blue');
437
+ # handle.selectOption(['red', 'green', 'blue']);
438
+ # ```
439
+ #
440
+ # ```python async
441
+ # # single selection matching the value
442
+ # await handle.select_option("blue")
443
+ # # single selection matching the label
444
+ # await handle.select_option(label="blue")
445
+ # # multiple selection
446
+ # await handle.select_option(value=["red", "green", "blue"])
447
+ # ```
251
448
  #
252
- # // multiple selection for blue, red and second option
253
- # handle.selectOption({ value: 'blue' }, { index: 2 }, 'red');
449
+ # ```python sync
450
+ # # single selection matching the value
451
+ # handle.select_option("blue")
452
+ # # single selection matching both the label
453
+ # handle.select_option(label="blue")
454
+ # # multiple selection
455
+ # handle.select_option(value=["red", "green", "blue"])
456
+ # ```
457
+ #
458
+ # ```python sync
459
+ # # FIXME
460
+ # # single selection matching the value
461
+ # handle.select_option("blue")
462
+ # # single selection matching both the value and the label
463
+ # handle.select_option(label="blue")
464
+ # # multiple selection
465
+ # handle.select_option("red", "green", "blue")
466
+ # # multiple selection for blue, red and second option
467
+ # handle.select_option(value="blue", { index: 2 }, "red")
254
468
  # ```
255
469
  def select_option(values, noWaitAfter: nil, timeout: nil)
256
- raise NotImplementedError.new('select_option is not implemented yet.')
470
+ wrap_impl(@impl.select_option(unwrap_impl(values), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
257
471
  end
258
472
 
259
- # This method waits for actionability checks, then focuses the element and selects all its text content.
473
+ # This method waits for [actionability](./actionability.md) checks, then focuses the element and selects all its text
474
+ # content.
260
475
  def select_text(timeout: nil)
261
- raise NotImplementedError.new('select_text is not implemented yet.')
476
+ wrap_impl(@impl.select_text(timeout: unwrap_impl(timeout)))
262
477
  end
263
478
 
264
- # This method expects `elementHandle` to point to an input element.
265
- # Sets the value of the file input to these file paths or files. If some of the `filePaths` are relative paths, then they are resolved relative to the the current working directory. For empty array, clears the selected files.
479
+ # This method expects `elementHandle` to point to an
480
+ # [input element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input).
481
+ #
482
+ # Sets the value of the file input to these file paths or files. If some of the `filePaths` are relative paths, then they
483
+ # are resolved relative to the the current working directory. For empty array, clears the selected files.
266
484
  def set_input_files(files, noWaitAfter: nil, timeout: nil)
267
- raise NotImplementedError.new('set_input_files is not implemented yet.')
485
+ wrap_impl(@impl.set_input_files(unwrap_impl(files), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
268
486
  end
487
+ alias_method :input_files=, :set_input_files
269
488
 
270
489
  # This method taps the element by performing the following steps:
271
- #
272
- # Wait for actionability checks on the element, unless `force` option is set.
273
- # Scroll the element into view if needed.
274
- # Use page.touchscreen to tap in the center of the element, or the specified `position`.
275
- # Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
490
+ # 1. Wait for [actionability](./actionability.md) checks on the element, unless `force` option is set.
491
+ # 1. Scroll the element into view if needed.
492
+ # 1. Use [`property: Page.touchscreen`] to tap the center of the element, or the specified `position`.
493
+ # 1. Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
276
494
  #
277
495
  # If the element is detached from the DOM at any moment during the action, this method rejects.
278
- # When all steps combined have not finished during the specified `timeout`, this method rejects with a TimeoutError. Passing zero timeout disables this.
279
496
  #
280
- # **NOTE** `elementHandle.tap()` requires that the `hasTouch` option of the browser context be set to true.
497
+ # When all steps combined have not finished during the specified `timeout`, this method rejects with a `TimeoutError`.
498
+ # Passing zero timeout disables this.
499
+ #
500
+ # > NOTE: `elementHandle.tap()` requires that the `hasTouch` option of the browser context be set to true.
281
501
  def tap_point(
282
- position: nil,
283
- modifiers: nil,
284
502
  force: nil,
503
+ modifiers: nil,
285
504
  noWaitAfter: nil,
505
+ position: nil,
286
506
  timeout: nil)
287
- raise NotImplementedError.new('tap_point is not implemented yet.')
507
+ 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)))
288
508
  end
289
509
 
290
510
  # Returns the `node.textContent`.
291
511
  def text_content
292
- raise NotImplementedError.new('text_content is not implemented yet.')
293
- end
294
-
295
- def to_string
296
- raise NotImplementedError.new('to_string is not implemented yet.')
512
+ wrap_impl(@impl.text_content)
297
513
  end
298
514
 
299
515
  # Focuses the element, and then sends a `keydown`, `keypress`/`input`, and `keyup` event for each character in the text.
300
- # To press a special key, like `Control` or `ArrowDown`, use `elementHandle.press(key[, options])`.
516
+ #
517
+ # To press a special key, like `Control` or `ArrowDown`, use [`method: ElementHandle.press`].
518
+ #
301
519
  #
302
520
  # ```js
303
521
  # await elementHandle.type('Hello'); // Types instantly
304
522
  # await elementHandle.type('World', {delay: 100}); // Types slower, like a user
305
523
  # ```
524
+ #
525
+ # ```python async
526
+ # await element_handle.type("hello") # types instantly
527
+ # await element_handle.type("world", delay=100) # types slower, like a user
528
+ # ```
529
+ #
530
+ # ```python sync
531
+ # element_handle.type("hello") # types instantly
532
+ # element_handle.type("world", delay=100) # types slower, like a user
533
+ # ```
534
+ #
306
535
  # An example of typing into a text field and then submitting the form:
536
+ #
307
537
  #
308
538
  # ```js
309
539
  # const elementHandle = await page.$('input');
310
540
  # await elementHandle.type('some text');
311
541
  # await elementHandle.press('Enter');
312
542
  # ```
313
- def type_text(text, delay: nil, noWaitAfter: nil, timeout: nil)
314
- raise NotImplementedError.new('type_text is not implemented yet.')
543
+ #
544
+ # ```python async
545
+ # element_handle = await page.query_selector("input")
546
+ # await element_handle.type("some text")
547
+ # await element_handle.press("Enter")
548
+ # ```
549
+ #
550
+ # ```python sync
551
+ # element_handle = page.query_selector("input")
552
+ # element_handle.type("some text")
553
+ # element_handle.press("Enter")
554
+ # ```
555
+ def type(text, delay: nil, noWaitAfter: nil, timeout: nil)
556
+ wrap_impl(@impl.type(unwrap_impl(text), delay: unwrap_impl(delay), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
315
557
  end
316
558
 
317
559
  # This method checks the element by performing the following steps:
318
- #
319
- # Ensure that element is a checkbox or a radio input. If not, this method rejects. If the element is already unchecked, this method returns immediately.
320
- # Wait for actionability checks on the element, unless `force` option is set.
321
- # Scroll the element into view if needed.
322
- # Use page.mouse to click in the center of the element.
323
- # Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
324
- # Ensure that the element is now unchecked. If not, this method rejects.
560
+ # 1. Ensure that element is a checkbox or a radio input. If not, this method rejects. If the element is already
561
+ # unchecked, this method returns immediately.
562
+ # 1. Wait for [actionability](./actionability.md) checks on the element, unless `force` option is set.
563
+ # 1. Scroll the element into view if needed.
564
+ # 1. Use [`property: Page.mouse`] to click in the center of the element.
565
+ # 1. Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
566
+ # 1. Ensure that the element is now unchecked. If not, this method rejects.
325
567
  #
326
568
  # If the element is detached from the DOM at any moment during the action, this method rejects.
327
- # When all steps combined have not finished during the specified `timeout`, this method rejects with a TimeoutError. Passing zero timeout disables this.
569
+ #
570
+ # When all steps combined have not finished during the specified `timeout`, this method rejects with a `TimeoutError`.
571
+ # Passing zero timeout disables this.
328
572
  def uncheck(force: nil, noWaitAfter: nil, timeout: nil)
329
- raise NotImplementedError.new('uncheck is not implemented yet.')
573
+ wrap_impl(@impl.uncheck(force: unwrap_impl(force), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
330
574
  end
331
575
 
332
- # Returns the element satisfies the `state`.
333
- # Depending on the `state` parameter, this method waits for one of the actionability checks to pass. This method throws when the element is detached while waiting, unless waiting for the `"hidden"` state.
576
+ # Returns when the element satisfies the `state`.
334
577
  #
335
- # `"visible"` Wait until the element is visible.
336
- # `"hidden"` Wait until the element is not visible or not attached. Note that waiting for hidden does not throw when the element detaches.
337
- # `"stable"` Wait until the element is both visible and stable.
338
- # `"enabled"` Wait until the element is enabled.
339
- # `"disabled"` Wait until the element is not enabled.
578
+ # Depending on the `state` parameter, this method waits for one of the [actionability](./actionability.md) checks to pass.
579
+ # This method throws when the element is detached while waiting, unless waiting for the `"hidden"` state.
580
+ # - `"visible"` Wait until the element is [visible](./actionability.md#visible).
581
+ # - `"hidden"` Wait until the element is [not visible](./actionability.md#visible) or
582
+ # [not attached](./actionability.md#attached). Note that waiting for hidden does not throw when the element detaches.
583
+ # - `"stable"` Wait until the element is both [visible](./actionability.md#visible) and
584
+ # [stable](./actionability.md#stable).
585
+ # - `"enabled"` Wait until the element is [enabled](./actionability.md#enabled).
586
+ # - `"disabled"` Wait until the element is [not enabled](./actionability.md#enabled).
587
+ # - `"editable"` Wait until the element is [editable](./actionability.md#editable).
340
588
  #
341
589
  # If the element does not satisfy the condition for the `timeout` milliseconds, this method will throw.
342
590
  def wait_for_element_state(state, timeout: nil)
343
- raise NotImplementedError.new('wait_for_element_state is not implemented yet.')
591
+ wrap_impl(@impl.wait_for_element_state(unwrap_impl(state), timeout: unwrap_impl(timeout)))
344
592
  end
345
593
 
346
- # Returns element specified by selector satisfies `state` option. Returns `null` if waiting for `hidden` or `detached`.
347
- # Wait for the `selector` relative to the element handle to satisfy `state` option (either appear/disappear from dom, or become visible/hidden). If at the moment of calling the method `selector` already satisfies the condition, the method will return immediately. If the selector doesn't satisfy the condition for the `timeout` milliseconds, the function will throw.
594
+ # Returns element specified by selector when it satisfies `state` option. Returns `null` if waiting for `hidden` or
595
+ # `detached`.
596
+ #
597
+ # Wait for the `selector` relative to the element handle to satisfy `state` option (either appear/disappear from dom, or
598
+ # become visible/hidden). If at the moment of calling the method `selector` already satisfies the condition, the method
599
+ # will return immediately. If the selector doesn't satisfy the condition for the `timeout` milliseconds, the function will
600
+ # throw.
601
+ #
348
602
  #
349
603
  # ```js
350
604
  # await page.setContent(`<div><span></span></div>`);
@@ -353,9 +607,41 @@ module Playwright
353
607
  # const span = await div.waitForSelector('span', { state: 'attached' });
354
608
  # ```
355
609
  #
356
- # **NOTE** This method does not work across navigations, use `page.waitForSelector(selector[, options])` instead.
610
+ # ```python async
611
+ # await page.set_content("<div><span></span></div>")
612
+ # div = await page.query_selector("div")
613
+ # # waiting for the "span" selector relative to the div.
614
+ # span = await div.wait_for_selector("span", state="attached")
615
+ # ```
616
+ #
617
+ # ```python sync
618
+ # page.set_content("<div><span></span></div>")
619
+ # div = page.query_selector("div")
620
+ # # waiting for the "span" selector relative to the div.
621
+ # span = div.wait_for_selector("span", state="attached")
622
+ # ```
623
+ #
624
+ # > NOTE: This method does not work across navigations, use [`method: Page.waitForSelector`] instead.
357
625
  def wait_for_selector(selector, state: nil, timeout: nil)
358
- raise NotImplementedError.new('wait_for_selector is not implemented yet.')
626
+ wrap_impl(@impl.wait_for_selector(unwrap_impl(selector), state: unwrap_impl(state), timeout: unwrap_impl(timeout)))
627
+ end
628
+
629
+ # -- inherited from EventEmitter --
630
+ # @nodoc
631
+ def on(event, callback)
632
+ wrap_impl(@impl.on(unwrap_impl(event), unwrap_impl(callback)))
633
+ end
634
+
635
+ # -- inherited from EventEmitter --
636
+ # @nodoc
637
+ def off(event, callback)
638
+ wrap_impl(@impl.off(unwrap_impl(event), unwrap_impl(callback)))
639
+ end
640
+
641
+ # -- inherited from EventEmitter --
642
+ # @nodoc
643
+ def once(event, callback)
644
+ wrap_impl(@impl.once(unwrap_impl(event), unwrap_impl(callback)))
359
645
  end
360
646
  end
361
647
  end