puppeteer-ruby 0.37.0 → 0.37.4
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 +4 -4
- data/CHANGELOG.md +25 -1
- data/README.md +1 -1
- data/docs/api_coverage.md +38 -34
- data/lib/puppeteer/browser_runner.rb +1 -1
- data/lib/puppeteer/element_handle.rb +10 -8
- data/lib/puppeteer/executable_path_finder.rb +28 -0
- data/lib/puppeteer/frame.rb +1 -1
- data/lib/puppeteer/frame_manager.rb +2 -2
- data/lib/puppeteer/{request.rb → http_request.rb} +150 -21
- data/lib/puppeteer/{response.rb → http_response.rb} +2 -2
- data/lib/puppeteer/launcher/chrome.rb +20 -3
- data/lib/puppeteer/launcher/firefox.rb +10 -3
- data/lib/puppeteer/launcher/launch_options.rb +3 -3
- data/lib/puppeteer/lifecycle_watcher.rb +2 -2
- data/lib/puppeteer/network_manager.rb +17 -7
- data/lib/puppeteer/page.rb +15 -37
- data/lib/puppeteer/version.rb +1 -1
- data/lib/puppeteer/wait_task.rb +1 -1
- data/lib/puppeteer.rb +3 -2
- data/puppeteer-ruby.gemspec +1 -1
- metadata +7 -6
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: '000206932f5d3d4626602e984cff4015039644eea2ef89ff139b239fffb9f673'
|
4
|
+
data.tar.gz: 0e560f862a3317a42c1e0e2907c599bc654d05e3f17fd5a650126b73bfd6948e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: aac4be4a26f3116eee198ea65c0017359589f2ad11cc95125497e3f84ea1277d9bbb8d1071b57fb42812bb12afd4370534c48586fbb79897acafb54d03222159
|
7
|
+
data.tar.gz: de51d1ca30e26e13346532118df225370fad4b1967d205dad0c150574c4fa60a649973aab83e24b2140b8f98f05626eb106a9141f04b94fe5d3927b1231737d4
|
data/CHANGELOG.md
CHANGED
@@ -1,7 +1,31 @@
|
|
1
|
-
###
|
1
|
+
### main [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.37.4...main)]
|
2
2
|
|
3
3
|
- xxx
|
4
4
|
|
5
|
+
### 0.37.4 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.37.3...0.37.4)]
|
6
|
+
|
7
|
+
Bugfix:
|
8
|
+
|
9
|
+
- Fix ElementHandle#screenshot to work.
|
10
|
+
|
11
|
+
### 0.37.3 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.37.2...0.37.3)]
|
12
|
+
|
13
|
+
Improvement:
|
14
|
+
|
15
|
+
- Improve the logic of detection of Chrome/Firefox executable path on Linux.
|
16
|
+
|
17
|
+
### 0.37.2 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.37.1...0.37.2)]
|
18
|
+
|
19
|
+
Bugfix:
|
20
|
+
|
21
|
+
- `timeout: 0` did set the timeout value to zero. Now it disables the timeout as expected.
|
22
|
+
|
23
|
+
### 0.37.1 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.37.0...0.37.1)]
|
24
|
+
|
25
|
+
Bugfix:
|
26
|
+
|
27
|
+
- Fix handle_SIGINT, handle_SIGTERM, handle_SIGHUP options to work with `false` value specified.
|
28
|
+
|
5
29
|
### 0.37.0 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.36.0...0.37.0)]
|
6
30
|
|
7
31
|
New features:
|
data/README.md
CHANGED
@@ -41,7 +41,7 @@ NOTE: `require 'puppeteer-ruby'` is not necessary in Rails.
|
|
41
41
|
```ruby
|
42
42
|
require 'puppeteer-ruby'
|
43
43
|
|
44
|
-
Puppeteer.launch(headless: false, slow_mo: 50, args: ['--
|
44
|
+
Puppeteer.launch(headless: false, slow_mo: 50, args: ['--window-size=1280,800']) do |browser|
|
45
45
|
page = browser.new_page
|
46
46
|
page.viewport = Puppeteer::Viewport.new(width: 1280, height: 800)
|
47
47
|
page.goto("https://github.com/", wait_until: 'domcontentloaded')
|
data/docs/api_coverage.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# API coverages
|
2
|
-
- Puppeteer version:
|
3
|
-
- puppeteer-ruby version: 0.37.
|
2
|
+
- Puppeteer version: v12.0.0
|
3
|
+
- puppeteer-ruby version: 0.37.4
|
4
4
|
|
5
5
|
## Puppeteer
|
6
6
|
|
@@ -134,6 +134,7 @@
|
|
134
134
|
* viewport
|
135
135
|
* ~~waitFor~~
|
136
136
|
* waitForFileChooser => `#wait_for_file_chooser`
|
137
|
+
* ~~waitForFrame~~
|
137
138
|
* waitForFunction => `#wait_for_function`
|
138
139
|
* waitForNavigation => `#wait_for_navigation`
|
139
140
|
* ~~waitForNetworkIdle~~
|
@@ -226,6 +227,7 @@
|
|
226
227
|
* goto
|
227
228
|
* hover
|
228
229
|
* isDetached => `#detached?`
|
230
|
+
* ~~isOOPFrame~~
|
229
231
|
* name
|
230
232
|
* parentFrame => `#parent_frame`
|
231
233
|
* select
|
@@ -295,43 +297,44 @@
|
|
295
297
|
* type => `#type_text`
|
296
298
|
* uploadFile => `#upload_file`
|
297
299
|
|
298
|
-
##
|
299
|
-
|
300
|
-
*
|
301
|
-
*
|
302
|
-
*
|
303
|
-
*
|
304
|
-
*
|
305
|
-
*
|
306
|
-
*
|
307
|
-
*
|
308
|
-
*
|
309
|
-
* ~~
|
310
|
-
*
|
311
|
-
*
|
312
|
-
*
|
313
|
-
*
|
314
|
-
*
|
315
|
-
*
|
316
|
-
*
|
317
|
-
*
|
300
|
+
## HTTPRequest
|
301
|
+
|
302
|
+
* abort
|
303
|
+
* abortErrorReason => `#abort_error_reason`
|
304
|
+
* continue
|
305
|
+
* continueRequestOverrides => `#continue_request_overrides`
|
306
|
+
* enqueueInterceptAction => `#enqueue_intercept_action`
|
307
|
+
* failure
|
308
|
+
* finalizeInterceptions => `#finalize_interceptions`
|
309
|
+
* frame
|
310
|
+
* headers
|
311
|
+
* ~~initiator~~
|
312
|
+
* isNavigationRequest => `#navigation_request?`
|
313
|
+
* method
|
314
|
+
* postData => `#post_data`
|
315
|
+
* redirectChain => `#redirect_chain`
|
316
|
+
* resourceType => `#resource_type`
|
317
|
+
* respond
|
318
|
+
* response
|
319
|
+
* responseForRequest => `#response_for_request`
|
320
|
+
* url
|
318
321
|
|
319
|
-
##
|
322
|
+
## HTTPResponse
|
320
323
|
|
321
|
-
*
|
322
|
-
*
|
324
|
+
* buffer
|
325
|
+
* frame
|
323
326
|
* ~~fromCache~~
|
324
327
|
* ~~fromServiceWorker~~
|
325
|
-
*
|
326
|
-
*
|
328
|
+
* headers
|
329
|
+
* json
|
327
330
|
* ~~ok~~
|
328
|
-
*
|
329
|
-
*
|
330
|
-
*
|
331
|
-
*
|
332
|
-
*
|
333
|
-
*
|
334
|
-
*
|
331
|
+
* remoteAddress => `#remote_address`
|
332
|
+
* request
|
333
|
+
* securityDetails => `#security_details`
|
334
|
+
* status
|
335
|
+
* statusText => `#status_text`
|
336
|
+
* text
|
337
|
+
* url
|
335
338
|
|
336
339
|
## ~~SecurityDetails~~
|
337
340
|
|
@@ -357,6 +360,7 @@
|
|
357
360
|
|
358
361
|
* connection
|
359
362
|
* detach
|
363
|
+
* ~~id~~
|
360
364
|
* send
|
361
365
|
|
362
366
|
## Coverage
|
@@ -323,7 +323,7 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
|
|
323
323
|
end
|
324
324
|
end
|
325
325
|
|
326
|
-
def screenshot(
|
326
|
+
def screenshot(type: nil, path: nil, full_page: nil, clip: nil, quality: nil, omit_background: nil, encoding: nil)
|
327
327
|
needs_viewport_reset = false
|
328
328
|
|
329
329
|
box = bounding_box
|
@@ -358,14 +358,16 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
|
|
358
358
|
page_x = layout_metrics["layoutViewport"]["pageX"]
|
359
359
|
page_y = layout_metrics["layoutViewport"]["pageY"]
|
360
360
|
|
361
|
-
clip
|
362
|
-
|
363
|
-
|
364
|
-
|
365
|
-
|
366
|
-
|
361
|
+
if clip.nil?
|
362
|
+
clip = {
|
363
|
+
x: page_x + box.x,
|
364
|
+
y: page_y + box.y,
|
365
|
+
width: box.width,
|
366
|
+
height: box.height,
|
367
|
+
}
|
368
|
+
end
|
367
369
|
|
368
|
-
@page.screenshot(
|
370
|
+
@page.screenshot(type: type, path: path, full_page: full_page, clip: clip, quality: quality, omit_background: omit_background, encoding: encoding)
|
369
371
|
ensure
|
370
372
|
if needs_viewport_reset
|
371
373
|
@page.viewport = viewport
|
@@ -0,0 +1,28 @@
|
|
1
|
+
class Puppeteer::ExecutablePathFinder
|
2
|
+
# @param executable_names [Array<String>] executable file names to find.
|
3
|
+
def initialize(*executable_names)
|
4
|
+
@executable_names = executable_names
|
5
|
+
end
|
6
|
+
|
7
|
+
def find_executables_in_path
|
8
|
+
Enumerator.new do |result|
|
9
|
+
@executable_names.each do |name|
|
10
|
+
# Find the first existing path.
|
11
|
+
paths.each do |path|
|
12
|
+
candidate = File.join(path, name)
|
13
|
+
next unless File.exist?(candidate)
|
14
|
+
result << candidate
|
15
|
+
break
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def find_first
|
22
|
+
find_executables_in_path.first
|
23
|
+
end
|
24
|
+
|
25
|
+
private def paths
|
26
|
+
ENV['PATH'].split(File::PATH_SEPARATOR)
|
27
|
+
end
|
28
|
+
end
|
data/lib/puppeteer/frame.rb
CHANGED
@@ -28,7 +28,7 @@ class Puppeteer::Frame
|
|
28
28
|
# @param rederer [String]
|
29
29
|
# @param timeout [number|nil]
|
30
30
|
# @param wait_until [string|nil] 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2'
|
31
|
-
# @return [Puppeteer::
|
31
|
+
# @return [Puppeteer::HTTPResponse]
|
32
32
|
def goto(url, referer: nil, timeout: nil, wait_until: nil)
|
33
33
|
@frame_manager.navigate_frame(self, url, referer: referer, timeout: timeout, wait_until: wait_until)
|
34
34
|
end
|
@@ -82,7 +82,7 @@ class Puppeteer::FrameManager
|
|
82
82
|
# @param frame [Puppeteer::Frame]
|
83
83
|
# @param url [String]
|
84
84
|
# @param {!{referer?: string, timeout?: number, waitUntil?: string|!Array<string>}=} options
|
85
|
-
# @return [Puppeteer::
|
85
|
+
# @return [Puppeteer::HTTPResponse]
|
86
86
|
def navigate_frame(frame, url, referer: nil, timeout: nil, wait_until: nil)
|
87
87
|
assert_no_legacy_navigation_options(wait_until: wait_until)
|
88
88
|
|
@@ -132,7 +132,7 @@ class Puppeteer::FrameManager
|
|
132
132
|
|
133
133
|
# @param timeout [number|nil]
|
134
134
|
# @param wait_until [string|nil] 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2'
|
135
|
-
# @return [Puppeteer::
|
135
|
+
# @return [Puppeteer::HTTPResponse]
|
136
136
|
def wait_for_frame_navigation(frame, timeout: nil, wait_until: nil)
|
137
137
|
assert_no_legacy_navigation_options(wait_until: wait_until)
|
138
138
|
|
@@ -1,4 +1,4 @@
|
|
1
|
-
class Puppeteer::
|
1
|
+
class Puppeteer::HTTPRequest
|
2
2
|
include Puppeteer::DebugPrint
|
3
3
|
include Puppeteer::IfPresent
|
4
4
|
|
@@ -16,7 +16,7 @@ class Puppeteer::Request
|
|
16
16
|
@request.instance_variable_get(:@interception_id)
|
17
17
|
end
|
18
18
|
|
19
|
-
# @param response [Puppeteer::
|
19
|
+
# @param response [Puppeteer::HTTPResponse]
|
20
20
|
def response=(response)
|
21
21
|
@request.instance_variable_set(:@response, response)
|
22
22
|
end
|
@@ -56,6 +56,12 @@ class Puppeteer::Request
|
|
56
56
|
@post_data = event['request']['postData']
|
57
57
|
@frame = frame
|
58
58
|
@redirect_chain = redirect_chain
|
59
|
+
@continue_request_overrides = {}
|
60
|
+
@current_strategy = 'none'
|
61
|
+
@current_priority = nil
|
62
|
+
@intercept_actions = []
|
63
|
+
@initiator = event['initiator']
|
64
|
+
|
59
65
|
@headers = {}
|
60
66
|
event['request']['headers'].each do |key, value|
|
61
67
|
@headers[key.downcase] = value
|
@@ -68,6 +74,76 @@ class Puppeteer::Request
|
|
68
74
|
attr_reader :internal
|
69
75
|
attr_reader :url, :resource_type, :method, :post_data, :headers, :response, :frame
|
70
76
|
|
77
|
+
private def assert_interception_allowed
|
78
|
+
unless @allow_interception
|
79
|
+
raise InterceptionNotEnabledError.new
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
private def assert_interception_not_handled
|
84
|
+
if @interception_handled
|
85
|
+
raise AlreadyHandledError.new
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# @returns the `ContinueRequestOverrides` that will be used
|
90
|
+
# if the interception is allowed to continue (ie, `abort()` and
|
91
|
+
# `respond()` aren't called).
|
92
|
+
def continue_request_overrides
|
93
|
+
assert_interception_allowed
|
94
|
+
@continue_request_overrides
|
95
|
+
end
|
96
|
+
|
97
|
+
# @returns The `ResponseForRequest` that gets used if the
|
98
|
+
# interception is allowed to respond (ie, `abort()` is not called).
|
99
|
+
def response_for_request
|
100
|
+
assert_interception_allowed
|
101
|
+
@response_for_request
|
102
|
+
end
|
103
|
+
|
104
|
+
# @returns the most recent reason for aborting the request
|
105
|
+
def abort_error_reason
|
106
|
+
assert_interception_allowed
|
107
|
+
@abort_error_reason
|
108
|
+
end
|
109
|
+
|
110
|
+
# @returns An array of the current intercept resolution strategy and priority
|
111
|
+
# `[strategy,priority]`. Strategy is one of: `abort`, `respond`, `continue`,
|
112
|
+
# `disabled`, `none`, or `already-handled`.
|
113
|
+
def intercept_resolution
|
114
|
+
if !@allow_interception
|
115
|
+
['disabled']
|
116
|
+
elsif @interception_handled
|
117
|
+
['already-handled']
|
118
|
+
else
|
119
|
+
[@current_strategy, @current_priority]
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
# Adds an async request handler to the processing queue.
|
124
|
+
# Deferred handlers are not guaranteed to execute in any particular order,
|
125
|
+
# but they are guarnateed to resolve before the request interception
|
126
|
+
# is finalized.
|
127
|
+
#
|
128
|
+
# @param pending_handler [Proc]
|
129
|
+
def enqueue_intercept_action(pending_handler)
|
130
|
+
@intercept_actions << pending_handler
|
131
|
+
end
|
132
|
+
|
133
|
+
# Awaits pending interception handlers and then decides how to fulfill
|
134
|
+
# the request interception.
|
135
|
+
def finalize_interceptions
|
136
|
+
@intercept_actions.each(&:call)
|
137
|
+
case @intercept_resolution
|
138
|
+
when :abort
|
139
|
+
abort_impl(**@abort_error_reason)
|
140
|
+
when :respond
|
141
|
+
respond_impl(**@response_for_request)
|
142
|
+
when :continue
|
143
|
+
continue_impl(@continue_request_overrides)
|
144
|
+
end
|
145
|
+
end
|
146
|
+
|
71
147
|
def navigation_request?
|
72
148
|
@is_navigation_request
|
73
149
|
end
|
@@ -116,24 +192,43 @@ class Puppeteer::Request
|
|
116
192
|
# end
|
117
193
|
#
|
118
194
|
# @param error_code [String|Symbol]
|
119
|
-
def continue(url: nil, method: nil, post_data: nil, headers: nil)
|
195
|
+
def continue(url: nil, method: nil, post_data: nil, headers: nil, priority: nil)
|
120
196
|
# Request interception is not supported for data: urls.
|
121
197
|
return if @url.start_with?('data:')
|
122
198
|
|
123
|
-
|
124
|
-
|
125
|
-
end
|
126
|
-
if @interception_handled
|
127
|
-
raise AlreadyHandledError.new
|
128
|
-
end
|
129
|
-
@interception_handled = true
|
199
|
+
assert_interception_allowed
|
200
|
+
assert_interception_not_handled
|
130
201
|
|
131
202
|
overrides = {
|
132
203
|
url: url,
|
133
204
|
method: method,
|
134
|
-
|
205
|
+
postData: post_data,
|
135
206
|
headers: headers_to_array(headers),
|
136
207
|
}.compact
|
208
|
+
|
209
|
+
if priority.nil?
|
210
|
+
continue_impl(overrides)
|
211
|
+
return
|
212
|
+
end
|
213
|
+
|
214
|
+
@continue_request_overrides = overrides
|
215
|
+
if @current_priority.nil? || priority > @current_priority
|
216
|
+
@current_strategy = :continue
|
217
|
+
@current_priority = priority
|
218
|
+
return
|
219
|
+
end
|
220
|
+
|
221
|
+
if priority == @current_priority
|
222
|
+
if @current_strategy == :abort || @current_strategy == :respond
|
223
|
+
return
|
224
|
+
end
|
225
|
+
@current_strategy = :continue
|
226
|
+
end
|
227
|
+
end
|
228
|
+
|
229
|
+
private def continue_impl(overrides)
|
230
|
+
@interception_handled = true
|
231
|
+
|
137
232
|
begin
|
138
233
|
@client.send_message('Fetch.continueRequest',
|
139
234
|
requestId: @interception_id,
|
@@ -162,16 +257,40 @@ class Puppeteer::Request
|
|
162
257
|
# @param headers [Hash<String, String>]
|
163
258
|
# @param content_type [String]
|
164
259
|
# @param body [String]
|
165
|
-
def respond(status: nil, headers: nil, content_type: nil, body: nil)
|
260
|
+
def respond(status: nil, headers: nil, content_type: nil, body: nil, priority: nil)
|
166
261
|
# Mocking responses for dataURL requests is not currently supported.
|
167
262
|
return if @url.start_with?('data:')
|
168
263
|
|
169
|
-
|
170
|
-
|
264
|
+
assert_interception_allowed
|
265
|
+
assert_interception_not_handled
|
266
|
+
|
267
|
+
if priority.nil?
|
268
|
+
respond_impl(status: status, headers: headers, content_type: content_type, body: body)
|
269
|
+
return
|
171
270
|
end
|
172
|
-
|
173
|
-
|
271
|
+
|
272
|
+
@response_for_request = {
|
273
|
+
status: status,
|
274
|
+
headers: headers,
|
275
|
+
content_type: content_type,
|
276
|
+
body: body,
|
277
|
+
}
|
278
|
+
|
279
|
+
if @current_priority.nil? || priority > @current_priority
|
280
|
+
@current_strategy = :respond
|
281
|
+
@current_priority = priority
|
282
|
+
return
|
283
|
+
end
|
284
|
+
|
285
|
+
if priority == @current_priority
|
286
|
+
if @current_strategy == :abort
|
287
|
+
return
|
288
|
+
end
|
289
|
+
@current_strategy = :respond
|
174
290
|
end
|
291
|
+
end
|
292
|
+
|
293
|
+
private def respond_impl(status: nil, headers: nil, content_type: nil, body: nil)
|
175
294
|
@interception_handled = true
|
176
295
|
|
177
296
|
mock_response_headers = {}
|
@@ -191,6 +310,7 @@ class Puppeteer::Request
|
|
191
310
|
responseHeaders: headers_to_array(mock_response_headers),
|
192
311
|
body: if_present(body) { |mock_body| Base64.strict_encode64(mock_body) },
|
193
312
|
}.compact
|
313
|
+
|
194
314
|
begin
|
195
315
|
@client.send_message('Fetch.fulfillRequest',
|
196
316
|
requestId: @interception_id,
|
@@ -216,7 +336,7 @@ class Puppeteer::Request
|
|
216
336
|
# end
|
217
337
|
#
|
218
338
|
# @param error_code [String|Symbol]
|
219
|
-
def abort(error_code: :failed)
|
339
|
+
def abort(error_code: :failed, priority: nil)
|
220
340
|
# Request interception is not supported for data: urls.
|
221
341
|
return if @url.start_with?('data:')
|
222
342
|
|
@@ -224,12 +344,21 @@ class Puppeteer::Request
|
|
224
344
|
unless error_reason
|
225
345
|
raise ArgumentError.new("Unknown error code: #{error_code}")
|
226
346
|
end
|
227
|
-
|
228
|
-
|
347
|
+
assert_interception_allowed
|
348
|
+
assert_interception_not_handled
|
349
|
+
|
350
|
+
if priority.nil?
|
351
|
+
abort_impl(error_reason)
|
229
352
|
end
|
230
|
-
|
231
|
-
|
353
|
+
@abort_error_reason = error_reason
|
354
|
+
|
355
|
+
if @current_priority.nil? || priority > @current_priority
|
356
|
+
@current_strategy = :abort
|
357
|
+
@current_priority = priority
|
232
358
|
end
|
359
|
+
end
|
360
|
+
|
361
|
+
private def abort_impl(error_reason)
|
233
362
|
@interception_handled = true
|
234
363
|
|
235
364
|
begin
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'json'
|
2
2
|
|
3
|
-
class Puppeteer::
|
3
|
+
class Puppeteer::HTTPResponse
|
4
4
|
include Puppeteer::IfPresent
|
5
5
|
|
6
6
|
class Redirected < StandardError
|
@@ -29,7 +29,7 @@ class Puppeteer::Response
|
|
29
29
|
end
|
30
30
|
|
31
31
|
# @param client [Puppeteer::CDPSession]
|
32
|
-
# @param request [Puppeteer::
|
32
|
+
# @param request [Puppeteer::HTTPRequest]
|
33
33
|
# @param response_payload [Hash]
|
34
34
|
def initialize(client, request, response_payload)
|
35
35
|
@client = client
|
@@ -48,7 +48,7 @@ module Puppeteer::Launcher
|
|
48
48
|
if @launch_options.channel
|
49
49
|
executable_path_for_channel(@launch_options.channel.to_s)
|
50
50
|
else
|
51
|
-
@launch_options.executable_path ||
|
51
|
+
@launch_options.executable_path || fallback_executable_path
|
52
52
|
end
|
53
53
|
use_pipe = chrome_arguments.include?('--remote-debugging-pipe')
|
54
54
|
runner = Puppeteer::BrowserRunner.new(chrome_executable, chrome_arguments, temporary_user_data_dir)
|
@@ -216,10 +216,14 @@ module Puppeteer::Launcher
|
|
216
216
|
if channel
|
217
217
|
executable_path_for_channel(channel.to_s)
|
218
218
|
else
|
219
|
-
|
219
|
+
fallback_executable_path
|
220
220
|
end
|
221
221
|
end
|
222
222
|
|
223
|
+
private def fallback_executable_path
|
224
|
+
executable_path_for_channel('chrome')
|
225
|
+
end
|
226
|
+
|
223
227
|
CHROMIUM_CHANNELS = {
|
224
228
|
windows: {
|
225
229
|
'chrome' => "#{ENV['PROGRAMFILES']}\\Google\\Chrome\\Application\\chrome.exe",
|
@@ -236,7 +240,16 @@ module Puppeteer::Launcher
|
|
236
240
|
'msedge' => '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge',
|
237
241
|
},
|
238
242
|
linux: {
|
239
|
-
'chrome' =>
|
243
|
+
'chrome' => -> {
|
244
|
+
Puppeteer::ExecutablePathFinder.new(
|
245
|
+
'google-chrome-stable',
|
246
|
+
'google-chrome',
|
247
|
+
'chrome',
|
248
|
+
'chromium-freeworld',
|
249
|
+
'chromium-browser',
|
250
|
+
'chromium',
|
251
|
+
).find_first
|
252
|
+
},
|
240
253
|
'chrome-beta' => '/opt/google/chrome-beta/chrome',
|
241
254
|
'chrome-dev' => '/opt/google/chrome-unstable/chrome',
|
242
255
|
},
|
@@ -254,6 +267,10 @@ module Puppeteer::Launcher
|
|
254
267
|
end
|
255
268
|
|
256
269
|
chrome_path = chrome_path_map[channel]
|
270
|
+
if chrome_path.is_a?(Proc)
|
271
|
+
chrome_path = chrome_path.call
|
272
|
+
end
|
273
|
+
|
257
274
|
unless chrome_path
|
258
275
|
raise ArgumentError.new("Invalid channel: '#{channel}'. Allowed channel is #{chrome_path_map.keys}")
|
259
276
|
end
|
@@ -42,7 +42,7 @@ module Puppeteer::Launcher
|
|
42
42
|
if @launch_options.channel
|
43
43
|
executable_path_for_channel(@launch_options.channel.to_s)
|
44
44
|
else
|
45
|
-
@launch_options.executable_path ||
|
45
|
+
@launch_options.executable_path || fallback_executable_path
|
46
46
|
end
|
47
47
|
runner = Puppeteer::BrowserRunner.new(firefox_executable, firefox_arguments, temporary_user_data_dir)
|
48
48
|
runner.start(
|
@@ -138,14 +138,18 @@ module Puppeteer::Launcher
|
|
138
138
|
if channel
|
139
139
|
executable_path_for_channel(channel.to_s)
|
140
140
|
else
|
141
|
-
|
141
|
+
fallback_executable_path
|
142
142
|
end
|
143
143
|
end
|
144
144
|
|
145
|
+
private def fallback_executable_path
|
146
|
+
executable_path_for_channel('firefox')
|
147
|
+
end
|
148
|
+
|
145
149
|
FIREFOX_EXECUTABLE_PATHS = {
|
146
150
|
windows: "#{ENV['PROGRAMFILES']}\\Firefox Nightly\\firefox.exe",
|
147
151
|
darwin: '/Applications/Firefox Nightly.app/Contents/MacOS/firefox',
|
148
|
-
linux: '
|
152
|
+
linux: -> { Puppeteer::ExecutablePathFinder.new('firefox').find_first },
|
149
153
|
}.freeze
|
150
154
|
|
151
155
|
# @param channel [String]
|
@@ -163,6 +167,9 @@ module Puppeteer::Launcher
|
|
163
167
|
else
|
164
168
|
FIREFOX_EXECUTABLE_PATHS[:linux]
|
165
169
|
end
|
170
|
+
if firefox_path.is_a?(Proc)
|
171
|
+
firefox_path = firefox_path.call
|
172
|
+
end
|
166
173
|
|
167
174
|
unless File.exist?(firefox_path)
|
168
175
|
raise "Nightly version of Firefox is not installed on this system.\nExpected path: #{firefox_path}"
|
@@ -35,9 +35,9 @@ module Puppeteer::Launcher
|
|
35
35
|
@channel = options[:channel]
|
36
36
|
@executable_path = options[:executable_path]
|
37
37
|
@ignore_default_args = options[:ignore_default_args] || false
|
38
|
-
@handle_SIGINT = options
|
39
|
-
@handle_SIGTERM = options
|
40
|
-
@handle_SIGHUP = options
|
38
|
+
@handle_SIGINT = options.fetch(:handle_SIGINT, true)
|
39
|
+
@handle_SIGTERM = options.fetch(:handle_SIGTERM, true)
|
40
|
+
@handle_SIGHUP = options.fetch(:handle_SIGHUP, true)
|
41
41
|
@timeout = options[:timeout] || 30000
|
42
42
|
@dumpio = options[:dumpio] || false
|
43
43
|
@env = options[:env] || ENV
|
@@ -88,7 +88,7 @@ class Puppeteer::LifecycleWatcher
|
|
88
88
|
check_lifecycle_complete
|
89
89
|
end
|
90
90
|
|
91
|
-
# @param [Puppeteer::
|
91
|
+
# @param [Puppeteer::HTTPRequest] request
|
92
92
|
def handle_request(request)
|
93
93
|
return if request.frame != @frame || !request.navigation_request?
|
94
94
|
@navigation_request = request
|
@@ -103,7 +103,7 @@ class Puppeteer::LifecycleWatcher
|
|
103
103
|
check_lifecycle_complete
|
104
104
|
end
|
105
105
|
|
106
|
-
# @return [Puppeteer::
|
106
|
+
# @return [Puppeteer::HTTPResponse]
|
107
107
|
def navigation_response
|
108
108
|
if_present(@navigation_request) do |request|
|
109
109
|
request.response
|
@@ -142,9 +142,14 @@ class Puppeteer::NetworkManager
|
|
142
142
|
end
|
143
143
|
|
144
144
|
# @param user_agent [String]
|
145
|
-
|
146
|
-
|
145
|
+
# @param user_agent_metadata [Hash]
|
146
|
+
def set_user_agent(user_agent, user_agent_metadata = nil)
|
147
|
+
@client.send_message('Network.setUserAgentOverride', {
|
148
|
+
userAgent: user_agent,
|
149
|
+
userAgentMetadata: user_agent_metadata,
|
150
|
+
}.compact)
|
147
151
|
end
|
152
|
+
alias_method :user_agent=, :set_user_agent
|
148
153
|
|
149
154
|
def cache_enabled=(enabled)
|
150
155
|
@user_cache_disabled = !enabled
|
@@ -246,9 +251,14 @@ class Puppeteer::NetworkManager
|
|
246
251
|
end
|
247
252
|
end
|
248
253
|
frame = if_present(event['frameId']) { |frame_id| @frame_manager.frame(frame_id) }
|
249
|
-
request = Puppeteer::
|
254
|
+
request = Puppeteer::HTTPRequest.new(@client, frame, interception_id, @user_request_interception_enabled, event, redirect_chain)
|
250
255
|
@request_id_to_request[event['requestId']] = request
|
251
256
|
emit_event(NetworkManagerEmittedEvents::Request, request)
|
257
|
+
begin
|
258
|
+
request.finalize_interceptions
|
259
|
+
rescue => err
|
260
|
+
debug_puts(err)
|
261
|
+
end
|
252
262
|
end
|
253
263
|
|
254
264
|
private def handle_request_served_from_cache(event)
|
@@ -257,13 +267,13 @@ class Puppeteer::NetworkManager
|
|
257
267
|
end
|
258
268
|
end
|
259
269
|
|
260
|
-
# @param request [Puppeteer::
|
270
|
+
# @param request [Puppeteer::HTTPRequest]
|
261
271
|
# @param response_payload [Hash]
|
262
272
|
private def handle_request_redirect(request, response_payload)
|
263
|
-
response = Puppeteer::
|
273
|
+
response = Puppeteer::HTTPResponse.new(@client, request, response_payload)
|
264
274
|
request.internal.response = response
|
265
275
|
request.internal.redirect_chain << request
|
266
|
-
response.internal.body_loaded_promise.reject(Puppeteer::
|
276
|
+
response.internal.body_loaded_promise.reject(Puppeteer::HTTPResponse::Redirected.new)
|
267
277
|
@request_id_to_request.delete(request.internal.request_id)
|
268
278
|
@attempted_authentications.delete(request.internal.interception_id)
|
269
279
|
emit_event(NetworkManagerEmittedEvents::Response, response)
|
@@ -276,7 +286,7 @@ class Puppeteer::NetworkManager
|
|
276
286
|
# FileUpload sends a response without a matching request.
|
277
287
|
return unless request
|
278
288
|
|
279
|
-
response = Puppeteer::
|
289
|
+
response = Puppeteer::HTTPResponse.new(@client, request, event['response'])
|
280
290
|
request.internal.response = response
|
281
291
|
emit_event(NetworkManagerEmittedEvents::Response, response)
|
282
292
|
end
|
data/lib/puppeteer/page.rb
CHANGED
@@ -153,6 +153,12 @@ class Puppeteer::Page
|
|
153
153
|
raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{PageEmittedEvents.values.to_a.join(", ")}")
|
154
154
|
end
|
155
155
|
|
156
|
+
if event_name.to_s == 'request'
|
157
|
+
super('request') do |req|
|
158
|
+
req.enqueue_intercept_action(-> { block.call(req) })
|
159
|
+
end
|
160
|
+
end
|
161
|
+
|
156
162
|
super(event_name.to_s, &block)
|
157
163
|
end
|
158
164
|
|
@@ -461,37 +467,6 @@ class Puppeteer::Page
|
|
461
467
|
|
462
468
|
nil
|
463
469
|
end
|
464
|
-
# /**
|
465
|
-
# * @param {string} name
|
466
|
-
# * @param {Function} puppeteerFunction
|
467
|
-
# */
|
468
|
-
# async exposeFunction(name, puppeteerFunction) {
|
469
|
-
# if (this._pageBindings.has(name))
|
470
|
-
# throw new Error(`Failed to add page binding with name ${name}: window['${name}'] already exists!`);
|
471
|
-
# this._pageBindings.set(name, puppeteerFunction);
|
472
|
-
|
473
|
-
# const expression = helper.evaluationString(addPageBinding, name);
|
474
|
-
# await this._client.send('Runtime.addBinding', {name: name});
|
475
|
-
# await this._client.send('Page.addScriptToEvaluateOnNewDocument', {source: expression});
|
476
|
-
# await Promise.all(this.frames().map(frame => frame.evaluate(expression).catch(debugError)));
|
477
|
-
|
478
|
-
# function addPageBinding(bindingName) {
|
479
|
-
# const binding = window[bindingName];
|
480
|
-
# window[bindingName] = (...args) => {
|
481
|
-
# const me = window[bindingName];
|
482
|
-
# let callbacks = me['callbacks'];
|
483
|
-
# if (!callbacks) {
|
484
|
-
# callbacks = new Map();
|
485
|
-
# me['callbacks'] = callbacks;
|
486
|
-
# }
|
487
|
-
# const seq = (me['lastSeq'] || 0) + 1;
|
488
|
-
# me['lastSeq'] = seq;
|
489
|
-
# const promise = new Promise((resolve, reject) => callbacks.set(seq, {resolve, reject}));
|
490
|
-
# binding(JSON.stringify({name: bindingName, seq, args}));
|
491
|
-
# return promise;
|
492
|
-
# };
|
493
|
-
# }
|
494
|
-
# }
|
495
470
|
|
496
471
|
# @param username [String?]
|
497
472
|
# @param password [String?]
|
@@ -505,9 +480,11 @@ class Puppeteer::Page
|
|
505
480
|
end
|
506
481
|
|
507
482
|
# @param user_agent [String]
|
508
|
-
|
509
|
-
|
483
|
+
# @param user_agent_metadata [Hash]
|
484
|
+
def set_user_agent(user_agent, user_agent_metadata = nil)
|
485
|
+
@frame_manager.network_manager.set_user_agent(user_agent, user_agent_metadata)
|
510
486
|
end
|
487
|
+
alias_method :user_agent=, :set_user_agent
|
511
488
|
|
512
489
|
def metrics
|
513
490
|
response = @client.send_message('Performance.getMetrics')
|
@@ -667,7 +644,7 @@ class Puppeteer::Page
|
|
667
644
|
|
668
645
|
# @param timeout [number|nil]
|
669
646
|
# @param wait_until [string|nil] 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2'
|
670
|
-
# @return [Puppeteer::
|
647
|
+
# @return [Puppeteer::HTTPResponse]
|
671
648
|
def reload(timeout: nil, wait_until: nil)
|
672
649
|
wait_for_navigation(timeout: timeout, wait_until: wait_until) do
|
673
650
|
@client.send_message('Page.reload')
|
@@ -697,11 +674,12 @@ class Puppeteer::Page
|
|
697
674
|
@wait_for_network_manager_event_listener_ids[event_name] =
|
698
675
|
@frame_manager.network_manager.add_event_listener(event_name) do |event_target|
|
699
676
|
if predicate.call(event_target)
|
700
|
-
promise.fulfill(
|
677
|
+
promise.fulfill(event_target)
|
701
678
|
end
|
702
679
|
end
|
703
680
|
|
704
681
|
begin
|
682
|
+
# Timeout.timeout(0) means "no limit" for timeout.
|
705
683
|
Timeout.timeout(option_timeout / 1000.0) do
|
706
684
|
await_any(promise, session_close_promise)
|
707
685
|
end
|
@@ -751,7 +729,7 @@ class Puppeteer::Page
|
|
751
729
|
# wait_for_request(predicate: -> (req){ req.url.start_with?('https://example.com/search') })
|
752
730
|
#
|
753
731
|
# @param url [String]
|
754
|
-
# @param predicate [Proc(Puppeteer::
|
732
|
+
# @param predicate [Proc(Puppeteer::HTTPRequest -> Boolean)]
|
755
733
|
define_async_method :async_wait_for_request
|
756
734
|
|
757
735
|
def wait_for_response(url: nil, predicate: nil, timeout: nil)
|
@@ -777,7 +755,7 @@ class Puppeteer::Page
|
|
777
755
|
# @!method async_wait_for_response(url: nil, predicate: nil, timeout: nil)
|
778
756
|
#
|
779
757
|
# @param url [String]
|
780
|
-
# @param predicate [Proc(Puppeteer::
|
758
|
+
# @param predicate [Proc(Puppeteer::HTTPRequest -> Boolean)]
|
781
759
|
define_async_method :async_wait_for_response
|
782
760
|
|
783
761
|
# @param timeout [number|nil]
|
data/lib/puppeteer/version.rb
CHANGED
data/lib/puppeteer/wait_task.rb
CHANGED
@@ -37,7 +37,7 @@ class Puppeteer::WaitTask
|
|
37
37
|
|
38
38
|
# Since page navigation requires us to re-install the pageScript, we should track
|
39
39
|
# timeout on our end.
|
40
|
-
if timeout
|
40
|
+
if timeout && timeout > 0
|
41
41
|
timeout_error = TimeoutError.new(title: title, timeout: timeout)
|
42
42
|
Concurrent::Promises.schedule(timeout / 1000.0) { terminate(timeout_error) unless @timeout_cleared }
|
43
43
|
end
|
data/lib/puppeteer.rb
CHANGED
@@ -33,10 +33,13 @@ require 'puppeteer/dialog'
|
|
33
33
|
require 'puppeteer/dom_world'
|
34
34
|
require 'puppeteer/emulation_manager'
|
35
35
|
require 'puppeteer/exception_details'
|
36
|
+
require 'puppeteer/executable_path_finder'
|
36
37
|
require 'puppeteer/execution_context'
|
37
38
|
require 'puppeteer/file_chooser'
|
38
39
|
require 'puppeteer/frame'
|
39
40
|
require 'puppeteer/frame_manager'
|
41
|
+
require 'puppeteer/http_request'
|
42
|
+
require 'puppeteer/http_response'
|
40
43
|
require 'puppeteer/js_coverage'
|
41
44
|
require 'puppeteer/js_handle'
|
42
45
|
require 'puppeteer/keyboard'
|
@@ -50,8 +53,6 @@ require 'puppeteer/protocol_stream_reader'
|
|
50
53
|
require 'puppeteer/puppeteer'
|
51
54
|
require 'puppeteer/query_handler_manager'
|
52
55
|
require 'puppeteer/remote_object'
|
53
|
-
require 'puppeteer/request'
|
54
|
-
require 'puppeteer/response'
|
55
56
|
require 'puppeteer/target'
|
56
57
|
require 'puppeteer/tracing'
|
57
58
|
require 'puppeteer/timeout_helper'
|
data/puppeteer-ruby.gemspec
CHANGED
@@ -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.
|
35
|
+
spec.add_development_dependency 'rubocop', '~> 1.23.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.37.
|
4
|
+
version: 0.37.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- YusukeIwaki
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-
|
11
|
+
date: 2021-12-05 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.
|
173
|
+
version: 1.23.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.
|
180
|
+
version: 1.23.0
|
181
181
|
- !ruby/object:Gem::Dependency
|
182
182
|
name: rubocop-rspec
|
183
183
|
requirement: !ruby/object:Gem::Requirement
|
@@ -282,11 +282,14 @@ files:
|
|
282
282
|
- lib/puppeteer/event_callbackable.rb
|
283
283
|
- lib/puppeteer/events.rb
|
284
284
|
- lib/puppeteer/exception_details.rb
|
285
|
+
- lib/puppeteer/executable_path_finder.rb
|
285
286
|
- lib/puppeteer/execution_context.rb
|
286
287
|
- lib/puppeteer/file_chooser.rb
|
287
288
|
- lib/puppeteer/frame.rb
|
288
289
|
- lib/puppeteer/frame_manager.rb
|
289
290
|
- lib/puppeteer/geolocation.rb
|
291
|
+
- lib/puppeteer/http_request.rb
|
292
|
+
- lib/puppeteer/http_response.rb
|
290
293
|
- lib/puppeteer/if_present.rb
|
291
294
|
- lib/puppeteer/js_coverage.rb
|
292
295
|
- lib/puppeteer/js_handle.rb
|
@@ -313,8 +316,6 @@ files:
|
|
313
316
|
- lib/puppeteer/puppeteer.rb
|
314
317
|
- lib/puppeteer/query_handler_manager.rb
|
315
318
|
- lib/puppeteer/remote_object.rb
|
316
|
-
- lib/puppeteer/request.rb
|
317
|
-
- lib/puppeteer/response.rb
|
318
319
|
- lib/puppeteer/target.rb
|
319
320
|
- lib/puppeteer/timeout_helper.rb
|
320
321
|
- lib/puppeteer/timeout_settings.rb
|