playwright-ruby-client 0.0.4 → 0.0.9

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