puppeteer-ruby 0.37.1 → 0.38.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 +4 -4
- data/CHANGELOG.md +31 -1
- data/README.md +1 -1
- data/docs/api_coverage.md +38 -34
- data/lib/puppeteer/cdp_session.rb +5 -0
- data/lib/puppeteer/dom_world.rb +9 -5
- data/lib/puppeteer/element_handle.rb +10 -8
- data/lib/puppeteer/executable_path_finder.rb +28 -0
- data/lib/puppeteer/frame.rb +31 -9
- data/lib/puppeteer/frame_manager.rb +138 -61
- data/lib/puppeteer/{request.rb → http_request.rb} +159 -22
- data/lib/puppeteer/{response.rb → http_response.rb} +2 -2
- data/lib/puppeteer/launcher/chrome.rb +26 -6
- data/lib/puppeteer/launcher/chrome_arg_options.rb +2 -1
- data/lib/puppeteer/launcher/firefox.rb +16 -6
- data/lib/puppeteer/lifecycle_watcher.rb +2 -2
- data/lib/puppeteer/network_manager.rb +10 -5
- data/lib/puppeteer/page/screenshot_options.rb +1 -1
- data/lib/puppeteer/page.rb +85 -22
- data/lib/puppeteer/puppeteer.rb +2 -0
- data/lib/puppeteer/target.rb +5 -0
- 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
@@ -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
|
@@ -66,7 +72,85 @@ class Puppeteer::Request
|
|
66
72
|
end
|
67
73
|
|
68
74
|
attr_reader :internal
|
69
|
-
attr_reader :url, :resource_type, :method, :post_data, :headers, :response, :frame
|
75
|
+
attr_reader :url, :resource_type, :method, :post_data, :headers, :response, :frame, :initiator
|
76
|
+
|
77
|
+
def inspect
|
78
|
+
values = %i[request_id method url].map do |sym|
|
79
|
+
value = instance_variable_get(:"@#{sym}")
|
80
|
+
"@#{sym}=#{value}"
|
81
|
+
end
|
82
|
+
"#<Puppeteer::HTTPRequest #{values.join(' ')}>"
|
83
|
+
end
|
84
|
+
|
85
|
+
private def assert_interception_allowed
|
86
|
+
unless @allow_interception
|
87
|
+
raise InterceptionNotEnabledError.new
|
88
|
+
end
|
89
|
+
end
|
90
|
+
|
91
|
+
private def assert_interception_not_handled
|
92
|
+
if @interception_handled
|
93
|
+
raise AlreadyHandledError.new
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
# @returns the `ContinueRequestOverrides` that will be used
|
98
|
+
# if the interception is allowed to continue (ie, `abort()` and
|
99
|
+
# `respond()` aren't called).
|
100
|
+
def continue_request_overrides
|
101
|
+
assert_interception_allowed
|
102
|
+
@continue_request_overrides
|
103
|
+
end
|
104
|
+
|
105
|
+
# @returns The `ResponseForRequest` that gets used if the
|
106
|
+
# interception is allowed to respond (ie, `abort()` is not called).
|
107
|
+
def response_for_request
|
108
|
+
assert_interception_allowed
|
109
|
+
@response_for_request
|
110
|
+
end
|
111
|
+
|
112
|
+
# @returns the most recent reason for aborting the request
|
113
|
+
def abort_error_reason
|
114
|
+
assert_interception_allowed
|
115
|
+
@abort_error_reason
|
116
|
+
end
|
117
|
+
|
118
|
+
# @returns An array of the current intercept resolution strategy and priority
|
119
|
+
# `[strategy,priority]`. Strategy is one of: `abort`, `respond`, `continue`,
|
120
|
+
# `disabled`, `none`, or `already-handled`.
|
121
|
+
def intercept_resolution
|
122
|
+
if !@allow_interception
|
123
|
+
['disabled']
|
124
|
+
elsif @interception_handled
|
125
|
+
['already-handled']
|
126
|
+
else
|
127
|
+
[@current_strategy, @current_priority]
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
# Adds an async request handler to the processing queue.
|
132
|
+
# Deferred handlers are not guaranteed to execute in any particular order,
|
133
|
+
# but they are guarnateed to resolve before the request interception
|
134
|
+
# is finalized.
|
135
|
+
#
|
136
|
+
# @param pending_handler [Proc]
|
137
|
+
def enqueue_intercept_action(pending_handler)
|
138
|
+
@intercept_actions << pending_handler
|
139
|
+
end
|
140
|
+
|
141
|
+
# Awaits pending interception handlers and then decides how to fulfill
|
142
|
+
# the request interception.
|
143
|
+
def finalize_interceptions
|
144
|
+
@intercept_actions.each(&:call)
|
145
|
+
case @intercept_resolution
|
146
|
+
when :abort
|
147
|
+
abort_impl(**@abort_error_reason)
|
148
|
+
when :respond
|
149
|
+
respond_impl(**@response_for_request)
|
150
|
+
when :continue
|
151
|
+
continue_impl(@continue_request_overrides)
|
152
|
+
end
|
153
|
+
end
|
70
154
|
|
71
155
|
def navigation_request?
|
72
156
|
@is_navigation_request
|
@@ -116,24 +200,43 @@ class Puppeteer::Request
|
|
116
200
|
# end
|
117
201
|
#
|
118
202
|
# @param error_code [String|Symbol]
|
119
|
-
def continue(url: nil, method: nil, post_data: nil, headers: nil)
|
203
|
+
def continue(url: nil, method: nil, post_data: nil, headers: nil, priority: nil)
|
120
204
|
# Request interception is not supported for data: urls.
|
121
205
|
return if @url.start_with?('data:')
|
122
206
|
|
123
|
-
|
124
|
-
|
125
|
-
end
|
126
|
-
if @interception_handled
|
127
|
-
raise AlreadyHandledError.new
|
128
|
-
end
|
129
|
-
@interception_handled = true
|
207
|
+
assert_interception_allowed
|
208
|
+
assert_interception_not_handled
|
130
209
|
|
131
210
|
overrides = {
|
132
211
|
url: url,
|
133
212
|
method: method,
|
134
|
-
|
213
|
+
postData: post_data,
|
135
214
|
headers: headers_to_array(headers),
|
136
215
|
}.compact
|
216
|
+
|
217
|
+
if priority.nil?
|
218
|
+
continue_impl(overrides)
|
219
|
+
return
|
220
|
+
end
|
221
|
+
|
222
|
+
@continue_request_overrides = overrides
|
223
|
+
if @current_priority.nil? || priority > @current_priority
|
224
|
+
@current_strategy = :continue
|
225
|
+
@current_priority = priority
|
226
|
+
return
|
227
|
+
end
|
228
|
+
|
229
|
+
if priority == @current_priority
|
230
|
+
if @current_strategy == :abort || @current_strategy == :respond
|
231
|
+
return
|
232
|
+
end
|
233
|
+
@current_strategy = :continue
|
234
|
+
end
|
235
|
+
end
|
236
|
+
|
237
|
+
private def continue_impl(overrides)
|
238
|
+
@interception_handled = true
|
239
|
+
|
137
240
|
begin
|
138
241
|
@client.send_message('Fetch.continueRequest',
|
139
242
|
requestId: @interception_id,
|
@@ -162,16 +265,40 @@ class Puppeteer::Request
|
|
162
265
|
# @param headers [Hash<String, String>]
|
163
266
|
# @param content_type [String]
|
164
267
|
# @param body [String]
|
165
|
-
def respond(status: nil, headers: nil, content_type: nil, body: nil)
|
268
|
+
def respond(status: nil, headers: nil, content_type: nil, body: nil, priority: nil)
|
166
269
|
# Mocking responses for dataURL requests is not currently supported.
|
167
270
|
return if @url.start_with?('data:')
|
168
271
|
|
169
|
-
|
170
|
-
|
272
|
+
assert_interception_allowed
|
273
|
+
assert_interception_not_handled
|
274
|
+
|
275
|
+
if priority.nil?
|
276
|
+
respond_impl(status: status, headers: headers, content_type: content_type, body: body)
|
277
|
+
return
|
171
278
|
end
|
172
|
-
|
173
|
-
|
279
|
+
|
280
|
+
@response_for_request = {
|
281
|
+
status: status,
|
282
|
+
headers: headers,
|
283
|
+
content_type: content_type,
|
284
|
+
body: body,
|
285
|
+
}
|
286
|
+
|
287
|
+
if @current_priority.nil? || priority > @current_priority
|
288
|
+
@current_strategy = :respond
|
289
|
+
@current_priority = priority
|
290
|
+
return
|
291
|
+
end
|
292
|
+
|
293
|
+
if priority == @current_priority
|
294
|
+
if @current_strategy == :abort
|
295
|
+
return
|
296
|
+
end
|
297
|
+
@current_strategy = :respond
|
174
298
|
end
|
299
|
+
end
|
300
|
+
|
301
|
+
private def respond_impl(status: nil, headers: nil, content_type: nil, body: nil)
|
175
302
|
@interception_handled = true
|
176
303
|
|
177
304
|
mock_response_headers = {}
|
@@ -191,6 +318,7 @@ class Puppeteer::Request
|
|
191
318
|
responseHeaders: headers_to_array(mock_response_headers),
|
192
319
|
body: if_present(body) { |mock_body| Base64.strict_encode64(mock_body) },
|
193
320
|
}.compact
|
321
|
+
|
194
322
|
begin
|
195
323
|
@client.send_message('Fetch.fulfillRequest',
|
196
324
|
requestId: @interception_id,
|
@@ -216,7 +344,7 @@ class Puppeteer::Request
|
|
216
344
|
# end
|
217
345
|
#
|
218
346
|
# @param error_code [String|Symbol]
|
219
|
-
def abort(error_code: :failed)
|
347
|
+
def abort(error_code: :failed, priority: nil)
|
220
348
|
# Request interception is not supported for data: urls.
|
221
349
|
return if @url.start_with?('data:')
|
222
350
|
|
@@ -224,12 +352,21 @@ class Puppeteer::Request
|
|
224
352
|
unless error_reason
|
225
353
|
raise ArgumentError.new("Unknown error code: #{error_code}")
|
226
354
|
end
|
227
|
-
|
228
|
-
|
355
|
+
assert_interception_allowed
|
356
|
+
assert_interception_not_handled
|
357
|
+
|
358
|
+
if priority.nil?
|
359
|
+
abort_impl(error_reason)
|
229
360
|
end
|
230
|
-
|
231
|
-
|
361
|
+
@abort_error_reason = error_reason
|
362
|
+
|
363
|
+
if @current_priority.nil? || priority > @current_priority
|
364
|
+
@current_strategy = :abort
|
365
|
+
@current_priority = priority
|
232
366
|
end
|
367
|
+
end
|
368
|
+
|
369
|
+
private def abort_impl(error_reason)
|
233
370
|
@interception_handled = true
|
234
371
|
|
235
372
|
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
|
@@ -34,13 +34,13 @@ module Puppeteer::Launcher
|
|
34
34
|
if @launch_options.pipe?
|
35
35
|
chrome_arguments << '--remote-debugging-pipe'
|
36
36
|
else
|
37
|
-
chrome_arguments <<
|
37
|
+
chrome_arguments << "--remote-debugging-port=#{@chrome_arg_options.debugging_port}"
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
41
|
temporary_user_data_dir = nil
|
42
42
|
if chrome_arguments.none? { |arg| arg.start_with?('--user-data-dir') }
|
43
|
-
temporary_user_data_dir = Dir.mktmpdir('puppeteer_dev_chrome_profile-')
|
43
|
+
temporary_user_data_dir = Dir.mktmpdir('puppeteer_dev_chrome_profile-', ENV['PUPPETEER_TMP_DIR'])
|
44
44
|
chrome_arguments << "--user-data-dir=#{temporary_user_data_dir}"
|
45
45
|
end
|
46
46
|
|
@@ -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)
|
@@ -78,7 +78,10 @@ module Puppeteer::Launcher
|
|
78
78
|
close_callback: -> { runner.close },
|
79
79
|
)
|
80
80
|
|
81
|
-
browser.wait_for_target(
|
81
|
+
browser.wait_for_target(
|
82
|
+
predicate: ->(target) { target.type == 'page' },
|
83
|
+
timeout: @launch_options.timeout,
|
84
|
+
)
|
82
85
|
|
83
86
|
browser
|
84
87
|
rescue
|
@@ -216,10 +219,14 @@ module Puppeteer::Launcher
|
|
216
219
|
if channel
|
217
220
|
executable_path_for_channel(channel.to_s)
|
218
221
|
else
|
219
|
-
|
222
|
+
fallback_executable_path
|
220
223
|
end
|
221
224
|
end
|
222
225
|
|
226
|
+
private def fallback_executable_path
|
227
|
+
executable_path_for_channel('chrome')
|
228
|
+
end
|
229
|
+
|
223
230
|
CHROMIUM_CHANNELS = {
|
224
231
|
windows: {
|
225
232
|
'chrome' => "#{ENV['PROGRAMFILES']}\\Google\\Chrome\\Application\\chrome.exe",
|
@@ -236,7 +243,16 @@ module Puppeteer::Launcher
|
|
236
243
|
'msedge' => '/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft Edge',
|
237
244
|
},
|
238
245
|
linux: {
|
239
|
-
'chrome' =>
|
246
|
+
'chrome' => -> {
|
247
|
+
Puppeteer::ExecutablePathFinder.new(
|
248
|
+
'google-chrome-stable',
|
249
|
+
'google-chrome',
|
250
|
+
'chrome',
|
251
|
+
'chromium-freeworld',
|
252
|
+
'chromium-browser',
|
253
|
+
'chromium',
|
254
|
+
).find_first
|
255
|
+
},
|
240
256
|
'chrome-beta' => '/opt/google/chrome-beta/chrome',
|
241
257
|
'chrome-dev' => '/opt/google/chrome-unstable/chrome',
|
242
258
|
},
|
@@ -254,6 +270,10 @@ module Puppeteer::Launcher
|
|
254
270
|
end
|
255
271
|
|
256
272
|
chrome_path = chrome_path_map[channel]
|
273
|
+
if chrome_path.is_a?(Proc)
|
274
|
+
chrome_path = chrome_path.call
|
275
|
+
end
|
276
|
+
|
257
277
|
unless chrome_path
|
258
278
|
raise ArgumentError.new("Invalid channel: '#{channel}'. Allowed channel is #{chrome_path_map.keys}")
|
259
279
|
end
|
@@ -34,9 +34,10 @@ module Puppeteer::Launcher
|
|
34
34
|
if @headless.nil?
|
35
35
|
@headless = !@devtools
|
36
36
|
end
|
37
|
+
@debugging_port = options[:debugging_port] || 0
|
37
38
|
end
|
38
39
|
|
39
|
-
attr_reader :args, :user_data_dir
|
40
|
+
attr_reader :args, :user_data_dir, :debugging_port
|
40
41
|
|
41
42
|
def headless?
|
42
43
|
@headless
|
@@ -28,7 +28,7 @@ module Puppeteer::Launcher
|
|
28
28
|
end
|
29
29
|
|
30
30
|
if firefox_arguments.none? { |arg| arg.start_with?('--remote-debugging-') }
|
31
|
-
firefox_arguments <<
|
31
|
+
firefox_arguments << "--remote-debugging-port=#{@chrome_arg_options.debugging_port}"
|
32
32
|
end
|
33
33
|
|
34
34
|
temporary_user_data_dir = nil
|
@@ -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(
|
@@ -71,7 +71,10 @@ module Puppeteer::Launcher
|
|
71
71
|
close_callback: -> { runner.close },
|
72
72
|
)
|
73
73
|
|
74
|
-
browser.wait_for_target(
|
74
|
+
browser.wait_for_target(
|
75
|
+
predicate: ->(target) { target.type == 'page' },
|
76
|
+
timeout: @launch_options.timeout,
|
77
|
+
)
|
75
78
|
|
76
79
|
browser
|
77
80
|
rescue
|
@@ -138,14 +141,18 @@ module Puppeteer::Launcher
|
|
138
141
|
if channel
|
139
142
|
executable_path_for_channel(channel.to_s)
|
140
143
|
else
|
141
|
-
|
144
|
+
fallback_executable_path
|
142
145
|
end
|
143
146
|
end
|
144
147
|
|
148
|
+
private def fallback_executable_path
|
149
|
+
executable_path_for_channel('firefox')
|
150
|
+
end
|
151
|
+
|
145
152
|
FIREFOX_EXECUTABLE_PATHS = {
|
146
153
|
windows: "#{ENV['PROGRAMFILES']}\\Firefox Nightly\\firefox.exe",
|
147
154
|
darwin: '/Applications/Firefox Nightly.app/Contents/MacOS/firefox',
|
148
|
-
linux: '
|
155
|
+
linux: -> { Puppeteer::ExecutablePathFinder.new('firefox').find_first },
|
149
156
|
}.freeze
|
150
157
|
|
151
158
|
# @param channel [String]
|
@@ -163,6 +170,9 @@ module Puppeteer::Launcher
|
|
163
170
|
else
|
164
171
|
FIREFOX_EXECUTABLE_PATHS[:linux]
|
165
172
|
end
|
173
|
+
if firefox_path.is_a?(Proc)
|
174
|
+
firefox_path = firefox_path.call
|
175
|
+
end
|
166
176
|
|
167
177
|
unless File.exist?(firefox_path)
|
168
178
|
raise "Nightly version of Firefox is not installed on this system.\nExpected path: #{firefox_path}"
|
@@ -221,7 +231,7 @@ module Puppeteer::Launcher
|
|
221
231
|
end
|
222
232
|
|
223
233
|
private def create_profile(extra_prefs = {})
|
224
|
-
Dir.mktmpdir('puppeteer_dev_firefox_profile-').tap do |profile_path|
|
234
|
+
Dir.mktmpdir('puppeteer_dev_firefox_profile-', ENV['PUPPETEER_TMP_DIR']).tap do |profile_path|
|
225
235
|
server = 'dummy.test'
|
226
236
|
default_preferences = {
|
227
237
|
# Make sure Shield doesn't hit the network.
|
@@ -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
|
@@ -251,9 +251,14 @@ class Puppeteer::NetworkManager
|
|
251
251
|
end
|
252
252
|
end
|
253
253
|
frame = if_present(event['frameId']) { |frame_id| @frame_manager.frame(frame_id) }
|
254
|
-
request = Puppeteer::
|
254
|
+
request = Puppeteer::HTTPRequest.new(@client, frame, interception_id, @user_request_interception_enabled, event, redirect_chain)
|
255
255
|
@request_id_to_request[event['requestId']] = request
|
256
256
|
emit_event(NetworkManagerEmittedEvents::Request, request)
|
257
|
+
begin
|
258
|
+
request.finalize_interceptions
|
259
|
+
rescue => err
|
260
|
+
debug_puts(err)
|
261
|
+
end
|
257
262
|
end
|
258
263
|
|
259
264
|
private def handle_request_served_from_cache(event)
|
@@ -262,13 +267,13 @@ class Puppeteer::NetworkManager
|
|
262
267
|
end
|
263
268
|
end
|
264
269
|
|
265
|
-
# @param request [Puppeteer::
|
270
|
+
# @param request [Puppeteer::HTTPRequest]
|
266
271
|
# @param response_payload [Hash]
|
267
272
|
private def handle_request_redirect(request, response_payload)
|
268
|
-
response = Puppeteer::
|
273
|
+
response = Puppeteer::HTTPResponse.new(@client, request, response_payload)
|
269
274
|
request.internal.response = response
|
270
275
|
request.internal.redirect_chain << request
|
271
|
-
response.internal.body_loaded_promise.reject(Puppeteer::
|
276
|
+
response.internal.body_loaded_promise.reject(Puppeteer::HTTPResponse::Redirected.new)
|
272
277
|
@request_id_to_request.delete(request.internal.request_id)
|
273
278
|
@attempted_authentications.delete(request.internal.interception_id)
|
274
279
|
emit_event(NetworkManagerEmittedEvents::Response, response)
|
@@ -281,7 +286,7 @@ class Puppeteer::NetworkManager
|
|
281
286
|
# FileUpload sends a response without a matching request.
|
282
287
|
return unless request
|
283
288
|
|
284
|
-
response = Puppeteer::
|
289
|
+
response = Puppeteer::HTTPResponse.new(@client, request, event['response'])
|
285
290
|
request.internal.response = response
|
286
291
|
emit_event(NetworkManagerEmittedEvents::Response, response)
|
287
292
|
end
|
@@ -34,7 +34,7 @@ class Puppeteer::Page
|
|
34
34
|
@type ||= 'png'
|
35
35
|
|
36
36
|
if options[:quality]
|
37
|
-
|
37
|
+
if @type != 'jpeg' && @type != 'webp'
|
38
38
|
raise ArgumentError.new("options.quality is unsupported for the #{@type} screenshots")
|
39
39
|
end
|
40
40
|
unless options[:quality].is_a?(Numeric)
|