playwright-ruby-client 0.3.0 → 0.5.6

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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +17 -5
  3. data/docs/api_coverage.md +14 -25
  4. data/lib/playwright.rb +47 -9
  5. data/lib/playwright/channel.rb +19 -9
  6. data/lib/playwright/channel_owners/artifact.rb +30 -0
  7. data/lib/playwright/channel_owners/browser.rb +21 -0
  8. data/lib/playwright/channel_owners/browser_context.rb +5 -0
  9. data/lib/playwright/channel_owners/browser_type.rb +28 -0
  10. data/lib/playwright/channel_owners/element_handle.rb +7 -7
  11. data/lib/playwright/channel_owners/frame.rb +26 -5
  12. data/lib/playwright/channel_owners/js_handle.rb +2 -2
  13. data/lib/playwright/channel_owners/page.rb +78 -15
  14. data/lib/playwright/channel_owners/playwright.rb +22 -29
  15. data/lib/playwright/channel_owners/stream.rb +15 -0
  16. data/lib/playwright/connection.rb +11 -32
  17. data/lib/playwright/download.rb +27 -0
  18. data/lib/playwright/errors.rb +6 -0
  19. data/lib/playwright/events.rb +2 -5
  20. data/lib/playwright/keyboard_impl.rb +1 -1
  21. data/lib/playwright/mouse_impl.rb +41 -0
  22. data/lib/playwright/playwright_api.rb +5 -3
  23. data/lib/playwright/route_handler_entry.rb +1 -9
  24. data/lib/playwright/select_option_values.rb +31 -22
  25. data/lib/playwright/transport.rb +29 -7
  26. data/lib/playwright/url_matcher.rb +1 -1
  27. data/lib/playwright/utils.rb +8 -0
  28. data/lib/playwright/version.rb +1 -1
  29. data/lib/playwright/video.rb +51 -0
  30. data/lib/playwright/wait_helper.rb +2 -2
  31. data/lib/playwright_api/accessibility.rb +39 -1
  32. data/lib/playwright_api/android.rb +10 -10
  33. data/lib/playwright_api/android_device.rb +10 -9
  34. data/lib/playwright_api/browser.rb +83 -8
  35. data/lib/playwright_api/browser_context.rb +157 -9
  36. data/lib/playwright_api/browser_type.rb +35 -4
  37. data/lib/playwright_api/console_message.rb +6 -6
  38. data/lib/playwright_api/dialog.rb +28 -8
  39. data/lib/playwright_api/element_handle.rb +111 -37
  40. data/lib/playwright_api/file_chooser.rb +5 -0
  41. data/lib/playwright_api/frame.rb +228 -37
  42. data/lib/playwright_api/js_handle.rb +26 -3
  43. data/lib/playwright_api/keyboard.rb +48 -1
  44. data/lib/playwright_api/mouse.rb +26 -5
  45. data/lib/playwright_api/page.rb +454 -46
  46. data/lib/playwright_api/playwright.rb +26 -9
  47. data/lib/playwright_api/request.rb +34 -6
  48. data/lib/playwright_api/response.rb +6 -6
  49. data/lib/playwright_api/route.rb +30 -6
  50. data/lib/playwright_api/selectors.rb +32 -6
  51. data/lib/playwright_api/touchscreen.rb +1 -1
  52. data/lib/playwright_api/worker.rb +25 -1
  53. data/playwright.gemspec +4 -2
  54. metadata +37 -14
  55. data/lib/playwright/channel_owners/chromium_browser.rb +0 -8
  56. data/lib/playwright/channel_owners/chromium_browser_context.rb +0 -8
  57. data/lib/playwright/channel_owners/download.rb +0 -27
  58. data/lib/playwright/channel_owners/firefox_browser.rb +0 -8
  59. data/lib/playwright/channel_owners/webkit_browser.rb +0 -8
  60. data/lib/playwright_api/binding_call.rb +0 -32
  61. data/lib/playwright_api/chromium_browser_context.rb +0 -59
  62. data/lib/playwright_api/download.rb +0 -95
  63. data/lib/playwright_api/video.rb +0 -24
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cbaaa0e61bbc515a26d0f0e6af6ca8c36bbf3db5cc6913a6895f175154ba893b
4
- data.tar.gz: cdc467f161030497d4efb94689bef4901c0e15bd24e9cc8be189106f5dfe4493
3
+ metadata.gz: 00cad3443e3aa3e8f527ceda91858789a4ab9ed2853a99f48c24abae1e0e1a0e
4
+ data.tar.gz: f326aa14284545710e95eb53986053325fbf37b5ddc3a82edc9fecf1454afccf
5
5
  SHA512:
6
- metadata.gz: 585d3989547fd8e38e1e9503bf8aee20e732b1234bd62783c51b2e77a6061325c9a0c44de0de2b65557726dbebd6dc944ab44f72ffb8cbba69449ff3c0886a59
7
- data.tar.gz: e50bd506a34d5fe1d84d6f75d0fbe8bc1128c0f93c3529dc94ba6af7dabf59e564625e6ca0b5a16cf7ad8066ffe91aeeda369599a30c0bb9e5629f54dfe54fd1
6
+ metadata.gz: 81d0d106ae9bdc7dd12e001dd82aec2e5cfe507cb04330df67e480127f8cd07f92f92dcca078900069ba134bcd34c9643ec17c1629ee288037d85e062cda741f
7
+ data.tar.gz: 6ff3bf21ddcf009eb5eda9365ad324796692993166ead922d71a145b0c861161c6062f0ddb3fe0f6471eb5c5c6de6bbb52399ad5fa128ebd070c7fc322a624c2
data/README.md CHANGED
@@ -9,22 +9,34 @@ Note: Currently, this Gem is just a PoC (Proof of Concept). If you want to devel
9
9
  At this point, playwright-ruby-client doesn't include the downloader of playwright driver, so **we have to install [playwright](https://github.com/microsoft/playwright) in advance**.
10
10
 
11
11
  ```sh
12
+ npx playwright install
13
+ ```
14
+
15
+ and then, set `playwright_cli_executable_path: "npx playwright"` at `Playwright.create`.
16
+
17
+ **Prefer npm install instead of npx?**
18
+
19
+ Actually `npx playwright` is a bit slow. We can also use `npm install` to setup.
20
+
21
+ Instead of `npx playwright install`:
22
+
23
+ ```
12
24
  npm install playwright
13
25
  ./node_modules/.bin/playwright install
14
26
  ```
15
27
 
16
- and then, set `playwright_cli_executable_path: ./node_modules/.bin/playwright` at `Playwright.create`.
28
+ And set `playwright_cli_executable_path: './node_modules/.bin/playwright'`
17
29
 
18
30
  **Prefer playwrighting without Node.js?**
19
31
 
20
- Instead of npm install, you can also directly download playwright driver from playwright.azureedge.net/builds/. The URL can be easily detected from [here](https://github.com/microsoft/playwright-python/blob/79f6ce0a6a69c480573372706df84af5ef99c4a4/setup.py#L56-L61)
32
+ Instead of npm, you can also directly download playwright driver from playwright.azureedge.net/builds/. The URL can be easily detected from [here](https://github.com/microsoft/playwright-python/blob/79f6ce0a6a69c480573372706df84af5ef99c4a4/setup.py#L56-L61)
21
33
 
22
34
  ### Capture a site
23
35
 
24
36
  ```ruby
25
37
  require 'playwright'
26
38
 
27
- Playwright.create(playwright_cli_executable_path: '/path/to/playwright') do |playwright|
39
+ Playwright.create(playwright_cli_executable_path: 'npx playwright') do |playwright|
28
40
  playwright.chromium.launch(headless: false) do |browser|
29
41
  page = browser.new_page
30
42
  page.goto('https://github.com/YusukeIwaki')
@@ -40,7 +52,7 @@ end
40
52
  ```ruby
41
53
  require 'playwright'
42
54
 
43
- Playwright.create(playwright_cli_executable_path: './node_modules/.bin/playwright') do |playwright|
55
+ Playwright.create(playwright_cli_executable_path: 'npx playwright') do |playwright|
44
56
  playwright.chromium.launch(headless: false) do |browser|
45
57
  page = browser.new_page
46
58
  page.goto('https://github.com/')
@@ -82,7 +94,7 @@ $ bundle exec ruby main.rb
82
94
  ```ruby
83
95
  require 'playwright'
84
96
 
85
- Playwright.create(playwright_cli_executable_path: './node_modules/.bin/playwright') do |playwright|
97
+ Playwright.create(playwright_cli_executable_path: 'npx playwright') do |playwright|
86
98
  devices = playwright.android.devices
87
99
  unless devices.empty?
88
100
  device = devices.last
data/docs/api_coverage.md CHANGED
@@ -55,11 +55,11 @@
55
55
 
56
56
  ## Mouse
57
57
 
58
- * ~~click~~
59
- * ~~dblclick~~
60
- * ~~down~~
61
- * ~~move~~
62
- * ~~up~~
58
+ * click
59
+ * dblclick
60
+ * down
61
+ * move
62
+ * up
63
63
 
64
64
  ## Touchscreen
65
65
 
@@ -173,6 +173,7 @@
173
173
  * expect_navigation
174
174
  * wait_for_selector
175
175
  * ~~wait_for_timeout~~
176
+ * wait_for_url
176
177
 
177
178
  ## ~~Worker~~
178
179
 
@@ -199,19 +200,6 @@
199
200
  * message
200
201
  * type
201
202
 
202
- ## Download
203
-
204
- * delete
205
- * failure
206
- * path
207
- * save_as
208
- * suggested_filename
209
- * url
210
-
211
- ## ~~Video~~
212
-
213
- * ~~path~~
214
-
215
203
  ## Page
216
204
 
217
205
  * add_init_script
@@ -274,7 +262,7 @@
274
262
  * uncheck
275
263
  * unroute
276
264
  * url
277
- * ~~video~~
265
+ * video
278
266
  * viewport_size
279
267
  * expect_console_message
280
268
  * expect_download
@@ -288,6 +276,7 @@
288
276
  * expect_response
289
277
  * wait_for_selector
290
278
  * ~~wait_for_timeout~~
279
+ * wait_for_url
291
280
  * ~~expect_worker~~
292
281
  * ~~workers~~
293
282
  * ~~wait_for_event~~
@@ -300,6 +289,7 @@
300
289
 
301
290
  * add_cookies
302
291
  * add_init_script
292
+ * ~~background_pages~~
303
293
  * browser
304
294
  * clear_cookies
305
295
  * clear_permissions
@@ -308,9 +298,11 @@
308
298
  * expose_binding
309
299
  * expose_function
310
300
  * grant_permissions
301
+ * ~~new_cdp_session~~
311
302
  * new_page
312
303
  * pages
313
304
  * route
305
+ * ~~service_workers~~
314
306
  * set_default_navigation_timeout
315
307
  * set_default_timeout
316
308
  * set_extra_http_headers
@@ -327,19 +319,16 @@
327
319
  * ~~detach~~
328
320
  * ~~send_message~~
329
321
 
330
- ## ChromiumBrowserContext
331
-
332
- * ~~background_pages~~
333
- * ~~new_cdp_session~~
334
- * ~~service_workers~~
335
-
336
322
  ## Browser
337
323
 
338
324
  * close
339
325
  * contexts
340
326
  * connected?
327
+ * ~~new_browser_cdp_session~~
341
328
  * new_context
342
329
  * new_page
330
+ * start_tracing
331
+ * stop_tracing
343
332
  * version
344
333
 
345
334
  ## BrowserType
data/lib/playwright.rb CHANGED
@@ -17,6 +17,7 @@ require 'playwright/utils'
17
17
  require 'playwright/api_implementation'
18
18
  require 'playwright/channel'
19
19
  require 'playwright/channel_owner'
20
+ require 'playwright/download'
20
21
  require 'playwright/http_headers'
21
22
  require 'playwright/input_files'
22
23
  require 'playwright/connection'
@@ -26,6 +27,7 @@ require 'playwright/timeout_settings'
26
27
  require 'playwright/transport'
27
28
  require 'playwright/url_matcher'
28
29
  require 'playwright/version'
30
+ require 'playwright/video'
29
31
  require 'playwright/wait_helper'
30
32
 
31
33
  require 'playwright/playwright_api'
@@ -33,18 +35,54 @@ require 'playwright/playwright_api'
33
35
  Dir[File.join(__dir__, 'playwright_api', '*.rb')].each { |f| require f }
34
36
 
35
37
  module Playwright
36
- module_function def create(playwright_cli_executable_path:, &block)
37
- raise ArgumentError.new("block must be provided") unless block
38
+ class Execution
39
+ def initialize(connection, playwright)
40
+ @connection = connection
41
+ @playwright = playwright
42
+ end
43
+
44
+ def stop
45
+ @connection.stop
46
+ end
47
+
48
+ attr_reader :playwright
49
+ end
38
50
 
51
+ # Recommended to call this method with block.
52
+ #
53
+ # Playwright.create(...) do |playwright|
54
+ # browser = playwright.chromium.launch
55
+ # ...
56
+ # end
57
+ #
58
+ # When we use this method without block, an instance of Puppeteer::Execution is returned
59
+ # and we *must* call execution.stop on the end.
60
+ # The instance of playwright is available by calling execution.playwright
61
+ module_function def create(playwright_cli_executable_path:, &block)
39
62
  connection = Connection.new(playwright_cli_executable_path: playwright_cli_executable_path)
63
+ connection.async_run
64
+
65
+ execution =
66
+ begin
67
+ playwright = connection.wait_for_object_with_known_name('Playwright')
68
+ Execution.new(connection, PlaywrightApi.wrap(playwright))
69
+ rescue
70
+ connection.stop
71
+ raise
72
+ end
40
73
 
41
- playwright_promise = connection.async_wait_for_object_with_known_name('Playwright')
42
- Thread.new { connection.run }
43
- playwright = PlaywrightApi.wrap(playwright_promise.value!)
44
- begin
45
- block.call(playwright)
46
- ensure
47
- connection.stop
74
+ if block
75
+ begin
76
+ block.call(execution.playwright)
77
+ ensure
78
+ execution.stop
79
+ end
80
+ else
81
+ execution
48
82
  end
49
83
  end
84
+
85
+ module_function def instance
86
+ @playwright_instance
87
+ end
50
88
  end
@@ -15,21 +15,31 @@ module Playwright
15
15
 
16
16
  # @param method [String]
17
17
  # @param params [Hash]
18
+ # @return [Playwright::ChannelOwner|nil]
18
19
  def send_message_to_server(method, params = {})
19
- async_send_message_to_server(method, params).value!
20
+ result = send_message_to_server_result(method, params)
21
+ if result.is_a?(Hash)
22
+ _type, channel_owner = result.first
23
+ channel_owner
24
+ else
25
+ nil
26
+ end
20
27
  end
21
28
 
22
29
  # @param method [String]
23
30
  # @param params [Hash]
31
+ # @return [Hash]
32
+ def send_message_to_server_result(method, params)
33
+ @connection.send_message_to_server(@guid, method, params)
34
+ end
35
+
36
+ # @param method [String]
37
+ # @param params [Hash]
38
+ # @returns nil
24
39
  def async_send_message_to_server(method, params = {})
25
- @connection.async_send_message_to_server(@guid, method, params).then do |result|
26
- if result.is_a?(Hash)
27
- _type, channel_owner = result.first
28
- channel_owner
29
- else
30
- nil
31
- end
32
- end
40
+ @connection.async_send_message_to_server(@guid, method, params)
41
+
42
+ nil
33
43
  end
34
44
  end
35
45
  end
@@ -0,0 +1,30 @@
1
+ module Playwright
2
+ define_channel_owner :Artifact do
3
+ private def after_initialize
4
+ @is_remote = false
5
+ @absolute_path = @initializer['absolutePath']
6
+ end
7
+
8
+ attr_reader :absolute_path
9
+
10
+ def path_after_finished
11
+ if @is_remote
12
+ raise "Path is not available when using browser_type.connect(). Use save_as() to save a local copy."
13
+ end
14
+ @channel.send_message_to_server('pathAfterFinished')
15
+ end
16
+
17
+ def save_as(path)
18
+ stream = ChannelOwners::Stream.from(@channel.send_message_to_server('saveAsStream'))
19
+ stream.save_as(path)
20
+ end
21
+
22
+ def failure
23
+ @channel.send_message_to_server('failure')
24
+ end
25
+
26
+ def delete
27
+ @channel.send_message_to_server('delete')
28
+ end
29
+ end
30
+ end
@@ -59,12 +59,33 @@ module Playwright
59
59
  @initializer['version']
60
60
  end
61
61
 
62
+ def start_tracing(page: nil, categories: nil, path: nil, screenshots: nil)
63
+ params = {
64
+ page: page&.channel,
65
+ categories: categories,
66
+ path: path,
67
+ screenshots: screenshots,
68
+ }.compact
69
+
70
+ @channel.send_message_to_server('startTracing', params)
71
+ end
72
+
73
+ def stop_tracing
74
+ encoded_binary = @channel.send_message_to_server("stopTracing")
75
+ return Base64.strict_decode64(encoded_binary)
76
+ end
77
+
62
78
  private def on_close(_ = {})
63
79
  @connected = false
64
80
  emit(Events::Browser::Disconnected)
65
81
  @closed_or_closing = false
66
82
  end
67
83
 
84
+ # called from BrowserType#connectOverCDP
85
+ private def add_context(context)
86
+ @contexts << context
87
+ end
88
+
68
89
  # called from BrowserContext#on_close with send(:remove_context), so keep private.
69
90
  private def remove_context(context)
70
91
  @contexts.delete(context)
@@ -23,6 +23,7 @@ module Playwright
23
23
  page.send(:update_browser_context, self)
24
24
  @pages << page
25
25
  emit(Events::BrowserContext::Page, page)
26
+ page.send(:emit_popup_event_from_browser_context)
26
27
  end
27
28
 
28
29
  private def on_route(route, request)
@@ -206,5 +207,9 @@ module Playwright
206
207
  private def _timeout_settings
207
208
  @timeout_settings
208
209
  end
210
+
211
+ private def has_record_video_option?
212
+ @options.key?(:recordVideo)
213
+ end
209
214
  end
210
215
  end
@@ -22,5 +22,33 @@ module Playwright
22
22
  browser
23
23
  end
24
24
  end
25
+
26
+ def connect_over_cdp(endpointURL, slowMo: nil, timeout: nil, &block)
27
+ raise 'Connecting over CDP is only supported in Chromium.' unless name == 'chromium'
28
+
29
+ params = {
30
+ sdkLanguage: 'ruby',
31
+ endpointURL: endpointURL,
32
+ slowMo: slowMo,
33
+ timeout: timeout,
34
+ }.compact
35
+ result = @channel.send_message_to_server_result('connectOverCDP', params)
36
+ browser = ChannelOwners::Browser.from(result['browser'])
37
+
38
+ if result['defaultContext']
39
+ context = ChannelOwners::BrowserContext.from(result['defaultContext'])
40
+ browser.send(:add_context, context)
41
+ end
42
+
43
+ if block
44
+ begin
45
+ block.call(browser)
46
+ ensure
47
+ browser.close
48
+ end
49
+ else
50
+ browser
51
+ end
52
+ end
25
53
  end
26
54
  end
@@ -82,7 +82,7 @@ module Playwright
82
82
  modifiers: modifiers,
83
83
  position: position,
84
84
  timeout: timeout,
85
- }
85
+ }.compact
86
86
  @channel.send_message_to_server('hover', params)
87
87
 
88
88
  nil
@@ -149,10 +149,8 @@ module Playwright
149
149
  value: value,
150
150
  label: label,
151
151
  ).as_params
152
- params = base_params + { noWaitAfter: noWaitAfter, timeout: timeout }.compact
152
+ params = base_params.merge({ noWaitAfter: noWaitAfter, timeout: timeout }.compact)
153
153
  @channel.send_message_to_server('selectOption', params)
154
-
155
- nil
156
154
  end
157
155
 
158
156
  def tap_point(
@@ -179,7 +177,7 @@ module Playwright
179
177
  value: value,
180
178
  noWaitAfter: noWaitAfter,
181
179
  timeout: timeout,
182
- }
180
+ }.compact
183
181
  @channel.send_message_to_server('fill', params)
184
182
 
185
183
  nil
@@ -230,10 +228,11 @@ module Playwright
230
228
  nil
231
229
  end
232
230
 
233
- def check(force: nil, noWaitAfter: nil, timeout: nil)
231
+ def check(force: nil, noWaitAfter: nil, position: nil, timeout: nil)
234
232
  params = {
235
233
  force: force,
236
234
  noWaitAfter: noWaitAfter,
235
+ position: position,
237
236
  timeout: timeout,
238
237
  }.compact
239
238
  @channel.send_message_to_server('check', params)
@@ -241,10 +240,11 @@ module Playwright
241
240
  nil
242
241
  end
243
242
 
244
- def uncheck(force: nil, noWaitAfter: nil, timeout: nil)
243
+ def uncheck(force: nil, noWaitAfter: nil, position: nil, timeout: nil)
245
244
  params = {
246
245
  force: force,
247
246
  noWaitAfter: noWaitAfter,
247
+ position: position,
248
248
  timeout: timeout,
249
249
  }.compact
250
250
  @channel.send_message_to_server('uncheck', params)