puppeteer-ruby 0.36.0 → 0.37.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1d4af926ca9ad39046dcc4ce9507622bf72c3263b747516ee1ba642c02e8e38d
4
- data.tar.gz: 3eff89952883a47270dee6a9ee7281609dbbe7bac197eada9e6b6dcabbaa1f78
3
+ metadata.gz: 9e46056e6227e597554a407d47c132610af952d42b1cd7c2149e2046e0d8f1bb
4
+ data.tar.gz: 99a5c6fd6885181e32c72086a768c60583738974a3c86a05a693af2b97b51bc3
5
5
  SHA512:
6
- metadata.gz: d83085eb31bb6d0d9f125e4c82fe172f46676bc373bd7652b2be430984570f7facff20bd3b1da20dbcb41beca52a740064b9b6d5cb6f51a69bf8f4f97e699947
7
- data.tar.gz: 141bed0475d5e40a0ddb9ec0cb2a82f44313a14e835a7d5cc271a413dad0c9881658a81f0ec0567d7896a7658539fc131bb5069c1c07c6573f6b633c99a53f8e
6
+ metadata.gz: d4b1032b52bb5a0ad92e57f0bac5fe5208b785679f1d7efff0ab335cb28478f6110979102d0ec4759ef2f86654b4d231e018aa9cdb3982dc1ffa2e985fa4c55f
7
+ data.tar.gz: 42f81fe580fcb85b5c57397962362c3c6b0ba7462fe210c65ee017b9e73c0a3d9d091c03a7b18f6e6d78f3a3c52572a5d0bb8284f1087412344a184e8624170d
data/CHANGELOG.md CHANGED
@@ -1,51 +1,57 @@
1
- ### master [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.36.0...master)]
1
+ ### master [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.37.0...master)]
2
2
 
3
- * xxx
3
+ - xxx
4
+
5
+ ### 0.37.0 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.36.0...0.37.0)]
6
+
7
+ New features:
8
+
9
+ - Some features introduced in Puppeteer 10.4
4
10
 
5
11
  ### 0.36.0 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.35.1...0.36.0)]
6
12
 
7
13
  New features:
8
14
 
9
- * Drag and Drop feature introduced in Puppeteer 10.1
10
- * `Page#emulateNetworkConditions`, `Page#emulateCPUThrottling`
11
- * `Page#exposeFunction`
12
- * Metrics
15
+ - Drag and Drop feature introduced in Puppeteer 10.1
16
+ - `Page#emulateNetworkConditions`, `Page#emulateCPUThrottling`
17
+ - `Page#exposeFunction`
18
+ - Metrics
13
19
 
14
20
  ### 0.35.1 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.35.0...0.35.1)]
15
21
 
16
22
  New features:
17
23
 
18
- * Allow Rails users to use this library without `require 'puppeteer'`.
24
+ - Allow Rails users to use this library without `require 'puppeteer'`.
19
25
 
20
26
  ### 0.35.0 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.34.3...0.35.0)]
21
27
 
22
28
  New features:
23
29
 
24
- * Add `channel` parameter for Puppeteer.launch. Now `channel: chrome` or `channel: chrome-canary` (chrome-beta, chrome-dev is also available) automatically detects the executablePath of Google Chrome. Windows/macOS users can also use `channel: msedge`.
30
+ - Add `channel` parameter for Puppeteer.launch. Now `channel: chrome` or `channel: chrome-canary` (chrome-beta, chrome-dev is also available) automatically detects the executablePath of Google Chrome. Windows/macOS users can also use `channel: msedge`.
25
31
 
26
32
  ### 0.34.3 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.34.2...0.34.3)]
27
33
 
28
34
  Bugfix:
29
35
 
30
- * Fix wait_for_xxx's timeout error type.
36
+ - Fix wait_for_xxx's timeout error type.
31
37
 
32
38
  ### 0.34.2 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.34.1...0.34.2)]
33
39
 
34
40
  New features:
35
41
 
36
- * Add `Page#bring_to_front`.
42
+ - Add `Page#bring_to_front`.
37
43
 
38
44
  ### 0.34.1 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.34.0...0.34.1)]
39
45
 
40
46
  Bugfix:
41
47
 
42
- * Fix `Page#pdf` to work without `path` parameter.
48
+ - Fix `Page#pdf` to work without `path` parameter.
43
49
 
44
50
  ### 0.34.0 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.33.0...0.34.0)]
45
51
 
46
52
  New features:
47
53
 
48
- * Sync API with block
54
+ - Sync API with block
49
55
 
50
56
  ### 0.33.0 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.32.4...0.33.0)]
51
57
 
@@ -53,170 +59,169 @@ NOTE: Requires Ruby version >= 2.6 explicitly since this version.
53
59
 
54
60
  Bugfix:
55
61
 
56
- * Fix PDF options to work correctly on decimal numbers specified.
62
+ - Fix PDF options to work correctly on decimal numbers specified.
57
63
 
58
64
  ### 0.32.4 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.32.3...0.32.4)]
59
65
 
60
66
  Bugfix:
61
67
 
62
- * Fix `#type_text` to input '<' correctly.
68
+ - Fix `#type_text` to input '<' correctly.
63
69
 
64
70
  ### 0.32.3 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.32.2...0.32.3)]
65
71
 
66
72
  Bugfix:
67
73
 
68
- * Fix puppeteer-ruby to work on Rails in development mode.
69
-
74
+ - Fix puppeteer-ruby to work on Rails in development mode.
70
75
 
71
76
  ### 0.32.2 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.32.1...0.32.2)]
72
77
 
73
78
  Bugfix:
74
79
 
75
- * Fix full_page option in screenshot.
80
+ - Fix full_page option in screenshot.
76
81
 
77
82
  ### 0.32.1 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.32.0...0.32.1)]
78
83
 
79
84
  Bugfix:
80
85
 
81
- * Fix WebSocket to work with `wss://...` endpoint (ex. browserless.io)
86
+ - Fix WebSocket to work with `wss://...` endpoint (ex. browserless.io)
82
87
 
83
88
  ### 0.32.0 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.31.6...0.32.0)]
84
89
 
85
90
  New features:
86
91
 
87
- * Tracing
88
- * JS/CSS coverages
92
+ - Tracing
93
+ - JS/CSS coverages
89
94
 
90
95
  Improvement:
91
96
 
92
- * Increase stability [#92](https://github.com/YusukeIwaki/puppeteer-ruby/pull/92)
97
+ - Increase stability [#92](https://github.com/YusukeIwaki/puppeteer-ruby/pull/92)
93
98
 
94
99
  ### 0.31.6 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.31.5...0.31.6)]
95
100
 
96
101
  Improvement:
97
102
 
98
- * Increase stability [#87](https://github.com/YusukeIwaki/puppeteer-ruby/pull/87)
103
+ - Increase stability [#87](https://github.com/YusukeIwaki/puppeteer-ruby/pull/87)
99
104
 
100
105
  ### 0.31.5 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.31.4...0.31.5)]
101
106
 
102
107
  Bugfix:
103
108
 
104
- * Fix file uploading to work without crash.
109
+ - Fix file uploading to work without crash.
105
110
 
106
111
  ### 0.31.4 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.31.3...0.31.4)]
107
112
 
108
113
  Bugfix:
109
114
 
110
- * Fix PDF options (format, margin, omit_background) to work.
115
+ - Fix PDF options (format, margin, omit_background) to work.
111
116
 
112
117
  ### 0.31.3 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.31.1...0.31.3)]
113
118
 
114
119
  Bugfix:
115
120
 
116
- * Fix `wait_for_selector` to work. *It is strongly recommended to update for 0.29.0-0.31.x users.*
121
+ - Fix `wait_for_selector` to work. _It is strongly recommended to update for 0.29.0-0.31.x users._
117
122
 
118
123
  ### 0.31.1 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.31.0...0.31.1)]
119
124
 
120
125
  Bugfix:
121
126
 
122
- * Fix `Page#pdf` to work on Windows.
127
+ - Fix `Page#pdf` to work on Windows.
123
128
 
124
129
  ### 0.31.0 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.30.0...0.31.0)]
125
130
 
126
131
  New features:
127
132
 
128
- * Now puppeteer-ruby is compatible with Windows
133
+ - Now puppeteer-ruby is compatible with Windows
129
134
 
130
135
  Bugfix:
131
136
 
132
- * Fix `Page#add_script_tag` and `Page#add_style_tag` to work
137
+ - Fix `Page#add_script_tag` and `Page#add_style_tag` to work
133
138
 
134
139
  ### 0.30.0 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.29.0...0.30.0)]
135
140
 
136
141
  New features:
137
142
 
138
- * S, SS, Seval, SSeval is renamed to query_selector, query_selector_all, eval_on_selector, eval_on_selector_all
143
+ - S, SS, Seval, SSeval is renamed to query_selector, query_selector_all, eval_on_selector, eval_on_selector_all
139
144
 
140
145
  ### 0.29.0 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.28.1...0.29.0)]
141
146
 
142
147
  New features:
143
148
 
144
- * Add `AriaQueryHandler`. Now we can use "aria/...." for selectors.
149
+ - Add `AriaQueryHandler`. Now we can use "aria/...." for selectors.
145
150
 
146
151
  ### 0.28.1 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.0.27...0.28.1)]
147
152
 
148
153
  New features:
149
154
 
150
- * Add `Page#emulate_idle_state`
151
- * Change versioning rule.
155
+ - Add `Page#emulate_idle_state`
156
+ - Change versioning rule.
152
157
 
153
158
  ### 0.0.27 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.0.26...0.0.27)]
154
159
 
155
160
  New features:
156
161
 
157
- * Now puppeteer-ruby is Ruby 3.0 compatible!
162
+ - Now puppeteer-ruby is Ruby 3.0 compatible!
158
163
 
159
164
  ### 0.0.26 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.0.25...0.0.26)]
160
165
 
161
166
  Bugfix:
162
167
 
163
- * Fix `Page#screenshot` working correctly with `quality` parameter.
168
+ - Fix `Page#screenshot` working correctly with `quality` parameter.
164
169
 
165
170
  ### 0.0.25 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.0.23...0.0.25)]
166
171
 
167
172
  New feature:
168
173
 
169
- * **Cookie** feature: `Page#set_cookie`, `Page#cookies`
174
+ - **Cookie** feature: `Page#set_cookie`, `Page#cookies`
170
175
 
171
176
  ### 0.0.23 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.0.22...0.0.23)]
172
177
 
173
178
  New feature:
174
179
 
175
- * **GeoLocation** feature
176
- * grant/clear permission
180
+ - **GeoLocation** feature
181
+ - grant/clear permission
177
182
 
178
183
  Bugfix/Improvement:
179
184
 
180
- * Refactoring for events ([#31](https://github.com/YusukeIwaki/puppeteer-ruby/pull/31))
181
- * Improve SEND/RECV handling in CDPSession ([#34](https://github.com/YusukeIwaki/puppeteer-ruby/pull/34))
185
+ - Refactoring for events ([#31](https://github.com/YusukeIwaki/puppeteer-ruby/pull/31))
186
+ - Improve SEND/RECV handling in CDPSession ([#34](https://github.com/YusukeIwaki/puppeteer-ruby/pull/34))
182
187
 
183
188
  ### 0.0.22 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.0.21...0.0.22)]
184
189
 
185
190
  Bugfix
186
191
 
187
- * Make `Puppeteer#default_args` to work
188
- * Respect Firefox launch options
189
- * Respect `default_viewport: nil`
192
+ - Make `Puppeteer#default_args` to work
193
+ - Respect Firefox launch options
194
+ - Respect `default_viewport: nil`
190
195
 
191
196
  ### 0.0.21 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.0.20...0.0.21)]
192
197
 
193
198
  Bugfix/Improvement:
194
199
 
195
- * Update DeviceDescriptors (list of emulatable devices)
196
- * Fix bug on inputing "(" ([#25](https://github.com/YusukeIwaki/puppeteer-ruby/pull/25))
200
+ - Update DeviceDescriptors (list of emulatable devices)
201
+ - Fix bug on inputing "(" ([#25](https://github.com/YusukeIwaki/puppeteer-ruby/pull/25))
197
202
 
198
203
  ### 0.0.20 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.0.19...0.0.20)]
199
204
 
200
205
  New feature
201
206
 
202
- * Dialog-handling feature
207
+ - Dialog-handling feature
203
208
 
204
209
  ### 0.0.19 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.0.18...0.0.19)]
205
210
 
206
211
  New feature
207
212
 
208
- * **Firefox support**
213
+ - **Firefox support**
209
214
 
210
215
  Bugfix/Improvement
211
216
 
212
- * Allow `Page#keyboard` with block ([#18](https://github.com/YusukeIwaki/puppeteer-ruby/pull/18))
217
+ - Allow `Page#keyboard` with block ([#18](https://github.com/YusukeIwaki/puppeteer-ruby/pull/18))
213
218
 
214
219
  ### 0.0.18 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.0.17...0.0.18)]
215
220
 
216
221
  New feature
217
222
 
218
- * **Firefox support**
223
+ - **Firefox support**
219
224
 
220
225
  Bugfix/Improvement
221
226
 
222
- * Allow `Page#keyboard` with block ([#18](https://github.com/YusukeIwaki/puppeteer-ruby/pull/18))
227
+ - Allow `Page#keyboard` with block ([#18](https://github.com/YusukeIwaki/puppeteer-ruby/pull/18))
data/README.md CHANGED
@@ -156,6 +156,75 @@ RSpec.describe 'hotel.testplanisphere.dev', type: :feature do
156
156
 
157
157
  The detailed step of configuration can be found [here](https://github.com/YusukeIwaki/puppeteer-ruby-example/tree/master/_with_capybara-rspec).
158
158
 
159
+ ## :bulb: Use Puppeteer methods simply without Capybara::DSL
160
+
161
+ We can also use puppeteer-ruby as it is without Capybara DSL. When you want to just test a Rails application simply with Puppeteer, refer this section.
162
+
163
+ Also, if you have trouble with handling flaky/unstable testcases in existing feature/system specs, consider replacing Capybara::DSL with raw puppeteer-ruby codes like `page.wait_for_selector(...)` or `page.wait_for_navigation { ... }`.
164
+
165
+ Capybara prepares test server even when Capybara DSL is not used.
166
+
167
+ Sample configuration is shown below. You can use it by putting the file at `spec/support/puppeteer_ruby.rb` or another location where RSpec loads on initialization.
168
+
169
+ ```ruby
170
+ RSpec.configure do |config|
171
+ require 'capybara'
172
+
173
+ # This driver only requests Capybara to launch test server.
174
+ # Remark that no Capybara::DSL is available with this driver.
175
+ class CapybaraNullDriver < Capybara::Driver::Base
176
+ def needs_server?
177
+ true
178
+ end
179
+ end
180
+
181
+ Capybara.register_driver(:null) { CapybaraNullDriver.new }
182
+
183
+ config.around(driver: :null) do |example|
184
+ Capybara.current_driver = :null
185
+
186
+ # Rails server is launched here,
187
+ # (at the first time of accessing Capybara.current_session.server)
188
+ @base_url = Capybara.current_session.server.base_url
189
+
190
+ require 'puppeteer'
191
+ launch_options = {
192
+ # Use launch options as you like.
193
+ channel: :chrome,
194
+ headless: false,
195
+ }
196
+ Puppeteer.launch(**launch_options) do |browser|
197
+ @puppeteer_page = browser.new_page
198
+ example.run
199
+ end
200
+
201
+ Capybara.reset_sessions!
202
+ Capybara.use_default_driver
203
+ end
204
+ end
205
+ ```
206
+
207
+ Now, we can work with integration test using `Puppeteer::Page` in puppeteer-ruby.
208
+
209
+ ```ruby
210
+ RSpec.describe 'Sample integration tests', driver: :null do
211
+ let(:page) { @puppeteer_page }
212
+ let(:base_url) { @base_url }
213
+
214
+ it 'should work with Puppeteer' do
215
+ # null driver only launches server, and Capybara::DSL is unavailable.
216
+ expect { visit '/' }.to raise_error(/NotImplementedError/)
217
+
218
+ page.goto("#{base_url}/")
219
+
220
+ # Automation with Puppeteer
221
+ h1_text = page.eval_on_selector('h1', '(el) => el.textContent')
222
+ expect(h1_text).to eq('It works!')
223
+ end
224
+ end
225
+ ```
226
+
227
+
159
228
  ## API
160
229
 
161
230
  https://yusukeiwaki.github.io/puppeteer-ruby-docs/
data/docs/api_coverage.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # API coverages
2
- - Puppeteer version: v10.2.0
3
- - puppeteer-ruby version: 0.36.0
2
+ - Puppeteer version: v10.4.0
3
+ - puppeteer-ruby version: 0.37.0
4
4
 
5
5
  ## Puppeteer
6
6
 
@@ -136,6 +136,7 @@
136
136
  * waitForFileChooser => `#wait_for_file_chooser`
137
137
  * waitForFunction => `#wait_for_function`
138
138
  * waitForNavigation => `#wait_for_navigation`
139
+ * ~~waitForNetworkIdle~~
139
140
  * waitForRequest => `#wait_for_request`
140
141
  * waitForResponse => `#wait_for_response`
141
142
  * waitForSelector => `#wait_for_selector`
@@ -223,7 +223,7 @@ class Puppeteer::Browser
223
223
  # @param predicate [Proc(Puppeteer::Target -> Boolean)]
224
224
  # @return [Puppeteer::Target]
225
225
  def wait_for_target(predicate:, timeout: nil)
226
- timeout_in_sec = (timeout || 30000).to_i / 1000.0
226
+ timeout_helper = Puppeteer::TimeoutHelper.new('target', timeout_ms: timeout, default_timeout_ms: 30000)
227
227
  existing_target = targets.find { |target| predicate.call(target) }
228
228
  return existing_target if existing_target
229
229
 
@@ -241,15 +241,9 @@ class Puppeteer::Browser
241
241
  end
242
242
 
243
243
  begin
244
- if timeout_in_sec > 0
245
- Timeout.timeout(timeout_in_sec) do
246
- target_promise.value!
247
- end
248
- else
244
+ timeout_helper.with_timeout do
249
245
  target_promise.value!
250
246
  end
251
- rescue Timeout::Error
252
- raise Puppeteer::TimeoutError.new("waiting for target failed: timeout #{timeout}ms exceeded")
253
247
  ensure
254
248
  remove_event_listener(*event_listening_ids)
255
249
  end
@@ -74,6 +74,7 @@ class Puppeteer::BrowserContext
74
74
  'clipboard-read' => 'clipboardReadWrite',
75
75
  'clipboard-write' => 'clipboardReadWrite',
76
76
  'payment-handler' => 'paymentHandler',
77
+ 'persistent-storage' => 'durableStorage',
77
78
  'idle-detection' => 'idleDetection',
78
79
  # chrome-specific permissions we have.
79
80
  'midi-sysex' => 'midiSysex',
@@ -5,10 +5,14 @@ class Puppeteer::Coverage
5
5
  @css = Puppeteer::CSSCoverage.new(client)
6
6
  end
7
7
 
8
- def start_js_coverage(reset_on_navigation: nil, report_anonymous_scripts: nil)
8
+ def start_js_coverage(
9
+ reset_on_navigation: nil,
10
+ report_anonymous_scripts: nil,
11
+ include_raw_script_coverage: nil)
9
12
  @js.start(
10
13
  reset_on_navigation: reset_on_navigation,
11
14
  report_anonymous_scripts: report_anonymous_scripts,
15
+ include_raw_script_coverage: include_raw_script_coverage,
12
16
  )
13
17
  end
14
18
 
@@ -16,7 +20,11 @@ class Puppeteer::Coverage
16
20
  @js.stop
17
21
  end
18
22
 
19
- def js_coverage(reset_on_navigation: nil, report_anonymous_scripts: nil, &block)
23
+ def js_coverage(
24
+ reset_on_navigation: nil,
25
+ report_anonymous_scripts: nil,
26
+ include_raw_script_coverage: nil,
27
+ &block)
20
28
  unless block
21
29
  raise ArgumentError.new('Block must be given')
22
30
  end
@@ -24,6 +32,7 @@ class Puppeteer::Coverage
24
32
  start_js_coverage(
25
33
  reset_on_navigation: reset_on_navigation,
26
34
  report_anonymous_scripts: report_anonymous_scripts,
35
+ include_raw_script_coverage: include_raw_script_coverage,
27
36
  )
28
37
  block.call
29
38
  stop_js_coverage
@@ -158,6 +158,84 @@ Puppeteer::DEVICES = Hash[
158
158
  isLandscape: true,
159
159
  },
160
160
  },
161
+ {
162
+ name: 'Galaxy S8',
163
+ userAgent:
164
+ 'Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36',
165
+ viewport: {
166
+ width: 360,
167
+ height: 740,
168
+ deviceScaleFactor: 3,
169
+ isMobile: true,
170
+ hasTouch: true,
171
+ isLandscape: false,
172
+ },
173
+ },
174
+ {
175
+ name: 'Galaxy S8 landscape',
176
+ userAgent:
177
+ 'Mozilla/5.0 (Linux; Android 7.0; SM-G950U Build/NRD90M) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/62.0.3202.84 Mobile Safari/537.36',
178
+ viewport: {
179
+ width: 740,
180
+ height: 360,
181
+ deviceScaleFactor: 3,
182
+ isMobile: true,
183
+ hasTouch: true,
184
+ isLandscape: true,
185
+ },
186
+ },
187
+ {
188
+ name: 'Galaxy S9+',
189
+ userAgent:
190
+ 'Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36',
191
+ viewport: {
192
+ width: 320,
193
+ height: 658,
194
+ deviceScaleFactor: 4.5,
195
+ isMobile: true,
196
+ hasTouch: true,
197
+ isLandscape: false,
198
+ },
199
+ },
200
+ {
201
+ name: 'Galaxy S9+ landscape',
202
+ userAgent:
203
+ 'Mozilla/5.0 (Linux; Android 8.0.0; SM-G965U Build/R16NW) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/63.0.3239.111 Mobile Safari/537.36',
204
+ viewport: {
205
+ width: 658,
206
+ height: 320,
207
+ deviceScaleFactor: 4.5,
208
+ isMobile: true,
209
+ hasTouch: true,
210
+ isLandscape: true,
211
+ },
212
+ },
213
+ {
214
+ name: 'Galaxy Tab S4',
215
+ userAgent:
216
+ 'Mozilla/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Safari/537.36',
217
+ viewport: {
218
+ width: 712,
219
+ height: 1138,
220
+ deviceScaleFactor: 2.25,
221
+ isMobile: true,
222
+ hasTouch: true,
223
+ isLandscape: false,
224
+ },
225
+ },
226
+ {
227
+ name: 'Galaxy Tab S4 landscape',
228
+ userAgent:
229
+ 'Mozilla/5.0 (Linux; Android 8.1.0; SM-T837A) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/70.0.3538.80 Safari/537.36',
230
+ viewport: {
231
+ width: 1138,
232
+ height: 712,
233
+ deviceScaleFactor: 2.25,
234
+ isMobile: true,
235
+ hasTouch: true,
236
+ isLandscape: true,
237
+ },
238
+ },
161
239
  {
162
240
  name: 'iPad',
163
241
  userAgent:
@@ -1003,6 +1081,58 @@ Puppeteer::DEVICES = Hash[
1003
1081
  isLandscape: true,
1004
1082
  },
1005
1083
  },
1084
+ {
1085
+ name: 'Pixel 3',
1086
+ userAgent:
1087
+ 'Mozilla/5.0 (Linux; Android 9; Pixel 3 Build/PQ1A.181105.017.A1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36',
1088
+ viewport: {
1089
+ width: 393,
1090
+ height: 786,
1091
+ deviceScaleFactor: 2.75,
1092
+ isMobile: true,
1093
+ hasTouch: true,
1094
+ isLandscape: false,
1095
+ },
1096
+ },
1097
+ {
1098
+ name: 'Pixel 3 landscape',
1099
+ userAgent:
1100
+ 'Mozilla/5.0 (Linux; Android 9; Pixel 3 Build/PQ1A.181105.017.A1) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/66.0.3359.158 Mobile Safari/537.36',
1101
+ viewport: {
1102
+ width: 786,
1103
+ height: 393,
1104
+ deviceScaleFactor: 2.75,
1105
+ isMobile: true,
1106
+ hasTouch: true,
1107
+ isLandscape: true,
1108
+ },
1109
+ },
1110
+ {
1111
+ name: 'Pixel 4',
1112
+ userAgent:
1113
+ 'Mozilla/5.0 (Linux; Android 10; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Mobile Safari/537.36',
1114
+ viewport: {
1115
+ width: 353,
1116
+ height: 745,
1117
+ deviceScaleFactor: 3,
1118
+ isMobile: true,
1119
+ hasTouch: true,
1120
+ isLandscape: false,
1121
+ },
1122
+ },
1123
+ {
1124
+ name: 'Pixel 4 landscape',
1125
+ userAgent:
1126
+ 'Mozilla/5.0 (Linux; Android 10; Pixel 4) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Mobile Safari/537.36',
1127
+ viewport: {
1128
+ width: 745,
1129
+ height: 353,
1130
+ deviceScaleFactor: 3,
1131
+ isMobile: true,
1132
+ hasTouch: true,
1133
+ isLandscape: true,
1134
+ },
1135
+ },
1006
1136
  ].map do |json|
1007
1137
  [
1008
1138
  json[:name],
@@ -233,12 +233,13 @@ class Puppeteer::DOMWorld
233
233
  # @param url [String?]
234
234
  # @param path [String?]
235
235
  # @param content [String?]
236
+ # @param id [String?]
236
237
  # @param type [String?]
237
- def add_script_tag(url: nil, path: nil, content: nil, type: nil)
238
+ def add_script_tag(url: nil, path: nil, content: nil, id: nil, type: nil)
238
239
  if url
239
240
  begin
240
241
  return execution_context.
241
- evaluate_handle(ADD_SCRIPT_URL, url, type || '').
242
+ evaluate_handle(ADD_SCRIPT_URL, url, id, type || '').
242
243
  as_element
243
244
  rescue Puppeteer::ExecutionContext::EvaluationError # for Chrome
244
245
  raise "Loading script from #{url} failed"
@@ -251,13 +252,13 @@ class Puppeteer::DOMWorld
251
252
  contents = File.read(path)
252
253
  contents += "//# sourceURL=#{path.gsub(/\n/, '')}"
253
254
  return execution_context.
254
- evaluate_handle(ADD_SCRIPT_CONTENT, contents, type || '').
255
+ evaluate_handle(ADD_SCRIPT_CONTENT, contents, id, type || 'text/javascript').
255
256
  as_element
256
257
  end
257
258
 
258
259
  if content
259
260
  return execution_context.
260
- evaluate_handle(ADD_SCRIPT_CONTENT, content, type || '').
261
+ evaluate_handle(ADD_SCRIPT_CONTENT, content, id, type || 'text/javascript').
261
262
  as_element
262
263
  end
263
264
 
@@ -265,11 +266,11 @@ class Puppeteer::DOMWorld
265
266
  end
266
267
 
267
268
  ADD_SCRIPT_URL = <<~JAVASCRIPT
268
- async (url, type) => {
269
+ async (url, id, type) => {
269
270
  const script = document.createElement('script');
270
271
  script.src = url;
271
- if (type)
272
- script.type = type;
272
+ if (id) script.id = id;
273
+ if (type) script.type = type;
273
274
  const promise = new Promise((res, rej) => {
274
275
  script.onload = res;
275
276
  script.onerror = rej;
@@ -281,11 +282,11 @@ class Puppeteer::DOMWorld
281
282
  JAVASCRIPT
282
283
 
283
284
  ADD_SCRIPT_CONTENT = <<~JAVASCRIPT
284
- (content, type) => {
285
- if (type === undefined) type = 'text/javascript';
285
+ (content, id, type) => {
286
286
  const script = document.createElement('script');
287
287
  script.type = type;
288
288
  script.text = content;
289
+ if (id) script.id = id;
289
290
  let error = null;
290
291
  script.onerror = e => error = e;
291
292
  document.head.appendChild(script);
@@ -0,0 +1,28 @@
1
+ class Puppeteer::ElementHandle < Puppeteer::JSHandle
2
+ # A class to represent (x, y)-offset coordinates
3
+ class Offset
4
+ def initialize(x:, y:)
5
+ @x = x
6
+ @y = y
7
+ end
8
+
9
+ def self.from(offset)
10
+ case offset
11
+ when nil
12
+ nil
13
+ when Hash
14
+ if offset[:x] && offset[:y]
15
+ Offset.new(x: offset[:x], y: offset[:y])
16
+ else
17
+ raise ArgumentError.new('offset parameter must have x, y coordinates')
18
+ end
19
+ when Offset
20
+ offset
21
+ else
22
+ raise ArgumentError.new('Offset.from(Hash|Offset)')
23
+ end
24
+ end
25
+
26
+ attr_reader :x, :y
27
+ end
28
+ end
@@ -21,6 +21,17 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
21
21
  )
22
22
  end
23
23
 
24
+ def ==(other)
25
+ case other
26
+ when Hash
27
+ @x == other[:x] && @y == other[:y]
28
+ when Point
29
+ @x == other.x && @y == other.y
30
+ else
31
+ super
32
+ end
33
+ end
34
+
24
35
  attr_reader :x, :y
25
36
  end
26
37
  end
@@ -1,5 +1,6 @@
1
1
  require_relative './element_handle/bounding_box'
2
2
  require_relative './element_handle/box_model'
3
+ require_relative './element_handle/offset'
3
4
  require_relative './element_handle/point'
4
5
 
5
6
  class Puppeteer::ElementHandle < Puppeteer::JSHandle
@@ -79,7 +80,9 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
79
80
  end
80
81
  end
81
82
 
82
- def clickable_point
83
+ def clickable_point(offset = nil)
84
+ offset_param = Offset.from(offset)
85
+
83
86
  result =
84
87
  begin
85
88
  @remote_object.content_quads(@client)
@@ -105,6 +108,19 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
105
108
  raise ElementNotVisibleError.new
106
109
  end
107
110
 
111
+ if offset_param
112
+ # Return the point of the first quad identified by offset.
113
+ quad = quads.first
114
+ min_x = quad.map(&:x).min
115
+ min_y = quad.map(&:y).min
116
+ if min_x && min_y
117
+ return Point.new(
118
+ x: min_x + offset_param.x,
119
+ y: min_y + offset_param.y,
120
+ )
121
+ end
122
+ end
123
+
108
124
  # Return the middle point of the first quad.
109
125
  quads.first.reduce(:+) / 4
110
126
  end
@@ -139,9 +155,10 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
139
155
  # @param delay [Number]
140
156
  # @param button [String] "left"|"right"|"middle"
141
157
  # @param click_count [Number]
142
- def click(delay: nil, button: nil, click_count: nil)
158
+ # @param offset [Hash]
159
+ def click(delay: nil, button: nil, click_count: nil, offset: nil)
143
160
  scroll_into_view_if_needed
144
- point = clickable_point
161
+ point = clickable_point(offset)
145
162
  @page.mouse.click(point.x, point.y, delay: delay, button: button, click_count: click_count)
146
163
  end
147
164
 
@@ -436,10 +453,12 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
436
453
  define_async_method :async_Sx
437
454
 
438
455
  # in JS, #isIntersectingViewport.
456
+ # @param threshold [Float|nil]
439
457
  # @return [Boolean]
440
- def intersecting_viewport?
458
+ def intersecting_viewport?(threshold: nil)
459
+ option_threshold = threshold || 0
441
460
  js = <<~JAVASCRIPT
442
- async element => {
461
+ async (element, threshold) => {
443
462
  const visibleRatio = await new Promise(resolve => {
444
463
  const observer = new IntersectionObserver(entries => {
445
464
  resolve(entries[0].intersectionRatio);
@@ -447,11 +466,12 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
447
466
  });
448
467
  observer.observe(element);
449
468
  });
450
- return visibleRatio > 0;
469
+ if (threshold === 1) return visibleRatio === 1;
470
+ else return visibleRatio > threshold;
451
471
  }
452
472
  JAVASCRIPT
453
473
 
454
- evaluate(js)
474
+ evaluate(js, option_threshold)
455
475
  end
456
476
 
457
477
  # @param quad [Array<Point>]
@@ -157,8 +157,9 @@ class Puppeteer::Frame
157
157
  # @param path [String?]
158
158
  # @param content [String?]
159
159
  # @param type [String?]
160
- def add_script_tag(url: nil, path: nil, content: nil, type: nil)
161
- @main_world.add_script_tag(url: url, path: path, content: content, type: type)
160
+ # @param id [String?]
161
+ def add_script_tag(url: nil, path: nil, content: nil, type: nil, id: nil)
162
+ @main_world.add_script_tag(url: url, path: path, content: content, type: type, id: id)
162
163
  end
163
164
 
164
165
  # @param url [String?]
@@ -12,6 +12,14 @@ class Puppeteer::JSCoverage
12
12
  attr_reader :url, :ranges, :text
13
13
  end
14
14
 
15
+ class ItemWithRawScriptCoverage < Item
16
+ def initialize(url:, ranges:, text:, raw_script_coverage:)
17
+ super(url: url, ranges: ranges, text: text)
18
+ @raw_script_coverage = raw_script_coverage
19
+ end
20
+ attr_reader :raw_script_coverage
21
+ end
22
+
15
23
  # @param client [Puppeteer::CDPSession]
16
24
  def initialize(client)
17
25
  @client = client
@@ -20,7 +28,10 @@ class Puppeteer::JSCoverage
20
28
  @script_sources = {}
21
29
  end
22
30
 
23
- def start(reset_on_navigation: nil, report_anonymous_scripts: nil)
31
+ def start(
32
+ reset_on_navigation: nil,
33
+ report_anonymous_scripts: nil,
34
+ include_raw_script_coverage: nil)
24
35
  raise 'JSCoverage is already enabled' if @enabled
25
36
 
26
37
  @reset_on_navigation =
@@ -30,6 +41,7 @@ class Puppeteer::JSCoverage
30
41
  true
31
42
  end
32
43
  @report_anonymous_scripts = report_anonymous_scripts || false
44
+ @include_raw_script_coverage = include_raw_script_coverage || false
33
45
  @enabled = true
34
46
  @script_urls.clear
35
47
  @script_sources.clear
@@ -43,7 +55,7 @@ class Puppeteer::JSCoverage
43
55
  await_all(
44
56
  @client.async_send_message('Profiler.enable'),
45
57
  @client.async_send_message('Profiler.startPreciseCoverage',
46
- callCount: false,
58
+ callCount: @include_raw_script_coverage,
47
59
  detailed: true,
48
60
  ),
49
61
  @client.async_send_message('Debugger.enable'),
@@ -107,11 +119,20 @@ class Puppeteer::JSCoverage
107
119
  end
108
120
  end
109
121
 
110
- coverage << Item.new(
111
- url: url,
112
- ranges: convert_to_disjoint_ranges(flatten_ranges),
113
- text: text,
114
- )
122
+ if @include_raw_script_coverage
123
+ coverage << ItemWithRawScriptCoverage.new(
124
+ url: url,
125
+ ranges: convert_to_disjoint_ranges(flatten_ranges),
126
+ text: text,
127
+ raw_script_coverage: entry,
128
+ )
129
+ else
130
+ coverage << Item.new(
131
+ url: url,
132
+ ranges: convert_to_disjoint_ranges(flatten_ranges),
133
+ text: text,
134
+ )
135
+ end
115
136
  end
116
137
 
117
138
  coverage
@@ -15,7 +15,7 @@ class Puppeteer::Page
15
15
  # @params options [Hash]
16
16
  def initialize(options)
17
17
  if options[:type]
18
- unless [:png, :jpeg].include?(options[:type].to_sym)
18
+ unless [:png, :jpeg, :webp].include?(options[:type].to_sym)
19
19
  raise ArgumentError.new("Unknown options.type value: #{options[:type]}")
20
20
  end
21
21
  @type = options[:type]
@@ -25,6 +25,8 @@ class Puppeteer::Page
25
25
  @type = 'png'
26
26
  elsif mime_types.include?('image/jpeg')
27
27
  @type = 'jpeg'
28
+ elsif mime_types.include?('image/webp')
29
+ @type = 'webp'
28
30
  else
29
31
  raise ArgumentError.new("Unsupported screenshot mime type resolved: #{mime_types}, path: #{options[:path]}")
30
32
  end
@@ -404,8 +404,9 @@ class Puppeteer::Page
404
404
  # @param path [String?]
405
405
  # @param content [String?]
406
406
  # @param type [String?]
407
- def add_script_tag(url: nil, path: nil, content: nil, type: nil)
408
- main_frame.add_script_tag(url: url, path: path, content: content, type: type)
407
+ # @param id [String?]
408
+ def add_script_tag(url: nil, path: nil, content: nil, type: nil, id: nil)
409
+ main_frame.add_script_tag(url: url, path: path, content: content, type: type, id: id)
409
410
  end
410
411
 
411
412
  # @param url [String?]
@@ -965,7 +966,7 @@ class Puppeteer::Page
965
966
  main_frame.title
966
967
  end
967
968
 
968
- # @param type [String] "png"|"jpeg"
969
+ # @param type [String] "png"|"jpeg"|"webp"
969
970
  # @param path [String]
970
971
  # @param full_page [Boolean]
971
972
  # @param clip [Hash]
@@ -1059,11 +1060,20 @@ class Puppeteer::Page
1059
1060
 
1060
1061
  # @return [Enumerable<String>]
1061
1062
  def create_pdf_stream(options = {})
1063
+ timeout_helper = Puppeteer::TimeoutHelper.new('Page.printToPDF',
1064
+ timeout_ms: options[:timeout],
1065
+ default_timeout_ms: 30000)
1062
1066
  pdf_options = PDFOptions.new(options)
1063
1067
  omit_background = options[:omit_background]
1064
1068
  set_transparent_background_color if omit_background
1065
- result = @client.send_message('Page.printToPDF', pdf_options.page_print_args)
1066
- reset_default_background_color if omit_background
1069
+ result =
1070
+ begin
1071
+ timeout_helper.with_timeout do
1072
+ @client.send_message('Page.printToPDF', pdf_options.page_print_args)
1073
+ end
1074
+ ensure
1075
+ reset_default_background_color if omit_background
1076
+ end
1067
1077
 
1068
1078
  Puppeteer::ProtocolStreamReader.new(
1069
1079
  client: @client,
@@ -0,0 +1,22 @@
1
+ require 'timeout'
2
+
3
+ class Puppeteer::TimeoutHelper
4
+ # @param timeout_ms [String|Integer|nil]
5
+ # @param default_timeout_ms [Integer]
6
+ def initialize(task_name, timeout_ms:, default_timeout_ms:)
7
+ @task_name = task_name
8
+ @timeout_ms = (timeout_ms || default_timeout_ms).to_i
9
+ end
10
+
11
+ def with_timeout(&block)
12
+ if @timeout_ms > 0
13
+ begin
14
+ Timeout.timeout(@timeout_ms / 1000.0, &block)
15
+ rescue Timeout::Error
16
+ raise Puppeteer::TimeoutError.new("waiting for #{@task_name} failed: timeout #{@timeout_ms}ms exceeded")
17
+ end
18
+ else
19
+ block.call
20
+ end
21
+ end
22
+ end
@@ -27,11 +27,16 @@ class Puppeteer::Tracing
27
27
  option_categories << 'disabled-by-default-devtools.screenshot'
28
28
  end
29
29
 
30
+ ex_cat = option_categories.select { |cat| cat.start_with?('-') }.map { |cat| cat[1..-1] }
31
+ in_cat = option_categories.reject { |cat| cat.start_with?('-') }
30
32
  @path = path
31
33
  @recording = true
32
34
  @client.send_message('Tracing.start',
33
35
  transferMode: 'ReturnAsStream',
34
- categories: option_categories.join(','),
36
+ traceConfig: {
37
+ excludedCategories: ex_cat,
38
+ includedCategories: in_cat,
39
+ },
35
40
  )
36
41
  end
37
42
 
@@ -1,3 +1,3 @@
1
1
  module Puppeteer
2
- VERSION = '0.36.0'
2
+ VERSION = '0.37.0'
3
3
  end
@@ -55,6 +55,7 @@ class Puppeteer::WebSocket
55
55
  def initialize(url:, max_payload_size:)
56
56
  @impl = DriverImpl.new(url)
57
57
  @driver = ::WebSocket::Driver.client(@impl, max_length: max_payload_size)
58
+ @driver.set_header('User-Agent', "Puppeteer #{Puppeteer::VERSION}")
58
59
 
59
60
  setup
60
61
  @driver.start
data/lib/puppeteer.rb CHANGED
@@ -54,6 +54,7 @@ require 'puppeteer/request'
54
54
  require 'puppeteer/response'
55
55
  require 'puppeteer/target'
56
56
  require 'puppeteer/tracing'
57
+ require 'puppeteer/timeout_helper'
57
58
  require 'puppeteer/timeout_settings'
58
59
  require 'puppeteer/touch_screen'
59
60
  require 'puppeteer/version'
@@ -66,17 +67,19 @@ require 'puppeteer/element_handle'
66
67
 
67
68
  # ref: https://github.com/puppeteer/puppeteer/blob/master/lib/Puppeteer.js
68
69
  module Puppeteer
69
- module_function def method_missing(method, *args, **kwargs, &block)
70
- @puppeteer ||= ::Puppeteer::Puppeteer.new(
71
- project_root: __dir__,
72
- preferred_revision: '706915',
73
- is_puppeteer_core: true,
74
- )
75
-
76
- if kwargs.empty? # for Ruby < 2.7
77
- @puppeteer.public_send(method, *args, &block)
78
- else
79
- @puppeteer.public_send(method, *args, **kwargs, &block)
70
+ @puppeteer ||= ::Puppeteer::Puppeteer.new(
71
+ project_root: __dir__,
72
+ preferred_revision: '706915',
73
+ is_puppeteer_core: true,
74
+ ).tap do |instance|
75
+ instance.public_methods(false).each do |method_name|
76
+ define_singleton_method(method_name) do |*args, **kwargs, &block|
77
+ if kwargs.empty? # for Ruby < 2.7
78
+ @puppeteer.public_send(method_name, *args, &block)
79
+ else
80
+ @puppeteer.public_send(method_name, *args, **kwargs, &block)
81
+ end
82
+ end
80
83
  end
81
84
  end
82
85
  end
@@ -32,7 +32,7 @@ Gem::Specification.new do |spec|
32
32
  spec.add_development_dependency 'rollbar'
33
33
  spec.add_development_dependency 'rspec', '~> 3.10.0 '
34
34
  spec.add_development_dependency 'rspec_junit_formatter' # for CircleCI.
35
- spec.add_development_dependency 'rubocop', '~> 1.19.0'
35
+ spec.add_development_dependency 'rubocop', '~> 1.21.0'
36
36
  spec.add_development_dependency 'rubocop-rspec'
37
37
  spec.add_development_dependency 'sinatra'
38
38
  spec.add_development_dependency 'webrick'
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: puppeteer-ruby
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.36.0
4
+ version: 0.37.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - YusukeIwaki
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2021-08-17 00:00:00.000000000 Z
11
+ date: 2021-09-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: concurrent-ruby
@@ -170,14 +170,14 @@ dependencies:
170
170
  requirements:
171
171
  - - "~>"
172
172
  - !ruby/object:Gem::Version
173
- version: 1.19.0
173
+ version: 1.21.0
174
174
  type: :development
175
175
  prerelease: false
176
176
  version_requirements: !ruby/object:Gem::Requirement
177
177
  requirements:
178
178
  - - "~>"
179
179
  - !ruby/object:Gem::Version
180
- version: 1.19.0
180
+ version: 1.21.0
181
181
  - !ruby/object:Gem::Dependency
182
182
  name: rubocop-rspec
183
183
  requirement: !ruby/object:Gem::Requirement
@@ -274,6 +274,7 @@ files:
274
274
  - lib/puppeteer/element_handle.rb
275
275
  - lib/puppeteer/element_handle/bounding_box.rb
276
276
  - lib/puppeteer/element_handle/box_model.rb
277
+ - lib/puppeteer/element_handle/offset.rb
277
278
  - lib/puppeteer/element_handle/point.rb
278
279
  - lib/puppeteer/emulation_manager.rb
279
280
  - lib/puppeteer/env.rb
@@ -315,6 +316,7 @@ files:
315
316
  - lib/puppeteer/request.rb
316
317
  - lib/puppeteer/response.rb
317
318
  - lib/puppeteer/target.rb
319
+ - lib/puppeteer/timeout_helper.rb
318
320
  - lib/puppeteer/timeout_settings.rb
319
321
  - lib/puppeteer/touch_screen.rb
320
322
  - lib/puppeteer/tracing.rb