playwright-ruby-client 0.3.0 → 0.5.2

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