playwright-ruby-client 0.0.4 → 0.0.9

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