playwright-ruby-client 0.1.0 → 0.5.3

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 (75) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +20 -8
  3. data/docs/api_coverage.md +123 -73
  4. data/lib/playwright.rb +48 -9
  5. data/lib/playwright/channel.rb +12 -2
  6. data/lib/playwright/channel_owner.rb +3 -5
  7. data/lib/playwright/channel_owners/android.rb +1 -1
  8. data/lib/playwright/channel_owners/android_device.rb +11 -11
  9. data/lib/playwright/channel_owners/artifact.rb +30 -0
  10. data/lib/playwright/channel_owners/binding_call.rb +3 -0
  11. data/lib/playwright/channel_owners/browser.rb +22 -1
  12. data/lib/playwright/channel_owners/browser_context.rb +155 -4
  13. data/lib/playwright/channel_owners/browser_type.rb +28 -0
  14. data/lib/playwright/channel_owners/dialog.rb +28 -0
  15. data/lib/playwright/channel_owners/element_handle.rb +18 -5
  16. data/lib/playwright/channel_owners/frame.rb +40 -5
  17. data/lib/playwright/channel_owners/js_handle.rb +3 -3
  18. data/lib/playwright/channel_owners/page.rb +172 -51
  19. data/lib/playwright/channel_owners/playwright.rb +24 -27
  20. data/lib/playwright/channel_owners/request.rb +27 -3
  21. data/lib/playwright/channel_owners/response.rb +60 -0
  22. data/lib/playwright/channel_owners/route.rb +78 -0
  23. data/lib/playwright/channel_owners/selectors.rb +19 -1
  24. data/lib/playwright/channel_owners/stream.rb +15 -0
  25. data/lib/playwright/connection.rb +11 -32
  26. data/lib/playwright/download.rb +27 -0
  27. data/lib/playwright/errors.rb +6 -0
  28. data/lib/playwright/events.rb +2 -5
  29. data/lib/playwright/keyboard_impl.rb +1 -1
  30. data/lib/playwright/mouse_impl.rb +41 -0
  31. data/lib/playwright/playwright_api.rb +3 -1
  32. data/lib/playwright/route_handler_entry.rb +28 -0
  33. data/lib/playwright/select_option_values.rb +14 -4
  34. data/lib/playwright/transport.rb +28 -7
  35. data/lib/playwright/url_matcher.rb +1 -1
  36. data/lib/playwright/utils.rb +11 -2
  37. data/lib/playwright/version.rb +1 -1
  38. data/lib/playwright/video.rb +51 -0
  39. data/lib/playwright/wait_helper.rb +2 -2
  40. data/lib/playwright_api/accessibility.rb +39 -1
  41. data/lib/playwright_api/android.rb +72 -5
  42. data/lib/playwright_api/android_device.rb +139 -26
  43. data/lib/playwright_api/android_input.rb +17 -13
  44. data/lib/playwright_api/android_socket.rb +16 -0
  45. data/lib/playwright_api/android_web_view.rb +21 -0
  46. data/lib/playwright_api/browser.rb +87 -19
  47. data/lib/playwright_api/browser_context.rb +216 -32
  48. data/lib/playwright_api/browser_type.rb +45 -58
  49. data/lib/playwright_api/dialog.rb +54 -7
  50. data/lib/playwright_api/element_handle.rb +113 -33
  51. data/lib/playwright_api/file_chooser.rb +6 -1
  52. data/lib/playwright_api/frame.rb +238 -43
  53. data/lib/playwright_api/js_handle.rb +20 -2
  54. data/lib/playwright_api/keyboard.rb +48 -1
  55. data/lib/playwright_api/mouse.rb +26 -5
  56. data/lib/playwright_api/page.rb +534 -63
  57. data/lib/playwright_api/playwright.rb +43 -47
  58. data/lib/playwright_api/request.rb +38 -12
  59. data/lib/playwright_api/response.rb +27 -10
  60. data/lib/playwright_api/route.rb +51 -6
  61. data/lib/playwright_api/selectors.rb +28 -2
  62. data/lib/playwright_api/touchscreen.rb +1 -1
  63. data/lib/playwright_api/web_socket.rb +15 -0
  64. data/lib/playwright_api/worker.rb +25 -1
  65. data/playwright.gemspec +4 -2
  66. metadata +42 -14
  67. data/lib/playwright/channel_owners/chromium_browser.rb +0 -8
  68. data/lib/playwright/channel_owners/chromium_browser_context.rb +0 -8
  69. data/lib/playwright/channel_owners/download.rb +0 -27
  70. data/lib/playwright/channel_owners/firefox_browser.rb +0 -8
  71. data/lib/playwright/channel_owners/webkit_browser.rb +0 -8
  72. data/lib/playwright_api/binding_call.rb +0 -27
  73. data/lib/playwright_api/chromium_browser_context.rb +0 -59
  74. data/lib/playwright_api/download.rb +0 -100
  75. data/lib/playwright_api/video.rb +0 -24
@@ -15,6 +15,23 @@ module Playwright
15
15
  # })();
16
16
  # ```
17
17
  #
18
+ # ```java
19
+ # import com.microsoft.playwright.*;
20
+ #
21
+ # public class Example {
22
+ # public static void main(String[] args) {
23
+ # try (Playwright playwright = Playwright.create()) {
24
+ # BrowserType chromium = playwright.chromium();
25
+ # Browser browser = chromium.launch();
26
+ # Page page = browser.newPage();
27
+ # page.navigate("http://example.com");
28
+ # // other actions...
29
+ # browser.close();
30
+ # }
31
+ # }
32
+ # }
33
+ # ```
34
+ #
18
35
  # ```python async
19
36
  # import asyncio
20
37
  # from playwright.async_api import async_playwright
@@ -49,7 +66,7 @@ module Playwright
49
66
  # ```
50
67
  class Playwright < PlaywrightApi
51
68
 
52
- # This object can be used to launch or connect to Chromium, returning instances of `ChromiumBrowser`.
69
+ # This object can be used to launch or connect to Chromium, returning instances of `Browser`.
53
70
  def chromium # property
54
71
  wrap_impl(@impl.chromium)
55
72
  end
@@ -113,43 +130,7 @@ module Playwright
113
130
  wrap_impl(@impl.devices)
114
131
  end
115
132
 
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`.
133
+ # This object can be used to launch or connect to Firefox, returning instances of `Browser`.
153
134
  def firefox # property
154
135
  wrap_impl(@impl.firefox)
155
136
  end
@@ -157,27 +138,42 @@ module Playwright
157
138
  # Selectors can be used to install custom selector engines. See [Working with selectors](./selectors.md) for more
158
139
  # information.
159
140
  def selectors # property
160
- raise NotImplementedError.new('selectors is not implemented yet.')
141
+ wrap_impl(@impl.selectors)
161
142
  end
162
143
 
163
- # This object can be used to launch or connect to WebKit, returning instances of `WebKitBrowser`.
144
+ # This object can be used to launch or connect to WebKit, returning instances of `Browser`.
164
145
  def webkit # property
165
146
  wrap_impl(@impl.webkit)
166
147
  end
167
148
 
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.')
149
+ # Terminates this instance of Playwright in case it was created bypassing the Python context manager. This is useful in
150
+ # REPL applications.
151
+ #
152
+ # ```py
153
+ # >>> from playwright.sync_api import sync_playwright
154
+ #
155
+ # >>> playwright = sync_playwright().start()
156
+ #
157
+ # >>> browser = playwright.chromium.launch()
158
+ # >>> page = browser.new_page()
159
+ # >>> page.goto("http://whatsmyuseragent.org/")
160
+ # >>> page.screenshot(path="example.png")
161
+ # >>> browser.close()
162
+ #
163
+ # >>> playwright.stop()
164
+ # ```
165
+ def stop
166
+ raise NotImplementedError.new('stop is not implemented yet.')
171
167
  end
172
168
 
173
169
  # @nodoc
174
- def electron
175
- wrap_impl(@impl.electron)
170
+ def android
171
+ wrap_impl(@impl.android)
176
172
  end
177
173
 
178
174
  # @nodoc
179
- def android
180
- wrap_impl(@impl.android)
175
+ def electron
176
+ wrap_impl(@impl.electron)
181
177
  end
182
178
 
183
179
  # -- inherited from EventEmitter --
@@ -2,10 +2,10 @@ module Playwright
2
2
  # Whenever the page sends a request for a network resource the following sequence of events are emitted by `Page`:
3
3
  # - [`event: Page.request`] emitted when the request is issued by the page.
4
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.
5
+ # - [`event: Page.requestFinished`] emitted when the response body is downloaded and the request is complete.
6
6
  #
7
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.
8
+ # the [`event: Page.requestFailed`] event is emitted.
9
9
  #
10
10
  # > NOTE: HTTP Error responses, such as 404 or 503, are still successful responses from HTTP standpoint, so request will
11
11
  # complete with `'requestfinished'` event.
@@ -25,6 +25,12 @@ module Playwright
25
25
  # });
26
26
  # ```
27
27
  #
28
+ # ```java
29
+ # page.onRequestFailed(request -> {
30
+ # System.out.println(request.url() + " " + request.failure());
31
+ # });
32
+ # ```
33
+ #
28
34
  # ```py
29
35
  # page.on("requestfailed", lambda request: print(request.url + " " + request.failure))
30
36
  # ```
@@ -62,6 +68,14 @@ module Playwright
62
68
  wrap_impl(@impl.post_data_buffer)
63
69
  end
64
70
 
71
+ # Returns parsed request's body for `form-urlencoded` and JSON as a fallback if any.
72
+ #
73
+ # When the response is `application/x-www-form-urlencoded` then a key/value object of the values will be returned.
74
+ # Otherwise it will be parsed as JSON.
75
+ def post_data_json
76
+ wrap_impl(@impl.post_data_json)
77
+ end
78
+
65
79
  # Request that was redirected by the server to this one, if any.
66
80
  #
67
81
  # When the server responds with a redirect, Playwright creates a new `Request` object. The two requests are connected by
@@ -76,6 +90,11 @@ module Playwright
76
90
  # console.log(response.request().redirectedFrom().url()); // 'http://example.com'
77
91
  # ```
78
92
  #
93
+ # ```java
94
+ # Response response = page.navigate("http://example.com");
95
+ # System.out.println(response.request().redirectedFrom().url()); // "http://example.com"
96
+ # ```
97
+ #
79
98
  # ```python async
80
99
  # response = await page.goto("http://example.com")
81
100
  # print(response.request.redirected_from.url) # "http://example.com"
@@ -94,6 +113,11 @@ module Playwright
94
113
  # console.log(response.request().redirectedFrom()); // null
95
114
  # ```
96
115
  #
116
+ # ```java
117
+ # Response response = page.navigate("https://google.com");
118
+ # System.out.println(response.request().redirectedFrom()); // null
119
+ # ```
120
+ #
97
121
  # ```python async
98
122
  # response = await page.goto("https://google.com")
99
123
  # print(response.request.redirected_from) # None
@@ -116,6 +140,10 @@ module Playwright
116
140
  # console.log(request.redirectedFrom().redirectedTo() === request); // true
117
141
  # ```
118
142
  #
143
+ # ```java
144
+ # System.out.println(request.redirectedFrom().redirectedTo() == request); // true
145
+ # ```
146
+ #
119
147
  # ```py
120
148
  # assert request.redirected_from.redirected_to == request
121
149
  # ```
@@ -148,6 +176,14 @@ module Playwright
148
176
  # console.log(request.timing());
149
177
  # ```
150
178
  #
179
+ # ```java
180
+ # page.onRequestFinished(request -> {
181
+ # Timing timing = request.timing();
182
+ # System.out.println(timing.responseEnd - timing.startTime);
183
+ # });
184
+ # page.navigate("http://example.com");
185
+ # ```
186
+ #
151
187
  # ```python async
152
188
  # async with page.expect_event("requestfinished") as request_info:
153
189
  # await page.goto("http://example.com")
@@ -170,16 +206,6 @@ module Playwright
170
206
  wrap_impl(@impl.url)
171
207
  end
172
208
 
173
- # @nodoc
174
- def post_data_json
175
- wrap_impl(@impl.post_data_json)
176
- end
177
-
178
- # @nodoc
179
- def after_initialize
180
- wrap_impl(@impl.after_initialize)
181
- end
182
-
183
209
  # -- inherited from EventEmitter --
184
210
  # @nodoc
185
211
  def once(event, callback)
@@ -4,52 +4,69 @@ module Playwright
4
4
 
5
5
  # Returns the buffer with response body.
6
6
  def body
7
- raise NotImplementedError.new('body is not implemented yet.')
7
+ wrap_impl(@impl.body)
8
8
  end
9
9
 
10
10
  # Waits for this response to finish, returns failure error if request failed.
11
11
  def finished
12
- raise NotImplementedError.new('finished is not implemented yet.')
12
+ wrap_impl(@impl.finished)
13
13
  end
14
14
 
15
15
  # Returns the `Frame` that initiated this response.
16
16
  def frame
17
- raise NotImplementedError.new('frame is not implemented yet.')
17
+ wrap_impl(@impl.frame)
18
18
  end
19
19
 
20
20
  # Returns the object with HTTP headers associated with the response. All header names are lower-case.
21
21
  def headers
22
- raise NotImplementedError.new('headers is not implemented yet.')
22
+ wrap_impl(@impl.headers)
23
+ end
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
+ wrap_impl(@impl.json)
23
30
  end
24
31
 
25
32
  # Contains a boolean stating whether the response was successful (status in the range 200-299) or not.
26
33
  def ok
27
- raise NotImplementedError.new('ok is not implemented yet.')
34
+ wrap_impl(@impl.ok)
28
35
  end
29
36
 
30
37
  # Returns the matching `Request` object.
31
38
  def request
32
- raise NotImplementedError.new('request is not implemented yet.')
39
+ wrap_impl(@impl.request)
33
40
  end
34
41
 
35
42
  # Contains the status code of the response (e.g., 200 for a success).
36
43
  def status
37
- raise NotImplementedError.new('status is not implemented yet.')
44
+ wrap_impl(@impl.status)
38
45
  end
39
46
 
40
47
  # Contains the status text of the response (e.g. usually an "OK" for a success).
41
48
  def status_text
42
- raise NotImplementedError.new('status_text is not implemented yet.')
49
+ wrap_impl(@impl.status_text)
43
50
  end
44
51
 
45
52
  # Returns the text representation of response body.
46
53
  def text
47
- raise NotImplementedError.new('text is not implemented yet.')
54
+ wrap_impl(@impl.text)
48
55
  end
49
56
 
50
57
  # Contains the URL of the response.
51
58
  def url
52
- raise NotImplementedError.new('url is not implemented yet.')
59
+ wrap_impl(@impl.url)
60
+ end
61
+
62
+ # @nodoc
63
+ def after_initialize
64
+ wrap_impl(@impl.after_initialize)
65
+ end
66
+
67
+ # @nodoc
68
+ def ok?
69
+ wrap_impl(@impl.ok?)
53
70
  end
54
71
 
55
72
  # -- inherited from EventEmitter --
@@ -5,7 +5,7 @@ module Playwright
5
5
 
6
6
  # Aborts the route's request.
7
7
  def abort(errorCode: nil)
8
- raise NotImplementedError.new('abort is not implemented yet.')
8
+ wrap_impl(@impl.abort(errorCode: unwrap_impl(errorCode)))
9
9
  end
10
10
 
11
11
  # Continues route's request with optional overrides.
@@ -23,6 +23,16 @@ module Playwright
23
23
  # });
24
24
  # ```
25
25
  #
26
+ # ```java
27
+ # page.route("**/*", route -> {
28
+ # // Override headers
29
+ # Map<String, String> headers = new HashMap<>(route.request().headers());
30
+ # headers.put("foo", "bar"); // set "foo" header
31
+ # headers.remove("origin"); // remove "origin" header
32
+ # route.resume(new Route.ResumeOptions().setHeaders(headers));
33
+ # });
34
+ # ```
35
+ #
26
36
  # ```python async
27
37
  # async def handle(route, request):
28
38
  # # override headers
@@ -48,8 +58,8 @@ module Playwright
48
58
  # }
49
59
  # page.route("**/*", handle)
50
60
  # ```
51
- def continue_(headers: nil, method: nil, postData: nil, url: nil)
52
- raise NotImplementedError.new('continue_ is not implemented yet.')
61
+ def continue(headers: nil, method: nil, postData: nil, url: nil)
62
+ wrap_impl(@impl.continue(headers: unwrap_impl(headers), method: unwrap_impl(method), postData: unwrap_impl(postData), url: unwrap_impl(url)))
53
63
  end
54
64
 
55
65
  # Fulfills route's request with given response.
@@ -67,6 +77,15 @@ module Playwright
67
77
  # });
68
78
  # ```
69
79
  #
80
+ # ```java
81
+ # page.route("**/*", route -> {
82
+ # route.fulfill(new Route.FulfillOptions()
83
+ # .setStatus(404)
84
+ # .setContentType("text/plain")
85
+ # .setBody("Not Found!"));
86
+ # });
87
+ # ```
88
+ #
70
89
  # ```python async
71
90
  # await page.route("**/*", lambda route: route.fulfill(
72
91
  # status=404,
@@ -88,6 +107,11 @@ module Playwright
88
107
  # await page.route('**/xhr_endpoint', route => route.fulfill({ path: 'mock_data.json' }));
89
108
  # ```
90
109
  #
110
+ # ```java
111
+ # page.route("**/xhr_endpoint", route -> route.fulfill(
112
+ # new Route.FulfillOptions().setPath(Paths.get("mock_data.json")));
113
+ # ```
114
+ #
91
115
  # ```python async
92
116
  # await page.route("**/xhr_endpoint", lambda route: route.fulfill(path="mock_data.json"))
93
117
  # ```
@@ -97,17 +121,38 @@ module Playwright
97
121
  # ```
98
122
  def fulfill(
99
123
  body: nil,
100
- bodyBytes: nil,
101
124
  contentType: nil,
102
125
  headers: nil,
103
126
  path: nil,
104
127
  status: nil)
105
- raise NotImplementedError.new('fulfill is not implemented yet.')
128
+ wrap_impl(@impl.fulfill(body: unwrap_impl(body), contentType: unwrap_impl(contentType), headers: unwrap_impl(headers), path: unwrap_impl(path), status: unwrap_impl(status)))
106
129
  end
107
130
 
108
131
  # A request to be routed.
109
132
  def request
110
- raise NotImplementedError.new('request is not implemented yet.')
133
+ wrap_impl(@impl.request)
134
+ end
135
+
136
+ # -- inherited from EventEmitter --
137
+ # @nodoc
138
+ def once(event, callback)
139
+ event_emitter_proxy.once(event, callback)
140
+ end
141
+
142
+ # -- inherited from EventEmitter --
143
+ # @nodoc
144
+ def on(event, callback)
145
+ event_emitter_proxy.on(event, callback)
146
+ end
147
+
148
+ # -- inherited from EventEmitter --
149
+ # @nodoc
150
+ def off(event, callback)
151
+ event_emitter_proxy.off(event, callback)
152
+ end
153
+
154
+ private def event_emitter_proxy
155
+ @event_emitter_proxy ||= EventEmitterProxy.new(self, @impl)
111
156
  end
112
157
  end
113
158
  end
@@ -41,6 +41,32 @@ module Playwright
41
41
  # })();
42
42
  # ```
43
43
  #
44
+ # ```java
45
+ # // Script that evaluates to a selector engine instance.
46
+ # String createTagNameEngine = "{\n" +
47
+ # " // Returns the first element matching given selector in the root's subtree.\n" +
48
+ # " query(root, selector) {\n" +
49
+ # " return root.querySelector(selector);\n" +
50
+ # " },\n" +
51
+ # " // Returns all elements matching given selector in the root's subtree.\n" +
52
+ # " queryAll(root, selector) {\n" +
53
+ # " return Array.from(root.querySelectorAll(selector));\n" +
54
+ # " }\n" +
55
+ # "}";
56
+ # // Register the engine. Selectors will be prefixed with "tag=".
57
+ # playwright.selectors().register("tag", createTagNameEngine);
58
+ # Browser browser = playwright.firefox().launch();
59
+ # Page page = browser.newPage();
60
+ # page.setContent("<div><button>Click me</button></div>");
61
+ # // Use the selector prefixed with its name.
62
+ # ElementHandle button = page.querySelector("tag=button");
63
+ # // Combine it with other selector engines.
64
+ # page.click("tag=div >> text=\"Click me\"");
65
+ # // Can use it in any methods supporting selectors.
66
+ # int buttonCount = (int) page.evalOnSelectorAll("tag=button", "buttons => buttons.length");
67
+ # browser.close();
68
+ # ```
69
+ #
44
70
  # ```python async
45
71
  # # FIXME: add snippet
46
72
  # ```
@@ -48,8 +74,8 @@ module Playwright
48
74
  # ```python sync
49
75
  # # FIXME: add snippet
50
76
  # ```
51
- def register(name, script, contentScript: nil)
52
- raise NotImplementedError.new('register is not implemented yet.')
77
+ def register(name, contentScript: nil, path: nil, script: nil)
78
+ wrap_impl(@impl.register(unwrap_impl(name), contentScript: unwrap_impl(contentScript), path: unwrap_impl(path), script: unwrap_impl(script)))
53
79
  end
54
80
 
55
81
  # -- inherited from EventEmitter --