playwright-ruby-client 0.3.0 → 0.5.2

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 (61) 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/channel.rb +19 -9
  5. data/lib/playwright/channel_owners/artifact.rb +30 -0
  6. data/lib/playwright/channel_owners/browser.rb +21 -0
  7. data/lib/playwright/channel_owners/browser_context.rb +5 -0
  8. data/lib/playwright/channel_owners/browser_type.rb +28 -0
  9. data/lib/playwright/channel_owners/element_handle.rb +1 -1
  10. data/lib/playwright/channel_owners/frame.rb +25 -2
  11. data/lib/playwright/channel_owners/js_handle.rb +2 -2
  12. data/lib/playwright/channel_owners/page.rb +78 -15
  13. data/lib/playwright/channel_owners/playwright.rb +22 -29
  14. data/lib/playwright/channel_owners/stream.rb +15 -0
  15. data/lib/playwright/connection.rb +11 -32
  16. data/lib/playwright/download.rb +27 -0
  17. data/lib/playwright/errors.rb +6 -0
  18. data/lib/playwright/events.rb +2 -5
  19. data/lib/playwright/keyboard_impl.rb +1 -1
  20. data/lib/playwright/mouse_impl.rb +41 -0
  21. data/lib/playwright/route_handler_entry.rb +1 -9
  22. data/lib/playwright/transport.rb +27 -6
  23. data/lib/playwright/url_matcher.rb +1 -1
  24. data/lib/playwright/utils.rb +8 -0
  25. data/lib/playwright/version.rb +1 -1
  26. data/lib/playwright/video.rb +51 -0
  27. data/lib/playwright/wait_helper.rb +2 -2
  28. data/lib/playwright.rb +47 -9
  29. data/lib/playwright_api/accessibility.rb +39 -1
  30. data/lib/playwright_api/android.rb +10 -10
  31. data/lib/playwright_api/android_device.rb +10 -9
  32. data/lib/playwright_api/browser.rb +83 -8
  33. data/lib/playwright_api/browser_context.rb +163 -15
  34. data/lib/playwright_api/browser_type.rb +35 -4
  35. data/lib/playwright_api/console_message.rb +6 -6
  36. data/lib/playwright_api/dialog.rb +28 -8
  37. data/lib/playwright_api/element_handle.rb +111 -37
  38. data/lib/playwright_api/file_chooser.rb +5 -0
  39. data/lib/playwright_api/frame.rb +228 -37
  40. data/lib/playwright_api/js_handle.rb +26 -3
  41. data/lib/playwright_api/keyboard.rb +48 -1
  42. data/lib/playwright_api/mouse.rb +26 -5
  43. data/lib/playwright_api/page.rb +456 -48
  44. data/lib/playwright_api/playwright.rb +26 -9
  45. data/lib/playwright_api/request.rb +34 -6
  46. data/lib/playwright_api/response.rb +8 -8
  47. data/lib/playwright_api/route.rb +30 -6
  48. data/lib/playwright_api/selectors.rb +32 -6
  49. data/lib/playwright_api/touchscreen.rb +1 -1
  50. data/lib/playwright_api/worker.rb +25 -1
  51. data/playwright.gemspec +4 -2
  52. metadata +37 -14
  53. data/lib/playwright/channel_owners/chromium_browser.rb +0 -8
  54. data/lib/playwright/channel_owners/chromium_browser_context.rb +0 -8
  55. data/lib/playwright/channel_owners/download.rb +0 -27
  56. data/lib/playwright/channel_owners/firefox_browser.rb +0 -8
  57. data/lib/playwright/channel_owners/webkit_browser.rb +0 -8
  58. data/lib/playwright_api/binding_call.rb +0 -32
  59. data/lib/playwright_api/chromium_browser_context.rb +0 -59
  60. data/lib/playwright_api/download.rb +0 -95
  61. 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: 8979977d78ed7f62007ac6049ccf50a4c865093ac0d4c8828a8f8b8fdd69beef
4
+ data.tar.gz: 20346e5f5a373b49441c81a1fc77cc15ed0afb3bd47479e7cb6e545935fb7dfa
5
5
  SHA512:
6
- metadata.gz: 585d3989547fd8e38e1e9503bf8aee20e732b1234bd62783c51b2e77a6061325c9a0c44de0de2b65557726dbebd6dc944ab44f72ffb8cbba69449ff3c0886a59
7
- data.tar.gz: e50bd506a34d5fe1d84d6f75d0fbe8bc1128c0f93c3529dc94ba6af7dabf59e564625e6ca0b5a16cf7ad8066ffe91aeeda369599a30c0bb9e5629f54dfe54fd1
6
+ metadata.gz: f74fc9b91dccf461603ef6be94c7dbb6aae4899f7246fb4db1456018cc16c9e4fc63d6bf8c9912623b69d20d2901fcd5aab6e128638afc799fa20caac989ddaf
7
+ data.tar.gz: f25f60d3d258fc5fa3592201a45e46e6b111a8508b4493c4308a206d4b33f7909925a1b8760e433a2b7139223e7670b4c9fa0474eccfc3ec2bf2c46061af04b4
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
@@ -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
@@ -179,7 +179,7 @@ module Playwright
179
179
  value: value,
180
180
  noWaitAfter: noWaitAfter,
181
181
  timeout: timeout,
182
- }
182
+ }.compact
183
183
  @channel.send_message_to_server('fill', params)
184
184
 
185
185
  nil
@@ -98,6 +98,15 @@ module Playwright
98
98
  request&.response
99
99
  end
100
100
 
101
+ def wait_for_url(url, timeout: nil, waitUntil: nil)
102
+ matcher = UrlMatcher.new(url)
103
+ if matcher.match?(@url)
104
+ wait_for_load_state(state: waitUntil, timeout: timeout)
105
+ else
106
+ expect_navigation(timeout: timeout, url: url, waitUntil: waitUntil)
107
+ end
108
+ end
109
+
101
110
  def wait_for_load_state(state: nil, timeout: nil)
102
111
  option_state = state || 'load'
103
112
  option_timeout = timeout || @page.send(:timeout_settings).navigation_timeout
@@ -464,11 +473,18 @@ module Playwright
464
473
  nil
465
474
  end
466
475
 
467
- def check(selector, force: nil, noWaitAfter: nil, timeout: nil)
476
+ def check(
477
+ selector,
478
+ force: nil,
479
+ noWaitAfter: nil,
480
+ position: nil,
481
+ timeout: nil)
482
+
468
483
  params = {
469
484
  selector: selector,
470
485
  force: force,
471
486
  noWaitAfter: noWaitAfter,
487
+ position: position,
472
488
  timeout: timeout,
473
489
  }.compact
474
490
  @channel.send_message_to_server('check', params)
@@ -476,11 +492,18 @@ module Playwright
476
492
  nil
477
493
  end
478
494
 
479
- def uncheck(selector, force: nil, noWaitAfter: nil, timeout: nil)
495
+ def uncheck(
496
+ selector,
497
+ force: nil,
498
+ noWaitAfter: nil,
499
+ position: nil,
500
+ timeout: nil)
501
+
480
502
  params = {
481
503
  selector: selector,
482
504
  force: force,
483
505
  noWaitAfter: noWaitAfter,
506
+ position: position,
484
507
  timeout: timeout,
485
508
  }.compact
486
509
  @channel.send_message_to_server('uncheck', params)
@@ -9,8 +9,8 @@ module Playwright
9
9
  @preview
10
10
  end
11
11
 
12
- private def on_preview_updated(preview)
13
- @preview = preview
12
+ private def on_preview_updated(params)
13
+ @preview = params['preview']
14
14
  end
15
15
 
16
16
  def evaluate(pageFunction, arg: nil)
@@ -28,6 +28,7 @@ module Playwright
28
28
  @main_frame.send(:update_page_from_page, self)
29
29
  @frames = Set.new
30
30
  @frames << @main_frame
31
+ @opener = ChannelOwners::Page.from_nullable(@initializer['opener'])
31
32
 
32
33
  @channel.once('close', ->(_) { on_close })
33
34
  @channel.on('console', ->(params) {
@@ -37,9 +38,7 @@ module Playwright
37
38
  @channel.on('crash', ->(_) { emit(Events::Page::Crash) })
38
39
  @channel.on('dialog', method(:on_dialog))
39
40
  @channel.on('domcontentloaded', ->(_) { emit(Events::Page::DOMContentLoaded) })
40
- @channel.on('download', ->(params) {
41
- emit(Events::Page::Download, ChannelOwners::Download.from(params['download']))
42
- })
41
+ @channel.on('download', method(:on_download))
43
42
  @channel.on('fileChooser', ->(params) {
44
43
  chooser = FileChooserImpl.new(
45
44
  page: self,
@@ -57,9 +56,6 @@ module Playwright
57
56
  @channel.on('pageError', ->(params) {
58
57
  emit(Events::Page::PageError, Error.parse(params['error']['error']))
59
58
  })
60
- @channel.on('popup', ->(params) {
61
- emit(Events::Page::Popup, ChannelOwners::Page.from(params['page']))
62
- })
63
59
  @channel.on('request', ->(params) {
64
60
  emit(Events::Page::Request, ChannelOwners::Request.from(params['request']))
65
61
  })
@@ -82,9 +78,7 @@ module Playwright
82
78
  @channel.on('route', ->(params) {
83
79
  on_route(ChannelOwners::Route.from(params['route']), ChannelOwners::Request.from(params['request']))
84
80
  })
85
- @channel.on('video', ->(params) {
86
- video.send(:update_relative_path, params['relativePath'])
87
- })
81
+ @channel.on('video', method(:on_video))
88
82
  @channel.on('webSocket', ->(params) {
89
83
  emit(Events::Page::WebSocket, ChannelOwners::WebSocket.from(params['webSocket']))
90
84
  })
@@ -149,6 +143,20 @@ module Playwright
149
143
  end
150
144
  end
151
145
 
146
+ private def on_download(params)
147
+ download = Download.new(
148
+ url: params['url'],
149
+ suggested_filename: params['suggestedFilename'],
150
+ artifact: ChannelOwners::Artifact.from(params['artifact']),
151
+ )
152
+ emit(Events::Page::Download, download)
153
+ end
154
+
155
+ private def on_video(params)
156
+ artifact = ChannelOwners::Artifact.from(params['artifact'])
157
+ video.send(:set_artifact, artifact)
158
+ end
159
+
152
160
  # @override
153
161
  def on(event, callback)
154
162
  if event == Events::Page::FileChooser && listener_count(event) == 0
@@ -178,8 +186,17 @@ module Playwright
178
186
  end
179
187
 
180
188
  def opener
181
- resp = @channel.send_message_to_server('opener')
182
- ChannelOwners::Page.from(resp)
189
+ if @opener&.closed?
190
+ nil
191
+ else
192
+ @opener
193
+ end
194
+ end
195
+
196
+ private def emit_popup_event_from_browser_context
197
+ if @opener && !@opener.closed?
198
+ @opener.emit(Events::Page::Popup, self)
199
+ end
183
200
  end
184
201
 
185
202
  def frame(name: nil, url: nil)
@@ -326,6 +343,10 @@ module Playwright
326
343
  @main_frame.wait_for_load_state(state: state, timeout: timeout)
327
344
  end
328
345
 
346
+ def wait_for_url(url, timeout: nil, waitUntil: nil)
347
+ @main_frame.wait_for_url(url, timeout: timeout, waitUntil: waitUntil)
348
+ end
349
+
329
350
  def go_back(timeout: nil, waitUntil: nil)
330
351
  params = { timeout: timeout, waitUntil: waitUntil }.compact
331
352
  resp = @channel.send_message_to_server('goBack', params)
@@ -578,12 +599,24 @@ module Playwright
578
599
  @main_frame.press(selector, key, delay: delay, noWaitAfter: noWaitAfter, timeout: timeout)
579
600
  end
580
601
 
581
- def check(selector, force: nil, noWaitAfter: nil, timeout: nil)
582
- @main_frame.check(selector, force: force, noWaitAfter: noWaitAfter, timeout: timeout)
602
+ def check(
603
+ selector,
604
+ force: nil,
605
+ noWaitAfter: nil,
606
+ position: nil,
607
+ timeout: nil)
608
+
609
+ @main_frame.check(selector, force: force, noWaitAfter: noWaitAfter, position: position, timeout: timeout)
583
610
  end
584
611
 
585
- def uncheck(selector, force: nil, noWaitAfter: nil, timeout: nil)
586
- @main_frame.uncheck(selector, force: force, noWaitAfter: noWaitAfter, timeout: timeout)
612
+ def uncheck(
613
+ selector,
614
+ force: nil,
615
+ noWaitAfter: nil,
616
+ position: nil,
617
+ timeout: nil)
618
+
619
+ @main_frame.uncheck(selector, force: force, noWaitAfter: noWaitAfter, position: position, timeout: timeout)
587
620
  end
588
621
 
589
622
  def wait_for_function(pageFunction, arg: nil, polling: nil, timeout: nil)
@@ -629,6 +662,36 @@ module Playwright
629
662
  decoded_binary
630
663
  end
631
664
 
665
+ def video
666
+ return nil unless @browser_context.send(:has_record_video_option?)
667
+ @video ||= Video.new(self)
668
+ end
669
+
670
+ def start_js_coverage(resetOnNavigation: nil, reportAnonymousScripts: nil)
671
+ params = {
672
+ resetOnNavigation: resetOnNavigation,
673
+ reportAnonymousScripts: reportAnonymousScripts,
674
+ }.compact
675
+
676
+ @channel.send_message_to_server('startJSCoverage', params)
677
+ end
678
+
679
+ def stop_js_coverage
680
+ @channel.send_message_to_server('stopJSCoverage')
681
+ end
682
+
683
+ def start_css_coverage(resetOnNavigation: nil, reportAnonymousScripts: nil)
684
+ params = {
685
+ resetOnNavigation: resetOnNavigation,
686
+ }.compact
687
+
688
+ @channel.send_message_to_server('startCSSCoverage', params)
689
+ end
690
+
691
+ def stop_css_coverage
692
+ @channel.send_message_to_server('stopCSSCoverage')
693
+ end
694
+
632
695
  class CrashedError < StandardError
633
696
  def initialize
634
697
  super('Page crashed')
@@ -24,38 +24,31 @@ module Playwright
24
24
  @selectors ||= ::Playwright::ChannelOwners::Selectors.from(@initializer['selectors'])
25
25
  end
26
26
 
27
- class DeviceDescriptor
28
- class Viewport
29
- def initialize(hash)
30
- @width = hash['width']
31
- @heirhgt = hash['height']
32
- end
33
- attr_reader :width, :height
34
- end
35
-
36
- def initialize(hash)
37
- @user_agent = hash["userAgent"]
38
- @viewport = Viewport.new(hash["viewport"])
39
- @device_scale_factor = hash["deviceScaleFactor"]
40
- @is_mobile = hash["isMobile"]
41
- @has_touch = hash["hasTouch"]
42
- end
43
-
44
- attr_reader :user_agent, :viewport, :device_scale_factor
45
-
46
- def mobile?
47
- @is_mobile
48
- end
49
-
50
- def has_touch?
51
- @has_touch
52
- end
53
- end
54
-
55
27
  def devices
56
28
  @devices ||= @initializer['deviceDescriptors'].map do |item|
57
- [item['name'], DeviceDescriptor.new(item['descriptor'])]
29
+ [item['name'], parse_device_descriptor(item['descriptor'])]
58
30
  end.to_h
59
31
  end
32
+
33
+ private def parse_device_descriptor(descriptor)
34
+ # This return value can be passed into Browser#new_context as it is.
35
+ # ex:
36
+ # ```
37
+ # iPhone = playwright.devices['iPhone 6']
38
+ # context = browser.new_context(**iPhone)
39
+ # page = context.new_page
40
+ #
41
+ # ```
42
+ {
43
+ userAgent: descriptor['userAgent'],
44
+ viewport: {
45
+ width: descriptor['viewport']['width'],
46
+ height: descriptor['viewport']['height'],
47
+ },
48
+ deviceScaleFactor: descriptor['deviceScaleFactor'],
49
+ isMobile: descriptor['isMobile'],
50
+ hasTouch: descriptor['hasTouch'],
51
+ }
52
+ end
60
53
  end
61
54
  end
@@ -0,0 +1,15 @@
1
+ require 'base64'
2
+
3
+ module Playwright
4
+ define_channel_owner :Stream do
5
+ def save_as(path)
6
+ File.open(path, 'wb') do |f|
7
+ loop do
8
+ binary = @channel.send_message_to_server('read')
9
+ break if !binary || binary.length == 0
10
+ f.write(Base64.strict_decode64(binary))
11
+ end
12
+ end
13
+ end
14
+ end
15
+ end