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,11 +1,20 @@
1
1
  module Playwright
2
- # FileChooser objects are dispatched by the page in the page.on('filechooser') event.
2
+ # `FileChooser` objects are dispatched by the page in the [`event: Page.filechooser`] event.
3
+ #
3
4
  #
4
5
  # ```js
5
6
  # page.on('filechooser', async (fileChooser) => {
6
7
  # await fileChooser.setFiles('/tmp/myfile.pdf');
7
8
  # });
8
9
  # ```
10
+ #
11
+ # ```python async
12
+ # page.on("filechooser", lambda file_chooser: file_chooser.set_files("/tmp/myfile.pdf"))
13
+ # ```
14
+ #
15
+ # ```python sync
16
+ # page.on("filechooser", lambda file_chooser: file_chooser.set_files("/tmp/myfile.pdf"))
17
+ # ```
9
18
  class FileChooser < PlaywrightApi
10
19
 
11
20
  # Returns input element associated with this file chooser.
@@ -23,9 +32,11 @@ module Playwright
23
32
  raise NotImplementedError.new('page is not implemented yet.')
24
33
  end
25
34
 
26
- # Sets the value of the file input this chooser is associated with. 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.
35
+ # Sets the value of the file input this chooser is associated with. If some of the `filePaths` are relative paths, then
36
+ # they are resolved relative to the the current working directory. For empty array, clears the selected files.
27
37
  def set_files(files, noWaitAfter: nil, timeout: nil)
28
38
  raise NotImplementedError.new('set_files is not implemented yet.')
29
39
  end
40
+ alias_method :files=, :set_files
30
41
  end
31
42
  end
@@ -1,12 +1,16 @@
1
1
  module Playwright
2
- # At every point of time, page exposes its current frame tree via the `page.mainFrame()` and `frame.childFrames()` methods.
3
- # Frame object's lifecycle is controlled by three events, dispatched on the page object:
2
+ # At every point of time, page exposes its current frame tree via the [`method: Page.mainFrame`] and
3
+ # [`method: Frame.childFrames`] methods.
4
4
  #
5
- # page.on('frameattached') - fired when the frame gets attached to the page. A Frame can be attached to the page only once.
6
- # page.on('framenavigated') - fired when the frame commits navigation to a different URL.
7
- # page.on('framedetached') - fired when the frame gets detached from the page. A Frame can be detached from the page only once.
5
+ # `Frame` object's lifecycle is controlled by three events, dispatched on the page object:
6
+ # - [`event: Page.frameattached`] - fired when the frame gets attached to the page. A Frame can be attached to the page
7
+ # only once.
8
+ # - [`event: Page.framenavigated`] - fired when the frame commits navigation to a different URL.
9
+ # - [`event: Page.framedetached`] - fired when the frame gets detached from the page. A Frame can be detached from the
10
+ # page only once.
8
11
  #
9
12
  # An example of dumping frame tree:
13
+ #
10
14
  #
11
15
  # ```js
12
16
  # const { firefox } = require('playwright'); // Or 'chromium' or 'webkit'.
@@ -26,164 +30,278 @@ module Playwright
26
30
  # }
27
31
  # })();
28
32
  # ```
29
- # An example of getting text from an iframe element:
30
- #
31
- # ```js
32
- # const frame = page.frames().find(frame => frame.name() === 'myframe');
33
- # const text = await frame.$eval('.selector', element => element.textContent);
34
- # console.log(text);
33
+ #
34
+ # ```python async
35
+ # import asyncio
36
+ # from playwright.async_api import async_playwright
37
+ #
38
+ # async def run(playwright):
39
+ # firefox = playwright.firefox
40
+ # browser = await firefox.launch()
41
+ # page = await browser.new_page()
42
+ # await page.goto("https://www.theverge.com")
43
+ # dump_frame_tree(page.main_frame, "")
44
+ # await browser.close()
45
+ #
46
+ # def dump_frame_tree(frame, indent):
47
+ # print(indent + frame.name + '@' + frame.url)
48
+ # for child in frame.child_frames:
49
+ # dump_frame_tree(child, indent + " ")
50
+ #
51
+ # async def main():
52
+ # async with async_playwright() as playwright:
53
+ # await run(playwright)
54
+ # asyncio.run(main())
55
+ # ```
56
+ #
57
+ # ```python sync
58
+ # from playwright.sync_api import sync_playwright
59
+ #
60
+ # def run(playwright):
61
+ # firefox = playwright.firefox
62
+ # browser = firefox.launch()
63
+ # page = browser.new_page()
64
+ # page.goto("https://www.theverge.com")
65
+ # dump_frame_tree(page.main_frame, "")
66
+ # browser.close()
67
+ #
68
+ # def dump_frame_tree(frame, indent):
69
+ # print(indent + frame.name + '@' + frame.url)
70
+ # for child in frame.child_frames:
71
+ # dump_frame_tree(child, indent + " ")
72
+ #
73
+ # with sync_playwright() as playwright:
74
+ # run(playwright)
35
75
  # ```
36
76
  class Frame < PlaywrightApi
37
77
 
38
78
  # Returns the ElementHandle pointing to the frame element.
39
- # The method finds an element matching the specified selector within the frame. See Working with selectors for more details. If no elements match the selector, returns `null`.
40
- def S(selector)
41
- raise NotImplementedError.new('S is not implemented yet.')
79
+ #
80
+ # The method finds an element matching the specified selector within the frame. See
81
+ # [Working with selectors](./selectors.md#working-with-selectors) for more details. If no elements match the selector,
82
+ # returns `null`.
83
+ def query_selector(selector)
84
+ wrap_impl(@impl.query_selector(unwrap_impl(selector)))
42
85
  end
43
86
 
44
87
  # Returns the ElementHandles pointing to the frame elements.
45
- # The method finds all elements matching the specified selector within the frame. See Working with selectors for more details. If no elements match the selector, returns empty array.
46
- def SS(selector)
47
- raise NotImplementedError.new('SS is not implemented yet.')
88
+ #
89
+ # The method finds all elements matching the specified selector within the frame. See
90
+ # [Working with selectors](./selectors.md#working-with-selectors) for more details. If no elements match the selector,
91
+ # returns empty array.
92
+ def query_selector_all(selector)
93
+ wrap_impl(@impl.query_selector_all(unwrap_impl(selector)))
48
94
  end
49
95
 
50
96
  # Returns the return value of `pageFunction`
51
- # The method finds an element matching the specified selector within the frame 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.
52
- # If `pageFunction` returns a Promise, then `frame.$eval` would wait for the promise to resolve and return its value.
97
+ #
98
+ # The method finds an element matching the specified selector within the frame and passes it as a first argument to
99
+ # `pageFunction`. See [Working with selectors](./selectors.md#working-with-selectors) for more details. If no elements
100
+ # match the selector, the method throws an error.
101
+ #
102
+ # If `pageFunction` returns a [Promise], then `frame.$eval` would wait for the promise to resolve and return its value.
103
+ #
53
104
  # Examples:
105
+ #
54
106
  #
55
107
  # ```js
56
108
  # const searchValue = await frame.$eval('#search', el => el.value);
57
109
  # const preloadHref = await frame.$eval('link[rel=preload]', el => el.href);
58
110
  # const html = await frame.$eval('.main-container', (e, suffix) => e.outerHTML + suffix, 'hello');
59
111
  # ```
60
- def Seval(selector, pageFunction, arg: nil)
61
- raise NotImplementedError.new('Seval is not implemented yet.')
112
+ #
113
+ # ```python async
114
+ # search_value = await frame.eval_on_selector("#search", "el => el.value")
115
+ # preload_href = await frame.eval_on_selector("link[rel=preload]", "el => el.href")
116
+ # html = await frame.eval_on_selector(".main-container", "(e, suffix) => e.outerHTML + suffix", "hello")
117
+ # ```
118
+ #
119
+ # ```python sync
120
+ # search_value = frame.eval_on_selector("#search", "el => el.value")
121
+ # preload_href = frame.eval_on_selector("link[rel=preload]", "el => el.href")
122
+ # html = frame.eval_on_selector(".main-container", "(e, suffix) => e.outerHTML + suffix", "hello")
123
+ # ```
124
+ def eval_on_selector(selector, pageFunction, arg: nil)
125
+ wrap_impl(@impl.eval_on_selector(unwrap_impl(selector), unwrap_impl(pageFunction), arg: unwrap_impl(arg)))
62
126
  end
63
127
 
64
128
  # Returns the return value of `pageFunction`
65
- # The method finds all elements matching the specified selector within the frame and passes an array of matched elements as a first argument to `pageFunction`. See Working with selectors for more details.
66
- # If `pageFunction` returns a Promise, then `frame.$$eval` would wait for the promise to resolve and return its value.
129
+ #
130
+ # The method finds all elements matching the specified selector within the frame and passes an array of matched elements
131
+ # as a first argument to `pageFunction`. See [Working with selectors](./selectors.md#working-with-selectors) for more
132
+ # details.
133
+ #
134
+ # If `pageFunction` returns a [Promise], then `frame.$$eval` would wait for the promise to resolve and return its value.
135
+ #
67
136
  # Examples:
137
+ #
68
138
  #
69
139
  # ```js
70
140
  # const divsCounts = await frame.$$eval('div', (divs, min) => divs.length >= min, 10);
71
141
  # ```
72
- def SSeval(selector, pageFunction, arg: nil)
73
- raise NotImplementedError.new('SSeval is not implemented yet.')
142
+ #
143
+ # ```python async
144
+ # divs_counts = await frame.eval_on_selector_all("div", "(divs, min) => divs.length >= min", 10)
145
+ # ```
146
+ #
147
+ # ```python sync
148
+ # divs_counts = frame.eval_on_selector_all("div", "(divs, min) => divs.length >= min", 10)
149
+ # ```
150
+ def eval_on_selector_all(selector, pageFunction, arg: nil)
151
+ wrap_impl(@impl.eval_on_selector_all(unwrap_impl(selector), unwrap_impl(pageFunction), arg: unwrap_impl(arg)))
74
152
  end
75
153
 
76
154
  # Returns the added tag when the script's onload fires or when the script content was injected into frame.
155
+ #
77
156
  # Adds a `<script>` tag into the page with the desired url or content.
78
- def add_script_tag(params)
79
- raise NotImplementedError.new('add_script_tag is not implemented yet.')
157
+ def add_script_tag(content: nil, path: nil, type: nil, url: nil)
158
+ wrap_impl(@impl.add_script_tag(content: unwrap_impl(content), path: unwrap_impl(path), type: unwrap_impl(type), url: unwrap_impl(url)))
80
159
  end
81
160
 
82
161
  # Returns the added tag when the stylesheet's onload fires or when the CSS content was injected into frame.
83
- # Adds a `<link rel="stylesheet">` tag into the page with the desired url or a `<style type="text/css">` tag with the content.
84
- def add_style_tag(params)
85
- raise NotImplementedError.new('add_style_tag is not implemented yet.')
162
+ #
163
+ # Adds a `<link rel="stylesheet">` tag into the page with the desired url or a `<style type="text/css">` tag with the
164
+ # content.
165
+ def add_style_tag(content: nil, path: nil, url: nil)
166
+ wrap_impl(@impl.add_style_tag(content: unwrap_impl(content), path: unwrap_impl(path), url: unwrap_impl(url)))
86
167
  end
87
168
 
88
169
  # This method checks an element matching `selector` by performing the following steps:
170
+ # 1. Find an element match matching `selector`. If there is none, wait until a matching element is attached to the DOM.
171
+ # 1. Ensure that matched element is a checkbox or a radio input. If not, this method rejects. If the element is already
172
+ # checked, this method returns immediately.
173
+ # 1. Wait for [actionability](./actionability.md) checks on the matched element, unless `force` option is set. If the
174
+ # element is detached during the checks, the whole action is retried.
175
+ # 1. Scroll the element into view if needed.
176
+ # 1. Use [`property: Page.mouse`] to click in the center of the element.
177
+ # 1. Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
178
+ # 1. Ensure that the element is now checked. If not, this method rejects.
89
179
  #
90
- # Find an element match matching `selector`. If there is none, wait until a matching element is attached to the DOM.
91
- # Ensure that matched element is a checkbox or a radio input. If not, this method rejects. If the element is already checked, this method returns immediately.
92
- # Wait for actionability checks on the matched element, unless `force` option is set. If the element is detached during the checks, the whole action is retried.
93
- # Scroll the element into view if needed.
94
- # Use page.mouse to click in the center of the element.
95
- # Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
96
- # Ensure that the element is now checked. If not, this method rejects.
97
- #
98
- # When all steps combined have not finished during the specified `timeout`, this method rejects with a TimeoutError. Passing zero timeout disables this.
180
+ # When all steps combined have not finished during the specified `timeout`, this method rejects with a `TimeoutError`.
181
+ # Passing zero timeout disables this.
99
182
  def check(selector, force: nil, noWaitAfter: nil, timeout: nil)
100
- raise NotImplementedError.new('check is not implemented yet.')
183
+ wrap_impl(@impl.check(unwrap_impl(selector), force: unwrap_impl(force), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
101
184
  end
102
185
 
103
186
  def child_frames
104
- raise NotImplementedError.new('child_frames is not implemented yet.')
187
+ wrap_impl(@impl.child_frames)
105
188
  end
106
189
 
107
190
  # This method clicks an element matching `selector` by performing the following steps:
191
+ # 1. Find an element match matching `selector`. If there is none, wait until a matching element is attached to the DOM.
192
+ # 1. Wait for [actionability](./actionability.md) checks on the matched element, unless `force` option is set. If the
193
+ # element is detached during the checks, the whole action is retried.
194
+ # 1. Scroll the element into view if needed.
195
+ # 1. Use [`property: Page.mouse`] to click in the center of the element, or the specified `position`.
196
+ # 1. Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
108
197
  #
109
- # Find an element match matching `selector`. If there is none, wait until a matching element is attached to the DOM.
110
- # Wait for actionability checks on the matched element, unless `force` option is set. If the element is detached during the checks, the whole action is retried.
111
- # Scroll the element into view if needed.
112
- # Use page.mouse to click in the center of the element, or the specified `position`.
113
- # Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
114
- #
115
- # When all steps combined have not finished during the specified `timeout`, this method rejects with a TimeoutError. Passing zero timeout disables this.
198
+ # When all steps combined have not finished during the specified `timeout`, this method rejects with a `TimeoutError`.
199
+ # Passing zero timeout disables this.
116
200
  def click(
117
201
  selector,
118
202
  button: nil,
119
203
  clickCount: nil,
120
204
  delay: nil,
121
- position: nil,
122
- modifiers: nil,
123
205
  force: nil,
206
+ modifiers: nil,
124
207
  noWaitAfter: nil,
208
+ position: nil,
125
209
  timeout: nil)
126
- raise NotImplementedError.new('click is not implemented yet.')
210
+ wrap_impl(@impl.click(unwrap_impl(selector), 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)))
127
211
  end
128
212
 
129
213
  # Gets the full HTML contents of the frame, including the doctype.
130
214
  def content
131
- raise NotImplementedError.new('content is not implemented yet.')
215
+ wrap_impl(@impl.content)
132
216
  end
133
217
 
134
218
  # This method double clicks an element matching `selector` by performing the following steps:
219
+ # 1. Find an element match matching `selector`. If there is none, wait until a matching element is attached to the DOM.
220
+ # 1. Wait for [actionability](./actionability.md) checks on the matched element, unless `force` option is set. If the
221
+ # element is detached during the checks, the whole action is retried.
222
+ # 1. Scroll the element into view if needed.
223
+ # 1. Use [`property: Page.mouse`] to double click in the center of the element, or the specified `position`.
224
+ # 1. Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set. Note that if the
225
+ # first click of the `dblclick()` triggers a navigation event, this method will reject.
135
226
  #
136
- # Find an element match matching `selector`. If there is none, wait until a matching element is attached to the DOM.
137
- # Wait for actionability checks on the matched element, unless `force` option is set. If the element is detached during the checks, the whole action is retried.
138
- # Scroll the element into view if needed.
139
- # Use page.mouse to double click in the center of the element, or the specified `position`.
140
- # 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.
227
+ # When all steps combined have not finished during the specified `timeout`, this method rejects with a `TimeoutError`.
228
+ # Passing zero timeout disables this.
141
229
  #
142
- # When all steps combined have not finished during the specified `timeout`, this method rejects with a TimeoutError. Passing zero timeout disables this.
143
- #
144
- # **NOTE** `frame.dblclick()` dispatches two `click` events and a single `dblclick` event.
230
+ # > NOTE: `frame.dblclick()` dispatches two `click` events and a single `dblclick` event.
145
231
  def dblclick(
146
232
  selector,
147
233
  button: nil,
148
234
  delay: nil,
149
- position: nil,
150
- modifiers: nil,
151
235
  force: nil,
236
+ modifiers: nil,
152
237
  noWaitAfter: nil,
238
+ position: nil,
153
239
  timeout: nil)
154
- raise NotImplementedError.new('dblclick is not implemented yet.')
240
+ wrap_impl(@impl.dblclick(unwrap_impl(selector), 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)))
155
241
  end
156
242
 
157
- # 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().
243
+ # The snippet below dispatches the `click` event on the element. Regardless of the visibility state of the elment, `click`
244
+ # is dispatched. This is equivalend to calling
245
+ # [element.click()](https://developer.mozilla.org/en-US/docs/Web/API/HTMLElement/click).
246
+ #
158
247
  #
159
248
  # ```js
160
249
  # await frame.dispatchEvent('button#submit', 'click');
161
250
  # ```
162
- # 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.
163
- # Since `eventInit` is event-specific, please refer to the events documentation for the lists of initial properties:
164
251
  #
165
- # DragEvent
166
- # FocusEvent
167
- # KeyboardEvent
168
- # MouseEvent
169
- # PointerEvent
170
- # TouchEvent
171
- # Event
252
+ # ```python async
253
+ # await frame.dispatch_event("button#submit", "click")
254
+ # ```
255
+ #
256
+ # ```python sync
257
+ # frame.dispatch_event("button#submit", "click")
258
+ # ```
259
+ #
260
+ # Under the hood, it creates an instance of an event based on the given `type`, initializes it with `eventInit` properties
261
+ # and dispatches it on the element. Events are `composed`, `cancelable` and bubble by default.
262
+ #
263
+ # Since `eventInit` is event-specific, please refer to the events documentation for the lists of initial properties:
264
+ # - [DragEvent](https://developer.mozilla.org/en-US/docs/Web/API/DragEvent/DragEvent)
265
+ # - [FocusEvent](https://developer.mozilla.org/en-US/docs/Web/API/FocusEvent/FocusEvent)
266
+ # - [KeyboardEvent](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/KeyboardEvent)
267
+ # - [MouseEvent](https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/MouseEvent)
268
+ # - [PointerEvent](https://developer.mozilla.org/en-US/docs/Web/API/PointerEvent/PointerEvent)
269
+ # - [TouchEvent](https://developer.mozilla.org/en-US/docs/Web/API/TouchEvent/TouchEvent)
270
+ # - [Event](https://developer.mozilla.org/en-US/docs/Web/API/Event/Event)
172
271
  #
173
272
  # You can also specify `JSHandle` as the property value if you want live objects to be passed into the event:
273
+ #
174
274
  #
175
275
  # ```js
176
276
  # // Note you can only create DataTransfer in Chromium and Firefox
177
277
  # const dataTransfer = await frame.evaluateHandle(() => new DataTransfer());
178
278
  # await frame.dispatchEvent('#source', 'dragstart', { dataTransfer });
179
279
  # ```
280
+ #
281
+ # ```python async
282
+ # # note you can only create data_transfer in chromium and firefox
283
+ # data_transfer = await frame.evaluate_handle("new DataTransfer()")
284
+ # await frame.dispatch_event("#source", "dragstart", { "dataTransfer": data_transfer })
285
+ # ```
286
+ #
287
+ # ```python sync
288
+ # # note you can only create data_transfer in chromium and firefox
289
+ # data_transfer = frame.evaluate_handle("new DataTransfer()")
290
+ # frame.dispatch_event("#source", "dragstart", { "dataTransfer": data_transfer })
291
+ # ```
180
292
  def dispatch_event(selector, type, eventInit: nil, timeout: nil)
181
- raise NotImplementedError.new('dispatch_event is not implemented yet.')
293
+ wrap_impl(@impl.dispatch_event(unwrap_impl(selector), unwrap_impl(type), eventInit: unwrap_impl(eventInit), timeout: unwrap_impl(timeout)))
182
294
  end
183
295
 
184
296
  # Returns the return value of `pageFunction`
185
- # If the function passed to the `frame.evaluate` returns a Promise, then `frame.evaluate` would wait for the promise to resolve and return its value.
186
- # If the function passed to the `frame.evaluate` returns a non-Serializable value, then `frame.evaluate` returns `undefined`. DevTools Protocol also supports transferring some additional values that are not serializable by `JSON`: `-0`, `NaN`, `Infinity`, `-Infinity`, and bigint literals.
297
+ #
298
+ # If the function passed to the [`method: Frame.evaluate`] returns a [Promise], then [`method: Frame.evaluate`] would wait
299
+ # for the promise to resolve and return its value.
300
+ #
301
+ # If the function passed to the [`method: Frame.evaluate`] returns a non-[Serializable] value,
302
+ # then[ method: `Frame.evaluate`] returns `undefined`. DevTools Protocol also supports transferring some additional values
303
+ # that are not serializable by `JSON`: `-0`, `NaN`, `Infinity`, `-Infinity`, and bigint literals.
304
+ #
187
305
  #
188
306
  # ```js
189
307
  # const result = await frame.evaluate(([x, y]) => {
@@ -191,36 +309,102 @@ module Playwright
191
309
  # }, [7, 8]);
192
310
  # console.log(result); // prints "56"
193
311
  # ```
312
+ #
313
+ # ```python async
314
+ # result = await frame.evaluate("([x, y]) => Promise.resolve(x * y)", [7, 8])
315
+ # print(result) # prints "56"
316
+ # ```
317
+ #
318
+ # ```python sync
319
+ # result = frame.evaluate("([x, y]) => Promise.resolve(x * y)", [7, 8])
320
+ # print(result) # prints "56"
321
+ # ```
322
+ #
194
323
  # A string can also be passed in instead of a function.
324
+ #
195
325
  #
196
326
  # ```js
197
327
  # console.log(await frame.evaluate('1 + 2')); // prints "3"
198
328
  # ```
199
- # ElementHandle instances can be passed as an argument to the `frame.evaluate`:
329
+ #
330
+ # ```python async
331
+ # print(await frame.evaluate("1 + 2")) # prints "3"
332
+ # x = 10
333
+ # print(await frame.evaluate(f"1 + {x}")) # prints "11"
334
+ # ```
335
+ #
336
+ # ```python sync
337
+ # print(frame.evaluate("1 + 2")) # prints "3"
338
+ # x = 10
339
+ # print(frame.evaluate(f"1 + {x}")) # prints "11"
340
+ # ```
341
+ #
342
+ # `ElementHandle` instances can be passed as an argument to the [`method: Frame.evaluate`]:
343
+ #
200
344
  #
201
345
  # ```js
202
346
  # const bodyHandle = await frame.$('body');
203
347
  # const html = await frame.evaluate(([body, suffix]) => body.innerHTML + suffix, [bodyHandle, 'hello']);
204
348
  # await bodyHandle.dispose();
205
349
  # ```
350
+ #
351
+ # ```python async
352
+ # body_handle = await frame.query_selector("body")
353
+ # html = await frame.evaluate("([body, suffix]) => body.innerHTML + suffix", [body_handle, "hello"])
354
+ # await body_handle.dispose()
355
+ # ```
356
+ #
357
+ # ```python sync
358
+ # body_handle = frame.query_selector("body")
359
+ # html = frame.evaluate("([body, suffix]) => body.innerHTML + suffix", [body_handle, "hello"])
360
+ # body_handle.dispose()
361
+ # ```
206
362
  def evaluate(pageFunction, arg: nil)
207
- raise NotImplementedError.new('evaluate is not implemented yet.')
363
+ wrap_impl(@impl.evaluate(unwrap_impl(pageFunction), arg: unwrap_impl(arg)))
208
364
  end
209
365
 
210
366
  # Returns the return value of `pageFunction` as in-page object (JSHandle).
211
- # The only difference between `frame.evaluate` and `frame.evaluateHandle` is that `frame.evaluateHandle` returns in-page object (JSHandle).
212
- # If the function, passed to the `frame.evaluateHandle`, returns a Promise, then `frame.evaluateHandle` would wait for the promise to resolve and return its value.
367
+ #
368
+ # The only difference between [`method: Frame.evaluate`] and [`method: Frame.evaluateHandle`] is
369
+ # that[ method: Fframe.evaluateHandle`] returns in-page object (JSHandle).
370
+ #
371
+ # If the function, passed to the [`method: Frame.evaluateHandle`], returns a [Promise],
372
+ # then[ method: Fframe.evaluateHandle`] would wait for the promise to resolve and return its value.
373
+ #
213
374
  #
214
375
  # ```js
215
376
  # const aWindowHandle = await frame.evaluateHandle(() => Promise.resolve(window));
216
377
  # aWindowHandle; // Handle for the window object.
217
378
  # ```
379
+ #
380
+ # ```python async
381
+ # # FIXME
382
+ # a_window_handle = await frame.evaluate_handle("Promise.resolve(window)")
383
+ # a_window_handle # handle for the window object.
384
+ # ```
385
+ #
386
+ # ```python sync
387
+ # a_window_handle = frame.evaluate_handle("Promise.resolve(window)")
388
+ # a_window_handle # handle for the window object.
389
+ # ```
390
+ #
218
391
  # A string can also be passed in instead of a function.
392
+ #
219
393
  #
220
394
  # ```js
221
395
  # const aHandle = await frame.evaluateHandle('document'); // Handle for the 'document'.
222
396
  # ```
223
- # JSHandle instances can be passed as an argument to the `frame.evaluateHandle`:
397
+ #
398
+ # ```python async
399
+ # a_handle = await page.evaluate_handle("document") # handle for the "document"
400
+ # ```
401
+ #
402
+ # ```python sync
403
+ # a_handle = page.evaluate_handle("document") # handle for the "document"
404
+ # ```
405
+ #
406
+ # `JSHandle` instances can be passed as an argument to the [`method: Frame.evaluateHandle`]:
407
+ #
224
408
  #
225
409
  # ```js
226
410
  # const aHandle = await frame.evaluateHandle(() => document.body);
@@ -228,124 +412,211 @@ module Playwright
228
412
  # console.log(await resultHandle.jsonValue());
229
413
  # await resultHandle.dispose();
230
414
  # ```
415
+ #
416
+ # ```python async
417
+ # a_handle = await page.evaluate_handle("document.body")
418
+ # result_handle = await page.evaluate_handle("body => body.innerHTML", a_handle)
419
+ # print(await result_handle.json_value())
420
+ # await result_handle.dispose()
421
+ # ```
422
+ #
423
+ # ```python sync
424
+ # a_handle = page.evaluate_handle("document.body")
425
+ # result_handle = page.evaluate_handle("body => body.innerHTML", a_handle)
426
+ # print(result_handle.json_value())
427
+ # result_handle.dispose()
428
+ # ```
231
429
  def evaluate_handle(pageFunction, arg: nil)
232
- raise NotImplementedError.new('evaluate_handle is not implemented yet.')
430
+ wrap_impl(@impl.evaluate_handle(unwrap_impl(pageFunction), arg: unwrap_impl(arg)))
233
431
  end
234
432
 
235
- # This method waits for an element matching `selector`, waits for actionability checks, focuses the element, fills it and triggers an `input` event after filling. If the element matching `selector` 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.
236
- # To send fine-grained keyboard events, use `frame.type(selector, text[, options])`.
433
+ # This method waits for an element matching `selector`, waits for [actionability](./actionability.md) checks, focuses the
434
+ # element, fills it and triggers an `input` event after filling. If the element matching `selector` is not an `<input>`,
435
+ # `<textarea>` or `[contenteditable]` element, this method throws an error. Note that you can pass an empty string to
436
+ # clear the input field.
437
+ #
438
+ # To send fine-grained keyboard events, use [`method: Frame.type`].
237
439
  def fill(selector, value, noWaitAfter: nil, timeout: nil)
238
- raise NotImplementedError.new('fill is not implemented yet.')
440
+ wrap_impl(@impl.fill(unwrap_impl(selector), unwrap_impl(value), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
239
441
  end
240
442
 
241
- # This method fetches an element with `selector` and focuses it. If there's no element matching `selector`, the method waits until a matching element appears in the DOM.
443
+ # This method fetches an element with `selector` and focuses it. If there's no element matching `selector`, the method
444
+ # waits until a matching element appears in the DOM.
242
445
  def focus(selector, timeout: nil)
243
- raise NotImplementedError.new('focus is not implemented yet.')
446
+ wrap_impl(@impl.focus(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
244
447
  end
245
448
 
246
449
  # Returns the `frame` or `iframe` element handle which corresponds to this frame.
247
- # This is an inverse of `elementHandle.contentFrame()`. Note that returned handle actually belongs to the parent frame.
450
+ #
451
+ # This is an inverse of [`method: ElementHandle.contentFrame`]. Note that returned handle actually belongs to the parent
452
+ # frame.
453
+ #
248
454
  # This method throws an error if the frame has been detached before `frameElement()` returns.
455
+ #
249
456
  #
250
457
  # ```js
251
458
  # const frameElement = await frame.frameElement();
252
459
  # const contentFrame = await frameElement.contentFrame();
253
460
  # console.log(frame === contentFrame); // -> true
254
461
  # ```
462
+ #
463
+ # ```python async
464
+ # frame_element = await frame.frame_element()
465
+ # content_frame = await frame_element.content_frame()
466
+ # assert frame == content_frame
467
+ # ```
468
+ #
469
+ # ```python sync
470
+ # frame_element = frame.frame_element()
471
+ # content_frame = frame_element.content_frame()
472
+ # assert frame == content_frame
473
+ # ```
255
474
  def frame_element
256
475
  raise NotImplementedError.new('frame_element is not implemented yet.')
257
476
  end
258
477
 
259
478
  # Returns element attribute value.
260
479
  def get_attribute(selector, name, timeout: nil)
261
- raise NotImplementedError.new('get_attribute is not implemented yet.')
480
+ wrap_impl(@impl.get_attribute(unwrap_impl(selector), unwrap_impl(name), timeout: unwrap_impl(timeout)))
262
481
  end
263
482
 
264
- # Returns the main resource response. In case of multiple redirects, the navigation will resolve with the response of the last redirect.
265
- # `frame.goto` will throw an error if:
483
+ # Returns the main resource response. In case of multiple redirects, the navigation will resolve with the response of the
484
+ # last redirect.
266
485
  #
267
- # there's an SSL error (e.g. in case of self-signed certificates).
268
- # target URL is invalid.
269
- # the `timeout` is exceeded during navigation.
270
- # the remote server does not respond or is unreachable.
271
- # the main resource failed to load.
486
+ # `frame.goto` will throw an error if:
487
+ # - there's an SSL error (e.g. in case of self-signed certificates).
488
+ # - target URL is invalid.
489
+ # - the `timeout` is exceeded during navigation.
490
+ # - the remote server does not respond or is unreachable.
491
+ # - the main resource failed to load.
272
492
  #
273
- # `frame.goto` will not throw an error when any valid HTTP status code is returned by the remote server, including 404 "Not Found" and 500 "Internal Server Error". The status code for such responses can be retrieved by calling `response.status()`.
493
+ # `frame.goto` will not throw an error when any valid HTTP status code is returned by the remote server, including 404
494
+ # "Not Found" and 500 "Internal Server Error". The status code for such responses can be retrieved by calling
495
+ # [`method: Response.status`].
274
496
  #
275
- # **NOTE** `frame.goto` either throws an error or returns a main resource response. The only exceptions are navigation to `about:blank` or navigation to the same URL with a different hash, which would succeed and return `null`.
276
- # **NOTE** Headless mode doesn't support navigation to a PDF document. See the upstream issue.
277
- def goto(url, timeout: nil, waitUntil: nil, referer: nil)
278
- wrap_channel_owner(@channel_owner.goto(url, timeout: timeout, waitUntil: waitUntil, referer: referer))
497
+ # > NOTE: `frame.goto` either throws an error or returns a main resource response. The only exceptions are navigation to
498
+ # `about:blank` or navigation to the same URL with a different hash, which would succeed and return `null`.
499
+ # > NOTE: Headless mode doesn't support navigation to a PDF document. See the
500
+ # [upstream issue](https://bugs.chromium.org/p/chromium/issues/detail?id=761295).
501
+ def goto(url, referer: nil, timeout: nil, waitUntil: nil)
502
+ wrap_impl(@impl.goto(unwrap_impl(url), referer: unwrap_impl(referer), timeout: unwrap_impl(timeout), waitUntil: unwrap_impl(waitUntil)))
279
503
  end
280
504
 
281
505
  # This method hovers over an element matching `selector` by performing the following steps:
506
+ # 1. Find an element match matching `selector`. If there is none, wait until a matching element is attached to the DOM.
507
+ # 1. Wait for [actionability](./actionability.md) checks on the matched element, unless `force` option is set. If the
508
+ # element is detached during the checks, the whole action is retried.
509
+ # 1. Scroll the element into view if needed.
510
+ # 1. Use [`property: Page.mouse`] to hover over the center of the element, or the specified `position`.
511
+ # 1. Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
282
512
  #
283
- # Find an element match matching `selector`. If there is none, wait until a matching element is attached to the DOM.
284
- # Wait for actionability checks on the matched element, unless `force` option is set. If the element is detached during the checks, the whole action is retried.
285
- # Scroll the element into view if needed.
286
- # Use page.mouse to hover over the center of the element, or the specified `position`.
287
- # Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
288
- #
289
- # When all steps combined have not finished during the specified `timeout`, this method rejects with a TimeoutError. Passing zero timeout disables this.
513
+ # When all steps combined have not finished during the specified `timeout`, this method rejects with a `TimeoutError`.
514
+ # Passing zero timeout disables this.
290
515
  def hover(
291
516
  selector,
292
- position: nil,
293
- modifiers: nil,
294
517
  force: nil,
518
+ modifiers: nil,
519
+ position: nil,
295
520
  timeout: nil)
296
- raise NotImplementedError.new('hover is not implemented yet.')
521
+ wrap_impl(@impl.hover(unwrap_impl(selector), force: unwrap_impl(force), modifiers: unwrap_impl(modifiers), position: unwrap_impl(position), timeout: unwrap_impl(timeout)))
297
522
  end
298
523
 
299
524
  # Returns `element.innerHTML`.
300
525
  def inner_html(selector, timeout: nil)
301
- raise NotImplementedError.new('inner_html is not implemented yet.')
526
+ wrap_impl(@impl.inner_html(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
302
527
  end
303
528
 
304
529
  # Returns `element.innerText`.
305
530
  def inner_text(selector, timeout: nil)
306
- raise NotImplementedError.new('inner_text is not implemented yet.')
531
+ wrap_impl(@impl.inner_text(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
532
+ end
533
+
534
+ # Returns whether the element is checked. Throws if the element is not a checkbox or radio input.
535
+ def checked?(selector, timeout: nil)
536
+ wrap_impl(@impl.checked?(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
307
537
  end
308
538
 
309
539
  # Returns `true` if the frame has been detached, or `false` otherwise.
310
540
  def detached?
311
- raise NotImplementedError.new('detached? is not implemented yet.')
541
+ wrap_impl(@impl.detached?)
542
+ end
543
+
544
+ # Returns whether the element is disabled, the opposite of [enabled](./actionability.md#enabled).
545
+ def disabled?(selector, timeout: nil)
546
+ wrap_impl(@impl.disabled?(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
547
+ end
548
+
549
+ # Returns whether the element is [editable](./actionability.md#editable).
550
+ def editable?(selector, timeout: nil)
551
+ wrap_impl(@impl.editable?(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
552
+ end
553
+
554
+ # Returns whether the element is [enabled](./actionability.md#enabled).
555
+ def enabled?(selector, timeout: nil)
556
+ wrap_impl(@impl.enabled?(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
557
+ end
558
+
559
+ # Returns whether the element is hidden, the opposite of [visible](./actionability.md#visible).
560
+ def hidden?(selector, timeout: nil)
561
+ wrap_impl(@impl.hidden?(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
562
+ end
563
+
564
+ # Returns whether the element is [visible](./actionability.md#visible).
565
+ def visible?(selector, timeout: nil)
566
+ wrap_impl(@impl.visible?(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
312
567
  end
313
568
 
314
569
  # Returns frame's name attribute as specified in the tag.
570
+ #
315
571
  # If the name is empty, returns the id attribute instead.
316
572
  #
317
- # **NOTE** This value is calculated once when the frame is created, and will not update if the attribute is changed later.
573
+ # > NOTE: This value is calculated once when the frame is created, and will not update if the attribute is changed later.
318
574
  def name
319
- raise NotImplementedError.new('name is not implemented yet.')
575
+ wrap_impl(@impl.name)
320
576
  end
321
577
 
322
578
  # Returns the page containing this frame.
323
579
  def page
324
- wrap_channel_owner(@channel_owner.page)
580
+ wrap_impl(@impl.page)
325
581
  end
326
582
 
327
583
  # Parent frame, if any. Detached frames and main frames return `null`.
328
584
  def parent_frame
329
- raise NotImplementedError.new('parent_frame is not implemented yet.')
585
+ wrap_impl(@impl.parent_frame)
330
586
  end
331
587
 
332
- # `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:
333
- # `F1` - `F12`, `Digit0`- `Digit9`, `KeyA`- `KeyZ`, `Backquote`, `Minus`, `Equal`, `Backslash`, `Backspace`, `Tab`, `Delete`, `Escape`, `ArrowDown`, `End`, `Enter`, `Home`, `Insert`, `PageDown`, `PageUp`, `ArrowRight`, `ArrowUp`, etc.
334
- # Following modification shortcuts are also suported: `Shift`, `Control`, `Alt`, `Meta`, `ShiftLeft`.
588
+ # `key` can specify the intended [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key)
589
+ # value or a single character to generate the text for. A superset of the `key` values can be found
590
+ # [here](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values). Examples of the keys are:
591
+ #
592
+ # `F1` - `F12`, `Digit0`- `Digit9`, `KeyA`- `KeyZ`, `Backquote`, `Minus`, `Equal`, `Backslash`, `Backspace`, `Tab`,
593
+ # `Delete`, `Escape`, `ArrowDown`, `End`, `Enter`, `Home`, `Insert`, `PageDown`, `PageUp`, `ArrowRight`, `ArrowUp`, etc.
594
+ #
595
+ # Following modification shortcuts are also supported: `Shift`, `Control`, `Alt`, `Meta`, `ShiftLeft`.
596
+ #
335
597
  # Holding down `Shift` will type the text that corresponds to the `key` in the upper case.
336
- # If `key` is a single character, it is case-sensitive, so the values `a` and `A` will generate different respective texts.
337
- # 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.
598
+ #
599
+ # If `key` is a single character, it is case-sensitive, so the values `a` and `A` will generate different respective
600
+ # texts.
601
+ #
602
+ # Shortcuts such as `key: "Control+o"` or `key: "Control+Shift+T"` are supported as well. When speficied with the
603
+ # modifier, modifier is pressed and being held while the subsequent key is being pressed.
338
604
  def press(
339
605
  selector,
340
606
  key,
341
607
  delay: nil,
342
608
  noWaitAfter: nil,
343
609
  timeout: nil)
344
- raise NotImplementedError.new('press is not implemented yet.')
610
+ wrap_impl(@impl.press(unwrap_impl(selector), unwrap_impl(key), delay: unwrap_impl(delay), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
345
611
  end
346
612
 
347
613
  # Returns the array of option values that have been successfully selected.
348
- # Triggers a `change` and `input` event once all the provided options have been selected. If there's no `<select>` element matching `selector`, the method throws an error.
614
+ #
615
+ # Triggers a `change` and `input` event once all the provided options have been selected. If there's no `<select>` element
616
+ # matching `selector`, the method throws an error.
617
+ #
618
+ # Will wait until all specified options are present in the `<select>` element.
619
+ #
349
620
  #
350
621
  # ```js
351
622
  # // single selection matching the value
@@ -357,89 +628,129 @@ module Playwright
357
628
  # // multiple selection
358
629
  # frame.selectOption('select#colors', 'red', 'green', 'blue');
359
630
  # ```
631
+ #
632
+ # ```python async
633
+ # # single selection matching the value
634
+ # await frame.select_option("select#colors", "blue")
635
+ # # single selection matching the label
636
+ # await frame.select_option("select#colors", label="blue")
637
+ # # multiple selection
638
+ # await frame.select_option("select#colors", value=["red", "green", "blue"])
639
+ # ```
640
+ #
641
+ # ```python sync
642
+ # # single selection matching the value
643
+ # frame.select_option("select#colors", "blue")
644
+ # # single selection matching both the label
645
+ # frame.select_option("select#colors", label="blue")
646
+ # # multiple selection
647
+ # frame.select_option("select#colors", value=["red", "green", "blue"])
648
+ # ```
360
649
  def select_option(selector, values, noWaitAfter: nil, timeout: nil)
361
- raise NotImplementedError.new('select_option is not implemented yet.')
650
+ wrap_impl(@impl.select_option(unwrap_impl(selector), unwrap_impl(values), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
362
651
  end
363
652
 
364
653
  def set_content(html, timeout: nil, waitUntil: nil)
365
- raise NotImplementedError.new('set_content is not implemented yet.')
654
+ wrap_impl(@impl.set_content(unwrap_impl(html), timeout: unwrap_impl(timeout), waitUntil: unwrap_impl(waitUntil)))
366
655
  end
656
+ alias_method :content=, :set_content
367
657
 
368
- # This method expects `selector` to point to an input element.
369
- # 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.
658
+ # This method expects `selector` to point to an
659
+ # [input element](https://developer.mozilla.org/en-US/docs/Web/HTML/Element/input).
660
+ #
661
+ # Sets the value of the file input to these file paths or files. If some of the `filePaths` are relative paths, then they
662
+ # are resolved relative to the the current working directory. For empty array, clears the selected files.
370
663
  def set_input_files(selector, files, noWaitAfter: nil, timeout: nil)
371
- raise NotImplementedError.new('set_input_files is not implemented yet.')
664
+ wrap_impl(@impl.set_input_files(unwrap_impl(selector), unwrap_impl(files), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
372
665
  end
373
666
 
374
667
  # This method taps an element matching `selector` by performing the following steps:
668
+ # 1. Find an element match matching `selector`. If there is none, wait until a matching element is attached to the DOM.
669
+ # 1. Wait for [actionability](./actionability.md) checks on the matched element, unless `force` option is set. If the
670
+ # element is detached during the checks, the whole action is retried.
671
+ # 1. Scroll the element into view if needed.
672
+ # 1. Use [`property: Page.touchscreen`] to tap the center of the element, or the specified `position`.
673
+ # 1. Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
375
674
  #
376
- # Find an element match matching `selector`. If there is none, wait until a matching element is attached to the DOM.
377
- # Wait for actionability checks on the matched element, unless `force` option is set. If the element is detached during the checks, the whole action is retried.
378
- # Scroll the element into view if needed.
379
- # Use page.touchscreen to tap the center of the element, or the specified `position`.
380
- # Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
675
+ # When all steps combined have not finished during the specified `timeout`, this method rejects with a `TimeoutError`.
676
+ # Passing zero timeout disables this.
381
677
  #
382
- # When all steps combined have not finished during the specified `timeout`, this method rejects with a TimeoutError. Passing zero timeout disables this.
383
- #
384
- # **NOTE** `frame.tap()` requires that the `hasTouch` option of the browser context be set to true.
678
+ # > NOTE: `frame.tap()` requires that the `hasTouch` option of the browser context be set to true.
385
679
  def tap_point(
386
680
  selector,
387
- position: nil,
681
+ force: nil,
388
682
  modifiers: nil,
389
683
  noWaitAfter: nil,
390
- force: nil,
684
+ position: nil,
391
685
  timeout: nil)
392
- raise NotImplementedError.new('tap_point is not implemented yet.')
686
+ wrap_impl(@impl.tap_point(unwrap_impl(selector), force: unwrap_impl(force), modifiers: unwrap_impl(modifiers), noWaitAfter: unwrap_impl(noWaitAfter), position: unwrap_impl(position), timeout: unwrap_impl(timeout)))
393
687
  end
394
688
 
395
689
  # Returns `element.textContent`.
396
690
  def text_content(selector, timeout: nil)
397
- raise NotImplementedError.new('text_content is not implemented yet.')
691
+ wrap_impl(@impl.text_content(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
398
692
  end
399
693
 
400
694
  # Returns the page title.
401
695
  def title
402
- raise NotImplementedError.new('title is not implemented yet.')
696
+ wrap_impl(@impl.title)
403
697
  end
404
698
 
405
- # Sends a `keydown`, `keypress`/`input`, and `keyup` event for each character in the text. `frame.type` can be used to send fine-grained keyboard events. To fill values in form fields, use `frame.fill(selector, value[, options])`.
406
- # To press a special key, like `Control` or `ArrowDown`, use `keyboard.press(key[, options])`.
699
+ # Sends a `keydown`, `keypress`/`input`, and `keyup` event for each character in the text. `frame.type` can be used to
700
+ # send fine-grained keyboard events. To fill values in form fields, use [`method: Frame.fill`].
701
+ #
702
+ # To press a special key, like `Control` or `ArrowDown`, use [`method: Keyboard.press`].
703
+ #
407
704
  #
408
705
  # ```js
409
706
  # await frame.type('#mytextarea', 'Hello'); // Types instantly
410
707
  # await frame.type('#mytextarea', 'World', {delay: 100}); // Types slower, like a user
411
708
  # ```
412
- def type_text(
709
+ #
710
+ # ```python async
711
+ # await frame.type("#mytextarea", "hello") # types instantly
712
+ # await frame.type("#mytextarea", "world", delay=100) # types slower, like a user
713
+ # ```
714
+ #
715
+ # ```python sync
716
+ # frame.type("#mytextarea", "hello") # types instantly
717
+ # frame.type("#mytextarea", "world", delay=100) # types slower, like a user
718
+ # ```
719
+ def type(
413
720
  selector,
414
721
  text,
415
722
  delay: nil,
416
723
  noWaitAfter: nil,
417
724
  timeout: nil)
418
- raise NotImplementedError.new('type_text is not implemented yet.')
725
+ wrap_impl(@impl.type(unwrap_impl(selector), unwrap_impl(text), delay: unwrap_impl(delay), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
419
726
  end
420
727
 
421
728
  # This method checks an element matching `selector` by performing the following steps:
729
+ # 1. Find an element match matching `selector`. If there is none, wait until a matching element is attached to the DOM.
730
+ # 1. Ensure that matched element is a checkbox or a radio input. If not, this method rejects. If the element is already
731
+ # unchecked, this method returns immediately.
732
+ # 1. Wait for [actionability](./actionability.md) checks on the matched element, unless `force` option is set. If the
733
+ # element is detached during the checks, the whole action is retried.
734
+ # 1. Scroll the element into view if needed.
735
+ # 1. Use [`property: Page.mouse`] to click in the center of the element.
736
+ # 1. Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
737
+ # 1. Ensure that the element is now unchecked. If not, this method rejects.
422
738
  #
423
- # Find an element match matching `selector`. If there is none, wait until a matching element is attached to the DOM.
424
- # Ensure that matched element is a checkbox or a radio input. If not, this method rejects. If the element is already unchecked, this method returns immediately.
425
- # Wait for actionability checks on the matched element, unless `force` option is set. If the element is detached during the checks, the whole action is retried.
426
- # Scroll the element into view if needed.
427
- # Use page.mouse to click in the center of the element.
428
- # Wait for initiated navigations to either succeed or fail, unless `noWaitAfter` option is set.
429
- # Ensure that the element is now unchecked. If not, this method rejects.
430
- #
431
- # When all steps combined have not finished during the specified `timeout`, this method rejects with a TimeoutError. Passing zero timeout disables this.
739
+ # When all steps combined have not finished during the specified `timeout`, this method rejects with a `TimeoutError`.
740
+ # Passing zero timeout disables this.
432
741
  def uncheck(selector, force: nil, noWaitAfter: nil, timeout: nil)
433
- raise NotImplementedError.new('uncheck is not implemented yet.')
742
+ wrap_impl(@impl.uncheck(unwrap_impl(selector), force: unwrap_impl(force), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
434
743
  end
435
744
 
436
745
  # Returns frame's url.
437
746
  def url
438
- raise NotImplementedError.new('url is not implemented yet.')
747
+ wrap_impl(@impl.url)
439
748
  end
440
749
 
441
750
  # Returns when the `pageFunction` returns a truthy value, returns that value.
751
+ #
442
752
  # The `waitForFunction` can be used to observe viewport size change:
753
+ #
443
754
  #
444
755
  # ```js
445
756
  # const { firefox } = require('playwright'); // Or 'chromium' or 'webkit'.
@@ -453,74 +764,217 @@ module Playwright
453
764
  # await browser.close();
454
765
  # })();
455
766
  # ```
767
+ #
768
+ # ```python async
769
+ # import asyncio
770
+ # from playwright.async_api import async_playwright
771
+ #
772
+ # async def run(playwright):
773
+ # webkit = playwright.webkit
774
+ # browser = await webkit.launch()
775
+ # page = await browser.new_page()
776
+ # await page.evaluate("window.x = 0; setTimeout(() => { window.x = 100 }, 1000);", force_expr=True)
777
+ # await page.main_frame.wait_for_function("() => window.x > 0")
778
+ # await browser.close()
779
+ #
780
+ # async def main():
781
+ # async with async_playwright() as playwright:
782
+ # await run(playwright)
783
+ # asyncio.run(main())
784
+ # ```
785
+ #
786
+ # ```python sync
787
+ # from playwright.sync_api import sync_playwright
788
+ #
789
+ # def run(playwright):
790
+ # webkit = playwright.webkit
791
+ # browser = webkit.launch()
792
+ # page = browser.new_page()
793
+ # page.evaluate("window.x = 0; setTimeout(() => { window.x = 100 }, 1000);", force_expr=True)
794
+ # page.main_frame.wait_for_function("() => window.x > 0")
795
+ # browser.close()
796
+ #
797
+ # with sync_playwright() as playwright:
798
+ # run(playwright)
799
+ # ```
800
+ #
456
801
  # To pass an argument to the predicate of `frame.waitForFunction` function:
802
+ #
457
803
  #
458
804
  # ```js
459
805
  # const selector = '.foo';
460
806
  # await frame.waitForFunction(selector => !!document.querySelector(selector), selector);
461
807
  # ```
808
+ #
809
+ # ```python async
810
+ # selector = ".foo"
811
+ # await frame.wait_for_function("selector => !!document.querySelector(selector)", selector)
812
+ # ```
813
+ #
814
+ # ```python sync
815
+ # selector = ".foo"
816
+ # frame.wait_for_function("selector => !!document.querySelector(selector)", selector)
817
+ # ```
462
818
  def wait_for_function(pageFunction, arg: nil, polling: nil, timeout: nil)
463
- raise NotImplementedError.new('wait_for_function is not implemented yet.')
819
+ wrap_impl(@impl.wait_for_function(unwrap_impl(pageFunction), arg: unwrap_impl(arg), polling: unwrap_impl(polling), timeout: unwrap_impl(timeout)))
464
820
  end
465
821
 
466
822
  # Waits for the required load state to be reached.
467
- # This returns when the frame reaches a required load state, `load` by default. The navigation must have been committed when this method is called. If current document has already reached the required state, resolves immediately.
823
+ #
824
+ # This returns when the frame reaches a required load state, `load` by default. The navigation must have been committed
825
+ # when this method is called. If current document has already reached the required state, resolves immediately.
826
+ #
468
827
  #
469
828
  # ```js
470
829
  # await frame.click('button'); // Click triggers navigation.
471
830
  # await frame.waitForLoadState(); // Waits for 'load' state by default.
472
831
  # ```
832
+ #
833
+ # ```python async
834
+ # await frame.click("button") # click triggers navigation.
835
+ # await frame.wait_for_load_state() # the promise resolves after "load" event.
836
+ # ```
837
+ #
838
+ # ```python sync
839
+ # frame.click("button") # click triggers navigation.
840
+ # frame.wait_for_load_state() # the promise resolves after "load" event.
841
+ # ```
473
842
  def wait_for_load_state(state: nil, timeout: nil)
474
- raise NotImplementedError.new('wait_for_load_state is not implemented yet.')
843
+ wrap_impl(@impl.wait_for_load_state(state: unwrap_impl(state), timeout: unwrap_impl(timeout)))
475
844
  end
476
845
 
477
- # Returns the main resource response. In case of multiple redirects, the navigation will resolve with the response of the last redirect. In case of navigation to a different anchor or navigation due to History API usage, the navigation will resolve with `null`.
478
- # This method waits for the frame to navigate to a new URL. It is useful for when you run code which will indirectly cause the frame to navigate. Consider this example:
846
+ # Waits for the frame navigation and returns the main resource response. In case of multiple redirects, the navigation
847
+ # will resolve with the response of the last redirect. In case of navigation to a different anchor or navigation due to
848
+ # History API usage, the navigation will resolve with `null`.
849
+ #
850
+ # This method waits for the frame to navigate to a new URL. It is useful for when you run code which will indirectly cause
851
+ # the frame to navigate. Consider this example:
852
+ #
479
853
  #
480
854
  # ```js
481
855
  # const [response] = await Promise.all([
482
- # frame.waitForNavigation(), // Wait for the navigation to finish
483
- # frame.click('a.my-link'), // Clicking the link will indirectly cause a navigation
856
+ # frame.waitForNavigation(), // The promise resolves after navigation has finished
857
+ # frame.click('a.delayed-navigation'), // Clicking the link will indirectly cause a navigation
484
858
  # ]);
485
859
  # ```
486
- # **NOTE** Usage of the History API to change the URL is considered a navigation.
487
- def wait_for_navigation(timeout: nil, url: nil, waitUntil: nil)
488
- raise NotImplementedError.new('wait_for_navigation is not implemented yet.')
860
+ #
861
+ # ```python async
862
+ # async with frame.expect_navigation():
863
+ # await frame.click("a.delayed-navigation") # clicking the link will indirectly cause a navigation
864
+ # # Resolves after navigation has finished
865
+ # ```
866
+ #
867
+ # ```python sync
868
+ # with frame.expect_navigation():
869
+ # frame.click("a.delayed-navigation") # clicking the link will indirectly cause a navigation
870
+ # # Resolves after navigation has finished
871
+ # ```
872
+ #
873
+ # > NOTE: Usage of the [History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API) to change the URL is
874
+ # considered a navigation.
875
+ def expect_navigation(timeout: nil, url: nil, waitUntil: nil, &block)
876
+ wrap_impl(@impl.expect_navigation(timeout: unwrap_impl(timeout), url: unwrap_impl(url), waitUntil: unwrap_impl(waitUntil), &wrap_block_call(block)))
489
877
  end
490
878
 
491
- # Returns when element specified by selector satisfies `state` option. Returns `null` if waiting for `hidden` or `detached`.
492
- # Wait for the `selector` 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.
879
+ # Returns when element specified by selector satisfies `state` option. Returns `null` if waiting for `hidden` or
880
+ # `detached`.
881
+ #
882
+ # Wait for the `selector` to satisfy `state` option (either appear/disappear from dom, or become visible/hidden). If at
883
+ # the moment of calling the method `selector` already satisfies the condition, the method will return immediately. If the
884
+ # selector doesn't satisfy the condition for the `timeout` milliseconds, the function will throw.
885
+ #
493
886
  # This method works across navigations:
887
+ #
494
888
  #
495
889
  # ```js
496
- # const { webkit } = require('playwright'); // Or 'chromium' or 'firefox'.
890
+ # const { chromium } = require('playwright'); // Or 'firefox' or 'webkit'.
497
891
  #
498
892
  # (async () => {
499
- # const browser = await webkit.launch();
893
+ # const browser = await chromium.launch();
500
894
  # const page = await browser.newPage();
501
- # let currentURL;
502
- # page.mainFrame()
503
- # .waitForSelector('img')
504
- # .then(() => console.log('First URL with image: ' + currentURL));
505
- # for (currentURL of ['https://example.com', 'https://google.com', 'https://bbc.com']) {
895
+ # for (let currentURL of ['https://google.com', 'https://bbc.com']) {
506
896
  # await page.goto(currentURL);
897
+ # const element = await page.mainFrame().waitForSelector('img');
898
+ # console.log('Loaded image: ' + await element.getAttribute('src'));
507
899
  # }
508
900
  # await browser.close();
509
901
  # })();
510
902
  # ```
903
+ #
904
+ # ```python async
905
+ # import asyncio
906
+ # from playwright.async_api import async_playwright
907
+ #
908
+ # async def run(playwright):
909
+ # chromium = playwright.chromium
910
+ # browser = await chromium.launch()
911
+ # page = await browser.new_page()
912
+ # for current_url in ["https://google.com", "https://bbc.com"]:
913
+ # await page.goto(current_url, wait_until="domcontentloaded")
914
+ # element = await page.main_frame.wait_for_selector("img")
915
+ # print("Loaded image: " + str(await element.get_attribute("src")))
916
+ # await browser.close()
917
+ #
918
+ # async def main():
919
+ # async with async_playwright() as playwright:
920
+ # await run(playwright)
921
+ # asyncio.run(main())
922
+ # ```
923
+ #
924
+ # ```python sync
925
+ # from playwright.sync_api import sync_playwright
926
+ #
927
+ # def run(playwright):
928
+ # chromium = playwright.chromium
929
+ # browser = chromium.launch()
930
+ # page = browser.new_page()
931
+ # for current_url in ["https://google.com", "https://bbc.com"]:
932
+ # page.goto(current_url, wait_until="domcontentloaded")
933
+ # element = page.main_frame.wait_for_selector("img")
934
+ # print("Loaded image: " + str(element.get_attribute("src")))
935
+ # browser.close()
936
+ #
937
+ # with sync_playwright() as playwright:
938
+ # run(playwright)
939
+ # ```
511
940
  def wait_for_selector(selector, state: nil, timeout: nil)
512
941
  raise NotImplementedError.new('wait_for_selector is not implemented yet.')
513
942
  end
514
943
 
515
944
  # Waits for the given `timeout` in milliseconds.
516
- # Note that `frame.waitForTimeout()` should only be used for debugging. Tests using the timer in production are going to be flaky. Use signals such as network events, selectors becoming visible and others instead.
945
+ #
946
+ # Note that `frame.waitForTimeout()` should only be used for debugging. Tests using the timer in production are going to
947
+ # be flaky. Use signals such as network events, selectors becoming visible and others instead.
517
948
  def wait_for_timeout(timeout)
518
949
  raise NotImplementedError.new('wait_for_timeout is not implemented yet.')
519
950
  end
520
951
 
952
+ # @nodoc
953
+ def detached=(req)
954
+ wrap_impl(@impl.detached=(unwrap_impl(req)))
955
+ end
956
+
521
957
  # @nodoc
522
958
  def after_initialize
523
- wrap_channel_owner(@channel_owner.after_initialize)
959
+ wrap_impl(@impl.after_initialize)
960
+ end
961
+
962
+ # -- inherited from EventEmitter --
963
+ # @nodoc
964
+ def on(event, callback)
965
+ wrap_impl(@impl.on(unwrap_impl(event), unwrap_impl(callback)))
966
+ end
967
+
968
+ # -- inherited from EventEmitter --
969
+ # @nodoc
970
+ def off(event, callback)
971
+ wrap_impl(@impl.off(unwrap_impl(event), unwrap_impl(callback)))
972
+ end
973
+
974
+ # -- inherited from EventEmitter --
975
+ # @nodoc
976
+ def once(event, callback)
977
+ wrap_impl(@impl.once(unwrap_impl(event), unwrap_impl(callback)))
524
978
  end
525
979
  end
526
980
  end