playwright-ruby-client 0.0.5 → 0.0.6

Sign up to get free protection for your applications and to get access to all the features.
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