puppeteer-ruby 0.38.0 → 0.40.2

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: d18f0aae5e331fee42f66c8140bdc3cced9c0514a03ab65460c4036a94bc6eb2
4
- data.tar.gz: babeb261ac3661a6738eb3d02dddeef22685590791fbd579483edd2da7800606
3
+ metadata.gz: e88033f07007a1841f99535a96497bef2aa35b58e0599d51886ec760ef8f8201
4
+ data.tar.gz: 3b4b69f023861cc24a4ecf402e2b6eff0cba0d57fbef37991996964a1b57007b
5
5
  SHA512:
6
- metadata.gz: 0d70da4b6dc257f39d020286672180d93a4fe2aa321828035eeba80aeff92e7b1f28ff07acd15396d03aad33ab84b4f3474f1c75b587cb833d90f17dde4b024f
7
- data.tar.gz: ccb8a58f1ffff28d1498c560c8f17671064ca00ce4b98af9dbc5e844ab1c77d9c28fc503c021ae019d9e799a287976fe01a88bbce3f87979d163f7d384336c0e
6
+ metadata.gz: 6e63bd3b526e4cc09f309fc206f9395618393ab104438e93eebc190e3efa36a7e12e3037388480b9dd735121f752cbbd0bd5dc1152ae39a57be6f855dc41b41f
7
+ data.tar.gz: fe6dff5b5b82813c003e67725868a467e2e9b43e16c4bf4bca1eb48c588daa2efd782d4c1c6b351117a3cfbf7daea4feb37b36fde3637abacea33cd2e3244cb4
data/.rubocop.yml CHANGED
@@ -149,6 +149,8 @@ Style/MethodCallWithArgsParentheses:
149
149
  # utils
150
150
  - debug_print
151
151
  - debug_puts
152
+ - exit
153
+ - puts
152
154
 
153
155
  Style/MethodCallWithoutArgsParentheses:
154
156
  Enabled: true
data/CHANGELOG.md CHANGED
@@ -1,7 +1,35 @@
1
- ### main [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.38.0...main)]
1
+ ### main [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.40.2...main)]
2
2
 
3
3
  - xxx
4
4
 
5
+ ### 0.40.2 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.40.1...0.40.2)]
6
+
7
+ Bugfix:
8
+
9
+ - Fix crash on setting response listener [#195](https://github.com/YusukeIwaki/puppeteer-ruby/pull/195)
10
+
11
+ ### 0.40.1 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.40.0...0.40.1)]
12
+
13
+ Bugfix:
14
+
15
+ - Fix error on reload [#190](https://github.com/YusukeIwaki/puppeteer-ruby/pull/190)
16
+ - Fix error message on failing to find Chrome executable.
17
+ - Fix apidoc
18
+
19
+ ### 0.40.0 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.39.0...0.40.0)]
20
+
21
+ New features:
22
+
23
+ - Puppeteer 13.0, 13.1 functionalities
24
+ - Support Ruby 3.1
25
+
26
+
27
+ ### 0.39.0 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.38.0...0.39.0)]
28
+
29
+ New features:
30
+
31
+ - Puppeteer 12.0 functionalities
32
+
5
33
  ### 0.38.0 [[diff](https://github.com/YusukeIwaki/puppeteer-ruby/compare/0.37.4...0.38.0)]
6
34
 
7
35
  New features:
data/docs/api_coverage.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # API coverages
2
- - Puppeteer version: v12.0.0
3
- - puppeteer-ruby version: 0.38.0
2
+ - Puppeteer version: v13.0.1
3
+ - puppeteer-ruby version: 0.40.2
4
4
 
5
5
  ## Puppeteer
6
6
 
@@ -296,6 +296,7 @@
296
296
  * ~~toString~~
297
297
  * type => `#type_text`
298
298
  * uploadFile => `#upload_file`
299
+ * waitForSelector => `#wait_for_selector`
299
300
 
300
301
  ## HTTPRequest
301
302
 
@@ -309,6 +310,8 @@
309
310
  * frame
310
311
  * headers
311
312
  * initiator
313
+ * ~~interceptResolutionState~~
314
+ * ~~isInterceptResolutionHandled~~
312
315
  * isNavigationRequest => `#navigation_request?`
313
316
  * method
314
317
  * postData => `#post_data`
@@ -7,10 +7,10 @@ class Puppeteer::AriaQueryHandler
7
7
  private def parse_aria_selector(selector)
8
8
  known_attributes = %w(name role)
9
9
  query_options = {}
10
- attribute_regexp = /\[\s*(?<attribute>\w+)\s*=\s*"(?<value>\\.|[^"\\]*)"\s*\]/
10
+ attribute_regexp = /\[\s*(?<attribute>\w+)\s*=\s*(?<quote>"|')(?<value>\\.|.*?(?=\k<quote>))\k<quote>\s*\]/
11
11
  default_name = selector.gsub(attribute_regexp) do
12
12
  attribute = $1.strip
13
- value = $2
13
+ value = $3
14
14
  unless known_attributes.include?(attribute)
15
15
  raise ArgumentError.new("Unkown aria attribute \"#{attribute}\" in selector")
16
16
  end
@@ -36,10 +36,11 @@ class Puppeteer::AriaQueryHandler
36
36
  end
37
37
  end
38
38
 
39
- def wait_for(dom_world, selector, visible: nil, hidden: nil, timeout: nil)
39
+ def wait_for(dom_world, selector, visible: nil, hidden: nil, timeout: nil, root: nil)
40
+ # addHandlerToWorld
40
41
  binding_function = Puppeteer::DOMWorld::BindingFunction.new(
41
42
  name: 'ariaQuerySelector',
42
- proc: -> (selector) { query_one(dom_world.send(:document), selector) },
43
+ proc: -> (sel) { query_one(root || dom_world.send(:document), sel) },
43
44
  )
44
45
  dom_world.send(:wait_for_selector_in_page,
45
46
  '(_, selector) => globalThis.ariaQuerySelector(selector)',
@@ -47,7 +48,9 @@ class Puppeteer::AriaQueryHandler
47
48
  visible: visible,
48
49
  hidden: hidden,
49
50
  timeout: timeout,
50
- binding_function: binding_function)
51
+ binding_function: binding_function,
52
+ root: root,
53
+ )
51
54
  end
52
55
 
53
56
  def query_all(element, selector)
@@ -4,13 +4,17 @@ require 'timeout'
4
4
 
5
5
  # https://github.com/puppeteer/puppeteer/blob/master/lib/Launcher.js
6
6
  class Puppeteer::BrowserRunner
7
+ include Puppeteer::DebugPrint
8
+
7
9
  # @param {string} executablePath
8
10
  # @param {!Array<string>} processArguments
9
11
  # @param {string=} tempDirectory
10
- def initialize(executable_path, process_arguments, temp_directory)
12
+ def initialize(for_firefox, executable_path, process_arguments, user_data_dir, using_temp_user_data_dir)
13
+ @for_firefox = for_firefox
11
14
  @executable_path = executable_path
12
15
  @process_arguments = process_arguments
13
- @temp_directory = temp_directory
16
+ @user_data_dir = user_data_dir
17
+ @using_temp_user_data_dir = using_temp_user_data_dir
14
18
  @proc = nil
15
19
  @connection = nil
16
20
  @closed = true
@@ -90,8 +94,8 @@ class Puppeteer::BrowserRunner
90
94
  @process_closing = -> {
91
95
  @proc.dispose
92
96
  @closed = true
93
- if @temp_directory
94
- FileUtils.rm_rf(@temp_directory)
97
+ if @using_temp_user_data_dir
98
+ FileUtils.rm_rf(@user_data_dir)
95
99
  end
96
100
  }
97
101
  at_exit do
@@ -122,7 +126,7 @@ class Puppeteer::BrowserRunner
122
126
  def close
123
127
  return if @closed
124
128
 
125
- if @temp_directory
129
+ if @using_temp_user_data_dir && !@for_firefox
126
130
  kill
127
131
  elsif @connection
128
132
  begin
@@ -137,11 +141,18 @@ class Puppeteer::BrowserRunner
137
141
 
138
142
  # @return {Promise}
139
143
  def kill
140
- if @temp_directory
141
- FileUtils.rm_rf(@temp_directory)
142
- end
143
- unless @closed
144
- @proc.kill
144
+ # If the process failed to launch (for example if the browser executable path
145
+ # is invalid), then the process does not get a pid assigned. A call to
146
+ # `proc.kill` would error, as the `pid` to-be-killed can not be found.
147
+ @proc&.kill
148
+
149
+ # Attempt to remove temporary profile directory to avoid littering.
150
+ begin
151
+ if @using_temp_user_data_dir
152
+ FileUtils.rm_rf(@user_data_dir)
153
+ end
154
+ rescue => err
155
+ debug_puts(err)
145
156
  end
146
157
  end
147
158
 
@@ -21,12 +21,12 @@ class Puppeteer::CustomQueryHandler
21
21
  nil
22
22
  end
23
23
 
24
- def wait_for(dom_world, selector, visible: nil, hidden: nil, timeout: nil)
24
+ def wait_for(dom_world, selector, visible: nil, hidden: nil, timeout: nil, root: nil)
25
25
  unless @query_one
26
26
  raise NotImplementedError.new("#{self.class}##{__method__} is not implemented.")
27
27
  end
28
28
 
29
- dom_world.send(:wait_for_selector_in_page, @query_one, selector, visible: visible, hidden: hidden, timeout: timeout)
29
+ dom_world.send(:wait_for_selector_in_page, @query_one, selector, visible: visible, hidden: hidden, timeout: timeout, root: root)
30
30
  end
31
31
 
32
32
  def query_all(element, selector)
@@ -420,10 +420,10 @@ class Puppeteer::DOMWorld
420
420
  # @param visible [Boolean] Wait for element visible (not 'display: none' nor 'visibility: hidden') on true. default to false.
421
421
  # @param hidden [Boolean] Wait for element invisible ('display: none' nor 'visibility: hidden') on true. default to false.
422
422
  # @param timeout [Integer]
423
- def wait_for_selector(selector, visible: nil, hidden: nil, timeout: nil)
423
+ def wait_for_selector(selector, visible: nil, hidden: nil, timeout: nil, root: nil)
424
424
  # call wait_for_selector_in_page with custom query selector.
425
425
  query_selector_manager = Puppeteer::QueryHandlerManager.instance
426
- query_selector_manager.detect_query_handler(selector).wait_for(self, visible: visible, hidden: hidden, timeout: timeout)
426
+ query_selector_manager.detect_query_handler(selector).wait_for(self, visible: visible, hidden: hidden, timeout: timeout, root: root)
427
427
  end
428
428
 
429
429
  private def binding_identifier(name, context)
@@ -497,10 +497,11 @@ class Puppeteer::DOMWorld
497
497
  # @param visible [Boolean] Wait for element visible (not 'display: none' nor 'visibility: hidden') on true. default to false.
498
498
  # @param hidden [Boolean] Wait for element invisible ('display: none' nor 'visibility: hidden') on true. default to false.
499
499
  # @param timeout [Integer]
500
- private def wait_for_selector_in_page(query_one, selector, visible: nil, hidden: nil, timeout: nil, binding_function: nil)
500
+ private def wait_for_selector_in_page(query_one, selector, visible: nil, hidden: nil, timeout: nil, root: nil, binding_function: nil)
501
501
  option_wait_for_visible = visible || false
502
502
  option_wait_for_hidden = hidden || false
503
503
  option_timeout = timeout || @timeout_settings.timeout
504
+ option_root = root
504
505
 
505
506
  polling =
506
507
  if option_wait_for_visible || option_wait_for_hidden
@@ -511,11 +512,11 @@ class Puppeteer::DOMWorld
511
512
  title = "selector #{selector}#{option_wait_for_hidden ? 'to be hidden' : ''}"
512
513
 
513
514
  selector_predicate = make_predicate_string(
514
- predicate_arg_def: '(selector, waitForVisible, waitForHidden)',
515
+ predicate_arg_def: '(root, selector, waitForVisible, waitForHidden)',
515
516
  predicate_query_handler: query_one,
516
517
  async: true,
517
518
  predicate_body: <<~JAVASCRIPT
518
- const node = await predicateQueryHandler(document, selector)
519
+ const node = await predicateQueryHandler(root, selector)
519
520
  return checkWaitForOptions(node, waitForVisible, waitForHidden);
520
521
  JAVASCRIPT
521
522
  )
@@ -527,6 +528,7 @@ class Puppeteer::DOMWorld
527
528
  polling: polling,
528
529
  timeout: option_timeout,
529
530
  args: [selector, option_wait_for_visible, option_wait_for_hidden],
531
+ root: option_root,
530
532
  binding_function: binding_function,
531
533
  )
532
534
  handle = wait_task.await_promise
@@ -541,10 +543,11 @@ class Puppeteer::DOMWorld
541
543
  # @param visible [Boolean] Wait for element visible (not 'display: none' nor 'visibility: hidden') on true. default to false.
542
544
  # @param hidden [Boolean] Wait for element invisible ('display: none' nor 'visibility: hidden') on true. default to false.
543
545
  # @param timeout [Integer]
544
- def wait_for_xpath(xpath, visible: nil, hidden: nil, timeout: nil)
546
+ def wait_for_xpath(xpath, visible: nil, hidden: nil, timeout: nil, root: nil)
545
547
  option_wait_for_visible = visible || false
546
548
  option_wait_for_hidden = hidden || false
547
549
  option_timeout = timeout || @timeout_settings.timeout
550
+ option_root = root
548
551
 
549
552
  polling =
550
553
  if option_wait_for_visible || option_wait_for_hidden
@@ -555,9 +558,9 @@ class Puppeteer::DOMWorld
555
558
  title = "XPath #{xpath}#{option_wait_for_hidden ? 'to be hidden' : ''}"
556
559
 
557
560
  xpath_predicate = make_predicate_string(
558
- predicate_arg_def: '(selector, waitForVisible, waitForHidden)',
561
+ predicate_arg_def: '(root, selector, waitForVisible, waitForHidden)',
559
562
  predicate_body: <<~JAVASCRIPT
560
- const node = document.evaluate(selector, document, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
563
+ const node = document.evaluate(selector, root, null, XPathResult.FIRST_ORDERED_NODE_TYPE, null).singleNodeValue;
561
564
  return checkWaitForOptions(node, waitForVisible, waitForHidden);
562
565
  JAVASCRIPT
563
566
  )
@@ -569,6 +572,7 @@ class Puppeteer::DOMWorld
569
572
  polling: polling,
570
573
  timeout: option_timeout,
571
574
  args: [xpath, option_wait_for_visible, option_wait_for_hidden],
575
+ root: option_root,
572
576
  )
573
577
  handle = wait_task.await_promise
574
578
  unless handle.as_element
@@ -20,6 +20,60 @@ class Puppeteer::ElementHandle < Puppeteer::JSHandle
20
20
  @disposed = false
21
21
  end
22
22
 
23
+ def inspect
24
+ values = %i[context remote_object page disposed].map do |sym|
25
+ value = instance_variable_get(:"@#{sym}")
26
+ "@#{sym}=#{value}"
27
+ end
28
+ "#<Puppeteer::ElementHandle #{values.join(' ')}>"
29
+ end
30
+
31
+ #
32
+ # Wait for the `selector` to appear within the element. If at the moment of calling the
33
+ # method the `selector` already exists, the method will return immediately. If
34
+ # the `selector` doesn't appear after the `timeout` milliseconds of waiting, the
35
+ # function will throw.
36
+ #
37
+ # This method does not work across navigations or if the element is detached from DOM.
38
+ #
39
+ # @param selector - A
40
+ # {@link https://developer.mozilla.org/en-US/docs/Web/CSS/CSS_Selectors | selector}
41
+ # of an element to wait for
42
+ # @param options - Optional waiting parameters
43
+ # @returns Promise which resolves when element specified by selector string
44
+ # is added to DOM. Resolves to `null` if waiting for hidden: `true` and
45
+ # selector is not found in DOM.
46
+ # @remarks
47
+ # The optional parameters in `options` are:
48
+ #
49
+ # - `visible`: wait for the selected element to be present in DOM and to be
50
+ # visible, i.e. to not have `display: none` or `visibility: hidden` CSS
51
+ # properties. Defaults to `false`.
52
+ #
53
+ # - `hidden`: wait for the selected element to not be found in the DOM or to be hidden,
54
+ # i.e. have `display: none` or `visibility: hidden` CSS properties. Defaults to
55
+ # `false`.
56
+ #
57
+ # - `timeout`: maximum time to wait in milliseconds. Defaults to `30000`
58
+ # (30 seconds). Pass `0` to disable timeout. The default value can be changed
59
+ # by using the {@link Page.setDefaultTimeout} method.
60
+ def wait_for_selector(selector, visible: nil, hidden: nil, timeout: nil)
61
+ frame = @context.frame
62
+
63
+ secondary_world = frame.secondary_world
64
+ adopted_root = secondary_world.execution_context.adopt_element_handle(self)
65
+ handle = secondary_world.wait_for_selector(selector, visible: visible, hidden: hidden, timeout: timeout, root: adopted_root)
66
+ adopted_root.dispose
67
+ return nil unless handle
68
+
69
+ main_world = frame.main_world
70
+ result = main_world.execution_context.adopt_element_handle(handle)
71
+ handle.dispose
72
+ result
73
+ end
74
+
75
+ define_async_method :async_wait_for_selector
76
+
23
77
  def as_element
24
78
  self
25
79
  end
@@ -81,6 +81,7 @@ module NetworkManagerEmittedEvents ; end
81
81
 
82
82
  {
83
83
  Request: EventsDefinitionUtils.symbol('NetworkManager.Request'),
84
+ RequestServedFromCache: EventsDefinitionUtils.symbol('NetworkManager.RequestServedFromCache'),
84
85
  Response: EventsDefinitionUtils.symbol('NetworkManager.Response'),
85
86
  RequestFailed: EventsDefinitionUtils.symbol('NetworkManager.RequestFailed'),
86
87
  RequestFinished: EventsDefinitionUtils.symbol('NetworkManager.RequestFinished'),
@@ -382,7 +382,7 @@ class Puppeteer::FrameManager
382
382
  @isolated_worlds << context_payload['name']
383
383
  end
384
384
 
385
- context = Puppeteer::ExecutionContext.new(frame._client || @client, context_payload, world)
385
+ context = Puppeteer::ExecutionContext.new(frame&._client || @client, context_payload, world)
386
386
  if world
387
387
  world.context = context
388
388
  end
@@ -31,7 +31,8 @@ class Puppeteer::HTTPResponse
31
31
  # @param client [Puppeteer::CDPSession]
32
32
  # @param request [Puppeteer::HTTPRequest]
33
33
  # @param response_payload [Hash]
34
- def initialize(client, request, response_payload)
34
+ # @param extra_info [Hash|nil]
35
+ def initialize(client, request, response_payload, extra_info)
35
36
  @client = client
36
37
  @request = request
37
38
 
@@ -41,14 +42,15 @@ class Puppeteer::HTTPResponse
41
42
  port: response_payload['remotePort'],
42
43
  )
43
44
 
44
- @status = response_payload['status']
45
- @status_text = response_payload['statusText']
45
+ @status_text = parse_štatus_text_from_extra_info(extra_info) || response_payload['statusText']
46
46
  @url = request.url
47
47
  @from_disk_cache = !!response_payload['fromDiskCache']
48
48
  @from_service_worker = !!response_payload['fromServiceWorker']
49
49
 
50
+ @status = extra_info ? extra_info['statusCode'] : response_payload['status']
50
51
  @headers = {}
51
- response_payload['headers'].each do |key, value|
52
+ headers = extra_info ? extra_info['headers'] : response_payload['headers']
53
+ headers.each do |key, value|
52
54
  @headers[key.downcase] = value
53
55
  end
54
56
  @security_details = if_present(response_payload['securityDetails']) do |security_payload|
@@ -62,6 +64,25 @@ class Puppeteer::HTTPResponse
62
64
 
63
65
  attr_reader :remote_address, :url, :status, :status_text, :headers, :security_details, :request
64
66
 
67
+ def inspect
68
+ values = %i[remote_address url status status_text headers security_details request].map do |sym|
69
+ value = instance_variable_get(:"@#{sym}")
70
+ "@#{sym}=#{value}"
71
+ end
72
+ "#<Puppeteer::HTTPRequest #{values.join(' ')}>"
73
+ end
74
+
75
+ private def parse_štatus_text_from_extra_info(extra_info)
76
+ return nil if !extra_info || !extra_info['headersText']
77
+ first_line = extra_info['headersText'].split("\r").first
78
+ return nil unless first_line
79
+ /[^ ]* [^ ]* (.*)/.match(first_line) do |m|
80
+ return m[1]
81
+ end
82
+
83
+ nil
84
+ end
85
+
65
86
  # @return [Boolean]
66
87
  def ok?
67
88
  @status == 0 || (@status >= 200 && @status <= 299)
@@ -36,6 +36,14 @@ class Puppeteer::JSHandle
36
36
 
37
37
  attr_reader :context, :remote_object
38
38
 
39
+ def inspect
40
+ values = %i[context remote_object disposed].map do |sym|
41
+ value = instance_variable_get(:"@#{sym}")
42
+ "@#{sym}=#{value}"
43
+ end
44
+ "#<Puppeteer::JSHandle #{values.join(' ')}>"
45
+ end
46
+
39
47
  # @return [Puppeteer::ExecutionContext]
40
48
  def execution_context
41
49
  @context
@@ -27,9 +27,6 @@ module Puppeteer::Launcher
27
27
  @chrome_arg_options.args.dup
28
28
  end
29
29
 
30
- #
31
- # let temporaryUserDataDir = null;
32
-
33
30
  if chrome_arguments.none? { |arg| arg.start_with?('--remote-debugging-') }
34
31
  if @launch_options.pipe?
35
32
  chrome_arguments << '--remote-debugging-pipe'
@@ -38,10 +35,17 @@ module Puppeteer::Launcher
38
35
  end
39
36
  end
40
37
 
41
- temporary_user_data_dir = nil
42
- if chrome_arguments.none? { |arg| arg.start_with?('--user-data-dir') }
43
- temporary_user_data_dir = Dir.mktmpdir('puppeteer_dev_chrome_profile-', ENV['PUPPETEER_TMP_DIR'])
44
- chrome_arguments << "--user-data-dir=#{temporary_user_data_dir}"
38
+ user_data_dir = chrome_arguments.find { |arg| arg.start_with?('--user-data-dir') }
39
+ if user_data_dir
40
+ user_data_dir = user_data_dir.split('=').last
41
+ unless File.exist?(user_data_dir)
42
+ raise ArgumentError.new("Chrome user data dir not found at '#{user_data_dir}'")
43
+ end
44
+ using_temp_user_data_dir = false
45
+ else
46
+ user_data_dir = Dir.mktmpdir('puppeteer_dev_chrome_profile-', ENV['PUPPETEER_TMP_DIR'])
47
+ chrome_arguments << "--user-data-dir=#{user_data_dir}"
48
+ using_temp_user_data_dir = true
45
49
  end
46
50
 
47
51
  chrome_executable =
@@ -51,7 +55,13 @@ module Puppeteer::Launcher
51
55
  @launch_options.executable_path || fallback_executable_path
52
56
  end
53
57
  use_pipe = chrome_arguments.include?('--remote-debugging-pipe')
54
- runner = Puppeteer::BrowserRunner.new(chrome_executable, chrome_arguments, temporary_user_data_dir)
58
+ runner = Puppeteer::BrowserRunner.new(
59
+ false,
60
+ chrome_executable,
61
+ chrome_arguments,
62
+ user_data_dir,
63
+ using_temp_user_data_dir,
64
+ )
55
65
  runner.start(
56
66
  handle_SIGHUP: @launch_options.handle_SIGHUP?,
57
67
  handle_SIGTERM: @launch_options.handle_SIGTERM?,
@@ -61,33 +71,39 @@ module Puppeteer::Launcher
61
71
  pipe: use_pipe,
62
72
  )
63
73
 
64
- begin
65
- connection = runner.setup_connection(
66
- use_pipe: use_pipe,
67
- timeout: @launch_options.timeout,
68
- slow_mo: @browser_options.slow_mo,
69
- preferred_revision: @preferred_revision,
70
- )
71
-
72
- browser = Puppeteer::Browser.create(
73
- connection: connection,
74
- context_ids: [],
75
- ignore_https_errors: @browser_options.ignore_https_errors?,
76
- default_viewport: @browser_options.default_viewport,
77
- process: runner.proc,
78
- close_callback: -> { runner.close },
79
- )
74
+ browser =
75
+ begin
76
+ connection = runner.setup_connection(
77
+ use_pipe: use_pipe,
78
+ timeout: @launch_options.timeout,
79
+ slow_mo: @browser_options.slow_mo,
80
+ preferred_revision: @preferred_revision,
81
+ )
82
+
83
+ Puppeteer::Browser.create(
84
+ connection: connection,
85
+ context_ids: [],
86
+ ignore_https_errors: @browser_options.ignore_https_errors?,
87
+ default_viewport: @browser_options.default_viewport,
88
+ process: runner.proc,
89
+ close_callback: -> { runner.close },
90
+ )
91
+ rescue
92
+ runner.kill
93
+ raise
94
+ end
80
95
 
96
+ begin
81
97
  browser.wait_for_target(
82
98
  predicate: ->(target) { target.type == 'page' },
83
99
  timeout: @launch_options.timeout,
84
100
  )
85
-
86
- browser
87
101
  rescue
88
- runner.kill
102
+ browser.close
89
103
  raise
90
104
  end
105
+
106
+ browser
91
107
  end
92
108
 
93
109
  class DefaultArgs
@@ -270,15 +286,15 @@ module Puppeteer::Launcher
270
286
  end
271
287
 
272
288
  chrome_path = chrome_path_map[channel]
273
- if chrome_path.is_a?(Proc)
274
- chrome_path = chrome_path.call
275
- end
276
-
277
289
  unless chrome_path
278
290
  raise ArgumentError.new("Invalid channel: '#{channel}'. Allowed channel is #{chrome_path_map.keys}")
279
291
  end
280
292
 
281
- unless File.exist?(chrome_path)
293
+ if chrome_path.is_a?(Proc)
294
+ chrome_path = chrome_path.call
295
+ end
296
+
297
+ if !chrome_path || !File.exist?(chrome_path)
282
298
  raise "#{channel} is not installed on this system.\nExpected path: #{chrome_path}"
283
299
  end
284
300