playwright-ruby-client 0.0.5 → 0.0.6

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 (42) hide show
  1. checksums.yaml +4 -4
  2. data/lib/playwright.rb +2 -0
  3. data/lib/playwright/channel_owners/element_handle.rb +75 -0
  4. data/lib/playwright/channel_owners/frame.rb +117 -0
  5. data/lib/playwright/channel_owners/page.rb +68 -11
  6. data/lib/playwright/channel_owners/request.rb +90 -0
  7. data/lib/playwright/input_type.rb +19 -0
  8. data/lib/playwright/input_types/keyboard.rb +32 -0
  9. data/lib/playwright/input_types/mouse.rb +4 -0
  10. data/lib/playwright/input_types/touchscreen.rb +4 -0
  11. data/lib/playwright/javascript/expression.rb +22 -0
  12. data/lib/playwright/javascript/function.rb +22 -0
  13. data/lib/playwright/playwright_api.rb +31 -23
  14. data/lib/playwright/timeout_settings.rb +1 -1
  15. data/lib/playwright/url_matcher.rb +19 -0
  16. data/lib/playwright/version.rb +1 -1
  17. data/lib/playwright_api/accessibility.rb +46 -6
  18. data/lib/playwright_api/binding_call.rb +6 -6
  19. data/lib/playwright_api/browser.rb +76 -16
  20. data/lib/playwright_api/browser_context.rb +284 -30
  21. data/lib/playwright_api/browser_type.rb +54 -9
  22. data/lib/playwright_api/cdp_session.rb +23 -1
  23. data/lib/playwright_api/chromium_browser_context.rb +16 -6
  24. data/lib/playwright_api/console_message.rb +10 -10
  25. data/lib/playwright_api/dialog.rb +42 -0
  26. data/lib/playwright_api/download.rb +19 -4
  27. data/lib/playwright_api/element_handle.rb +174 -21
  28. data/lib/playwright_api/file_chooser.rb +8 -0
  29. data/lib/playwright_api/frame.rb +355 -68
  30. data/lib/playwright_api/js_handle.rb +45 -9
  31. data/lib/playwright_api/keyboard.rb +98 -8
  32. data/lib/playwright_api/mouse.rb +22 -0
  33. data/lib/playwright_api/page.rb +779 -127
  34. data/lib/playwright_api/playwright.rb +98 -19
  35. data/lib/playwright_api/request.rb +70 -23
  36. data/lib/playwright_api/response.rb +6 -6
  37. data/lib/playwright_api/route.rb +48 -0
  38. data/lib/playwright_api/selectors.rb +14 -6
  39. data/lib/playwright_api/video.rb +8 -0
  40. data/lib/playwright_api/web_socket.rb +3 -5
  41. data/lib/playwright_api/worker.rb +12 -0
  42. metadata +7 -2
@@ -7,6 +7,14 @@ module Playwright
7
7
  # await fileChooser.setFiles('/tmp/myfile.pdf');
8
8
  # });
9
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
+ # ```
10
18
  class FileChooser < PlaywrightApi
11
19
 
12
20
  # Returns input element associated with this file chooser.
@@ -31,13 +31,47 @@ 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
 
@@ -47,7 +81,7 @@ module Playwright
47
81
  # [Working with selectors](./selectors.md#working-with-selectors) for more details. If no elements match the selector,
48
82
  # returns `null`.
49
83
  def query_selector(selector)
50
- raise NotImplementedError.new('query_selector is not implemented yet.')
84
+ wrap_impl(@impl.query_selector(selector))
51
85
  end
52
86
 
53
87
  # Returns the ElementHandles pointing to the frame elements.
@@ -56,7 +90,7 @@ module Playwright
56
90
  # [Working with selectors](./selectors.md#working-with-selectors) for more details. If no elements match the selector,
57
91
  # returns empty array.
58
92
  def query_selector_all(selector)
59
- raise NotImplementedError.new('query_selector_all is not implemented yet.')
93
+ wrap_impl(@impl.query_selector_all(selector))
60
94
  end
61
95
 
62
96
  # Returns the return value of `pageFunction`
@@ -75,8 +109,20 @@ module Playwright
75
109
  # const preloadHref = await frame.$eval('link[rel=preload]', el => el.href);
76
110
  # const html = await frame.$eval('.main-container', (e, suffix) => e.outerHTML + suffix, 'hello');
77
111
  # ```
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
+ # ```
78
124
  def eval_on_selector(selector, pageFunction, arg: nil)
79
- raise NotImplementedError.new('eval_on_selector is not implemented yet.')
125
+ wrap_impl(@impl.eval_on_selector(selector, pageFunction, arg: arg))
80
126
  end
81
127
 
82
128
  # Returns the return value of `pageFunction`
@@ -93,8 +139,16 @@ module Playwright
93
139
  # ```js
94
140
  # const divsCounts = await frame.$$eval('div', (divs, min) => divs.length >= min, 10);
95
141
  # ```
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
+ # ```
96
150
  def eval_on_selector_all(selector, pageFunction, arg: nil)
97
- raise NotImplementedError.new('eval_on_selector_all is not implemented yet.')
151
+ wrap_impl(@impl.eval_on_selector_all(selector, pageFunction, arg: arg))
98
152
  end
99
153
 
100
154
  # Returns the added tag when the script's onload fires or when the script content was injected into frame.
@@ -130,7 +184,7 @@ module Playwright
130
184
  end
131
185
 
132
186
  def child_frames
133
- wrap_channel_owner(@channel_owner.child_frames)
187
+ wrap_impl(@impl.child_frames)
134
188
  end
135
189
 
136
190
  # This method clicks an element matching `selector` by performing the following steps:
@@ -153,12 +207,12 @@ module Playwright
153
207
  noWaitAfter: nil,
154
208
  position: nil,
155
209
  timeout: nil)
156
- raise NotImplementedError.new('click is not implemented yet.')
210
+ wrap_impl(@impl.click(selector, button: button, clickCount: clickCount, delay: delay, force: force, modifiers: modifiers, noWaitAfter: noWaitAfter, position: position, timeout: timeout))
157
211
  end
158
212
 
159
213
  # Gets the full HTML contents of the frame, including the doctype.
160
214
  def content
161
- wrap_channel_owner(@channel_owner.content)
215
+ wrap_impl(@impl.content)
162
216
  end
163
217
 
164
218
  # This method double clicks an element matching `selector` by performing the following steps:
@@ -173,7 +227,7 @@ module Playwright
173
227
  # When all steps combined have not finished during the specified `timeout`, this method rejects with a `TimeoutError`.
174
228
  # Passing zero timeout disables this.
175
229
  #
176
- # > **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.
177
231
  def dblclick(
178
232
  selector,
179
233
  button: nil,
@@ -195,6 +249,14 @@ module Playwright
195
249
  # await frame.dispatchEvent('button#submit', 'click');
196
250
  # ```
197
251
  #
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
+ #
198
260
  # Under the hood, it creates an instance of an event based on the given `type`, initializes it with `eventInit` properties
199
261
  # and dispatches it on the element. Events are `composed`, `cancelable` and bubble by default.
200
262
  #
@@ -215,18 +277,30 @@ module Playwright
215
277
  # const dataTransfer = await frame.evaluateHandle(() => new DataTransfer());
216
278
  # await frame.dispatchEvent('#source', 'dragstart', { dataTransfer });
217
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
+ # ```
218
292
  def dispatch_event(selector, type, eventInit: nil, timeout: nil)
219
293
  raise NotImplementedError.new('dispatch_event is not implemented yet.')
220
294
  end
221
295
 
222
296
  # Returns the return value of `pageFunction`
223
297
  #
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.
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.
226
300
  #
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.
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.
230
304
  #
231
305
  #
232
306
  # ```js
@@ -236,6 +310,16 @@ module Playwright
236
310
  # console.log(result); // prints "56"
237
311
  # ```
238
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
+ #
239
323
  # A string can also be passed in instead of a function.
240
324
  #
241
325
  #
@@ -243,7 +327,19 @@ module Playwright
243
327
  # console.log(await frame.evaluate('1 + 2')); // prints "3"
244
328
  # ```
245
329
  #
246
- # `ElementHandle` instances can be passed as an argument to the `frame.evaluate`:
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`]:
247
343
  #
248
344
  #
249
345
  # ```js
@@ -251,17 +347,29 @@ module Playwright
251
347
  # const html = await frame.evaluate(([body, suffix]) => body.innerHTML + suffix, [bodyHandle, 'hello']);
252
348
  # await bodyHandle.dispose();
253
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
+ # ```
254
362
  def evaluate(pageFunction, arg: nil)
255
- wrap_channel_owner(@channel_owner.evaluate(pageFunction, arg: arg))
363
+ wrap_impl(@impl.evaluate(pageFunction, arg: arg))
256
364
  end
257
365
 
258
366
  # Returns the return value of `pageFunction` as in-page object (JSHandle).
259
367
  #
260
- # The only difference between `frame.evaluate` and `frame.evaluateHandle` is that `frame.evaluateHandle` returns in-page
261
- # object (JSHandle).
368
+ # The only difference between [`method: Frame.evaluate`] and [`method: Frame.evaluateHandle`] is
369
+ # that[ method: Fframe.evaluateHandle`] returns in-page object (JSHandle).
262
370
  #
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.
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.
265
373
  #
266
374
  #
267
375
  # ```js
@@ -269,6 +377,17 @@ module Playwright
269
377
  # aWindowHandle; // Handle for the window object.
270
378
  # ```
271
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
+ #
272
391
  # A string can also be passed in instead of a function.
273
392
  #
274
393
  #
@@ -276,7 +395,15 @@ module Playwright
276
395
  # const aHandle = await frame.evaluateHandle('document'); // Handle for the 'document'.
277
396
  # ```
278
397
  #
279
- # `JSHandle` instances can be passed as an argument to the `frame.evaluateHandle`:
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`]:
280
407
  #
281
408
  #
282
409
  # ```js
@@ -285,8 +412,22 @@ module Playwright
285
412
  # console.log(await resultHandle.jsonValue());
286
413
  # await resultHandle.dispose();
287
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
+ # ```
288
429
  def evaluate_handle(pageFunction, arg: nil)
289
- wrap_channel_owner(@channel_owner.evaluate_handle(pageFunction, arg: arg))
430
+ wrap_impl(@impl.evaluate_handle(pageFunction, arg: arg))
290
431
  end
291
432
 
292
433
  # This method waits for an element matching `selector`, waits for [actionability](./actionability.md) checks, focuses the
@@ -302,7 +443,7 @@ module Playwright
302
443
  # This method fetches an element with `selector` and focuses it. If there's no element matching `selector`, the method
303
444
  # waits until a matching element appears in the DOM.
304
445
  def focus(selector, timeout: nil)
305
- wrap_channel_owner(@channel_owner.focus(selector, timeout: timeout))
446
+ wrap_impl(@impl.focus(selector, timeout: timeout))
306
447
  end
307
448
 
308
449
  # Returns the `frame` or `iframe` element handle which corresponds to this frame.
@@ -318,6 +459,18 @@ module Playwright
318
459
  # const contentFrame = await frameElement.contentFrame();
319
460
  # console.log(frame === contentFrame); // -> true
320
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
+ # ```
321
474
  def frame_element
322
475
  raise NotImplementedError.new('frame_element is not implemented yet.')
323
476
  end
@@ -341,12 +494,12 @@ module Playwright
341
494
  # "Not Found" and 500 "Internal Server Error". The status code for such responses can be retrieved by calling
342
495
  # [`method: Response.status`].
343
496
  #
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
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
347
500
  # [upstream issue](https://bugs.chromium.org/p/chromium/issues/detail?id=761295).
348
501
  def goto(url, referer: nil, timeout: nil, waitUntil: nil)
349
- wrap_channel_owner(@channel_owner.goto(url, referer: referer, timeout: timeout, waitUntil: waitUntil))
502
+ wrap_impl(@impl.goto(url, referer: referer, timeout: timeout, waitUntil: waitUntil))
350
503
  end
351
504
 
352
505
  # This method hovers over an element matching `selector` by performing the following steps:
@@ -417,20 +570,19 @@ module Playwright
417
570
  #
418
571
  # If the name is empty, returns the id attribute instead.
419
572
  #
420
- # > **NOTE** This value is calculated once when the frame is created, and will not update if the attribute is changed
421
- # later.
573
+ # > NOTE: This value is calculated once when the frame is created, and will not update if the attribute is changed later.
422
574
  def name
423
- wrap_channel_owner(@channel_owner.name)
575
+ wrap_impl(@impl.name)
424
576
  end
425
577
 
426
578
  # Returns the page containing this frame.
427
579
  def page
428
- wrap_channel_owner(@channel_owner.page)
580
+ wrap_impl(@impl.page)
429
581
  end
430
582
 
431
583
  # Parent frame, if any. Detached frames and main frames return `null`.
432
584
  def parent_frame
433
- wrap_channel_owner(@channel_owner.parent_frame)
585
+ wrap_impl(@impl.parent_frame)
434
586
  end
435
587
 
436
588
  # `key` can specify the intended [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key)
@@ -455,7 +607,7 @@ module Playwright
455
607
  delay: nil,
456
608
  noWaitAfter: nil,
457
609
  timeout: nil)
458
- wrap_channel_owner(@channel_owner.press(selector, key, delay: delay, noWaitAfter: noWaitAfter, timeout: timeout))
610
+ wrap_impl(@impl.press(selector, key, delay: delay, noWaitAfter: noWaitAfter, timeout: timeout))
459
611
  end
460
612
 
461
613
  # Returns the array of option values that have been successfully selected.
@@ -463,6 +615,8 @@ module Playwright
463
615
  # Triggers a `change` and `input` event once all the provided options have been selected. If there's no `<select>` element
464
616
  # matching `selector`, the method throws an error.
465
617
  #
618
+ # Will wait until all specified options are present in the `<select>` element.
619
+ #
466
620
  #
467
621
  # ```js
468
622
  # // single selection matching the value
@@ -474,12 +628,30 @@ module Playwright
474
628
  # // multiple selection
475
629
  # frame.selectOption('select#colors', 'red', 'green', 'blue');
476
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
+ # ```
477
649
  def select_option(selector, values, noWaitAfter: nil, timeout: nil)
478
650
  raise NotImplementedError.new('select_option is not implemented yet.')
479
651
  end
480
652
 
481
653
  def set_content(html, timeout: nil, waitUntil: nil)
482
- wrap_channel_owner(@channel_owner.set_content(html, timeout: timeout, waitUntil: waitUntil))
654
+ wrap_impl(@impl.set_content(html, timeout: timeout, waitUntil: waitUntil))
483
655
  end
484
656
  alias_method :content=, :set_content
485
657
 
@@ -503,7 +675,7 @@ module Playwright
503
675
  # When all steps combined have not finished during the specified `timeout`, this method rejects with a `TimeoutError`.
504
676
  # Passing zero timeout disables this.
505
677
  #
506
- # > **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.
507
679
  def tap_point(
508
680
  selector,
509
681
  force: nil,
@@ -521,7 +693,7 @@ module Playwright
521
693
 
522
694
  # Returns the page title.
523
695
  def title
524
- wrap_channel_owner(@channel_owner.title)
696
+ wrap_impl(@impl.title)
525
697
  end
526
698
 
527
699
  # Sends a `keydown`, `keypress`/`input`, and `keyup` event for each character in the text. `frame.type` can be used to
@@ -534,13 +706,23 @@ module Playwright
534
706
  # await frame.type('#mytextarea', 'Hello'); // Types instantly
535
707
  # await frame.type('#mytextarea', 'World', {delay: 100}); // Types slower, like a user
536
708
  # ```
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
+ # ```
537
719
  def type_text(
538
720
  selector,
539
721
  text,
540
722
  delay: nil,
541
723
  noWaitAfter: nil,
542
724
  timeout: nil)
543
- wrap_channel_owner(@channel_owner.type_text(selector, text, delay: delay, noWaitAfter: noWaitAfter, timeout: timeout))
725
+ wrap_impl(@impl.type_text(selector, text, delay: delay, noWaitAfter: noWaitAfter, timeout: timeout))
544
726
  end
545
727
 
546
728
  # This method checks an element matching `selector` by performing the following steps:
@@ -562,7 +744,7 @@ module Playwright
562
744
 
563
745
  # Returns frame's url.
564
746
  def url
565
- wrap_channel_owner(@channel_owner.url)
747
+ wrap_impl(@impl.url)
566
748
  end
567
749
 
568
750
  # Returns when the `pageFunction` returns a truthy value, returns that value.
@@ -583,6 +765,39 @@ module Playwright
583
765
  # })();
584
766
  # ```
585
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
+ #
586
801
  # To pass an argument to the predicate of `frame.waitForFunction` function:
587
802
  #
588
803
  #
@@ -590,6 +805,16 @@ module Playwright
590
805
  # const selector = '.foo';
591
806
  # await frame.waitForFunction(selector => !!document.querySelector(selector), selector);
592
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
+ # ```
593
818
  def wait_for_function(pageFunction, arg: nil, polling: nil, timeout: nil)
594
819
  raise NotImplementedError.new('wait_for_function is not implemented yet.')
595
820
  end
@@ -604,13 +829,23 @@ module Playwright
604
829
  # await frame.click('button'); // Click triggers navigation.
605
830
  # await frame.waitForLoadState(); // Waits for 'load' state by default.
606
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
+ # ```
607
842
  def wait_for_load_state(state: nil, timeout: nil)
608
- raise NotImplementedError.new('wait_for_load_state is not implemented yet.')
843
+ wrap_impl(@impl.wait_for_load_state(state: state, timeout: timeout))
609
844
  end
610
845
 
611
- # Returns the main resource response. In case of multiple redirects, the navigation will resolve with the response of the
612
- # last redirect. In case of navigation to a different anchor or navigation due to History API usage, the navigation will
613
- # resolve with `null`.
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`.
614
849
  #
615
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
616
851
  # the frame to navigate. Consider this example:
@@ -618,15 +853,27 @@ module Playwright
618
853
  #
619
854
  # ```js
620
855
  # const [response] = await Promise.all([
621
- # frame.waitForNavigation(), // Wait for the navigation to finish
622
- # 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
623
858
  # ]);
624
859
  # ```
625
860
  #
626
- # **NOTE** Usage of the [History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API) to change the URL is
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
627
874
  # considered a navigation.
628
- def wait_for_navigation(timeout: nil, url: nil, waitUntil: nil)
629
- raise NotImplementedError.new('wait_for_navigation is not implemented yet.')
875
+ def expect_navigation(timeout: nil, url: nil, waitUntil: nil)
876
+ raise NotImplementedError.new('expect_navigation is not implemented yet.')
630
877
  end
631
878
 
632
879
  # Returns when element specified by selector satisfies `state` option. Returns `null` if waiting for `hidden` or
@@ -640,21 +887,56 @@ module Playwright
640
887
  #
641
888
  #
642
889
  # ```js
643
- # const { webkit } = require('playwright'); // Or 'chromium' or 'firefox'.
890
+ # const { chromium } = require('playwright'); // Or 'firefox' or 'webkit'.
644
891
  #
645
892
  # (async () => {
646
- # const browser = await webkit.launch();
893
+ # const browser = await chromium.launch();
647
894
  # const page = await browser.newPage();
648
- # let currentURL;
649
- # page.mainFrame()
650
- # .waitForSelector('img')
651
- # .then(() => console.log('First URL with image: ' + currentURL));
652
- # for (currentURL of ['https://example.com', 'https://google.com', 'https://bbc.com']) {
895
+ # for (let currentURL of ['https://google.com', 'https://bbc.com']) {
653
896
  # await page.goto(currentURL);
897
+ # const element = await page.mainFrame().waitForSelector('img');
898
+ # console.log('Loaded image: ' + await element.getAttribute('src'));
654
899
  # }
655
900
  # await browser.close();
656
901
  # })();
657
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
+ # ```
658
940
  def wait_for_selector(selector, state: nil, timeout: nil)
659
941
  raise NotImplementedError.new('wait_for_selector is not implemented yet.')
660
942
  end
@@ -668,31 +950,36 @@ module Playwright
668
950
  end
669
951
 
670
952
  # @nodoc
671
- def detached=(req)
672
- wrap_channel_owner(@channel_owner.detached=(req))
953
+ def wait_for_navigation(timeout: nil, url: nil, waitUntil: nil, &block)
954
+ wrap_impl(@impl.wait_for_navigation(timeout: timeout, url: url, waitUntil: waitUntil, &wrap_block_call(block)))
673
955
  end
674
956
 
675
957
  # @nodoc
676
958
  def after_initialize
677
- wrap_channel_owner(@channel_owner.after_initialize)
959
+ wrap_impl(@impl.after_initialize)
960
+ end
961
+
962
+ # @nodoc
963
+ def detached=(req)
964
+ wrap_impl(@impl.detached=(req))
678
965
  end
679
966
 
680
967
  # -- inherited from EventEmitter --
681
968
  # @nodoc
682
- def off(event, callback)
683
- wrap_channel_owner(@channel_owner.off(event, callback))
969
+ def on(event, callback)
970
+ wrap_impl(@impl.on(event, callback))
684
971
  end
685
972
 
686
973
  # -- inherited from EventEmitter --
687
974
  # @nodoc
688
- def once(event, callback)
689
- wrap_channel_owner(@channel_owner.once(event, callback))
975
+ def off(event, callback)
976
+ wrap_impl(@impl.off(event, callback))
690
977
  end
691
978
 
692
979
  # -- inherited from EventEmitter --
693
980
  # @nodoc
694
- def on(event, callback)
695
- wrap_channel_owner(@channel_owner.on(event, callback))
981
+ def once(event, callback)
982
+ wrap_impl(@impl.once(event, callback))
696
983
  end
697
984
  end
698
985
  end