playwright-ruby-client 0.0.3 → 0.0.8

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 +119 -12
  3. data/docs/api_coverage.md +354 -0
  4. data/lib/playwright.rb +8 -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 +22 -29
  9. data/lib/playwright/channel_owners/browser_context.rb +43 -0
  10. data/lib/playwright/channel_owners/console_message.rb +21 -0
  11. data/lib/playwright/channel_owners/element_handle.rb +314 -0
  12. data/lib/playwright/channel_owners/frame.rb +466 -7
  13. data/lib/playwright/channel_owners/js_handle.rb +55 -0
  14. data/lib/playwright/channel_owners/page.rb +353 -5
  15. data/lib/playwright/channel_owners/request.rb +90 -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 +13 -0
  20. data/lib/playwright/input_files.rb +42 -0
  21. data/lib/playwright/input_type.rb +19 -0
  22. data/lib/playwright/input_types/android_input.rb +19 -0
  23. data/lib/playwright/input_types/keyboard.rb +32 -0
  24. data/lib/playwright/input_types/mouse.rb +4 -0
  25. data/lib/playwright/input_types/touchscreen.rb +4 -0
  26. data/lib/playwright/javascript.rb +13 -0
  27. data/lib/playwright/javascript/expression.rb +67 -0
  28. data/lib/playwright/javascript/function.rb +67 -0
  29. data/lib/playwright/javascript/value_parser.rb +75 -0
  30. data/lib/playwright/javascript/value_serializer.rb +54 -0
  31. data/lib/playwright/playwright_api.rb +45 -25
  32. data/lib/playwright/select_option_values.rb +32 -0
  33. data/lib/playwright/timeout_settings.rb +19 -0
  34. data/lib/playwright/url_matcher.rb +19 -0
  35. data/lib/playwright/utils.rb +37 -0
  36. data/lib/playwright/version.rb +1 -1
  37. data/lib/playwright/wait_helper.rb +73 -0
  38. data/lib/playwright_api/accessibility.rb +60 -6
  39. data/lib/playwright_api/android.rb +33 -0
  40. data/lib/playwright_api/android_device.rb +78 -0
  41. data/lib/playwright_api/android_input.rb +25 -0
  42. data/lib/playwright_api/binding_call.rb +18 -0
  43. data/lib/playwright_api/browser.rb +136 -44
  44. data/lib/playwright_api/browser_context.rb +378 -51
  45. data/lib/playwright_api/browser_type.rb +137 -55
  46. data/lib/playwright_api/cdp_session.rb +32 -7
  47. data/lib/playwright_api/chromium_browser_context.rb +31 -0
  48. data/lib/playwright_api/console_message.rb +27 -7
  49. data/lib/playwright_api/dialog.rb +47 -3
  50. data/lib/playwright_api/download.rb +29 -5
  51. data/lib/playwright_api/element_handle.rb +429 -143
  52. data/lib/playwright_api/file_chooser.rb +13 -2
  53. data/lib/playwright_api/frame.rb +633 -179
  54. data/lib/playwright_api/js_handle.rb +97 -17
  55. data/lib/playwright_api/keyboard.rb +152 -24
  56. data/lib/playwright_api/mouse.rb +28 -3
  57. data/lib/playwright_api/page.rb +1183 -317
  58. data/lib/playwright_api/playwright.rb +174 -13
  59. data/lib/playwright_api/request.rb +115 -30
  60. data/lib/playwright_api/response.rb +22 -3
  61. data/lib/playwright_api/route.rb +63 -4
  62. data/lib/playwright_api/selectors.rb +29 -7
  63. data/lib/playwright_api/touchscreen.rb +2 -1
  64. data/lib/playwright_api/video.rb +11 -1
  65. data/lib/playwright_api/web_socket.rb +5 -5
  66. data/lib/playwright_api/worker.rb +29 -5
  67. data/playwright.gemspec +3 -0
  68. metadata +68 -2
@@ -1,35 +1,196 @@
1
1
  module Playwright
2
- # @nodoc
2
+ # Playwright module provides a method to launch a browser instance. The following is a typical example of using Playwright
3
+ # to drive automation:
4
+ #
5
+ #
6
+ # ```js
7
+ # const { chromium, firefox, webkit } = require('playwright');
8
+ #
9
+ # (async () => {
10
+ # const browser = await chromium.launch(); // Or 'firefox' or 'webkit'.
11
+ # const page = await browser.newPage();
12
+ # await page.goto('http://example.com');
13
+ # // other actions...
14
+ # await browser.close();
15
+ # })();
16
+ # ```
17
+ #
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
+ # ```
3
50
  class Playwright < PlaywrightApi
4
51
 
5
- # @nodoc
6
- def android
7
- wrap_channel_owner(@channel_owner.android)
52
+ # This object can be used to launch or connect to Chromium, returning instances of `ChromiumBrowser`.
53
+ def chromium # property
54
+ wrap_impl(@impl.chromium)
55
+ end
56
+
57
+ # Returns a dictionary of devices to be used with [`method: Browser.newContext`] or [`method: Browser.newPage`].
58
+ #
59
+ #
60
+ # ```js
61
+ # const { webkit, devices } = require('playwright');
62
+ # const iPhone = devices['iPhone 6'];
63
+ #
64
+ # (async () => {
65
+ # const browser = await webkit.launch();
66
+ # const context = await browser.newContext({
67
+ # ...iPhone
68
+ # });
69
+ # const page = await context.newPage();
70
+ # await page.goto('http://example.com');
71
+ # // other actions...
72
+ # await browser.close();
73
+ # })();
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
+ # ```
112
+ def devices # property
113
+ wrap_impl(@impl.devices)
114
+ end
115
+
116
+ # Playwright methods might throw errors if they are unable to fulfill a request. For example,
117
+ # [`method: Page.waitForSelector`] might fail if the selector doesn't match any nodes during the given timeframe.
118
+ #
119
+ # For certain types of errors Playwright uses specific error classes. These classes are available via
120
+ # [`playwright.errors`](#playwrighterrors).
121
+ #
122
+ # An example of handling a timeout error:
123
+ #
124
+ #
125
+ # ```js
126
+ # try {
127
+ # await page.waitForSelector('.foo');
128
+ # } catch (e) {
129
+ # if (e instanceof playwright.errors.TimeoutError) {
130
+ # // Do something if this is a timeout.
131
+ # }
132
+ # }
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
+ # ```
148
+ def errors # property
149
+ raise NotImplementedError.new('errors is not implemented yet.')
150
+ end
151
+
152
+ # This object can be used to launch or connect to Firefox, returning instances of `FirefoxBrowser`.
153
+ def firefox # property
154
+ wrap_impl(@impl.firefox)
155
+ end
156
+
157
+ # Selectors can be used to install custom selector engines. See
158
+ # [Working with selectors](./selectors.md#working-with-selectors) for more information.
159
+ def selectors # property
160
+ raise NotImplementedError.new('selectors is not implemented yet.')
161
+ end
162
+
163
+ # This object can be used to launch or connect to WebKit, returning instances of `WebKitBrowser`.
164
+ def webkit # property
165
+ wrap_impl(@impl.webkit)
8
166
  end
9
167
 
10
168
  # @nodoc
11
- def chromium
12
- wrap_channel_owner(@channel_owner.chromium)
169
+ def android
170
+ wrap_impl(@impl.android)
13
171
  end
14
172
 
15
173
  # @nodoc
16
174
  def electron
17
- wrap_channel_owner(@channel_owner.electron)
175
+ wrap_impl(@impl.electron)
18
176
  end
19
177
 
178
+ # -- inherited from EventEmitter --
20
179
  # @nodoc
21
- def firefox
22
- wrap_channel_owner(@channel_owner.firefox)
180
+ def on(event, callback)
181
+ wrap_impl(@impl.on(unwrap_impl(event), unwrap_impl(callback)))
23
182
  end
24
183
 
184
+ # -- inherited from EventEmitter --
25
185
  # @nodoc
26
- def devices
27
- wrap_channel_owner(@channel_owner.devices)
186
+ def off(event, callback)
187
+ wrap_impl(@impl.off(unwrap_impl(event), unwrap_impl(callback)))
28
188
  end
29
189
 
190
+ # -- inherited from EventEmitter --
30
191
  # @nodoc
31
- def webkit
32
- wrap_channel_owner(@channel_owner.webkit)
192
+ def once(event, callback)
193
+ wrap_impl(@impl.once(unwrap_impl(event), unwrap_impl(callback)))
33
194
  end
34
195
  end
35
196
  end
@@ -1,119 +1,204 @@
1
1
  module Playwright
2
- # Whenever the page sends a request for a network resource the following sequence of events are emitted by Page:
2
+ # Whenever the page sends a request for a network resource the following sequence of events are emitted by `Page`:
3
+ # - [`event: Page.request`] emitted when the request is issued by the page.
4
+ # - [`event: Page.response`] emitted when/if the response status and headers are received for the request.
5
+ # - [`event: Page.requestfinished`] emitted when the response body is downloaded and the request is complete.
3
6
  #
4
- # page.on('request') emitted when the request is issued by the page.
5
- # page.on('response') emitted when/if the response status and headers are received for the request.
6
- # page.on('requestfinished') emitted when the response body is downloaded and the request is complete.
7
+ # If request fails at some point, then instead of `'requestfinished'` event (and possibly instead of 'response' event),
8
+ # the [`event: Page.requestfailed`] event is emitted.
7
9
  #
8
- # If request fails at some point, then instead of `'requestfinished'` event (and possibly instead of 'response' event), the page.on('requestfailed') event is emitted.
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.
9
12
  #
10
- # **NOTE** HTTP Error responses, such as 404 or 503, are still successful responses from HTTP standpoint, so request will complete with `'requestfinished'` event.
11
- #
12
- # If request gets a 'redirect' response, the request is successfully finished with the 'requestfinished' event, and a new request is issued to a redirected url.
13
+ # If request gets a 'redirect' response, the request is successfully finished with the 'requestfinished' event, and a new
14
+ # request is issued to a redirected url.
13
15
  class Request < PlaywrightApi
14
16
 
15
17
  # The method returns `null` unless this request has failed, as reported by `requestfailed` event.
18
+ #
16
19
  # Example of logging of all the failed requests:
20
+ #
17
21
  #
18
22
  # ```js
19
23
  # page.on('requestfailed', request => {
20
24
  # console.log(request.url() + ' ' + request.failure().errorText);
21
25
  # });
22
26
  # ```
27
+ #
28
+ # ```py
29
+ # page.on("requestfailed", lambda request: print(request.url + " " + request.failure))
30
+ # ```
23
31
  def failure
24
- raise NotImplementedError.new('failure is not implemented yet.')
32
+ wrap_impl(@impl.failure)
25
33
  end
26
34
 
27
- # Returns the Frame that initiated this request.
35
+ # Returns the `Frame` that initiated this request.
28
36
  def frame
29
- raise NotImplementedError.new('frame is not implemented yet.')
37
+ wrap_impl(@impl.frame)
30
38
  end
31
39
 
32
40
  # An object with HTTP headers associated with the request. All header names are lower-case.
33
41
  def headers
34
- raise NotImplementedError.new('headers is not implemented yet.')
42
+ wrap_impl(@impl.headers)
35
43
  end
36
44
 
37
45
  # Whether this request is driving frame's navigation.
38
46
  def navigation_request?
39
- raise NotImplementedError.new('navigation_request? is not implemented yet.')
47
+ wrap_impl(@impl.navigation_request?)
40
48
  end
41
49
 
42
50
  # Request's method (GET, POST, etc.)
43
51
  def method
44
- wrap_channel_owner(@channel_owner.method)
52
+ wrap_impl(@impl.method)
45
53
  end
46
54
 
47
55
  # Request's post body, if any.
48
56
  def post_data
49
- raise NotImplementedError.new('post_data is not implemented yet.')
57
+ wrap_impl(@impl.post_data)
50
58
  end
51
59
 
52
60
  # Request's post body in a binary form, if any.
53
61
  def post_data_buffer
54
- raise NotImplementedError.new('post_data_buffer is not implemented yet.')
62
+ wrap_impl(@impl.post_data_buffer)
55
63
  end
56
64
 
57
65
  # Returns parsed request's body for `form-urlencoded` and JSON as a fallback if any.
58
- # When the response is `application/x-www-form-urlencoded` then a key/value object of the values will be returned. Otherwise it will be parsed as JSON.
66
+ #
67
+ # When the response is `application/x-www-form-urlencoded` then a key/value object of the values will be returned.
68
+ # Otherwise it will be parsed as JSON.
59
69
  def post_data_json
60
- raise NotImplementedError.new('post_data_json is not implemented yet.')
70
+ wrap_impl(@impl.post_data_json)
61
71
  end
62
72
 
63
73
  # Request that was redirected by the server to this one, if any.
64
- # When the server responds with a redirect, Playwright creates a new Request object. The two requests are connected by `redirectedFrom()` and `redirectedTo()` methods. When multiple server redirects has happened, it is possible to construct the whole redirect chain by repeatedly calling `redirectedFrom()`.
74
+ #
75
+ # When the server responds with a redirect, Playwright creates a new `Request` object. The two requests are connected by
76
+ # `redirectedFrom()` and `redirectedTo()` methods. When multiple server redirects has happened, it is possible to
77
+ # construct the whole redirect chain by repeatedly calling `redirectedFrom()`.
78
+ #
65
79
  # For example, if the website `http://example.com` redirects to `https://example.com`:
80
+ #
66
81
  #
67
82
  # ```js
68
83
  # const response = await page.goto('http://example.com');
69
84
  # console.log(response.request().redirectedFrom().url()); // 'http://example.com'
70
85
  # ```
86
+ #
87
+ # ```python async
88
+ # response = await page.goto("http://example.com")
89
+ # print(response.request.redirected_from.url) # "http://example.com"
90
+ # ```
91
+ #
92
+ # ```python sync
93
+ # response = page.goto("http://example.com")
94
+ # print(response.request.redirected_from.url) # "http://example.com"
95
+ # ```
96
+ #
71
97
  # If the website `https://google.com` has no redirects:
98
+ #
72
99
  #
73
100
  # ```js
74
101
  # const response = await page.goto('https://google.com');
75
102
  # console.log(response.request().redirectedFrom()); // null
76
103
  # ```
104
+ #
105
+ # ```python async
106
+ # response = await page.goto("https://google.com")
107
+ # print(response.request.redirected_from) # None
108
+ # ```
109
+ #
110
+ # ```python sync
111
+ # response = page.goto("https://google.com")
112
+ # print(response.request.redirected_from) # None
113
+ # ```
77
114
  def redirected_from
78
- raise NotImplementedError.new('redirected_from is not implemented yet.')
115
+ wrap_impl(@impl.redirected_from)
79
116
  end
80
117
 
81
118
  # New request issued by the browser if the server responded with redirect.
82
- # This method is the opposite of `request.redirectedFrom()`:
119
+ #
120
+ # This method is the opposite of [`method: Request.redirectedFrom`]:
121
+ #
83
122
  #
84
123
  # ```js
85
124
  # console.log(request.redirectedFrom().redirectedTo() === request); // true
86
125
  # ```
126
+ #
127
+ # ```py
128
+ # assert request.redirected_from.redirected_to == request
129
+ # ```
87
130
  def redirected_to
88
- raise NotImplementedError.new('redirected_to is not implemented yet.')
131
+ wrap_impl(@impl.redirected_to)
89
132
  end
90
133
 
91
- # Contains the request's resource type as it was perceived by the rendering engine. ResourceType will be one of the following: `document`, `stylesheet`, `image`, `media`, `font`, `script`, `texttrack`, `xhr`, `fetch`, `eventsource`, `websocket`, `manifest`, `other`.
134
+ # Contains the request's resource type as it was perceived by the rendering engine. ResourceType will be one of the
135
+ # following: `document`, `stylesheet`, `image`, `media`, `font`, `script`, `texttrack`, `xhr`, `fetch`, `eventsource`,
136
+ # `websocket`, `manifest`, `other`.
92
137
  def resource_type
93
- raise NotImplementedError.new('resource_type is not implemented yet.')
138
+ wrap_impl(@impl.resource_type)
94
139
  end
95
140
 
96
- # Returns the matching Response object, or `null` if the response was not received due to error.
141
+ # Returns the matching `Response` object, or `null` if the response was not received due to error.
97
142
  def response
98
- raise NotImplementedError.new('response is not implemented yet.')
143
+ wrap_impl(@impl.response)
99
144
  end
100
145
 
101
- # Returns resource timing information for given request. Most of the timing values become available upon the response, `responseEnd` becomes available when request finishes. Find more information at Resource Timing API.
146
+ # Returns resource timing information for given request. Most of the timing values become available upon the response,
147
+ # `responseEnd` becomes available when request finishes. Find more information at
148
+ # [Resource Timing API](https://developer.mozilla.org/en-US/docs/Web/API/PerformanceResourceTiming).
149
+ #
102
150
  #
103
151
  # ```js
104
152
  # const [request] = await Promise.all([
105
153
  # page.waitForEvent('requestfinished'),
106
- # page.goto(httpsServer.EMPTY_PAGE)
154
+ # page.goto('http://example.com')
107
155
  # ]);
108
156
  # console.log(request.timing());
109
157
  # ```
158
+ #
159
+ # ```python async
160
+ # async with page.expect_event("requestfinished") as request_info:
161
+ # await page.goto("http://example.com")
162
+ # request = await request_info.value
163
+ # print(request.timing)
164
+ # ```
165
+ #
166
+ # ```python sync
167
+ # with page.expect_event("requestfinished") as request_info:
168
+ # page.goto("http://example.com")
169
+ # request = request_info.value
170
+ # print(request.timing)
171
+ # ```
110
172
  def timing
111
- raise NotImplementedError.new('timing is not implemented yet.')
173
+ wrap_impl(@impl.timing)
112
174
  end
113
175
 
114
176
  # URL of the request.
115
177
  def url
116
- raise NotImplementedError.new('url is not implemented yet.')
178
+ wrap_impl(@impl.url)
179
+ end
180
+
181
+ # @nodoc
182
+ def after_initialize
183
+ wrap_impl(@impl.after_initialize)
184
+ end
185
+
186
+ # -- inherited from EventEmitter --
187
+ # @nodoc
188
+ def on(event, callback)
189
+ wrap_impl(@impl.on(unwrap_impl(event), unwrap_impl(callback)))
190
+ end
191
+
192
+ # -- inherited from EventEmitter --
193
+ # @nodoc
194
+ def off(event, callback)
195
+ wrap_impl(@impl.off(unwrap_impl(event), unwrap_impl(callback)))
196
+ end
197
+
198
+ # -- inherited from EventEmitter --
199
+ # @nodoc
200
+ def once(event, callback)
201
+ wrap_impl(@impl.once(unwrap_impl(event), unwrap_impl(callback)))
117
202
  end
118
203
  end
119
204
  end
@@ -1,5 +1,5 @@
1
1
  module Playwright
2
- # Response class represents responses which are received by page.
2
+ # `Response` class represents responses which are received by page.
3
3
  class Response < PlaywrightApi
4
4
 
5
5
  # Returns the buffer with response body.
@@ -12,7 +12,7 @@ module Playwright
12
12
  raise NotImplementedError.new('finished is not implemented yet.')
13
13
  end
14
14
 
15
- # Returns the Frame that initiated this response.
15
+ # Returns the `Frame` that initiated this response.
16
16
  def frame
17
17
  raise NotImplementedError.new('frame is not implemented yet.')
18
18
  end
@@ -23,6 +23,7 @@ module Playwright
23
23
  end
24
24
 
25
25
  # Returns the JSON representation of response body.
26
+ #
26
27
  # This method will throw if the response body is not parsable via `JSON.parse`.
27
28
  def json
28
29
  raise NotImplementedError.new('json is not implemented yet.')
@@ -33,7 +34,7 @@ module Playwright
33
34
  raise NotImplementedError.new('ok is not implemented yet.')
34
35
  end
35
36
 
36
- # Returns the matching Request object.
37
+ # Returns the matching `Request` object.
37
38
  def request
38
39
  raise NotImplementedError.new('request is not implemented yet.')
39
40
  end
@@ -57,5 +58,23 @@ module Playwright
57
58
  def url
58
59
  raise NotImplementedError.new('url is not implemented yet.')
59
60
  end
61
+
62
+ # -- inherited from EventEmitter --
63
+ # @nodoc
64
+ def on(event, callback)
65
+ wrap_impl(@impl.on(unwrap_impl(event), unwrap_impl(callback)))
66
+ end
67
+
68
+ # -- inherited from EventEmitter --
69
+ # @nodoc
70
+ def off(event, callback)
71
+ wrap_impl(@impl.off(unwrap_impl(event), unwrap_impl(callback)))
72
+ end
73
+
74
+ # -- inherited from EventEmitter --
75
+ # @nodoc
76
+ def once(event, callback)
77
+ wrap_impl(@impl.once(unwrap_impl(event), unwrap_impl(callback)))
78
+ end
60
79
  end
61
80
  end