playwright-ruby-client 0.0.5 → 0.1.0

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