puppeteer-ruby 0.37.0 → 0.37.4

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9e46056e6227e597554a407d47c132610af952d42b1cd7c2149e2046e0d8f1bb
4
- data.tar.gz: 99a5c6fd6885181e32c72086a768c60583738974a3c86a05a693af2b97b51bc3
3
+ metadata.gz: '000206932f5d3d4626602e984cff4015039644eea2ef89ff139b239fffb9f673'
4
+ data.tar.gz: 0e560f862a3317a42c1e0e2907c599bc654d05e3f17fd5a650126b73bfd6948e
5
5
  SHA512:
6
- metadata.gz: d4b1032b52bb5a0ad92e57f0bac5fe5208b785679f1d7efff0ab335cb28478f6110979102d0ec4759ef2f86654b4d231e018aa9cdb3982dc1ffa2e985fa4c55f
7
- data.tar.gz: 42f81fe580fcb85b5c57397962362c3c6b0ba7462fe210c65ee017b9e73c0a3d9d091c03a7b18f6e6d78f3a3c52572a5d0bb8284f1087412344a184e8624170d
6
+ metadata.gz: aac4be4a26f3116eee198ea65c0017359589f2ad11cc95125497e3f84ea1277d9bbb8d1071b57fb42812bb12afd4370534c48586fbb79897acafb54d03222159
7
+ data.tar.gz: de51d1ca30e26e13346532118df225370fad4b1967d205dad0c150574c4fa60a649973aab83e24b2140b8f98f05626eb106a9141f04b94fe5d3927b1231737d4
data/CHANGELOG.md CHANGED
@@ -1,7 +1,31 @@
1
- ### master [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.37.0...master)]
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: ['--guest', '--window-size=1280,800']) do |browser|
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: v10.4.0
3
- - puppeteer-ruby version: 0.37.0
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
- ## ~~HTTPRequest~~
299
-
300
- * ~~abort~~
301
- * ~~abortErrorReason~~
302
- * ~~continue~~
303
- * ~~continueRequestOverrides~~
304
- * ~~enqueueInterceptAction~~
305
- * ~~failure~~
306
- * ~~finalizeInterceptions~~
307
- * ~~frame~~
308
- * ~~headers~~
309
- * ~~isNavigationRequest~~
310
- * ~~method~~
311
- * ~~postData~~
312
- * ~~redirectChain~~
313
- * ~~resourceType~~
314
- * ~~respond~~
315
- * ~~response~~
316
- * ~~responseForRequest~~
317
- * ~~url~~
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
- ## ~~HTTPResponse~~
322
+ ## HTTPResponse
320
323
 
321
- * ~~buffer~~
322
- * ~~frame~~
324
+ * buffer
325
+ * frame
323
326
  * ~~fromCache~~
324
327
  * ~~fromServiceWorker~~
325
- * ~~headers~~
326
- * ~~json~~
328
+ * headers
329
+ * json
327
330
  * ~~ok~~
328
- * ~~remoteAddress~~
329
- * ~~request~~
330
- * ~~securityDetails~~
331
- * ~~status~~
332
- * ~~statusText~~
333
- * ~~text~~
334
- * ~~url~~
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
@@ -94,7 +94,7 @@ class Puppeteer::BrowserRunner
94
94
  FileUtils.rm_rf(@temp_directory)
95
95
  end
96
96
  }
97
- trap(:EXIT) do
97
+ at_exit do
98
98
  kill
99
99
  end
100
100
 
@@ -323,7 +323,7 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
323
323
  end
324
324
  end
325
325
 
326
- def screenshot(options = {})
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
- x: page_x + box.x,
363
- y: page_y + box.y,
364
- width: box.width,
365
- height: box.height,
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({ clip: clip }.merge(options))
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
@@ -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::Response]
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::Response]
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::Response]
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::Request
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::Response]
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
- unless @allow_interception
124
- raise InterceptionNotEnabledError.new
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
- post_data: post_data,
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
- unless @allow_interception
170
- raise InterceptionNotEnabledError.new
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
- if @interception_handled
173
- raise AlreadyHandledError.new
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
- unless @allow_interception
228
- raise InterceptionNotEnabledError.new
347
+ assert_interception_allowed
348
+ assert_interception_not_handled
349
+
350
+ if priority.nil?
351
+ abort_impl(error_reason)
229
352
  end
230
- if @interception_handled
231
- raise AlreadyHandledError.new
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::Response
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::Request]
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 || executable_path_for_channel('chrome')
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
- executable_path_for_channel('chrome')
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' => '/opt/google/chrome/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 || executable_path_for_channel('nightly')
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
- executable_path_for_channel('firefox')
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: '/usr/bin/firefox',
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[:handle_SIGINT] || true
39
- @handle_SIGTERM = options[:handle_SIGTERM] || true
40
- @handle_SIGHUP = options[:handle_SIGHUP] || true
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::Request] request
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::Response]
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
- def user_agent=(user_agent)
146
- @client.send_message('Network.setUserAgentOverride', userAgent: user_agent)
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::Request.new(@client, frame, interception_id, @user_request_interception_enabled, event, redirect_chain)
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::Request]
270
+ # @param request [Puppeteer::HTTPRequest]
261
271
  # @param response_payload [Hash]
262
272
  private def handle_request_redirect(request, response_payload)
263
- response = Puppeteer::Response.new(@client, request, response_payload)
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::Response::Redirected.new)
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::Response.new(@client, request, event['response'])
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
@@ -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
- def user_agent=(user_agent)
509
- @frame_manager.network_manager.user_agent = user_agent
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::Response]
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(nil)
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::Request -> Boolean)]
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::Request -> Boolean)]
758
+ # @param predicate [Proc(Puppeteer::HTTPRequest -> Boolean)]
781
759
  define_async_method :async_wait_for_response
782
760
 
783
761
  # @param timeout [number|nil]
@@ -1,3 +1,3 @@
1
1
  module Puppeteer
2
- VERSION = '0.37.0'
2
+ VERSION = '0.37.4'
3
3
  end
@@ -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'
@@ -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.21.0'
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.0
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-09-29 00:00:00.000000000 Z
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.21.0
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.21.0
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