playwright-ruby-client 0.0.5 → 0.1.0

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 (70) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +114 -2
  3. data/docs/api_coverage.md +351 -0
  4. data/lib/playwright.rb +7 -1
  5. data/lib/playwright/android_input_impl.rb +23 -0
  6. data/lib/playwright/api_implementation.rb +18 -0
  7. data/lib/playwright/channel.rb +7 -0
  8. data/lib/playwright/channel_owner.rb +3 -2
  9. data/lib/playwright/channel_owners/android.rb +10 -1
  10. data/lib/playwright/channel_owners/android_device.rb +163 -0
  11. data/lib/playwright/channel_owners/browser.rb +13 -13
  12. data/lib/playwright/channel_owners/browser_context.rb +9 -1
  13. data/lib/playwright/channel_owners/download.rb +27 -0
  14. data/lib/playwright/channel_owners/element_handle.rb +306 -0
  15. data/lib/playwright/channel_owners/frame.rb +371 -19
  16. data/lib/playwright/channel_owners/js_handle.rb +51 -0
  17. data/lib/playwright/channel_owners/page.rb +416 -19
  18. data/lib/playwright/channel_owners/request.rb +98 -0
  19. data/lib/playwright/channel_owners/webkit_browser.rb +1 -1
  20. data/lib/playwright/connection.rb +9 -6
  21. data/lib/playwright/errors.rb +2 -2
  22. data/lib/playwright/event_emitter.rb +8 -1
  23. data/lib/playwright/event_emitter_proxy.rb +49 -0
  24. data/lib/playwright/file_chooser_impl.rb +23 -0
  25. data/lib/playwright/http_headers.rb +20 -0
  26. data/lib/playwright/input_files.rb +42 -0
  27. data/lib/playwright/javascript/expression.rb +37 -0
  28. data/lib/playwright/javascript/function.rb +37 -0
  29. data/lib/playwright/javascript/value_parser.rb +1 -1
  30. data/lib/playwright/javascript/value_serializer.rb +11 -11
  31. data/lib/playwright/keyboard_impl.rb +36 -0
  32. data/lib/playwright/mouse_impl.rb +7 -0
  33. data/lib/playwright/playwright_api.rb +84 -29
  34. data/lib/playwright/select_option_values.rb +32 -0
  35. data/lib/playwright/timeout_settings.rb +2 -2
  36. data/lib/playwright/touchscreen_impl.rb +7 -0
  37. data/lib/playwright/url_matcher.rb +19 -0
  38. data/lib/playwright/utils.rb +18 -0
  39. data/lib/playwright/version.rb +1 -1
  40. data/lib/playwright/wait_helper.rb +1 -1
  41. data/lib/playwright_api/accessibility.rb +46 -6
  42. data/lib/playwright_api/android.rb +37 -0
  43. data/lib/playwright_api/android_device.rb +82 -0
  44. data/lib/playwright_api/android_input.rb +25 -0
  45. data/lib/playwright_api/binding_call.rb +10 -6
  46. data/lib/playwright_api/browser.rb +85 -18
  47. data/lib/playwright_api/browser_context.rb +269 -37
  48. data/lib/playwright_api/browser_type.rb +60 -11
  49. data/lib/playwright_api/cdp_session.rb +23 -1
  50. data/lib/playwright_api/chromium_browser_context.rb +18 -6
  51. data/lib/playwright_api/console_message.rb +14 -15
  52. data/lib/playwright_api/dialog.rb +48 -2
  53. data/lib/playwright_api/download.rb +47 -10
  54. data/lib/playwright_api/element_handle.rb +269 -110
  55. data/lib/playwright_api/file_chooser.rb +23 -7
  56. data/lib/playwright_api/frame.rb +439 -154
  57. data/lib/playwright_api/js_handle.rb +69 -24
  58. data/lib/playwright_api/keyboard.rb +99 -9
  59. data/lib/playwright_api/mouse.rb +22 -0
  60. data/lib/playwright_api/page.rb +856 -229
  61. data/lib/playwright_api/playwright.rb +108 -20
  62. data/lib/playwright_api/request.rb +77 -29
  63. data/lib/playwright_api/response.rb +10 -13
  64. data/lib/playwright_api/route.rb +49 -0
  65. data/lib/playwright_api/selectors.rb +20 -8
  66. data/lib/playwright_api/video.rb +8 -0
  67. data/lib/playwright_api/web_socket.rb +0 -8
  68. data/lib/playwright_api/worker.rb +25 -13
  69. data/playwright.gemspec +1 -0
  70. metadata +33 -2
@@ -8,55 +8,74 @@ module Playwright
8
8
  # // ...
9
9
  # ```
10
10
  #
11
+ # ```python async
12
+ # window_handle = await page.evaluate_handle("window")
13
+ # # ...
14
+ # ```
15
+ #
16
+ # ```python sync
17
+ # window_handle = page.evaluate_handle("window")
18
+ # # ...
19
+ # ```
20
+ #
11
21
  # JSHandle prevents the referenced JavaScript object being garbage collected unless the handle is exposed with
12
22
  # [`method: JSHandle.dispose`]. JSHandles are auto-disposed when their origin frame gets navigated or the parent context
13
23
  # gets destroyed.
14
24
  #
15
- # JSHandle instances can be used as an argument in [`method: Page.$eval`], [`method: Page.evaluate`] and
25
+ # JSHandle instances can be used as an argument in [`method: Page.evalOnSelector`], [`method: Page.evaluate`] and
16
26
  # [`method: Page.evaluateHandle`] methods.
17
27
  class JSHandle < PlaywrightApi
18
28
 
19
29
  # Returns either `null` or the object handle itself, if the object handle is an instance of `ElementHandle`.
20
30
  def as_element
21
- raise NotImplementedError.new('as_element is not implemented yet.')
31
+ wrap_impl(@impl.as_element)
22
32
  end
23
33
 
24
34
  # The `jsHandle.dispose` method stops referencing the element handle.
25
35
  def dispose
26
- wrap_channel_owner(@channel_owner.dispose)
36
+ wrap_impl(@impl.dispose)
27
37
  end
28
38
 
29
- # Returns the return value of `pageFunction`
39
+ # Returns the return value of `expression`.
30
40
  #
31
- # This method passes this handle as the first argument to `pageFunction`.
41
+ # This method passes this handle as the first argument to `expression`.
32
42
  #
33
- # If `pageFunction` returns a [Promise], then `handle.evaluate` would wait for the promise to resolve and return its
34
- # value.
43
+ # If `expression` returns a [Promise], then `handle.evaluate` would wait for the promise to resolve and return its value.
35
44
  #
36
45
  # Examples:
37
46
  #
38
47
  #
39
48
  # ```js
40
49
  # const tweetHandle = await page.$('.tweet .retweets');
41
- # expect(await tweetHandle.evaluate((node, suffix) => node.innerText, ' retweets')).toBe('10 retweets');
50
+ # expect(await tweetHandle.evaluate(node => node.innerText)).toBe('10 retweets');
51
+ # ```
52
+ #
53
+ # ```python async
54
+ # tweet_handle = await page.query_selector(".tweet .retweets")
55
+ # assert await tweet_handle.evaluate("node => node.innerText") == "10 retweets"
42
56
  # ```
43
- def evaluate(pageFunction, arg: nil)
44
- raise NotImplementedError.new('evaluate is not implemented yet.')
57
+ #
58
+ # ```python sync
59
+ # tweet_handle = page.query_selector(".tweet .retweets")
60
+ # assert tweet_handle.evaluate("node => node.innerText") == "10 retweets"
61
+ # ```
62
+ def evaluate(expression, arg: nil)
63
+ wrap_impl(@impl.evaluate(unwrap_impl(expression), arg: unwrap_impl(arg)))
45
64
  end
46
65
 
47
- # Returns the return value of `pageFunction` as in-page object (JSHandle).
66
+ # Returns the return value of `expression` as a `JSHandle`.
48
67
  #
49
- # This method passes this handle as the first argument to `pageFunction`.
68
+ # This method passes this handle as the first argument to `expression`.
50
69
  #
51
70
  # The only difference between `jsHandle.evaluate` and `jsHandle.evaluateHandle` is that `jsHandle.evaluateHandle` returns
52
- # in-page object (JSHandle).
71
+ # `JSHandle`.
53
72
  #
54
73
  # If the function passed to the `jsHandle.evaluateHandle` returns a [Promise], then `jsHandle.evaluateHandle` would wait
55
74
  # for the promise to resolve and return its value.
56
75
  #
57
76
  # See [`method: Page.evaluateHandle`] for more details.
58
- def evaluate_handle(pageFunction, arg: nil)
59
- raise NotImplementedError.new('evaluate_handle is not implemented yet.')
77
+ def evaluate_handle(expression, arg: nil)
78
+ wrap_impl(@impl.evaluate_handle(unwrap_impl(expression), arg: unwrap_impl(arg)))
60
79
  end
61
80
 
62
81
  # The method returns a map with **own property names** as keys and JSHandle instances for the property values.
@@ -69,39 +88,65 @@ module Playwright
69
88
  # const documentHandle = properties.get('document');
70
89
  # await handle.dispose();
71
90
  # ```
91
+ #
92
+ # ```python async
93
+ # handle = await page.evaluate_handle("{window, document}")
94
+ # properties = await handle.get_properties()
95
+ # window_handle = properties.get("window")
96
+ # document_handle = properties.get("document")
97
+ # await handle.dispose()
98
+ # ```
99
+ #
100
+ # ```python sync
101
+ # handle = page.evaluate_handle("{window, document}")
102
+ # properties = handle.get_properties()
103
+ # window_handle = properties.get("window")
104
+ # document_handle = properties.get("document")
105
+ # handle.dispose()
106
+ # ```
72
107
  def get_properties
73
- raise NotImplementedError.new('get_properties is not implemented yet.')
108
+ wrap_impl(@impl.get_properties)
74
109
  end
110
+ alias_method :properties, :get_properties
75
111
 
76
112
  # Fetches a single property from the referenced object.
77
113
  def get_property(propertyName)
78
- raise NotImplementedError.new('get_property is not implemented yet.')
114
+ wrap_impl(@impl.get_property(unwrap_impl(propertyName)))
79
115
  end
80
116
 
81
117
  # Returns a JSON representation of the object. If the object has a `toJSON` function, it **will not be called**.
82
118
  #
83
- # > **NOTE** The method will return an empty JSON object if the referenced object is not stringifiable. It will throw an
119
+ # > NOTE: The method will return an empty JSON object if the referenced object is not stringifiable. It will throw an
84
120
  # error if the object has circular references.
85
121
  def json_value
86
- raise NotImplementedError.new('json_value is not implemented yet.')
122
+ wrap_impl(@impl.json_value)
87
123
  end
88
124
 
89
- # -- inherited from EventEmitter --
90
125
  # @nodoc
91
- def off(event, callback)
92
- wrap_channel_owner(@channel_owner.off(event, callback))
126
+ def after_initialize
127
+ wrap_impl(@impl.after_initialize)
93
128
  end
94
129
 
95
130
  # -- inherited from EventEmitter --
96
131
  # @nodoc
97
132
  def once(event, callback)
98
- wrap_channel_owner(@channel_owner.once(event, callback))
133
+ event_emitter_proxy.once(event, callback)
99
134
  end
100
135
 
101
136
  # -- inherited from EventEmitter --
102
137
  # @nodoc
103
138
  def on(event, callback)
104
- wrap_channel_owner(@channel_owner.on(event, callback))
139
+ event_emitter_proxy.on(event, callback)
140
+ end
141
+
142
+ # -- inherited from EventEmitter --
143
+ # @nodoc
144
+ def off(event, callback)
145
+ event_emitter_proxy.off(event, callback)
146
+ end
147
+
148
+ private def event_emitter_proxy
149
+ @event_emitter_proxy ||= EventEmitterProxy.new(self, @impl)
105
150
  end
106
151
  end
107
152
  end
@@ -21,6 +21,28 @@ module Playwright
21
21
  # // Result text will end up saying 'Hello!'
22
22
  # ```
23
23
  #
24
+ # ```python async
25
+ # await page.keyboard.type("Hello World!")
26
+ # await page.keyboard.press("ArrowLeft")
27
+ # await page.keyboard.down("Shift")
28
+ # for i in range(6):
29
+ # await page.keyboard.press("ArrowLeft")
30
+ # await page.keyboard.up("Shift")
31
+ # await page.keyboard.press("Backspace")
32
+ # # result text will end up saying "Hello!"
33
+ # ```
34
+ #
35
+ # ```python sync
36
+ # page.keyboard.type("Hello World!")
37
+ # page.keyboard.press("ArrowLeft")
38
+ # page.keyboard.down("Shift")
39
+ # for i in range(6):
40
+ # page.keyboard.press("ArrowLeft")
41
+ # page.keyboard.up("Shift")
42
+ # page.keyboard.press("Backspace")
43
+ # # result text will end up saying "Hello!"
44
+ # ```
45
+ #
24
46
  # An example of pressing uppercase `A`
25
47
  #
26
48
  #
@@ -30,6 +52,18 @@ module Playwright
30
52
  # await page.keyboard.press('Shift+A');
31
53
  # ```
32
54
  #
55
+ # ```python async
56
+ # await page.keyboard.press("Shift+KeyA")
57
+ # # or
58
+ # await page.keyboard.press("Shift+A")
59
+ # ```
60
+ #
61
+ # ```python sync
62
+ # page.keyboard.press("Shift+KeyA")
63
+ # # or
64
+ # page.keyboard.press("Shift+A")
65
+ # ```
66
+ #
33
67
  # An example to trigger select-all with the keyboard
34
68
  #
35
69
  #
@@ -39,6 +73,20 @@ module Playwright
39
73
  # // on macOS
40
74
  # await page.keyboard.press('Meta+A');
41
75
  # ```
76
+ #
77
+ # ```python async
78
+ # # on windows and linux
79
+ # await page.keyboard.press("Control+A")
80
+ # # on mac_os
81
+ # await page.keyboard.press("Meta+A")
82
+ # ```
83
+ #
84
+ # ```python sync
85
+ # # on windows and linux
86
+ # page.keyboard.press("Control+A")
87
+ # # on mac_os
88
+ # page.keyboard.press("Meta+A")
89
+ # ```
42
90
  class Keyboard < PlaywrightApi
43
91
 
44
92
  # Dispatches a `keydown` event.
@@ -64,9 +112,9 @@ module Playwright
64
112
  # [repeat](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/repeat) set to true. To release the key, use
65
113
  # [`method: Keyboard.up`].
66
114
  #
67
- # > **NOTE** Modifier keys DO influence `keyboard.down`. Holding down `Shift` will type the text in upper case.
115
+ # > NOTE: Modifier keys DO influence `keyboard.down`. Holding down `Shift` will type the text in upper case.
68
116
  def down(key)
69
- raise NotImplementedError.new('down is not implemented yet.')
117
+ wrap_impl(@impl.down(unwrap_impl(key)))
70
118
  end
71
119
 
72
120
  # Dispatches only `input` event, does not emit the `keydown`, `keyup` or `keypress` events.
@@ -76,9 +124,17 @@ module Playwright
76
124
  # page.keyboard.insertText('嗨');
77
125
  # ```
78
126
  #
79
- # > **NOTE** Modifier keys DO NOT effect `keyboard.insertText`. Holding down `Shift` will not type the text in upper case.
127
+ # ```python async
128
+ # await page.keyboard.insert_text("嗨")
129
+ # ```
130
+ #
131
+ # ```python sync
132
+ # page.keyboard.insert_text("嗨")
133
+ # ```
134
+ #
135
+ # > NOTE: Modifier keys DO NOT effect `keyboard.insertText`. Holding down `Shift` will not type the text in upper case.
80
136
  def insert_text(text)
81
- raise NotImplementedError.new('insert_text is not implemented yet.')
137
+ wrap_impl(@impl.insert_text(unwrap_impl(text)))
82
138
  end
83
139
 
84
140
  # `key` can specify the intended [keyboardEvent.key](https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key)
@@ -111,9 +167,33 @@ module Playwright
111
167
  # await browser.close();
112
168
  # ```
113
169
  #
170
+ # ```python async
171
+ # page = await browser.new_page()
172
+ # await page.goto("https://keycode.info")
173
+ # await page.keyboard.press("a")
174
+ # await page.screenshot(path="a.png")
175
+ # await page.keyboard.press("ArrowLeft")
176
+ # await page.screenshot(path="arrow_left.png")
177
+ # await page.keyboard.press("Shift+O")
178
+ # await page.screenshot(path="o.png")
179
+ # await browser.close()
180
+ # ```
181
+ #
182
+ # ```python sync
183
+ # page = browser.new_page()
184
+ # page.goto("https://keycode.info")
185
+ # page.keyboard.press("a")
186
+ # page.screenshot(path="a.png")
187
+ # page.keyboard.press("ArrowLeft")
188
+ # page.screenshot(path="arrow_left.png")
189
+ # page.keyboard.press("Shift+O")
190
+ # page.screenshot(path="o.png")
191
+ # browser.close()
192
+ # ```
193
+ #
114
194
  # Shortcut for [`method: Keyboard.down`] and [`method: Keyboard.up`].
115
195
  def press(key, delay: nil)
116
- raise NotImplementedError.new('press is not implemented yet.')
196
+ wrap_impl(@impl.press(unwrap_impl(key), delay: unwrap_impl(delay)))
117
197
  end
118
198
 
119
199
  # Sends a `keydown`, `keypress`/`input`, and `keyup` event for each character in the text.
@@ -126,14 +206,24 @@ module Playwright
126
206
  # await page.keyboard.type('World', {delay: 100}); // Types slower, like a user
127
207
  # ```
128
208
  #
129
- # > **NOTE** Modifier keys DO NOT effect `keyboard.type`. Holding down `Shift` will not type the text in upper case.
130
- def type_text(text, delay: nil)
131
- raise NotImplementedError.new('type_text is not implemented yet.')
209
+ # ```python async
210
+ # await page.keyboard.type("Hello") # types instantly
211
+ # await page.keyboard.type("World", delay=100) # types slower, like a user
212
+ # ```
213
+ #
214
+ # ```python sync
215
+ # page.keyboard.type("Hello") # types instantly
216
+ # page.keyboard.type("World", delay=100) # types slower, like a user
217
+ # ```
218
+ #
219
+ # > NOTE: Modifier keys DO NOT effect `keyboard.type`. Holding down `Shift` will not type the text in upper case.
220
+ def type(text, delay: nil)
221
+ wrap_impl(@impl.type(unwrap_impl(text), delay: unwrap_impl(delay)))
132
222
  end
133
223
 
134
224
  # Dispatches a `keyup` event.
135
225
  def up(key)
136
- raise NotImplementedError.new('up is not implemented yet.')
226
+ wrap_impl(@impl.up(unwrap_impl(key)))
137
227
  end
138
228
  end
139
229
  end
@@ -14,6 +14,28 @@ module Playwright
14
14
  # await page.mouse.move(0, 0);
15
15
  # await page.mouse.up();
16
16
  # ```
17
+ #
18
+ # ```python async
19
+ # # using ‘page.mouse’ to trace a 100x100 square.
20
+ # await page.mouse.move(0, 0)
21
+ # await page.mouse.down()
22
+ # await page.mouse.move(0, 100)
23
+ # await page.mouse.move(100, 100)
24
+ # await page.mouse.move(100, 0)
25
+ # await page.mouse.move(0, 0)
26
+ # await page.mouse.up()
27
+ # ```
28
+ #
29
+ # ```python sync
30
+ # # using ‘page.mouse’ to trace a 100x100 square.
31
+ # page.mouse.move(0, 0)
32
+ # page.mouse.down()
33
+ # page.mouse.move(0, 100)
34
+ # page.mouse.move(100, 100)
35
+ # page.mouse.move(100, 0)
36
+ # page.mouse.move(0, 0)
37
+ # page.mouse.up()
38
+ # ```
17
39
  class Mouse < PlaywrightApi
18
40
 
19
41
  # Shortcut for [`method: Mouse.move`], [`method: Mouse.down`], [`method: Mouse.up`].
@@ -1,9 +1,9 @@
1
1
  module Playwright
2
- # - extends: [EventEmitter](https://nodejs.org/api/events.html#events_class_eventemitter)
2
+ # - extends: [EventEmitter]
3
3
  #
4
4
  # Page provides methods to interact with a single tab in a `Browser`, or an
5
- # [extension background page](https://developer.chrome.com/extensions/background_pages) in Chromium. One [Browser]
6
- # instance might have multiple [Page] instances.
5
+ # [extension background page](https://developer.chrome.com/extensions/background_pages) in Chromium. One `Browser`
6
+ # instance might have multiple `Page` instances.
7
7
  #
8
8
  # This example creates a page, navigates it to a URL, and then saves a screenshot:
9
9
  #
@@ -21,6 +21,41 @@ module Playwright
21
21
  # })();
22
22
  # ```
23
23
  #
24
+ # ```python async
25
+ # import asyncio
26
+ # from playwright.async_api import async_playwright
27
+ #
28
+ # async def run(playwright):
29
+ # webkit = playwright.webkit
30
+ # browser = await webkit.launch()
31
+ # context = await browser.new_context()
32
+ # page = await context.new_page()
33
+ # await page.goto("https://example.com")
34
+ # await page.screenshot(path="screenshot.png")
35
+ # await browser.close()
36
+ #
37
+ # async def main():
38
+ # async with async_playwright() as playwright:
39
+ # await run(playwright)
40
+ # asyncio.run(main())
41
+ # ```
42
+ #
43
+ # ```python sync
44
+ # from playwright.sync_api import sync_playwright
45
+ #
46
+ # def run(playwright):
47
+ # webkit = playwright.webkit
48
+ # browser = webkit.launch()
49
+ # context = browser.new_context()
50
+ # page = context.new_page()
51
+ # page.goto("https://example.com")
52
+ # page.screenshot(path="screenshot.png")
53
+ # browser.close()
54
+ #
55
+ # with sync_playwright() as playwright:
56
+ # run(playwright)
57
+ # ```
58
+ #
24
59
  # The Page class emits various events (described below) which can be handled using any of Node's native
25
60
  # [`EventEmitter`](https://nodejs.org/api/events.html#events_class_eventemitter) methods, such as `on`, `once` or
26
61
  # `removeListener`.
@@ -32,6 +67,10 @@ module Playwright
32
67
  # page.once('load', () => console.log('Page loaded!'));
33
68
  # ```
34
69
  #
70
+ # ```py
71
+ # page.once("load", lambda: print("page loaded!"))
72
+ # ```
73
+ #
35
74
  # To unsubscribe from events use the `removeListener` method:
36
75
  #
37
76
  #
@@ -43,10 +82,18 @@ module Playwright
43
82
  # // Sometime later...
44
83
  # page.removeListener('request', logRequest);
45
84
  # ```
85
+ #
86
+ # ```py
87
+ # def log_request(intercepted_request):
88
+ # print("a request was made:", intercepted_request.url)
89
+ # page.on("request", log_request)
90
+ # # sometime later...
91
+ # page.remove_listener("request", log_request)
92
+ # ```
46
93
  class Page < PlaywrightApi
47
94
 
48
95
  def accessibility # property
49
- wrap_channel_owner(@channel_owner.accessibility)
96
+ wrap_impl(@impl.accessibility)
50
97
  end
51
98
 
52
99
  # Browser-specific Coverage implementation, only available for Chromium atm. See
@@ -56,67 +103,15 @@ module Playwright
56
103
  end
57
104
 
58
105
  def keyboard # property
59
- wrap_channel_owner(@channel_owner.keyboard)
106
+ wrap_impl(@impl.keyboard)
60
107
  end
61
108
 
62
109
  def mouse # property
63
- wrap_channel_owner(@channel_owner.mouse)
110
+ wrap_impl(@impl.mouse)
64
111
  end
65
112
 
66
113
  def touchscreen # property
67
- wrap_channel_owner(@channel_owner.touchscreen)
68
- end
69
-
70
- # The method finds an element matching the specified selector within the page. If no elements match the selector, the
71
- # return value resolves to `null`.
72
- #
73
- # Shortcut for main frame's [`method: Frame.$`].
74
- def query_selector(selector)
75
- raise NotImplementedError.new('query_selector is not implemented yet.')
76
- end
77
-
78
- # The method finds all elements matching the specified selector within the page. If no elements match the selector, the
79
- # return value resolves to `[]`.
80
- #
81
- # Shortcut for main frame's [`method: Frame.$$`].
82
- def query_selector_all(selector)
83
- raise NotImplementedError.new('query_selector_all is not implemented yet.')
84
- end
85
-
86
- # The method finds an element matching the specified selector within the page and passes it as a first argument to
87
- # `pageFunction`. If no elements match the selector, the method throws an error. Returns the value of `pageFunction`.
88
- #
89
- # If `pageFunction` returns a [Promise], then [`method: Page.$eval`] would wait for the promise to resolve and return its
90
- # value.
91
- #
92
- # Examples:
93
- #
94
- #
95
- # ```js
96
- # const searchValue = await page.$eval('#search', el => el.value);
97
- # const preloadHref = await page.$eval('link[rel=preload]', el => el.href);
98
- # const html = await page.$eval('.main-container', (e, suffix) => e.outerHTML + suffix, 'hello');
99
- # ```
100
- #
101
- # Shortcut for main frame's [`method: Frame.$eval`].
102
- def eval_on_selector(selector, pageFunction, arg: nil)
103
- raise NotImplementedError.new('eval_on_selector is not implemented yet.')
104
- end
105
-
106
- # The method finds all elements matching the specified selector within the page and passes an array of matched elements as
107
- # a first argument to `pageFunction`. Returns the result of `pageFunction` invocation.
108
- #
109
- # If `pageFunction` returns a [Promise], then [`method: Page.$$eval`] would wait for the promise to resolve and return its
110
- # value.
111
- #
112
- # Examples:
113
- #
114
- #
115
- # ```js
116
- # const divsCounts = await page.$$eval('div', (divs, min) => divs.length >= min, 10);
117
- # ```
118
- def eval_on_selector_all(selector, pageFunction, arg: nil)
119
- raise NotImplementedError.new('eval_on_selector_all is not implemented yet.')
114
+ wrap_impl(@impl.touchscreen)
120
115
  end
121
116
 
122
117
  # Adds a script which would be evaluated in one of the following scenarios:
@@ -130,19 +125,31 @@ module Playwright
130
125
  # An example of overriding `Math.random` before the page loads:
131
126
  #
132
127
  #
133
- # ```js
128
+ # ```js browser
134
129
  # // preload.js
135
130
  # Math.random = () => 42;
131
+ # ```
136
132
  #
133
+ #
134
+ # ```js
137
135
  # // In your playwright script, assuming the preload.js file is in same directory
138
- # const preloadFile = fs.readFileSync('./preload.js', 'utf8');
139
- # await page.addInitScript(preloadFile);
136
+ # await page.addInitScript({ path: './preload.js' });
137
+ # ```
138
+ #
139
+ # ```python async
140
+ # # in your playwright script, assuming the preload.js file is in same directory
141
+ # await page.add_init_script(path="./preload.js")
140
142
  # ```
141
143
  #
142
- # > **NOTE** The order of evaluation of multiple scripts installed via [`method: BrowserContext.addInitScript`] and
144
+ # ```python sync
145
+ # # in your playwright script, assuming the preload.js file is in same directory
146
+ # page.add_init_script(path="./preload.js")
147
+ # ```
148
+ #
149
+ # > NOTE: The order of evaluation of multiple scripts installed via [`method: BrowserContext.addInitScript`] and
143
150
  # [`method: Page.addInitScript`] is not defined.
144
151
  def add_init_script(script, arg: nil)
145
- raise NotImplementedError.new('add_init_script is not implemented yet.')
152
+ wrap_impl(@impl.add_init_script(unwrap_impl(script), arg: unwrap_impl(arg)))
146
153
  end
147
154
 
148
155
  # Adds a `<script>` tag into the page with the desired url or content. Returns the added tag when the script's onload
@@ -150,7 +157,7 @@ module Playwright
150
157
  #
151
158
  # Shortcut for main frame's [`method: Frame.addScriptTag`].
152
159
  def add_script_tag(content: nil, path: nil, type: nil, url: nil)
153
- raise NotImplementedError.new('add_script_tag is not implemented yet.')
160
+ wrap_impl(@impl.add_script_tag(content: unwrap_impl(content), path: unwrap_impl(path), type: unwrap_impl(type), url: unwrap_impl(url)))
154
161
  end
155
162
 
156
163
  # Adds a `<link rel="stylesheet">` tag into the page with the desired url or a `<style type="text/css">` tag with the
@@ -158,12 +165,12 @@ module Playwright
158
165
  #
159
166
  # Shortcut for main frame's [`method: Frame.addStyleTag`].
160
167
  def add_style_tag(content: nil, path: nil, url: nil)
161
- raise NotImplementedError.new('add_style_tag is not implemented yet.')
168
+ wrap_impl(@impl.add_style_tag(content: unwrap_impl(content), path: unwrap_impl(path), url: unwrap_impl(url)))
162
169
  end
163
170
 
164
171
  # Brings page to front (activates tab).
165
172
  def bring_to_front
166
- raise NotImplementedError.new('bring_to_front is not implemented yet.')
173
+ wrap_impl(@impl.bring_to_front)
167
174
  end
168
175
 
169
176
  # This method checks an element matching `selector` by performing the following steps:
@@ -182,7 +189,7 @@ module Playwright
182
189
  #
183
190
  # Shortcut for main frame's [`method: Frame.check`].
184
191
  def check(selector, force: nil, noWaitAfter: nil, timeout: nil)
185
- raise NotImplementedError.new('check is not implemented yet.')
192
+ wrap_impl(@impl.check(unwrap_impl(selector), force: unwrap_impl(force), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
186
193
  end
187
194
 
188
195
  # This method clicks an element matching `selector` by performing the following steps:
@@ -207,7 +214,7 @@ module Playwright
207
214
  noWaitAfter: nil,
208
215
  position: nil,
209
216
  timeout: nil)
210
- raise NotImplementedError.new('click is not implemented yet.')
217
+ 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)))
211
218
  end
212
219
 
213
220
  # If `runBeforeUnload` is `false`, does not run any unload handlers and waits for the page to be closed. If
@@ -215,20 +222,20 @@ module Playwright
215
222
  #
216
223
  # By default, `page.close()` **does not** run `beforeunload` handlers.
217
224
  #
218
- # > **NOTE** if `runBeforeUnload` is passed as true, a `beforeunload` dialog might be summoned
219
- # > and should be handled manually via [`event: Page.dialog`] event.
225
+ # > NOTE: if `runBeforeUnload` is passed as true, a `beforeunload` dialog might be summoned and should be handled manually
226
+ # via [`event: Page.dialog`] event.
220
227
  def close(runBeforeUnload: nil)
221
- wrap_channel_owner(@channel_owner.close(runBeforeUnload: runBeforeUnload))
228
+ wrap_impl(@impl.close(runBeforeUnload: unwrap_impl(runBeforeUnload)))
222
229
  end
223
230
 
224
231
  # Gets the full HTML contents of the page, including the doctype.
225
232
  def content
226
- wrap_channel_owner(@channel_owner.content)
233
+ wrap_impl(@impl.content)
227
234
  end
228
235
 
229
236
  # Get the browser context that the page belongs to.
230
237
  def context
231
- wrap_channel_owner(@channel_owner.context)
238
+ wrap_impl(@impl.context)
232
239
  end
233
240
 
234
241
  # This method double clicks an element matching `selector` by performing the following steps:
@@ -243,7 +250,7 @@ module Playwright
243
250
  # When all steps combined have not finished during the specified `timeout`, this method rejects with a `TimeoutError`.
244
251
  # Passing zero timeout disables this.
245
252
  #
246
- # > **NOTE** `page.dblclick()` dispatches two `click` events and a single `dblclick` event.
253
+ # > NOTE: `page.dblclick()` dispatches two `click` events and a single `dblclick` event.
247
254
  #
248
255
  # Shortcut for main frame's [`method: Frame.dblclick`].
249
256
  def dblclick(
@@ -255,7 +262,7 @@ module Playwright
255
262
  noWaitAfter: nil,
256
263
  position: nil,
257
264
  timeout: nil)
258
- raise NotImplementedError.new('dblclick is not implemented yet.')
265
+ 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)))
259
266
  end
260
267
 
261
268
  # The snippet below dispatches the `click` event on the element. Regardless of the visibility state of the elment, `click`
@@ -267,6 +274,14 @@ module Playwright
267
274
  # await page.dispatchEvent('button#submit', 'click');
268
275
  # ```
269
276
  #
277
+ # ```python async
278
+ # await page.dispatch_event("button#submit", "click")
279
+ # ```
280
+ #
281
+ # ```python sync
282
+ # page.dispatch_event("button#submit", "click")
283
+ # ```
284
+ #
270
285
  # Under the hood, it creates an instance of an event based on the given `type`, initializes it with `eventInit` properties
271
286
  # and dispatches it on the element. Events are `composed`, `cancelable` and bubble by default.
272
287
  #
@@ -287,8 +302,20 @@ module Playwright
287
302
  # const dataTransfer = await page.evaluateHandle(() => new DataTransfer());
288
303
  # await page.dispatchEvent('#source', 'dragstart', { dataTransfer });
289
304
  # ```
305
+ #
306
+ # ```python async
307
+ # # note you can only create data_transfer in chromium and firefox
308
+ # data_transfer = await page.evaluate_handle("new DataTransfer()")
309
+ # await page.dispatch_event("#source", "dragstart", { "dataTransfer": data_transfer })
310
+ # ```
311
+ #
312
+ # ```python sync
313
+ # # note you can only create data_transfer in chromium and firefox
314
+ # data_transfer = page.evaluate_handle("new DataTransfer()")
315
+ # page.dispatch_event("#source", "dragstart", { "dataTransfer": data_transfer })
316
+ # ```
290
317
  def dispatch_event(selector, type, eventInit: nil, timeout: nil)
291
- raise NotImplementedError.new('dispatch_event is not implemented yet.')
318
+ wrap_impl(@impl.dispatch_event(unwrap_impl(selector), unwrap_impl(type), eventInit: unwrap_impl(eventInit), timeout: unwrap_impl(timeout)))
292
319
  end
293
320
 
294
321
  #
@@ -312,6 +339,44 @@ module Playwright
312
339
  # // → false
313
340
  # ```
314
341
  #
342
+ # ```python async
343
+ # await page.evaluate("matchMedia('screen').matches")
344
+ # # → True
345
+ # await page.evaluate("matchMedia('print').matches")
346
+ # # → False
347
+ #
348
+ # await page.emulate_media(media="print")
349
+ # await page.evaluate("matchMedia('screen').matches")
350
+ # # → False
351
+ # await page.evaluate("matchMedia('print').matches")
352
+ # # → True
353
+ #
354
+ # await page.emulate_media()
355
+ # await page.evaluate("matchMedia('screen').matches")
356
+ # # → True
357
+ # await page.evaluate("matchMedia('print').matches")
358
+ # # → False
359
+ # ```
360
+ #
361
+ # ```python sync
362
+ # page.evaluate("matchMedia('screen').matches")
363
+ # # → True
364
+ # page.evaluate("matchMedia('print').matches")
365
+ # # → False
366
+ #
367
+ # page.emulate_media(media="print")
368
+ # page.evaluate("matchMedia('screen').matches")
369
+ # # → False
370
+ # page.evaluate("matchMedia('print').matches")
371
+ # # → True
372
+ #
373
+ # page.emulate_media()
374
+ # page.evaluate("matchMedia('screen').matches")
375
+ # # → True
376
+ # page.evaluate("matchMedia('print').matches")
377
+ # # → False
378
+ # ```
379
+ #
315
380
  #
316
381
  # ```js
317
382
  # await page.emulateMedia({ colorScheme: 'dark' });
@@ -322,20 +387,95 @@ module Playwright
322
387
  # await page.evaluate(() => matchMedia('(prefers-color-scheme: no-preference)').matches);
323
388
  # // → false
324
389
  # ```
325
- def emulate_media(params)
326
- raise NotImplementedError.new('emulate_media is not implemented yet.')
390
+ #
391
+ # ```python async
392
+ # await page.emulate_media(color_scheme="dark")
393
+ # await page.evaluate("matchMedia('(prefers-color-scheme: dark)').matches")
394
+ # # → True
395
+ # await page.evaluate("matchMedia('(prefers-color-scheme: light)').matches")
396
+ # # → False
397
+ # await page.evaluate("matchMedia('(prefers-color-scheme: no-preference)').matches")
398
+ # # → False
399
+ # ```
400
+ #
401
+ # ```python sync
402
+ # page.emulate_media(color_scheme="dark")
403
+ # page.evaluate("matchMedia('(prefers-color-scheme: dark)').matches")
404
+ # # → True
405
+ # page.evaluate("matchMedia('(prefers-color-scheme: light)').matches")
406
+ # # → False
407
+ # page.evaluate("matchMedia('(prefers-color-scheme: no-preference)').matches")
408
+ # ```
409
+ def emulate_media(colorScheme: nil, media: nil)
410
+ wrap_impl(@impl.emulate_media(colorScheme: unwrap_impl(colorScheme), media: unwrap_impl(media)))
327
411
  end
328
412
 
329
- # Returns the value of the `pageFunction` invocation.
413
+ # The method finds an element matching the specified selector within the page and passes it as a first argument to
414
+ # `expression`. If no elements match the selector, the method throws an error. Returns the value of `expression`.
415
+ #
416
+ # If `expression` returns a [Promise], then [`method: Page.evalOnSelector`] would wait for the promise to resolve and
417
+ # return its value.
418
+ #
419
+ # Examples:
420
+ #
421
+ #
422
+ # ```js
423
+ # const searchValue = await page.$eval('#search', el => el.value);
424
+ # const preloadHref = await page.$eval('link[rel=preload]', el => el.href);
425
+ # const html = await page.$eval('.main-container', (e, suffix) => e.outerHTML + suffix, 'hello');
426
+ # ```
427
+ #
428
+ # ```python async
429
+ # search_value = await page.eval_on_selector("#search", "el => el.value")
430
+ # preload_href = await page.eval_on_selector("link[rel=preload]", "el => el.href")
431
+ # html = await page.eval_on_selector(".main-container", "(e, suffix) => e.outer_html + suffix", "hello")
432
+ # ```
433
+ #
434
+ # ```python sync
435
+ # search_value = page.eval_on_selector("#search", "el => el.value")
436
+ # preload_href = page.eval_on_selector("link[rel=preload]", "el => el.href")
437
+ # html = page.eval_on_selector(".main-container", "(e, suffix) => e.outer_html + suffix", "hello")
438
+ # ```
439
+ #
440
+ # Shortcut for main frame's [`method: Frame.evalOnSelector`].
441
+ def eval_on_selector(selector, expression, arg: nil)
442
+ wrap_impl(@impl.eval_on_selector(unwrap_impl(selector), unwrap_impl(expression), arg: unwrap_impl(arg)))
443
+ end
444
+
445
+ # The method finds all elements matching the specified selector within the page and passes an array of matched elements as
446
+ # a first argument to `expression`. Returns the result of `expression` invocation.
447
+ #
448
+ # If `expression` returns a [Promise], then [`method: Page.evalOnSelectorAll`] would wait for the promise to resolve and
449
+ # return its value.
450
+ #
451
+ # Examples:
452
+ #
453
+ #
454
+ # ```js
455
+ # const divCounts = await page.$$eval('div', (divs, min) => divs.length >= min, 10);
456
+ # ```
457
+ #
458
+ # ```python async
459
+ # div_counts = await page.eval_on_selector_all("div", "(divs, min) => divs.length >= min", 10)
460
+ # ```
461
+ #
462
+ # ```python sync
463
+ # div_counts = page.eval_on_selector_all("div", "(divs, min) => divs.length >= min", 10)
464
+ # ```
465
+ def eval_on_selector_all(selector, expression, arg: nil)
466
+ wrap_impl(@impl.eval_on_selector_all(unwrap_impl(selector), unwrap_impl(expression), arg: unwrap_impl(arg)))
467
+ end
468
+
469
+ # Returns the value of the `expression` invocation.
330
470
  #
331
- # If the function passed to the `page.evaluate` returns a [Promise], then `page.evaluate` would wait for the promise to
332
- # resolve and return its value.
471
+ # If the function passed to the [`method: Page.evaluate`] returns a [Promise], then [`method: Page.evaluate`] would wait
472
+ # for the promise to resolve and return its value.
333
473
  #
334
- # If the function passed to the `page.evaluate` returns a non-[Serializable] value, then `page.evaluate` resolves to
335
- # `undefined`. DevTools Protocol also supports transferring some additional values that are not serializable by `JSON`:
336
- # `-0`, `NaN`, `Infinity`, `-Infinity`, and bigint literals.
474
+ # If the function passed to the [`method: Page.evaluate`] returns a non-[Serializable] value, then
475
+ # [`method: Page.evaluate`] resolves to `undefined`. Playwright also supports transferring some additional values that are
476
+ # not serializable by `JSON`: `-0`, `NaN`, `Infinity`, `-Infinity`.
337
477
  #
338
- # Passing argument to `pageFunction`:
478
+ # Passing argument to `expression`:
339
479
  #
340
480
  #
341
481
  # ```js
@@ -345,6 +485,16 @@ module Playwright
345
485
  # console.log(result); // prints "56"
346
486
  # ```
347
487
  #
488
+ # ```python async
489
+ # result = await page.evaluate("([x, y]) => Promise.resolve(x * y)", [7, 8])
490
+ # print(result) # prints "56"
491
+ # ```
492
+ #
493
+ # ```python sync
494
+ # result = page.evaluate("([x, y]) => Promise.resolve(x * y)", [7, 8])
495
+ # print(result) # prints "56"
496
+ # ```
497
+ #
348
498
  # A string can also be passed in instead of a function:
349
499
  #
350
500
  #
@@ -354,7 +504,19 @@ module Playwright
354
504
  # console.log(await page.evaluate(`1 + ${x}`)); // prints "11"
355
505
  # ```
356
506
  #
357
- # `ElementHandle` instances can be passed as an argument to the `page.evaluate`:
507
+ # ```python async
508
+ # print(await page.evaluate("1 + 2")) # prints "3"
509
+ # x = 10
510
+ # print(await page.evaluate(f"1 + {x}")) # prints "11"
511
+ # ```
512
+ #
513
+ # ```python sync
514
+ # print(page.evaluate("1 + 2")) # prints "3"
515
+ # x = 10
516
+ # print(page.evaluate(f"1 + {x}")) # prints "11"
517
+ # ```
518
+ #
519
+ # `ElementHandle` instances can be passed as an argument to the [`method: Page.evaluate`]:
358
520
  #
359
521
  #
360
522
  # ```js
@@ -363,18 +525,46 @@ module Playwright
363
525
  # await bodyHandle.dispose();
364
526
  # ```
365
527
  #
528
+ # ```python async
529
+ # body_handle = await page.query_selector("body")
530
+ # html = await page.evaluate("([body, suffix]) => body.innerHTML + suffix", [body_handle, "hello"])
531
+ # await body_handle.dispose()
532
+ # ```
533
+ #
534
+ # ```python sync
535
+ # body_handle = page.query_selector("body")
536
+ # html = page.evaluate("([body, suffix]) => body.innerHTML + suffix", [body_handle, "hello"])
537
+ # body_handle.dispose()
538
+ # ```
539
+ #
366
540
  # Shortcut for main frame's [`method: Frame.evaluate`].
367
- def evaluate(pageFunction, arg: nil)
368
- wrap_channel_owner(@channel_owner.evaluate(pageFunction, arg: arg))
541
+ def evaluate(expression, arg: nil)
542
+ wrap_impl(@impl.evaluate(unwrap_impl(expression), arg: unwrap_impl(arg)))
369
543
  end
370
544
 
371
- # Returns the value of the `pageFunction` invocation as in-page object (JSHandle).
545
+ # Returns the value of the `expression` invocation as a `JSHandle`.
546
+ #
547
+ # The only difference between [`method: Page.evaluate`] and [`method: Page.evaluateHandle`] is that
548
+ # [`method: Page.evaluateHandle`] returns `JSHandle`.
372
549
  #
373
- # The only difference between `page.evaluate` and `page.evaluateHandle` is that `page.evaluateHandle` returns in-page
374
- # object (JSHandle).
550
+ # If the function passed to the [`method: Page.evaluateHandle`] returns a [Promise], then [`method: Page.evaluateHandle`]
551
+ # would wait for the promise to resolve and return its value.
375
552
  #
376
- # If the function passed to the `page.evaluateHandle` returns a [Promise], then `page.evaluateHandle` would wait for the
377
- # promise to resolve and return its value.
553
+ #
554
+ # ```js
555
+ # const aWindowHandle = await page.evaluateHandle(() => Promise.resolve(window));
556
+ # aWindowHandle; // Handle for the window object.
557
+ # ```
558
+ #
559
+ # ```python async
560
+ # a_window_handle = await page.evaluate_handle("Promise.resolve(window)")
561
+ # a_window_handle # handle for the window object.
562
+ # ```
563
+ #
564
+ # ```python sync
565
+ # a_window_handle = page.evaluate_handle("Promise.resolve(window)")
566
+ # a_window_handle # handle for the window object.
567
+ # ```
378
568
  #
379
569
  # A string can also be passed in instead of a function:
380
570
  #
@@ -383,7 +573,15 @@ module Playwright
383
573
  # const aHandle = await page.evaluateHandle('document'); // Handle for the 'document'
384
574
  # ```
385
575
  #
386
- # `JSHandle` instances can be passed as an argument to the `page.evaluateHandle`:
576
+ # ```python async
577
+ # a_handle = await page.evaluate_handle("document") # handle for the "document"
578
+ # ```
579
+ #
580
+ # ```python sync
581
+ # a_handle = page.evaluate_handle("document") # handle for the "document"
582
+ # ```
583
+ #
584
+ # `JSHandle` instances can be passed as an argument to the [`method: Page.evaluateHandle`]:
387
585
  #
388
586
  #
389
587
  # ```js
@@ -392,8 +590,22 @@ module Playwright
392
590
  # console.log(await resultHandle.jsonValue());
393
591
  # await resultHandle.dispose();
394
592
  # ```
395
- def evaluate_handle(pageFunction, arg: nil)
396
- wrap_channel_owner(@channel_owner.evaluate_handle(pageFunction, arg: arg))
593
+ #
594
+ # ```python async
595
+ # a_handle = await page.evaluate_handle("document.body")
596
+ # result_handle = await page.evaluate_handle("body => body.innerHTML", a_handle)
597
+ # print(await result_handle.json_value())
598
+ # await result_handle.dispose()
599
+ # ```
600
+ #
601
+ # ```python sync
602
+ # a_handle = page.evaluate_handle("document.body")
603
+ # result_handle = page.evaluate_handle("body => body.innerHTML", a_handle)
604
+ # print(result_handle.json_value())
605
+ # result_handle.dispose()
606
+ # ```
607
+ def evaluate_handle(expression, arg: nil)
608
+ wrap_impl(@impl.evaluate_handle(unwrap_impl(expression), arg: unwrap_impl(arg)))
397
609
  end
398
610
 
399
611
  # The method adds a function called `name` on the `window` object of every frame in this page. When called, the function
@@ -405,7 +617,7 @@ module Playwright
405
617
  #
406
618
  # See [`method: BrowserContext.exposeBinding`] for the context-wide version.
407
619
  #
408
- # > **NOTE** Functions installed via `page.exposeBinding` survive navigations.
620
+ # > NOTE: Functions installed via [`method: Page.exposeBinding`] survive navigations.
409
621
  #
410
622
  # An example of exposing page URL to all frames in a page:
411
623
  #
@@ -431,6 +643,57 @@ module Playwright
431
643
  # })();
432
644
  # ```
433
645
  #
646
+ # ```python async
647
+ # import asyncio
648
+ # from playwright.async_api import async_playwright
649
+ #
650
+ # async def run(playwright):
651
+ # webkit = playwright.webkit
652
+ # browser = await webkit.launch(headless=false)
653
+ # context = await browser.new_context()
654
+ # page = await context.new_page()
655
+ # await page.expose_binding("pageURL", lambda source: source["page"].url)
656
+ # await page.set_content("""
657
+ # <script>
658
+ # async function onClick() {
659
+ # document.querySelector('div').textContent = await window.pageURL();
660
+ # }
661
+ # </script>
662
+ # <button onclick="onClick()">Click me</button>
663
+ # <div></div>
664
+ # """)
665
+ # await page.click("button")
666
+ #
667
+ # async def main():
668
+ # async with async_playwright() as playwright:
669
+ # await run(playwright)
670
+ # asyncio.run(main())
671
+ # ```
672
+ #
673
+ # ```python sync
674
+ # from playwright.sync_api import sync_playwright
675
+ #
676
+ # def run(playwright):
677
+ # webkit = playwright.webkit
678
+ # browser = webkit.launch(headless=false)
679
+ # context = browser.new_context()
680
+ # page = context.new_page()
681
+ # page.expose_binding("pageURL", lambda source: source["page"].url)
682
+ # page.set_content("""
683
+ # <script>
684
+ # async function onClick() {
685
+ # document.querySelector('div').textContent = await window.pageURL();
686
+ # }
687
+ # </script>
688
+ # <button onclick="onClick()">Click me</button>
689
+ # <div></div>
690
+ # """)
691
+ # page.click("button")
692
+ #
693
+ # with sync_playwright() as playwright:
694
+ # run(playwright)
695
+ # ```
696
+ #
434
697
  # An example of passing an element handle:
435
698
  #
436
699
  #
@@ -446,8 +709,36 @@ module Playwright
446
709
  # <div>Or click me</div>
447
710
  # `);
448
711
  # ```
712
+ #
713
+ # ```python async
714
+ # async def print(source, element):
715
+ # print(await element.text_content())
716
+ #
717
+ # await page.expose_binding("clicked", print, handle=true)
718
+ # await page.set_content("""
719
+ # <script>
720
+ # document.addEventListener('click', event => window.clicked(event.target));
721
+ # </script>
722
+ # <div>Click me</div>
723
+ # <div>Or click me</div>
724
+ # """)
725
+ # ```
726
+ #
727
+ # ```python sync
728
+ # def print(source, element):
729
+ # print(element.text_content())
730
+ #
731
+ # page.expose_binding("clicked", print, handle=true)
732
+ # page.set_content("""
733
+ # <script>
734
+ # document.addEventListener('click', event => window.clicked(event.target));
735
+ # </script>
736
+ # <div>Click me</div>
737
+ # <div>Or click me</div>
738
+ # """)
739
+ # ```
449
740
  def expose_binding(name, callback, handle: nil)
450
- raise NotImplementedError.new('expose_binding is not implemented yet.')
741
+ wrap_impl(@impl.expose_binding(unwrap_impl(name), unwrap_impl(callback), handle: unwrap_impl(handle)))
451
742
  end
452
743
 
453
744
  # The method adds a function called `name` on the `window` object of every frame in the page. When called, the function
@@ -457,9 +748,9 @@ module Playwright
457
748
  #
458
749
  # See [`method: BrowserContext.exposeFunction`] for context-wide exposed function.
459
750
  #
460
- # > **NOTE** Functions installed via `page.exposeFunction` survive navigations.
751
+ # > NOTE: Functions installed via [`method: Page.exposeFunction`] survive navigations.
461
752
  #
462
- # An example of adding an `md5` function to the page:
753
+ # An example of adding an `sha1` function to the page:
463
754
  #
464
755
  #
465
756
  # ```js
@@ -469,11 +760,11 @@ module Playwright
469
760
  # (async () => {
470
761
  # const browser = await webkit.launch({ headless: false });
471
762
  # const page = await browser.newPage();
472
- # await page.exposeFunction('md5', text => crypto.createHash('md5').update(text).digest('hex'));
763
+ # await page.exposeFunction('sha1', text => crypto.createHash('sha1').update(text).digest('hex'));
473
764
  # await page.setContent(`
474
765
  # <script>
475
766
  # async function onClick() {
476
- # document.querySelector('div').textContent = await window.md5('PLAYWRIGHT');
767
+ # document.querySelector('div').textContent = await window.sha1('PLAYWRIGHT');
477
768
  # }
478
769
  # </script>
479
770
  # <button onclick="onClick()">Click me</button>
@@ -483,49 +774,83 @@ module Playwright
483
774
  # })();
484
775
  # ```
485
776
  #
486
- # An example of adding a `window.readfile` function to the page:
487
- #
488
- #
489
- # ```js
490
- # const { chromium } = require('playwright'); // Or 'firefox' or 'webkit'.
491
- # const fs = require('fs');
777
+ # ```python async
778
+ # import asyncio
779
+ # import hashlib
780
+ # from playwright.async_api import async_playwright
781
+ #
782
+ # async def sha1(text):
783
+ # m = hashlib.sha1()
784
+ # m.update(bytes(text, "utf8"))
785
+ # return m.hexdigest()
786
+ #
787
+ #
788
+ # async def run(playwright):
789
+ # webkit = playwright.webkit
790
+ # browser = await webkit.launch(headless=False)
791
+ # page = await browser.new_page()
792
+ # await page.expose_function("sha1", sha1)
793
+ # await page.set_content("""
794
+ # <script>
795
+ # async function onClick() {
796
+ # document.querySelector('div').textContent = await window.sha1('PLAYWRIGHT');
797
+ # }
798
+ # </script>
799
+ # <button onclick="onClick()">Click me</button>
800
+ # <div></div>
801
+ # """)
802
+ # await page.click("button")
803
+ #
804
+ # async def main():
805
+ # async with async_playwright() as playwright:
806
+ # await run(playwright)
807
+ # asyncio.run(main())
808
+ # ```
492
809
  #
493
- # (async () => {
494
- # const browser = await chromium.launch();
495
- # const page = await browser.newPage();
496
- # page.on('console', msg => console.log(msg.text()));
497
- # await page.exposeFunction('readfile', async filePath => {
498
- # return new Promise((resolve, reject) => {
499
- # fs.readFile(filePath, 'utf8', (err, text) => {
500
- # if (err)
501
- # reject(err);
502
- # else
503
- # resolve(text);
504
- # });
505
- # });
506
- # });
507
- # await page.evaluate(async () => {
508
- # // use window.readfile to read contents of a file
509
- # const content = await window.readfile('/etc/hosts');
510
- # console.log(content);
511
- # });
512
- # await browser.close();
513
- # })();
810
+ # ```python sync
811
+ # import hashlib
812
+ # from playwright.sync_api import sync_playwright
813
+ #
814
+ # def sha1(text):
815
+ # m = hashlib.sha1()
816
+ # m.update(bytes(text, "utf8"))
817
+ # return m.hexdigest()
818
+ #
819
+ #
820
+ # def run(playwright):
821
+ # webkit = playwright.webkit
822
+ # browser = webkit.launch(headless=False)
823
+ # page = browser.new_page()
824
+ # page.expose_function("sha1", sha1)
825
+ # page.set_content("""
826
+ # <script>
827
+ # async function onClick() {
828
+ # document.querySelector('div').textContent = await window.sha1('PLAYWRIGHT');
829
+ # }
830
+ # </script>
831
+ # <button onclick="onClick()">Click me</button>
832
+ # <div></div>
833
+ # """)
834
+ # page.click("button")
835
+ #
836
+ # with sync_playwright() as playwright:
837
+ # run(playwright)
514
838
  # ```
515
839
  def expose_function(name, callback)
516
- raise NotImplementedError.new('expose_function is not implemented yet.')
840
+ wrap_impl(@impl.expose_function(unwrap_impl(name), unwrap_impl(callback)))
517
841
  end
518
842
 
519
843
  # This method waits for an element matching `selector`, waits for [actionability](./actionability.md) checks, focuses the
520
- # element, fills it and triggers an `input` event after filling. If the element matching `selector` is not an `<input>`,
521
- # `<textarea>` or `[contenteditable]` element, this method throws an error. Note that you can pass an empty string to
522
- # clear the input field.
844
+ # element, fills it and triggers an `input` event after filling. If the element is inside the `<label>` element that has
845
+ # associated [control](https://developer.mozilla.org/en-US/docs/Web/API/HTMLLabelElement/control), that control will be
846
+ # filled instead. If the element to be filled is not an `<input>`, `<textarea>` or `[contenteditable]` element, this
847
+ # method throws an error. Note that you can pass an empty string to clear the input field.
523
848
  #
524
849
  # To send fine-grained keyboard events, use [`method: Page.type`].
525
850
  #
526
851
  # Shortcut for main frame's [`method: Frame.fill`]
527
852
  def fill(selector, value, noWaitAfter: nil, timeout: nil)
528
- raise NotImplementedError.new('fill is not implemented yet.')
853
+ wrap_impl(@impl.fill(unwrap_impl(selector), unwrap_impl(value), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
529
854
  end
530
855
 
531
856
  # This method fetches an element with `selector` and focuses it. If there's no element matching `selector`, the method
@@ -533,7 +858,7 @@ module Playwright
533
858
  #
534
859
  # Shortcut for main frame's [`method: Frame.focus`].
535
860
  def focus(selector, timeout: nil)
536
- wrap_channel_owner(@channel_owner.focus(selector, timeout: timeout))
861
+ wrap_impl(@impl.focus(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
537
862
  end
538
863
 
539
864
  # Returns frame matching the specified criteria. Either `name` or `url` must be specified.
@@ -543,22 +868,30 @@ module Playwright
543
868
  # const frame = page.frame('frame-name');
544
869
  # ```
545
870
  #
871
+ # ```py
872
+ # frame = page.frame(name="frame-name")
873
+ # ```
874
+ #
546
875
  #
547
876
  # ```js
548
877
  # const frame = page.frame({ url: /.*domain.*/ });
549
878
  # ```
879
+ #
880
+ # ```py
881
+ # frame = page.frame(url=r".*domain.*")
882
+ # ```
550
883
  def frame(frameSelector)
551
- wrap_channel_owner(@channel_owner.frame(frameSelector))
884
+ wrap_impl(@impl.frame(unwrap_impl(frameSelector)))
552
885
  end
553
886
 
554
887
  # An array of all frames attached to the page.
555
888
  def frames
556
- wrap_channel_owner(@channel_owner.frames)
889
+ wrap_impl(@impl.frames)
557
890
  end
558
891
 
559
892
  # Returns element attribute value.
560
893
  def get_attribute(selector, name, timeout: nil)
561
- raise NotImplementedError.new('get_attribute is not implemented yet.')
894
+ wrap_impl(@impl.get_attribute(unwrap_impl(selector), unwrap_impl(name), timeout: unwrap_impl(timeout)))
562
895
  end
563
896
 
564
897
  # Returns the main resource response. In case of multiple redirects, the navigation will resolve with the response of the
@@ -566,7 +899,7 @@ module Playwright
566
899
  #
567
900
  # Navigate to the previous page in history.
568
901
  def go_back(timeout: nil, waitUntil: nil)
569
- raise NotImplementedError.new('go_back is not implemented yet.')
902
+ wrap_impl(@impl.go_back(timeout: unwrap_impl(timeout), waitUntil: unwrap_impl(waitUntil)))
570
903
  end
571
904
 
572
905
  # Returns the main resource response. In case of multiple redirects, the navigation will resolve with the response of the
@@ -574,7 +907,7 @@ module Playwright
574
907
  #
575
908
  # Navigate to the next page in history.
576
909
  def go_forward(timeout: nil, waitUntil: nil)
577
- raise NotImplementedError.new('go_forward is not implemented yet.')
910
+ wrap_impl(@impl.go_forward(timeout: unwrap_impl(timeout), waitUntil: unwrap_impl(waitUntil)))
578
911
  end
579
912
 
580
913
  # Returns the main resource response. In case of multiple redirects, the navigation will resolve with the response of the
@@ -591,14 +924,14 @@ module Playwright
591
924
  # Found" and 500 "Internal Server Error". The status code for such responses can be retrieved by calling
592
925
  # [`method: Response.status`].
593
926
  #
594
- # > **NOTE** `page.goto` either throws an error or returns a main resource response. The only exceptions are navigation to
927
+ # > NOTE: `page.goto` either throws an error or returns a main resource response. The only exceptions are navigation to
595
928
  # `about:blank` or navigation to the same URL with a different hash, which would succeed and return `null`.
596
- # > **NOTE** Headless mode doesn't support navigation to a PDF document. See the
929
+ # > NOTE: Headless mode doesn't support navigation to a PDF document. See the
597
930
  # [upstream issue](https://bugs.chromium.org/p/chromium/issues/detail?id=761295).
598
931
  #
599
932
  # Shortcut for main frame's [`method: Frame.goto`]
600
933
  def goto(url, referer: nil, timeout: nil, waitUntil: nil)
601
- wrap_channel_owner(@channel_owner.goto(url, referer: referer, timeout: timeout, waitUntil: waitUntil))
934
+ wrap_impl(@impl.goto(unwrap_impl(url), referer: unwrap_impl(referer), timeout: unwrap_impl(timeout), waitUntil: unwrap_impl(waitUntil)))
602
935
  end
603
936
 
604
937
  # This method hovers over an element matching `selector` by performing the following steps:
@@ -619,72 +952,84 @@ module Playwright
619
952
  modifiers: nil,
620
953
  position: nil,
621
954
  timeout: nil)
622
- raise NotImplementedError.new('hover is not implemented yet.')
955
+ wrap_impl(@impl.hover(unwrap_impl(selector), force: unwrap_impl(force), modifiers: unwrap_impl(modifiers), position: unwrap_impl(position), timeout: unwrap_impl(timeout)))
623
956
  end
624
957
 
625
958
  # Returns `element.innerHTML`.
626
959
  def inner_html(selector, timeout: nil)
627
- raise NotImplementedError.new('inner_html is not implemented yet.')
960
+ wrap_impl(@impl.inner_html(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
628
961
  end
629
962
 
630
963
  # Returns `element.innerText`.
631
964
  def inner_text(selector, timeout: nil)
632
- raise NotImplementedError.new('inner_text is not implemented yet.')
965
+ wrap_impl(@impl.inner_text(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
633
966
  end
634
967
 
635
968
  # Returns whether the element is checked. Throws if the element is not a checkbox or radio input.
636
969
  def checked?(selector, timeout: nil)
637
- raise NotImplementedError.new('checked? is not implemented yet.')
970
+ wrap_impl(@impl.checked?(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
638
971
  end
639
972
 
640
973
  # Indicates that the page has been closed.
641
974
  def closed?
642
- wrap_channel_owner(@channel_owner.closed?)
975
+ wrap_impl(@impl.closed?)
643
976
  end
644
977
 
645
978
  # Returns whether the element is disabled, the opposite of [enabled](./actionability.md#enabled).
646
979
  def disabled?(selector, timeout: nil)
647
- raise NotImplementedError.new('disabled? is not implemented yet.')
980
+ wrap_impl(@impl.disabled?(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
648
981
  end
649
982
 
650
983
  # Returns whether the element is [editable](./actionability.md#editable).
651
984
  def editable?(selector, timeout: nil)
652
- raise NotImplementedError.new('editable? is not implemented yet.')
985
+ wrap_impl(@impl.editable?(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
653
986
  end
654
987
 
655
988
  # Returns whether the element is [enabled](./actionability.md#enabled).
656
989
  def enabled?(selector, timeout: nil)
657
- raise NotImplementedError.new('enabled? is not implemented yet.')
990
+ wrap_impl(@impl.enabled?(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
658
991
  end
659
992
 
660
993
  # Returns whether the element is hidden, the opposite of [visible](./actionability.md#visible).
661
994
  def hidden?(selector, timeout: nil)
662
- raise NotImplementedError.new('hidden? is not implemented yet.')
995
+ wrap_impl(@impl.hidden?(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
663
996
  end
664
997
 
665
998
  # Returns whether the element is [visible](./actionability.md#visible).
666
999
  def visible?(selector, timeout: nil)
667
- raise NotImplementedError.new('visible? is not implemented yet.')
1000
+ wrap_impl(@impl.visible?(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
668
1001
  end
669
1002
 
670
1003
  # The page's main frame. Page is guaranteed to have a main frame which persists during navigations.
671
1004
  def main_frame
672
- wrap_channel_owner(@channel_owner.main_frame)
1005
+ wrap_impl(@impl.main_frame)
673
1006
  end
674
1007
 
675
1008
  # Returns the opener for popup pages and `null` for others. If the opener has been closed already the returns `null`.
676
1009
  def opener
677
- wrap_channel_owner(@channel_owner.opener)
1010
+ wrap_impl(@impl.opener)
1011
+ end
1012
+
1013
+ # Pauses script execution. Playwright will stop executing the script and wait for the user to either press 'Resume' button
1014
+ # in the page overlay or to call `playwright.resume()` in the DevTools console.
1015
+ #
1016
+ # User can inspect selectors or perform manual steps while paused. Resume will continue running the original script from
1017
+ # the place it was paused.
1018
+ #
1019
+ # > NOTE: This method requires Playwright to be started in a headed mode, with a falsy [`options: headless`] value in the
1020
+ # [`method: BrowserType.launch`].
1021
+ def pause
1022
+ raise NotImplementedError.new('pause is not implemented yet.')
678
1023
  end
679
1024
 
680
1025
  # Returns the PDF buffer.
681
1026
  #
682
- # > **NOTE** Generating a pdf is currently only supported in Chromium headless.
1027
+ # > NOTE: Generating a pdf is currently only supported in Chromium headless.
683
1028
  #
684
1029
  # `page.pdf()` generates a pdf of the page with `print` css media. To generate a pdf with `screen` media, call
685
1030
  # [`method: Page.emulateMedia`] before calling `page.pdf()`:
686
1031
  #
687
- # > **NOTE** By default, `page.pdf()` generates a pdf with modified colors for printing. Use the
1032
+ # > NOTE: By default, `page.pdf()` generates a pdf with modified colors for printing. Use the
688
1033
  # [`-webkit-print-color-adjust`](https://developer.mozilla.org/en-US/docs/Web/CSS/-webkit-print-color-adjust) property to
689
1034
  # force rendering of exact colors.
690
1035
  #
@@ -695,6 +1040,18 @@ module Playwright
695
1040
  # await page.pdf({path: 'page.pdf'});
696
1041
  # ```
697
1042
  #
1043
+ # ```python async
1044
+ # # generates a pdf with "screen" media type.
1045
+ # await page.emulate_media(media="screen")
1046
+ # await page.pdf(path="page.pdf")
1047
+ # ```
1048
+ #
1049
+ # ```python sync
1050
+ # # generates a pdf with "screen" media type.
1051
+ # page.emulate_media(media="screen")
1052
+ # page.pdf(path="page.pdf")
1053
+ # ```
1054
+ #
698
1055
  # The `width`, `height`, and `margin` options accept values labeled with units. Unlabeled values are treated as pixels.
699
1056
  #
700
1057
  # A few examples:
@@ -721,9 +1078,8 @@ module Playwright
721
1078
  # - `A5`: 5.83in x 8.27in
722
1079
  # - `A6`: 4.13in x 5.83in
723
1080
  #
724
- # > **NOTE** `headerTemplate` and `footerTemplate` markup have the following limitations:
725
- # > 1. Script tags inside templates are not evaluated.
726
- # > 2. Page styles are not visible inside templates.
1081
+ # > NOTE: `headerTemplate` and `footerTemplate` markup have the following limitations: > 1. Script tags inside templates
1082
+ # are not evaluated. > 2. Page styles are not visible inside templates.
727
1083
  def pdf(
728
1084
  displayHeaderFooter: nil,
729
1085
  footerTemplate: nil,
@@ -738,7 +1094,7 @@ module Playwright
738
1094
  printBackground: nil,
739
1095
  scale: nil,
740
1096
  width: nil)
741
- raise NotImplementedError.new('pdf is not implemented yet.')
1097
+ wrap_impl(@impl.pdf(displayHeaderFooter: unwrap_impl(displayHeaderFooter), footerTemplate: unwrap_impl(footerTemplate), format: unwrap_impl(format), headerTemplate: unwrap_impl(headerTemplate), height: unwrap_impl(height), landscape: unwrap_impl(landscape), margin: unwrap_impl(margin), pageRanges: unwrap_impl(pageRanges), path: unwrap_impl(path), preferCSSPageSize: unwrap_impl(preferCSSPageSize), printBackground: unwrap_impl(printBackground), scale: unwrap_impl(scale), width: unwrap_impl(width)))
742
1098
  end
743
1099
 
744
1100
  # Focuses the element, and then uses [`method: Keyboard.down`] and [`method: Keyboard.up`].
@@ -772,26 +1128,66 @@ module Playwright
772
1128
  # await page.screenshot({ path: 'O.png' });
773
1129
  # await browser.close();
774
1130
  # ```
1131
+ #
1132
+ # ```python async
1133
+ # page = await browser.new_page()
1134
+ # await page.goto("https://keycode.info")
1135
+ # await page.press("body", "A")
1136
+ # await page.screenshot(path="a.png")
1137
+ # await page.press("body", "ArrowLeft")
1138
+ # await page.screenshot(path="arrow_left.png")
1139
+ # await page.press("body", "Shift+O")
1140
+ # await page.screenshot(path="o.png")
1141
+ # await browser.close()
1142
+ # ```
1143
+ #
1144
+ # ```python sync
1145
+ # page = browser.new_page()
1146
+ # page.goto("https://keycode.info")
1147
+ # page.press("body", "A")
1148
+ # page.screenshot(path="a.png")
1149
+ # page.press("body", "ArrowLeft")
1150
+ # page.screenshot(path="arrow_left.png")
1151
+ # page.press("body", "Shift+O")
1152
+ # page.screenshot(path="o.png")
1153
+ # browser.close()
1154
+ # ```
775
1155
  def press(
776
1156
  selector,
777
1157
  key,
778
1158
  delay: nil,
779
1159
  noWaitAfter: nil,
780
1160
  timeout: nil)
781
- wrap_channel_owner(@channel_owner.press(selector, key, delay: delay, noWaitAfter: noWaitAfter, timeout: timeout))
1161
+ wrap_impl(@impl.press(unwrap_impl(selector), unwrap_impl(key), delay: unwrap_impl(delay), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
1162
+ end
1163
+
1164
+ # The method finds an element matching the specified selector within the page. If no elements match the selector, the
1165
+ # return value resolves to `null`.
1166
+ #
1167
+ # Shortcut for main frame's [`method: Frame.querySelector`].
1168
+ def query_selector(selector)
1169
+ wrap_impl(@impl.query_selector(unwrap_impl(selector)))
1170
+ end
1171
+
1172
+ # The method finds all elements matching the specified selector within the page. If no elements match the selector, the
1173
+ # return value resolves to `[]`.
1174
+ #
1175
+ # Shortcut for main frame's [`method: Frame.querySelectorAll`].
1176
+ def query_selector_all(selector)
1177
+ wrap_impl(@impl.query_selector_all(unwrap_impl(selector)))
782
1178
  end
783
1179
 
784
1180
  # Returns the main resource response. In case of multiple redirects, the navigation will resolve with the response of the
785
1181
  # last redirect.
786
1182
  def reload(timeout: nil, waitUntil: nil)
787
- raise NotImplementedError.new('reload is not implemented yet.')
1183
+ wrap_impl(@impl.reload(timeout: unwrap_impl(timeout), waitUntil: unwrap_impl(waitUntil)))
788
1184
  end
789
1185
 
790
1186
  # Routing provides the capability to modify network requests that are made by a page.
791
1187
  #
792
1188
  # Once routing is enabled, every request matching the url pattern will stall unless it's continued, fulfilled or aborted.
793
1189
  #
794
- # > **NOTE** The handler will only be called for the first url if the response is a redirect.
1190
+ # > NOTE: The handler will only be called for the first url if the response is a redirect.
795
1191
  #
796
1192
  # An example of a naïve handler that aborts all image requests:
797
1193
  #
@@ -803,6 +1199,20 @@ module Playwright
803
1199
  # await browser.close();
804
1200
  # ```
805
1201
  #
1202
+ # ```python async
1203
+ # page = await browser.new_page()
1204
+ # await page.route("**/*.{png,jpg,jpeg}", lambda route: route.abort())
1205
+ # await page.goto("https://example.com")
1206
+ # await browser.close()
1207
+ # ```
1208
+ #
1209
+ # ```python sync
1210
+ # page = browser.new_page()
1211
+ # page.route("**/*.{png,jpg,jpeg}", lambda route: route.abort())
1212
+ # page.goto("https://example.com")
1213
+ # browser.close()
1214
+ # ```
1215
+ #
806
1216
  # or the same snippet using a regex pattern instead:
807
1217
  #
808
1218
  #
@@ -813,17 +1223,31 @@ module Playwright
813
1223
  # await browser.close();
814
1224
  # ```
815
1225
  #
1226
+ # ```python async
1227
+ # page = await browser.new_page()
1228
+ # await page.route(re.compile(r"(\.png$)|(\.jpg$)"), lambda route: route.abort())
1229
+ # await page.goto("https://example.com")
1230
+ # await browser.close()
1231
+ # ```
1232
+ #
1233
+ # ```python sync
1234
+ # page = browser.new_page()
1235
+ # page.route(re.compile(r"(\.png$)|(\.jpg$)"), lambda route: route.abort())
1236
+ # page.goto("https://example.com")
1237
+ # browser.close()
1238
+ # ```
1239
+ #
816
1240
  # Page routes take precedence over browser context routes (set up with [`method: BrowserContext.route`]) when request
817
1241
  # matches both handlers.
818
1242
  #
819
- # > **NOTE** Enabling routing disables http cache.
1243
+ # > NOTE: Enabling routing disables http cache.
820
1244
  def route(url, handler)
821
1245
  raise NotImplementedError.new('route is not implemented yet.')
822
1246
  end
823
1247
 
824
1248
  # Returns the buffer with the captured screenshot.
825
1249
  #
826
- # > **NOTE** Screenshots take at least 1/6 second on Chromium OS X and Chromium Windows. See https://crbug.com/741689 for
1250
+ # > NOTE: Screenshots take at least 1/6 second on Chromium OS X and Chromium Windows. See https://crbug.com/741689 for
827
1251
  # discussion.
828
1252
  def screenshot(
829
1253
  clip: nil,
@@ -833,7 +1257,7 @@ module Playwright
833
1257
  quality: nil,
834
1258
  timeout: nil,
835
1259
  type: nil)
836
- wrap_channel_owner(@channel_owner.screenshot(clip: clip, fullPage: fullPage, omitBackground: omitBackground, path: path, quality: quality, timeout: timeout, type: type))
1260
+ wrap_impl(@impl.screenshot(clip: unwrap_impl(clip), fullPage: unwrap_impl(fullPage), omitBackground: unwrap_impl(omitBackground), path: unwrap_impl(path), quality: unwrap_impl(quality), timeout: unwrap_impl(timeout), type: unwrap_impl(type)))
837
1261
  end
838
1262
 
839
1263
  # Returns the array of option values that have been successfully selected.
@@ -841,12 +1265,14 @@ module Playwright
841
1265
  # Triggers a `change` and `input` event once all the provided options have been selected. If there's no `<select>` element
842
1266
  # matching `selector`, the method throws an error.
843
1267
  #
1268
+ # Will wait until all specified options are present in the `<select>` element.
1269
+ #
844
1270
  #
845
1271
  # ```js
846
1272
  # // single selection matching the value
847
1273
  # page.selectOption('select#colors', 'blue');
848
1274
  #
849
- # // single selection matching both the value and the label
1275
+ # // single selection matching the label
850
1276
  # page.selectOption('select#colors', { label: 'Blue' });
851
1277
  #
852
1278
  # // multiple selection
@@ -854,13 +1280,31 @@ module Playwright
854
1280
  #
855
1281
  # ```
856
1282
  #
1283
+ # ```python async
1284
+ # # single selection matching the value
1285
+ # await page.select_option("select#colors", "blue")
1286
+ # # single selection matching the label
1287
+ # await page.select_option("select#colors", label="blue")
1288
+ # # multiple selection
1289
+ # await page.select_option("select#colors", value=["red", "green", "blue"])
1290
+ # ```
1291
+ #
1292
+ # ```python sync
1293
+ # # single selection matching the value
1294
+ # page.select_option("select#colors", "blue")
1295
+ # # single selection matching both the label
1296
+ # page.select_option("select#colors", label="blue")
1297
+ # # multiple selection
1298
+ # page.select_option("select#colors", value=["red", "green", "blue"])
1299
+ # ```
1300
+ #
857
1301
  # Shortcut for main frame's [`method: Frame.selectOption`]
858
1302
  def select_option(selector, values, noWaitAfter: nil, timeout: nil)
859
- raise NotImplementedError.new('select_option is not implemented yet.')
1303
+ wrap_impl(@impl.select_option(unwrap_impl(selector), unwrap_impl(values), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
860
1304
  end
861
1305
 
862
1306
  def set_content(html, timeout: nil, waitUntil: nil)
863
- wrap_channel_owner(@channel_owner.set_content(html, timeout: timeout, waitUntil: waitUntil))
1307
+ wrap_impl(@impl.set_content(unwrap_impl(html), timeout: unwrap_impl(timeout), waitUntil: unwrap_impl(waitUntil)))
864
1308
  end
865
1309
  alias_method :content=, :set_content
866
1310
 
@@ -872,26 +1316,26 @@ module Playwright
872
1316
  # - [`method: Page.setContent`]
873
1317
  # - [`method: Page.waitForNavigation`]
874
1318
  #
875
- # > **NOTE** [`method: Page.setDefaultNavigationTimeout`] takes priority over [`method: Page.setDefaultTimeout`],
1319
+ # > NOTE: [`method: Page.setDefaultNavigationTimeout`] takes priority over [`method: Page.setDefaultTimeout`],
876
1320
  # [`method: BrowserContext.setDefaultTimeout`] and [`method: BrowserContext.setDefaultNavigationTimeout`].
877
1321
  def set_default_navigation_timeout(timeout)
878
- raise NotImplementedError.new('set_default_navigation_timeout is not implemented yet.')
1322
+ wrap_impl(@impl.set_default_navigation_timeout(unwrap_impl(timeout)))
879
1323
  end
880
1324
  alias_method :default_navigation_timeout=, :set_default_navigation_timeout
881
1325
 
882
1326
  # This setting will change the default maximum time for all the methods accepting `timeout` option.
883
1327
  #
884
- # > **NOTE** [`method: Page.setDefaultNavigationTimeout`] takes priority over [`method: Page.setDefaultTimeout`].
1328
+ # > NOTE: [`method: Page.setDefaultNavigationTimeout`] takes priority over [`method: Page.setDefaultTimeout`].
885
1329
  def set_default_timeout(timeout)
886
- raise NotImplementedError.new('set_default_timeout is not implemented yet.')
1330
+ wrap_impl(@impl.set_default_timeout(unwrap_impl(timeout)))
887
1331
  end
888
1332
  alias_method :default_timeout=, :set_default_timeout
889
1333
 
890
1334
  # The extra HTTP headers will be sent with every request the page initiates.
891
1335
  #
892
- # > **NOTE** page.setExtraHTTPHeaders does not guarantee the order of headers in the outgoing requests.
1336
+ # > NOTE: [`method: Page.setExtraHTTPHeaders`] does not guarantee the order of headers in the outgoing requests.
893
1337
  def set_extra_http_headers(headers)
894
- raise NotImplementedError.new('set_extra_http_headers is not implemented yet.')
1338
+ wrap_impl(@impl.set_extra_http_headers(unwrap_impl(headers)))
895
1339
  end
896
1340
  alias_method :extra_http_headers=, :set_extra_http_headers
897
1341
 
@@ -901,7 +1345,7 @@ module Playwright
901
1345
  # Sets the value of the file input to these file paths or files. If some of the `filePaths` are relative paths, then they
902
1346
  # are resolved relative to the the current working directory. For empty array, clears the selected files.
903
1347
  def set_input_files(selector, files, noWaitAfter: nil, timeout: nil)
904
- raise NotImplementedError.new('set_input_files is not implemented yet.')
1348
+ wrap_impl(@impl.set_input_files(unwrap_impl(selector), unwrap_impl(files), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
905
1349
  end
906
1350
 
907
1351
  # In the case of multiple pages in a single browser, each page can have its own viewport size. However,
@@ -919,8 +1363,20 @@ module Playwright
919
1363
  # });
920
1364
  # await page.goto('https://example.com');
921
1365
  # ```
1366
+ #
1367
+ # ```python async
1368
+ # page = await browser.new_page()
1369
+ # await page.set_viewport_size({"width": 640, "height": 480})
1370
+ # await page.goto("https://example.com")
1371
+ # ```
1372
+ #
1373
+ # ```python sync
1374
+ # page = browser.new_page()
1375
+ # page.set_viewport_size({"width": 640, "height": 480})
1376
+ # page.goto("https://example.com")
1377
+ # ```
922
1378
  def set_viewport_size(viewportSize)
923
- wrap_channel_owner(@channel_owner.set_viewport_size(viewportSize))
1379
+ wrap_impl(@impl.set_viewport_size(unwrap_impl(viewportSize)))
924
1380
  end
925
1381
  alias_method :viewport_size=, :set_viewport_size
926
1382
 
@@ -935,7 +1391,7 @@ module Playwright
935
1391
  # When all steps combined have not finished during the specified `timeout`, this method rejects with a `TimeoutError`.
936
1392
  # Passing zero timeout disables this.
937
1393
  #
938
- # > **NOTE** `page.tap()` requires that the `hasTouch` option of the browser context be set to true.
1394
+ # > NOTE: [`method: Page.tap`] requires that the `hasTouch` option of the browser context be set to true.
939
1395
  #
940
1396
  # Shortcut for main frame's [`method: Frame.tap`].
941
1397
  def tap_point(
@@ -945,17 +1401,17 @@ module Playwright
945
1401
  noWaitAfter: nil,
946
1402
  position: nil,
947
1403
  timeout: nil)
948
- raise NotImplementedError.new('tap_point is not implemented yet.')
1404
+ 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)))
949
1405
  end
950
1406
 
951
1407
  # Returns `element.textContent`.
952
1408
  def text_content(selector, timeout: nil)
953
- raise NotImplementedError.new('text_content is not implemented yet.')
1409
+ wrap_impl(@impl.text_content(unwrap_impl(selector), timeout: unwrap_impl(timeout)))
954
1410
  end
955
1411
 
956
1412
  # Returns the page's title. Shortcut for main frame's [`method: Frame.title`].
957
1413
  def title
958
- wrap_channel_owner(@channel_owner.title)
1414
+ wrap_impl(@impl.title)
959
1415
  end
960
1416
 
961
1417
  # Sends a `keydown`, `keypress`/`input`, and `keyup` event for each character in the text. `page.type` can be used to send
@@ -969,14 +1425,24 @@ module Playwright
969
1425
  # await page.type('#mytextarea', 'World', {delay: 100}); // Types slower, like a user
970
1426
  # ```
971
1427
  #
1428
+ # ```python async
1429
+ # await page.type("#mytextarea", "hello") # types instantly
1430
+ # await page.type("#mytextarea", "world", delay=100) # types slower, like a user
1431
+ # ```
1432
+ #
1433
+ # ```python sync
1434
+ # page.type("#mytextarea", "hello") # types instantly
1435
+ # page.type("#mytextarea", "world", delay=100) # types slower, like a user
1436
+ # ```
1437
+ #
972
1438
  # Shortcut for main frame's [`method: Frame.type`].
973
- def type_text(
1439
+ def type(
974
1440
  selector,
975
1441
  text,
976
1442
  delay: nil,
977
1443
  noWaitAfter: nil,
978
1444
  timeout: nil)
979
- wrap_channel_owner(@channel_owner.type_text(selector, text, delay: delay, noWaitAfter: noWaitAfter, timeout: timeout))
1445
+ wrap_impl(@impl.type(unwrap_impl(selector), unwrap_impl(text), delay: unwrap_impl(delay), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
980
1446
  end
981
1447
 
982
1448
  # This method unchecks an element matching `selector` by performing the following steps:
@@ -995,7 +1461,7 @@ module Playwright
995
1461
  #
996
1462
  # Shortcut for main frame's [`method: Frame.uncheck`].
997
1463
  def uncheck(selector, force: nil, noWaitAfter: nil, timeout: nil)
998
- raise NotImplementedError.new('uncheck is not implemented yet.')
1464
+ wrap_impl(@impl.uncheck(unwrap_impl(selector), force: unwrap_impl(force), noWaitAfter: unwrap_impl(noWaitAfter), timeout: unwrap_impl(timeout)))
999
1465
  end
1000
1466
 
1001
1467
  # Removes a route created with [`method: Page.route`]. When `handler` is not specified, removes all routes for the `url`.
@@ -1005,7 +1471,7 @@ module Playwright
1005
1471
 
1006
1472
  # Shortcut for main frame's [`method: Frame.url`].
1007
1473
  def url
1008
- wrap_channel_owner(@channel_owner.url)
1474
+ wrap_impl(@impl.url)
1009
1475
  end
1010
1476
 
1011
1477
  # Video object associated with this page.
@@ -1014,20 +1480,12 @@ module Playwright
1014
1480
  end
1015
1481
 
1016
1482
  def viewport_size
1017
- wrap_channel_owner(@channel_owner.viewport_size)
1483
+ wrap_impl(@impl.viewport_size)
1018
1484
  end
1019
1485
 
1020
- # Returns the event data value.
1486
+ # Returns when the `expression` returns a truthy value. It resolves to a JSHandle of the truthy value.
1021
1487
  #
1022
- # Waits for event to fire and passes its value into the predicate function. Returns when the predicate returns truthy
1023
- # value. Will throw an error if the page is closed before the event is fired.
1024
- def wait_for_event(event, optionsOrPredicate: nil, &block)
1025
- wrap_channel_owner(@channel_owner.wait_for_event(event, optionsOrPredicate: optionsOrPredicate, &wrap_block_call(block)))
1026
- end
1027
-
1028
- # Returns when the `pageFunction` returns a truthy value. It resolves to a JSHandle of the truthy value.
1029
- #
1030
- # The `waitForFunction` can be used to observe viewport size change:
1488
+ # The [`method: Page.waitForFunction`] can be used to observe viewport size change:
1031
1489
  #
1032
1490
  #
1033
1491
  # ```js
@@ -1036,14 +1494,47 @@ module Playwright
1036
1494
  # (async () => {
1037
1495
  # const browser = await webkit.launch();
1038
1496
  # const page = await browser.newPage();
1039
- # const watchDog = page.waitForFunction('window.innerWidth < 100');
1497
+ # const watchDog = page.waitForFunction(() => window.innerWidth < 100);
1040
1498
  # await page.setViewportSize({width: 50, height: 50});
1041
1499
  # await watchDog;
1042
1500
  # await browser.close();
1043
1501
  # })();
1044
1502
  # ```
1045
1503
  #
1046
- # To pass an argument to the predicate of `page.waitForFunction` function:
1504
+ # ```python async
1505
+ # import asyncio
1506
+ # from playwright.async_api import async_playwright
1507
+ #
1508
+ # async def run(playwright):
1509
+ # webkit = playwright.webkit
1510
+ # browser = await webkit.launch()
1511
+ # page = await browser.new_page()
1512
+ # await page.evaluate("window.x = 0; setTimeout(() => { window.x = 100 }, 1000);")
1513
+ # await page.wait_for_function("() => window.x > 0")
1514
+ # await browser.close()
1515
+ #
1516
+ # async def main():
1517
+ # async with async_playwright() as playwright:
1518
+ # await run(playwright)
1519
+ # asyncio.run(main())
1520
+ # ```
1521
+ #
1522
+ # ```python sync
1523
+ # from playwright.sync_api import sync_playwright
1524
+ #
1525
+ # def run(playwright):
1526
+ # webkit = playwright.webkit
1527
+ # browser = webkit.launch()
1528
+ # page = browser.new_page()
1529
+ # page.evaluate("window.x = 0; setTimeout(() => { window.x = 100 }, 1000);")
1530
+ # page.wait_for_function("() => window.x > 0")
1531
+ # browser.close()
1532
+ #
1533
+ # with sync_playwright() as playwright:
1534
+ # run(playwright)
1535
+ # ```
1536
+ #
1537
+ # To pass an argument to the predicate of [`method: Page.waitForFunction`] function:
1047
1538
  #
1048
1539
  #
1049
1540
  # ```js
@@ -1051,9 +1542,19 @@ module Playwright
1051
1542
  # await page.waitForFunction(selector => !!document.querySelector(selector), selector);
1052
1543
  # ```
1053
1544
  #
1545
+ # ```python async
1546
+ # selector = ".foo"
1547
+ # await page.wait_for_function("selector => !!document.querySelector(selector)", selector)
1548
+ # ```
1549
+ #
1550
+ # ```python sync
1551
+ # selector = ".foo"
1552
+ # page.wait_for_function("selector => !!document.querySelector(selector)", selector)
1553
+ # ```
1554
+ #
1054
1555
  # Shortcut for main frame's [`method: Frame.waitForFunction`].
1055
- def wait_for_function(pageFunction, arg: nil, polling: nil, timeout: nil)
1056
- raise NotImplementedError.new('wait_for_function is not implemented yet.')
1556
+ def wait_for_function(expression, arg: nil, polling: nil, timeout: nil)
1557
+ wrap_impl(@impl.wait_for_function(unwrap_impl(expression), arg: unwrap_impl(arg), polling: unwrap_impl(polling), timeout: unwrap_impl(timeout)))
1057
1558
  end
1058
1559
 
1059
1560
  # Returns when the required load state has been reached.
@@ -1067,6 +1568,16 @@ module Playwright
1067
1568
  # await page.waitForLoadState(); // The promise resolves after 'load' event.
1068
1569
  # ```
1069
1570
  #
1571
+ # ```python async
1572
+ # await page.click("button") # click triggers navigation.
1573
+ # await page.wait_for_load_state() # the promise resolves after "load" event.
1574
+ # ```
1575
+ #
1576
+ # ```python sync
1577
+ # page.click("button") # click triggers navigation.
1578
+ # page.wait_for_load_state() # the promise resolves after "load" event.
1579
+ # ```
1580
+ #
1070
1581
  #
1071
1582
  # ```js
1072
1583
  # const [popup] = await Promise.all([
@@ -1077,14 +1588,32 @@ module Playwright
1077
1588
  # console.log(await popup.title()); // Popup is ready to use.
1078
1589
  # ```
1079
1590
  #
1591
+ # ```python async
1592
+ # async with page.expect_popup() as page_info:
1593
+ # await page.click("button") # click triggers a popup.
1594
+ # popup = await page_info.value
1595
+ # # Following resolves after "domcontentloaded" event.
1596
+ # await popup.wait_for_load_state("domcontentloaded")
1597
+ # print(await popup.title()) # popup is ready to use.
1598
+ # ```
1599
+ #
1600
+ # ```python sync
1601
+ # with page.expect_popup() as page_info:
1602
+ # page.click("button") # click triggers a popup.
1603
+ # popup = page_info.value
1604
+ # # Following resolves after "domcontentloaded" event.
1605
+ # popup.wait_for_load_state("domcontentloaded")
1606
+ # print(popup.title()) # popup is ready to use.
1607
+ # ```
1608
+ #
1080
1609
  # Shortcut for main frame's [`method: Frame.waitForLoadState`].
1081
1610
  def wait_for_load_state(state: nil, timeout: nil)
1082
- raise NotImplementedError.new('wait_for_load_state is not implemented yet.')
1611
+ wrap_impl(@impl.wait_for_load_state(state: unwrap_impl(state), timeout: unwrap_impl(timeout)))
1083
1612
  end
1084
1613
 
1085
- # Returns the main resource response. In case of multiple redirects, the navigation will resolve with the response of the
1086
- # last redirect. In case of navigation to a different anchor or navigation due to History API usage, the navigation will
1087
- # resolve with `null`.
1614
+ # Waits for the main frame navigation and returns the main resource response. In case of multiple redirects, the
1615
+ # navigation will resolve with the response of the last redirect. In case of navigation to a different anchor or
1616
+ # navigation due to History API usage, the navigation will resolve with `null`.
1088
1617
  #
1089
1618
  # This resolves when the page navigates to a new URL or reloads. It is useful for when you run code which will indirectly
1090
1619
  # cause the page to navigate. e.g. The click target has an `onclick` handler that triggers navigation from a `setTimeout`.
@@ -1098,12 +1627,24 @@ module Playwright
1098
1627
  # ]);
1099
1628
  # ```
1100
1629
  #
1101
- # **NOTE** Usage of the [History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API) to change the URL is
1630
+ # ```python async
1631
+ # async with page.expect_navigation():
1632
+ # await page.click("a.delayed-navigation") # clicking the link will indirectly cause a navigation
1633
+ # # Resolves after navigation has finished
1634
+ # ```
1635
+ #
1636
+ # ```python sync
1637
+ # with page.expect_navigation():
1638
+ # page.click("a.delayed-navigation") # clicking the link will indirectly cause a navigation
1639
+ # # Resolves after navigation has finished
1640
+ # ```
1641
+ #
1642
+ # > NOTE: Usage of the [History API](https://developer.mozilla.org/en-US/docs/Web/API/History_API) to change the URL is
1102
1643
  # considered a navigation.
1103
1644
  #
1104
1645
  # Shortcut for main frame's [`method: Frame.waitForNavigation`].
1105
- def wait_for_navigation(timeout: nil, url: nil, waitUntil: nil)
1106
- raise NotImplementedError.new('wait_for_navigation is not implemented yet.')
1646
+ def expect_navigation(timeout: nil, url: nil, waitUntil: nil, &block)
1647
+ wrap_impl(@impl.expect_navigation(timeout: unwrap_impl(timeout), url: unwrap_impl(url), waitUntil: unwrap_impl(waitUntil), &wrap_block_call(block)))
1107
1648
  end
1108
1649
 
1109
1650
  # Waits for the matching request and returns it.
@@ -1115,12 +1656,32 @@ module Playwright
1115
1656
  # return firstRequest.url();
1116
1657
  # ```
1117
1658
  #
1659
+ # ```python async
1660
+ # async with page.expect_request("http://example.com/resource") as first:
1661
+ # await page.click('button')
1662
+ # first_request = await first.value
1663
+ #
1664
+ # async with page.expect_request(lambda request: request.url == "http://example.com" and request.method == "get") as second:
1665
+ # await page.click('img')
1666
+ # second_request = await second.value
1667
+ # ```
1668
+ #
1669
+ # ```python sync
1670
+ # with page.expect_request("http://example.com/resource") as first:
1671
+ # page.click('button')
1672
+ # first_request = first.value
1673
+ #
1674
+ # with page.expect_request(lambda request: request.url == "http://example.com" and request.method == "get") as second:
1675
+ # page.click('img')
1676
+ # second_request = second.value
1677
+ # ```
1678
+ #
1118
1679
  #
1119
1680
  # ```js
1120
1681
  # await page.waitForRequest(request => request.url().searchParams.get('foo') === 'bar' && request.url().searchParams.get('foo2') === 'bar2');
1121
1682
  # ```
1122
- def wait_for_request(urlOrPredicate, timeout: nil)
1123
- wrap_channel_owner(@channel_owner.wait_for_request(urlOrPredicate, timeout: timeout))
1683
+ def expect_request(urlOrPredicate, timeout: nil)
1684
+ wrap_impl(@impl.expect_request(unwrap_impl(urlOrPredicate), timeout: unwrap_impl(timeout)))
1124
1685
  end
1125
1686
 
1126
1687
  # Returns the matched response.
@@ -1131,8 +1692,20 @@ module Playwright
1131
1692
  # const finalResponse = await page.waitForResponse(response => response.url() === 'https://example.com' && response.status() === 200);
1132
1693
  # return finalResponse.ok();
1133
1694
  # ```
1134
- def wait_for_response(urlOrPredicate, timeout: nil)
1135
- wrap_channel_owner(@channel_owner.wait_for_response(urlOrPredicate, timeout: timeout))
1695
+ #
1696
+ # ```python async
1697
+ # first_response = await page.wait_for_response("https://example.com/resource")
1698
+ # final_response = await page.wait_for_response(lambda response: response.url == "https://example.com" and response.status === 200)
1699
+ # return final_response.ok
1700
+ # ```
1701
+ #
1702
+ # ```python sync
1703
+ # first_response = page.wait_for_response("https://example.com/resource")
1704
+ # final_response = page.wait_for_response(lambda response: response.url == "https://example.com" and response.status === 200)
1705
+ # return final_response.ok
1706
+ # ```
1707
+ def expect_response(urlOrPredicate, timeout: nil)
1708
+ wrap_impl(@impl.expect_response(unwrap_impl(urlOrPredicate), timeout: unwrap_impl(timeout)))
1136
1709
  end
1137
1710
 
1138
1711
  # Returns when element specified by selector satisfies `state` option. Returns `null` if waiting for `hidden` or
@@ -1151,18 +1724,53 @@ module Playwright
1151
1724
  # (async () => {
1152
1725
  # const browser = await chromium.launch();
1153
1726
  # const page = await browser.newPage();
1154
- # let currentURL;
1155
- # page
1156
- # .waitForSelector('img')
1157
- # .then(() => console.log('First URL with image: ' + currentURL));
1158
- # for (currentURL of ['https://example.com', 'https://google.com', 'https://bbc.com']) {
1727
+ # for (let currentURL of ['https://google.com', 'https://bbc.com']) {
1159
1728
  # await page.goto(currentURL);
1729
+ # const element = await page.waitForSelector('img');
1730
+ # console.log('Loaded image: ' + await element.getAttribute('src'));
1160
1731
  # }
1161
1732
  # await browser.close();
1162
1733
  # })();
1163
1734
  # ```
1735
+ #
1736
+ # ```python async
1737
+ # import asyncio
1738
+ # from playwright.async_api import async_playwright
1739
+ #
1740
+ # async def run(playwright):
1741
+ # chromium = playwright.chromium
1742
+ # browser = await chromium.launch()
1743
+ # page = await browser.new_page()
1744
+ # for current_url in ["https://google.com", "https://bbc.com"]:
1745
+ # await page.goto(current_url, wait_until="domcontentloaded")
1746
+ # element = await page.wait_for_selector("img")
1747
+ # print("Loaded image: " + str(await element.get_attribute("src")))
1748
+ # await browser.close()
1749
+ #
1750
+ # async def main():
1751
+ # async with async_playwright() as playwright:
1752
+ # await run(playwright)
1753
+ # asyncio.run(main())
1754
+ # ```
1755
+ #
1756
+ # ```python sync
1757
+ # from playwright.sync_api import sync_playwright
1758
+ #
1759
+ # def run(playwright):
1760
+ # chromium = playwright.chromium
1761
+ # browser = chromium.launch()
1762
+ # page = browser.new_page()
1763
+ # for current_url in ["https://google.com", "https://bbc.com"]:
1764
+ # page.goto(current_url, wait_until="domcontentloaded")
1765
+ # element = page.wait_for_selector("img")
1766
+ # print("Loaded image: " + str(element.get_attribute("src")))
1767
+ # browser.close()
1768
+ #
1769
+ # with sync_playwright() as playwright:
1770
+ # run(playwright)
1771
+ # ```
1164
1772
  def wait_for_selector(selector, state: nil, timeout: nil)
1165
- raise NotImplementedError.new('wait_for_selector is not implemented yet.')
1773
+ wrap_impl(@impl.wait_for_selector(unwrap_impl(selector), state: unwrap_impl(state), timeout: unwrap_impl(timeout)))
1166
1774
  end
1167
1775
 
1168
1776
  # Waits for the given `timeout` in milliseconds.
@@ -1176,6 +1784,16 @@ module Playwright
1176
1784
  # await page.waitForTimeout(1000);
1177
1785
  # ```
1178
1786
  #
1787
+ # ```python async
1788
+ # # wait for 1 second
1789
+ # await page.wait_for_timeout(1000)
1790
+ # ```
1791
+ #
1792
+ # ```python sync
1793
+ # # wait for 1 second
1794
+ # page.wait_for_timeout(1000)
1795
+ # ```
1796
+ #
1179
1797
  # Shortcut for main frame's [`method: Frame.waitForTimeout`].
1180
1798
  def wait_for_timeout(timeout)
1181
1799
  raise NotImplementedError.new('wait_for_timeout is not implemented yet.')
@@ -1184,37 +1802,46 @@ module Playwright
1184
1802
  # This method returns all of the dedicated [WebWorkers](https://developer.mozilla.org/en-US/docs/Web/API/Web_Workers_API)
1185
1803
  # associated with the page.
1186
1804
  #
1187
- # > **NOTE** This does not contain ServiceWorkers
1805
+ # > NOTE: This does not contain ServiceWorkers
1188
1806
  def workers
1189
1807
  raise NotImplementedError.new('workers is not implemented yet.')
1190
1808
  end
1191
1809
 
1192
1810
  # @nodoc
1193
- def owned_context=(req)
1194
- wrap_channel_owner(@channel_owner.owned_context=(req))
1811
+ def after_initialize
1812
+ wrap_impl(@impl.after_initialize)
1195
1813
  end
1196
1814
 
1197
1815
  # @nodoc
1198
- def after_initialize
1199
- wrap_channel_owner(@channel_owner.after_initialize)
1816
+ def expect_event(event, optionsOrPredicate: nil, &block)
1817
+ wrap_impl(@impl.expect_event(unwrap_impl(event), optionsOrPredicate: unwrap_impl(optionsOrPredicate), &wrap_block_call(block)))
1200
1818
  end
1201
1819
 
1202
- # -- inherited from EventEmitter --
1203
1820
  # @nodoc
1204
- def off(event, callback)
1205
- wrap_channel_owner(@channel_owner.off(event, callback))
1821
+ def owned_context=(req)
1822
+ wrap_impl(@impl.owned_context=(unwrap_impl(req)))
1206
1823
  end
1207
1824
 
1208
1825
  # -- inherited from EventEmitter --
1209
1826
  # @nodoc
1210
1827
  def once(event, callback)
1211
- wrap_channel_owner(@channel_owner.once(event, callback))
1828
+ event_emitter_proxy.once(event, callback)
1212
1829
  end
1213
1830
 
1214
1831
  # -- inherited from EventEmitter --
1215
1832
  # @nodoc
1216
1833
  def on(event, callback)
1217
- wrap_channel_owner(@channel_owner.on(event, callback))
1834
+ event_emitter_proxy.on(event, callback)
1835
+ end
1836
+
1837
+ # -- inherited from EventEmitter --
1838
+ # @nodoc
1839
+ def off(event, callback)
1840
+ event_emitter_proxy.off(event, callback)
1841
+ end
1842
+
1843
+ private def event_emitter_proxy
1844
+ @event_emitter_proxy ||= EventEmitterProxy.new(self, @impl)
1218
1845
  end
1219
1846
  end
1220
1847
  end