playwright-ruby-client 0.0.4 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +120 -6
  3. data/docs/api_coverage.md +351 -0
  4. data/lib/playwright.rb +9 -0
  5. data/lib/playwright/channel_owner.rb +16 -2
  6. data/lib/playwright/channel_owners/android.rb +10 -1
  7. data/lib/playwright/channel_owners/android_device.rb +163 -0
  8. data/lib/playwright/channel_owners/browser.rb +20 -27
  9. data/lib/playwright/channel_owners/browser_context.rb +51 -0
  10. data/lib/playwright/channel_owners/console_message.rb +0 -4
  11. data/lib/playwright/channel_owners/element_handle.rb +306 -0
  12. data/lib/playwright/channel_owners/frame.rb +473 -7
  13. data/lib/playwright/channel_owners/js_handle.rb +51 -0
  14. data/lib/playwright/channel_owners/page.rb +589 -4
  15. data/lib/playwright/channel_owners/request.rb +98 -0
  16. data/lib/playwright/channel_owners/webkit_browser.rb +1 -1
  17. data/lib/playwright/connection.rb +15 -14
  18. data/lib/playwright/errors.rb +1 -1
  19. data/lib/playwright/event_emitter.rb +17 -1
  20. data/lib/playwright/http_headers.rb +20 -0
  21. data/lib/playwright/input_files.rb +42 -0
  22. data/lib/playwright/input_type.rb +19 -0
  23. data/lib/playwright/input_types/android_input.rb +19 -0
  24. data/lib/playwright/input_types/keyboard.rb +32 -0
  25. data/lib/playwright/input_types/mouse.rb +4 -0
  26. data/lib/playwright/input_types/touchscreen.rb +4 -0
  27. data/lib/playwright/javascript.rb +13 -0
  28. data/lib/playwright/javascript/expression.rb +67 -0
  29. data/lib/playwright/javascript/function.rb +67 -0
  30. data/lib/playwright/javascript/value_parser.rb +75 -0
  31. data/lib/playwright/javascript/value_serializer.rb +54 -0
  32. data/lib/playwright/playwright_api.rb +45 -25
  33. data/lib/playwright/select_option_values.rb +32 -0
  34. data/lib/playwright/timeout_settings.rb +19 -0
  35. data/lib/playwright/url_matcher.rb +19 -0
  36. data/lib/playwright/utils.rb +37 -0
  37. data/lib/playwright/version.rb +1 -1
  38. data/lib/playwright/wait_helper.rb +73 -0
  39. data/lib/playwright_api/accessibility.rb +46 -6
  40. data/lib/playwright_api/android.rb +33 -0
  41. data/lib/playwright_api/android_device.rb +78 -0
  42. data/lib/playwright_api/android_input.rb +25 -0
  43. data/lib/playwright_api/binding_call.rb +18 -0
  44. data/lib/playwright_api/browser.rb +93 -12
  45. data/lib/playwright_api/browser_context.rb +279 -28
  46. data/lib/playwright_api/browser_type.rb +68 -5
  47. data/lib/playwright_api/cdp_session.rb +23 -1
  48. data/lib/playwright_api/chromium_browser_context.rb +26 -0
  49. data/lib/playwright_api/console_message.rb +20 -7
  50. data/lib/playwright_api/dialog.rb +48 -2
  51. data/lib/playwright_api/download.rb +19 -4
  52. data/lib/playwright_api/element_handle.rb +278 -104
  53. data/lib/playwright_api/file_chooser.rb +20 -3
  54. data/lib/playwright_api/frame.rb +452 -147
  55. data/lib/playwright_api/js_handle.rb +78 -19
  56. data/lib/playwright_api/keyboard.rb +99 -9
  57. data/lib/playwright_api/mouse.rb +22 -0
  58. data/lib/playwright_api/page.rb +864 -222
  59. data/lib/playwright_api/playwright.rb +116 -14
  60. data/lib/playwright_api/request.rb +86 -24
  61. data/lib/playwright_api/response.rb +18 -7
  62. data/lib/playwright_api/route.rb +49 -0
  63. data/lib/playwright_api/selectors.rb +28 -2
  64. data/lib/playwright_api/video.rb +8 -0
  65. data/lib/playwright_api/web_socket.rb +0 -8
  66. data/lib/playwright_api/worker.rb +25 -13
  67. data/playwright.gemspec +3 -0
  68. metadata +66 -2
@@ -15,18 +15,46 @@ module Playwright
15
15
  # })();
16
16
  # ```
17
17
  #
18
- # By default, the `playwright` NPM package automatically downloads browser executables during installation. The
19
- # `playwright-core` NPM package can be used to skip automatic downloads.
18
+ # ```python async
19
+ # import asyncio
20
+ # from playwright.async_api import async_playwright
21
+ #
22
+ # async def run(playwright):
23
+ # chromium = playwright.chromium # or "firefox" or "webkit".
24
+ # browser = await chromium.launch()
25
+ # page = await browser.new_page()
26
+ # await page.goto("http://example.com")
27
+ # # other actions...
28
+ # await browser.close()
29
+ #
30
+ # async def main():
31
+ # async with async_playwright() as playwright:
32
+ # await run(playwright)
33
+ # asyncio.run(main())
34
+ # ```
35
+ #
36
+ # ```python sync
37
+ # from playwright.sync_api import sync_playwright
38
+ #
39
+ # def run(playwright):
40
+ # chromium = playwright.chromium # or "firefox" or "webkit".
41
+ # browser = chromium.launch()
42
+ # page = browser.new_page()
43
+ # page.goto("http://example.com")
44
+ # # other actions...
45
+ # browser.close()
46
+ #
47
+ # with sync_playwright() as playwright:
48
+ # run(playwright)
49
+ # ```
20
50
  class Playwright < PlaywrightApi
21
51
 
22
52
  # This object can be used to launch or connect to Chromium, returning instances of `ChromiumBrowser`.
23
53
  def chromium # property
24
- wrap_channel_owner(@channel_owner.chromium)
54
+ wrap_impl(@impl.chromium)
25
55
  end
26
56
 
27
- # Returns a list of devices to be used with [`method: Browser.newContext`] or [`method: Browser.newPage`]. Actual list of
28
- # devices can be found in
29
- # [src/server/deviceDescriptors.ts](https://github.com/Microsoft/playwright/blob/master/src/server/deviceDescriptors.ts).
57
+ # Returns a dictionary of devices to be used with [`method: Browser.newContext`] or [`method: Browser.newPage`].
30
58
  #
31
59
  #
32
60
  # ```js
@@ -44,8 +72,45 @@ module Playwright
44
72
  # await browser.close();
45
73
  # })();
46
74
  # ```
75
+ #
76
+ # ```python async
77
+ # import asyncio
78
+ # from playwright.async_api import async_playwright
79
+ #
80
+ # async def run(playwright):
81
+ # webkit = playwright.webkit
82
+ # iphone = playwright.devices["iPhone 6"]
83
+ # browser = await webkit.launch()
84
+ # context = await browser.new_context(**iphone)
85
+ # page = await context.new_page()
86
+ # await page.goto("http://example.com")
87
+ # # other actions...
88
+ # await browser.close()
89
+ #
90
+ # async def main():
91
+ # async with async_playwright() as playwright:
92
+ # await run(playwright)
93
+ # asyncio.run(main())
94
+ # ```
95
+ #
96
+ # ```python sync
97
+ # from playwright.sync_api import sync_playwright
98
+ #
99
+ # def run(playwright):
100
+ # webkit = playwright.webkit
101
+ # iphone = playwright.devices["iPhone 6"]
102
+ # browser = webkit.launch()
103
+ # context = browser.new_context(**iphone)
104
+ # page = context.new_page()
105
+ # page.goto("http://example.com")
106
+ # # other actions...
107
+ # browser.close()
108
+ #
109
+ # with sync_playwright() as playwright:
110
+ # run(playwright)
111
+ # ```
47
112
  def devices # property
48
- wrap_channel_owner(@channel_owner.devices)
113
+ wrap_impl(@impl.devices)
49
114
  end
50
115
 
51
116
  # Playwright methods might throw errors if they are unable to fulfill a request. For example,
@@ -66,34 +131,71 @@ module Playwright
66
131
  # }
67
132
  # }
68
133
  # ```
134
+ #
135
+ # ```python async
136
+ # try:
137
+ # await page.wait_for_selector(".foo")
138
+ # except TimeoutError as e:
139
+ # # do something if this is a timeout.
140
+ # ```
141
+ #
142
+ # ```python sync
143
+ # try:
144
+ # page.wait_for_selector(".foo")
145
+ # except TimeoutError as e:
146
+ # # do something if this is a timeout.
147
+ # ```
69
148
  def errors # property
70
149
  raise NotImplementedError.new('errors is not implemented yet.')
71
150
  end
72
151
 
73
152
  # This object can be used to launch or connect to Firefox, returning instances of `FirefoxBrowser`.
74
153
  def firefox # property
75
- wrap_channel_owner(@channel_owner.firefox)
154
+ wrap_impl(@impl.firefox)
76
155
  end
77
156
 
78
- # Selectors can be used to install custom selector engines. See
79
- # [Working with selectors](./selectors.md#working-with-selectors) for more information.
157
+ # Selectors can be used to install custom selector engines. See [Working with selectors](./selectors.md) for more
158
+ # information.
80
159
  def selectors # property
81
160
  raise NotImplementedError.new('selectors is not implemented yet.')
82
161
  end
83
162
 
84
163
  # This object can be used to launch or connect to WebKit, returning instances of `WebKitBrowser`.
85
164
  def webkit # property
86
- wrap_channel_owner(@channel_owner.webkit)
165
+ wrap_impl(@impl.webkit)
166
+ end
167
+
168
+ # Terminates this instance of Playwright, will also close all created browsers if they are still running.
169
+ def close
170
+ raise NotImplementedError.new('close is not implemented yet.')
171
+ end
172
+
173
+ # @nodoc
174
+ def electron
175
+ wrap_impl(@impl.electron)
87
176
  end
88
177
 
89
178
  # @nodoc
90
179
  def android
91
- wrap_channel_owner(@channel_owner.android)
180
+ wrap_impl(@impl.android)
92
181
  end
93
182
 
183
+ # -- inherited from EventEmitter --
94
184
  # @nodoc
95
- def electron
96
- wrap_channel_owner(@channel_owner.electron)
185
+ def on(event, callback)
186
+ wrap_impl(@impl.on(unwrap_impl(event), unwrap_impl(callback)))
187
+ end
188
+
189
+ # -- inherited from EventEmitter --
190
+ # @nodoc
191
+ def off(event, callback)
192
+ wrap_impl(@impl.off(unwrap_impl(event), unwrap_impl(callback)))
193
+ end
194
+
195
+ # -- inherited from EventEmitter --
196
+ # @nodoc
197
+ def once(event, callback)
198
+ wrap_impl(@impl.once(unwrap_impl(event), unwrap_impl(callback)))
97
199
  end
98
200
  end
99
201
  end
@@ -7,8 +7,8 @@ module Playwright
7
7
  # If request fails at some point, then instead of `'requestfinished'` event (and possibly instead of 'response' event),
8
8
  # the [`event: Page.requestfailed`] event is emitted.
9
9
  #
10
- # > **NOTE** HTTP Error responses, such as 404 or 503, are still successful responses from HTTP standpoint, so request
11
- # will complete with `'requestfinished'` event.
10
+ # > NOTE: HTTP Error responses, such as 404 or 503, are still successful responses from HTTP standpoint, so request will
11
+ # complete with `'requestfinished'` event.
12
12
  #
13
13
  # If request gets a 'redirect' response, the request is successfully finished with the 'requestfinished' event, and a new
14
14
  # request is issued to a redirected url.
@@ -24,46 +24,42 @@ module Playwright
24
24
  # console.log(request.url() + ' ' + request.failure().errorText);
25
25
  # });
26
26
  # ```
27
+ #
28
+ # ```py
29
+ # page.on("requestfailed", lambda request: print(request.url + " " + request.failure))
30
+ # ```
27
31
  def failure
28
- raise NotImplementedError.new('failure is not implemented yet.')
32
+ wrap_impl(@impl.failure)
29
33
  end
30
34
 
31
35
  # Returns the `Frame` that initiated this request.
32
36
  def frame
33
- raise NotImplementedError.new('frame is not implemented yet.')
37
+ wrap_impl(@impl.frame)
34
38
  end
35
39
 
36
40
  # An object with HTTP headers associated with the request. All header names are lower-case.
37
41
  def headers
38
- raise NotImplementedError.new('headers is not implemented yet.')
42
+ wrap_impl(@impl.headers)
39
43
  end
40
44
 
41
45
  # Whether this request is driving frame's navigation.
42
46
  def navigation_request?
43
- raise NotImplementedError.new('navigation_request? is not implemented yet.')
47
+ wrap_impl(@impl.navigation_request?)
44
48
  end
45
49
 
46
50
  # Request's method (GET, POST, etc.)
47
51
  def method
48
- wrap_channel_owner(@channel_owner.method)
52
+ wrap_impl(@impl.method)
49
53
  end
50
54
 
51
55
  # Request's post body, if any.
52
56
  def post_data
53
- raise NotImplementedError.new('post_data is not implemented yet.')
57
+ wrap_impl(@impl.post_data)
54
58
  end
55
59
 
56
60
  # Request's post body in a binary form, if any.
57
61
  def post_data_buffer
58
- raise NotImplementedError.new('post_data_buffer is not implemented yet.')
59
- end
60
-
61
- # Returns parsed request's body for `form-urlencoded` and JSON as a fallback if any.
62
- #
63
- # When the response is `application/x-www-form-urlencoded` then a key/value object of the values will be returned.
64
- # Otherwise it will be parsed as JSON.
65
- def post_data_json
66
- raise NotImplementedError.new('post_data_json is not implemented yet.')
62
+ wrap_impl(@impl.post_data_buffer)
67
63
  end
68
64
 
69
65
  # Request that was redirected by the server to this one, if any.
@@ -80,6 +76,16 @@ module Playwright
80
76
  # console.log(response.request().redirectedFrom().url()); // 'http://example.com'
81
77
  # ```
82
78
  #
79
+ # ```python async
80
+ # response = await page.goto("http://example.com")
81
+ # print(response.request.redirected_from.url) # "http://example.com"
82
+ # ```
83
+ #
84
+ # ```python sync
85
+ # response = page.goto("http://example.com")
86
+ # print(response.request.redirected_from.url) # "http://example.com"
87
+ # ```
88
+ #
83
89
  # If the website `https://google.com` has no redirects:
84
90
  #
85
91
  #
@@ -87,8 +93,18 @@ module Playwright
87
93
  # const response = await page.goto('https://google.com');
88
94
  # console.log(response.request().redirectedFrom()); // null
89
95
  # ```
96
+ #
97
+ # ```python async
98
+ # response = await page.goto("https://google.com")
99
+ # print(response.request.redirected_from) # None
100
+ # ```
101
+ #
102
+ # ```python sync
103
+ # response = page.goto("https://google.com")
104
+ # print(response.request.redirected_from) # None
105
+ # ```
90
106
  def redirected_from
91
- raise NotImplementedError.new('redirected_from is not implemented yet.')
107
+ wrap_impl(@impl.redirected_from)
92
108
  end
93
109
 
94
110
  # New request issued by the browser if the server responded with redirect.
@@ -99,20 +115,24 @@ module Playwright
99
115
  # ```js
100
116
  # console.log(request.redirectedFrom().redirectedTo() === request); // true
101
117
  # ```
118
+ #
119
+ # ```py
120
+ # assert request.redirected_from.redirected_to == request
121
+ # ```
102
122
  def redirected_to
103
- raise NotImplementedError.new('redirected_to is not implemented yet.')
123
+ wrap_impl(@impl.redirected_to)
104
124
  end
105
125
 
106
126
  # Contains the request's resource type as it was perceived by the rendering engine. ResourceType will be one of the
107
127
  # following: `document`, `stylesheet`, `image`, `media`, `font`, `script`, `texttrack`, `xhr`, `fetch`, `eventsource`,
108
128
  # `websocket`, `manifest`, `other`.
109
129
  def resource_type
110
- raise NotImplementedError.new('resource_type is not implemented yet.')
130
+ wrap_impl(@impl.resource_type)
111
131
  end
112
132
 
113
133
  # Returns the matching `Response` object, or `null` if the response was not received due to error.
114
134
  def response
115
- raise NotImplementedError.new('response is not implemented yet.')
135
+ wrap_impl(@impl.response)
116
136
  end
117
137
 
118
138
  # Returns resource timing information for given request. Most of the timing values become available upon the response,
@@ -123,17 +143,59 @@ module Playwright
123
143
  # ```js
124
144
  # const [request] = await Promise.all([
125
145
  # page.waitForEvent('requestfinished'),
126
- # page.goto(httpsServer.EMPTY_PAGE)
146
+ # page.goto('http://example.com')
127
147
  # ]);
128
148
  # console.log(request.timing());
129
149
  # ```
150
+ #
151
+ # ```python async
152
+ # async with page.expect_event("requestfinished") as request_info:
153
+ # await page.goto("http://example.com")
154
+ # request = await request_info.value
155
+ # print(request.timing)
156
+ # ```
157
+ #
158
+ # ```python sync
159
+ # with page.expect_event("requestfinished") as request_info:
160
+ # page.goto("http://example.com")
161
+ # request = request_info.value
162
+ # print(request.timing)
163
+ # ```
130
164
  def timing
131
- raise NotImplementedError.new('timing is not implemented yet.')
165
+ wrap_impl(@impl.timing)
132
166
  end
133
167
 
134
168
  # URL of the request.
135
169
  def url
136
- raise NotImplementedError.new('url is not implemented yet.')
170
+ wrap_impl(@impl.url)
171
+ end
172
+
173
+ # @nodoc
174
+ def after_initialize
175
+ wrap_impl(@impl.after_initialize)
176
+ end
177
+
178
+ # @nodoc
179
+ def post_data_json
180
+ wrap_impl(@impl.post_data_json)
181
+ end
182
+
183
+ # -- inherited from EventEmitter --
184
+ # @nodoc
185
+ def on(event, callback)
186
+ wrap_impl(@impl.on(unwrap_impl(event), unwrap_impl(callback)))
187
+ end
188
+
189
+ # -- inherited from EventEmitter --
190
+ # @nodoc
191
+ def off(event, callback)
192
+ wrap_impl(@impl.off(unwrap_impl(event), unwrap_impl(callback)))
193
+ end
194
+
195
+ # -- inherited from EventEmitter --
196
+ # @nodoc
197
+ def once(event, callback)
198
+ wrap_impl(@impl.once(unwrap_impl(event), unwrap_impl(callback)))
137
199
  end
138
200
  end
139
201
  end
@@ -22,13 +22,6 @@ module Playwright
22
22
  raise NotImplementedError.new('headers is not implemented yet.')
23
23
  end
24
24
 
25
- # Returns the JSON representation of response body.
26
- #
27
- # This method will throw if the response body is not parsable via `JSON.parse`.
28
- def json
29
- raise NotImplementedError.new('json is not implemented yet.')
30
- end
31
-
32
25
  # Contains a boolean stating whether the response was successful (status in the range 200-299) or not.
33
26
  def ok
34
27
  raise NotImplementedError.new('ok is not implemented yet.')
@@ -58,5 +51,23 @@ module Playwright
58
51
  def url
59
52
  raise NotImplementedError.new('url is not implemented yet.')
60
53
  end
54
+
55
+ # -- inherited from EventEmitter --
56
+ # @nodoc
57
+ def on(event, callback)
58
+ wrap_impl(@impl.on(unwrap_impl(event), unwrap_impl(callback)))
59
+ end
60
+
61
+ # -- inherited from EventEmitter --
62
+ # @nodoc
63
+ def off(event, callback)
64
+ wrap_impl(@impl.off(unwrap_impl(event), unwrap_impl(callback)))
65
+ end
66
+
67
+ # -- inherited from EventEmitter --
68
+ # @nodoc
69
+ def once(event, callback)
70
+ wrap_impl(@impl.once(unwrap_impl(event), unwrap_impl(callback)))
71
+ end
61
72
  end
62
73
  end
@@ -22,6 +22,32 @@ module Playwright
22
22
  # route.continue({headers});
23
23
  # });
24
24
  # ```
25
+ #
26
+ # ```python async
27
+ # async def handle(route, request):
28
+ # # override headers
29
+ # headers = {
30
+ # **request.headers,
31
+ # "foo": "bar" # set "foo" header
32
+ # "origin": None # remove "origin" header
33
+ # }
34
+ # await route.continue(headers=headers)
35
+ # }
36
+ # await page.route("**/*", handle)
37
+ # ```
38
+ #
39
+ # ```python sync
40
+ # def handle(route, request):
41
+ # # override headers
42
+ # headers = {
43
+ # **request.headers,
44
+ # "foo": "bar" # set "foo" header
45
+ # "origin": None # remove "origin" header
46
+ # }
47
+ # route.continue(headers=headers)
48
+ # }
49
+ # page.route("**/*", handle)
50
+ # ```
25
51
  def continue_(headers: nil, method: nil, postData: nil, url: nil)
26
52
  raise NotImplementedError.new('continue_ is not implemented yet.')
27
53
  end
@@ -41,14 +67,37 @@ module Playwright
41
67
  # });
42
68
  # ```
43
69
  #
70
+ # ```python async
71
+ # await page.route("**/*", lambda route: route.fulfill(
72
+ # status=404,
73
+ # content_type="text/plain",
74
+ # body="not found!"))
75
+ # ```
76
+ #
77
+ # ```python sync
78
+ # page.route("**/*", lambda route: route.fulfill(
79
+ # status=404,
80
+ # content_type="text/plain",
81
+ # body="not found!"))
82
+ # ```
83
+ #
44
84
  # An example of serving static file:
45
85
  #
46
86
  #
47
87
  # ```js
48
88
  # await page.route('**/xhr_endpoint', route => route.fulfill({ path: 'mock_data.json' }));
49
89
  # ```
90
+ #
91
+ # ```python async
92
+ # await page.route("**/xhr_endpoint", lambda route: route.fulfill(path="mock_data.json"))
93
+ # ```
94
+ #
95
+ # ```python sync
96
+ # page.route("**/xhr_endpoint", lambda route: route.fulfill(path="mock_data.json"))
97
+ # ```
50
98
  def fulfill(
51
99
  body: nil,
100
+ bodyBytes: nil,
52
101
  contentType: nil,
53
102
  headers: nil,
54
103
  path: nil,