puppeteer-ruby 0.0.12 → 0.0.17

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.
Files changed (135) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +2 -14
  3. data/.github/workflows/docs.yml +45 -0
  4. data/.github/workflows/reviewdog.yml +15 -0
  5. data/README.md +52 -1
  6. data/lib/puppeteer.rb +10 -2
  7. data/lib/puppeteer/browser.rb +53 -34
  8. data/lib/puppeteer/browser_context.rb +35 -5
  9. data/lib/puppeteer/cdp_session.rb +3 -19
  10. data/lib/puppeteer/concurrent_ruby_utils.rb +6 -0
  11. data/lib/puppeteer/connection.rb +9 -16
  12. data/lib/puppeteer/debug_print.rb +1 -1
  13. data/lib/puppeteer/define_async_method.rb +23 -0
  14. data/lib/puppeteer/dom_world.rb +67 -78
  15. data/lib/puppeteer/element_handle.rb +19 -47
  16. data/lib/puppeteer/emulation_manager.rb +2 -6
  17. data/lib/puppeteer/env.rb +18 -0
  18. data/lib/puppeteer/execution_context.rb +1 -6
  19. data/lib/puppeteer/frame.rb +34 -39
  20. data/lib/puppeteer/frame_manager.rb +7 -25
  21. data/lib/puppeteer/js_handle.rb +3 -12
  22. data/lib/puppeteer/keyboard.rb +9 -29
  23. data/lib/puppeteer/launcher/chrome.rb +9 -7
  24. data/lib/puppeteer/mouse.rb +20 -24
  25. data/lib/puppeteer/network_manager.rb +163 -5
  26. data/lib/puppeteer/page.rb +213 -179
  27. data/lib/puppeteer/page/pdf_options.rb +166 -0
  28. data/lib/puppeteer/remote_object.rb +2 -5
  29. data/lib/puppeteer/request.rb +330 -0
  30. data/lib/puppeteer/response.rb +113 -0
  31. data/lib/puppeteer/touch_screen.rb +2 -7
  32. data/lib/puppeteer/version.rb +1 -1
  33. data/lib/puppeteer/wait_task.rb +2 -4
  34. data/lib/puppeteer/web_socket.rb +7 -0
  35. data/puppeteer-ruby.gemspec +2 -1
  36. metadata +25 -103
  37. data/docs/Puppeteer.html +0 -2338
  38. data/docs/Puppeteer/AsyncAwaitBehavior.html +0 -105
  39. data/docs/Puppeteer/Browser.html +0 -2258
  40. data/docs/Puppeteer/BrowserContext.html +0 -809
  41. data/docs/Puppeteer/BrowserFetcher.html +0 -214
  42. data/docs/Puppeteer/BrowserRunner.html +0 -914
  43. data/docs/Puppeteer/BrowserRunner/BrowserProcess.html +0 -477
  44. data/docs/Puppeteer/CDPSession.html +0 -813
  45. data/docs/Puppeteer/CDPSession/Error.html +0 -124
  46. data/docs/Puppeteer/ConcurrentRubyUtils.html +0 -438
  47. data/docs/Puppeteer/Connection.html +0 -964
  48. data/docs/Puppeteer/Connection/MessageCallback.html +0 -434
  49. data/docs/Puppeteer/Connection/ProtocolError.html +0 -216
  50. data/docs/Puppeteer/Connection/RequestDebugPrinter.html +0 -217
  51. data/docs/Puppeteer/Connection/ResponseDebugPrinter.html +0 -244
  52. data/docs/Puppeteer/ConsoleMessage.html +0 -565
  53. data/docs/Puppeteer/ConsoleMessage/Location.html +0 -433
  54. data/docs/Puppeteer/DOMWorld.html +0 -2219
  55. data/docs/Puppeteer/DOMWorld/DetachedError.html +0 -124
  56. data/docs/Puppeteer/DOMWorld/DocumentEvaluationError.html +0 -124
  57. data/docs/Puppeteer/DebugPrint.html +0 -233
  58. data/docs/Puppeteer/Device.html +0 -470
  59. data/docs/Puppeteer/Devices.html +0 -139
  60. data/docs/Puppeteer/ElementHandle.html +0 -2542
  61. data/docs/Puppeteer/ElementHandle/BoundingBox.html +0 -507
  62. data/docs/Puppeteer/ElementHandle/BoxModel.html +0 -404
  63. data/docs/Puppeteer/ElementHandle/ElementNotFoundError.html +0 -206
  64. data/docs/Puppeteer/ElementHandle/ElementNotVisibleError.html +0 -206
  65. data/docs/Puppeteer/ElementHandle/Point.html +0 -492
  66. data/docs/Puppeteer/ElementHandle/ScrollIntoViewError.html +0 -124
  67. data/docs/Puppeteer/EmulationManager.html +0 -454
  68. data/docs/Puppeteer/EventCallbackable.html +0 -499
  69. data/docs/Puppeteer/EventCallbackable/EventListeners.html +0 -435
  70. data/docs/Puppeteer/ExecutionContext.html +0 -998
  71. data/docs/Puppeteer/ExecutionContext/EvaluationError.html +0 -124
  72. data/docs/Puppeteer/ExecutionContext/JavaScriptExpression.html +0 -357
  73. data/docs/Puppeteer/ExecutionContext/JavaScriptFunction.html +0 -389
  74. data/docs/Puppeteer/FileChooser.html +0 -455
  75. data/docs/Puppeteer/Frame.html +0 -3813
  76. data/docs/Puppeteer/FrameManager.html +0 -2410
  77. data/docs/Puppeteer/FrameManager/NavigationError.html +0 -124
  78. data/docs/Puppeteer/IfPresent.html +0 -222
  79. data/docs/Puppeteer/JSHandle.html +0 -1352
  80. data/docs/Puppeteer/Keyboard.html +0 -1557
  81. data/docs/Puppeteer/Keyboard/KeyDefinition.html +0 -831
  82. data/docs/Puppeteer/Keyboard/KeyDescription.html +0 -603
  83. data/docs/Puppeteer/Launcher.html +0 -237
  84. data/docs/Puppeteer/Launcher/Base.html +0 -385
  85. data/docs/Puppeteer/Launcher/Base/ExecutablePathNotFound.html +0 -124
  86. data/docs/Puppeteer/Launcher/BrowserOptions.html +0 -441
  87. data/docs/Puppeteer/Launcher/Chrome.html +0 -669
  88. data/docs/Puppeteer/Launcher/Chrome/DefaultArgs.html +0 -382
  89. data/docs/Puppeteer/Launcher/ChromeArgOptions.html +0 -531
  90. data/docs/Puppeteer/Launcher/LaunchOptions.html +0 -893
  91. data/docs/Puppeteer/LifecycleWatcher.html +0 -834
  92. data/docs/Puppeteer/LifecycleWatcher/ExpectedLifecycle.html +0 -363
  93. data/docs/Puppeteer/LifecycleWatcher/FrameDetachedError.html +0 -206
  94. data/docs/Puppeteer/LifecycleWatcher/TerminatedError.html +0 -124
  95. data/docs/Puppeteer/Mouse.html +0 -1095
  96. data/docs/Puppeteer/Mouse/Button.html +0 -136
  97. data/docs/Puppeteer/NetworkManager.html +0 -901
  98. data/docs/Puppeteer/NetworkManager/Credentials.html +0 -385
  99. data/docs/Puppeteer/Page.html +0 -6173
  100. data/docs/Puppeteer/Page/FileChooserTimeoutError.html +0 -206
  101. data/docs/Puppeteer/Page/ScreenshotOptions.html +0 -845
  102. data/docs/Puppeteer/Page/ScriptTag.html +0 -555
  103. data/docs/Puppeteer/Page/StyleTag.html +0 -448
  104. data/docs/Puppeteer/Page/TargetCrashedError.html +0 -124
  105. data/docs/Puppeteer/RemoteObject.html +0 -1087
  106. data/docs/Puppeteer/Target.html +0 -1336
  107. data/docs/Puppeteer/Target/InitializeFailure.html +0 -124
  108. data/docs/Puppeteer/Target/TargetInfo.html +0 -729
  109. data/docs/Puppeteer/TimeoutError.html +0 -135
  110. data/docs/Puppeteer/TimeoutSettings.html +0 -496
  111. data/docs/Puppeteer/TouchScreen.html +0 -464
  112. data/docs/Puppeteer/Viewport.html +0 -837
  113. data/docs/Puppeteer/WaitTask.html +0 -637
  114. data/docs/Puppeteer/WaitTask/TerminatedError.html +0 -124
  115. data/docs/Puppeteer/WaitTask/TimeoutError.html +0 -206
  116. data/docs/Puppeteer/WebSocket.html +0 -673
  117. data/docs/Puppeteer/WebSocket/DriverImpl.html +0 -412
  118. data/docs/Puppeteer/WebSocket/TransportError.html +0 -124
  119. data/docs/Puppeteer/WebSocketTransport.html +0 -600
  120. data/docs/Puppeteer/WebSocktTransportError.html +0 -124
  121. data/docs/_index.html +0 -816
  122. data/docs/class_list.html +0 -51
  123. data/docs/css/common.css +0 -1
  124. data/docs/css/full_list.css +0 -58
  125. data/docs/css/style.css +0 -496
  126. data/docs/file.README.html +0 -125
  127. data/docs/file_list.html +0 -56
  128. data/docs/frames.html +0 -17
  129. data/docs/index.html +0 -125
  130. data/docs/js/app.js +0 -314
  131. data/docs/js/full_list.js +0 -216
  132. data/docs/js/jquery.js +0 -4
  133. data/docs/method_list.html +0 -4115
  134. data/docs/top-level-namespace.html +0 -126
  135. data/lib/puppeteer/async_await_behavior.rb +0 -38
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b420fde6222d1e26a5e8dc72b893a85e460b6db90483fcff3f97b7705b72a099
4
- data.tar.gz: 54dc20b27ccc4898e3e7281d224080d4eec966a41eeefa058b1243e32d3b639b
3
+ metadata.gz: 2277fda99720c2566927af9a2acfc56da2b8e87ee10521871c368fd4a05649b2
4
+ data.tar.gz: 59636e168935b0fb6c964cd62355ae3becf8199ed2ee1af58cb512ccacc9d7cb
5
5
  SHA512:
6
- metadata.gz: 65c9af35923c198fc9e17e5097f2258518f150f77056490065f820ba26703c2b239c86f8f0997d8f7ba51b8fb51f56e6f781a4ab0633b034ac04c462fe935f3c
7
- data.tar.gz: 52fa2316e02d9f28791f1750d3ddd7f0d3ae434d2890c409fef2b3135394f54fec40c9570d440a9608fb8ffcbd41a200d55a0b56c348141887d158fe5efd6bef
6
+ metadata.gz: b45495a2ae160e740e242bc04bb81bfa493c1101583393f78e8e7ff3d065c00594fe0196b8225ac73e281a17428127597d11c8f8323ba6b58d64b437e2979d97
7
+ data.tar.gz: 72c9bd1ca17f37927ceb51a79904583c638066e29cdb08cc2534e77bcc7b3ee348e53e69546ecd579917bd6d8db9c4413d4a63cf617ffa33b8c69c756603439e
@@ -13,21 +13,10 @@ jobs:
13
13
  - run:
14
14
  name: rspec
15
15
  command: |
16
- bundle exec rspec --profile 10 \
16
+ DEBUG=1 bundle exec rspec --profile 10 \
17
17
  --format RspecJunitFormatter \
18
18
  --out test_results/rspec.xml \
19
- --format progress
20
-
21
- rubocop:
22
- docker:
23
- - image: circleci/ruby:2.6.3-stretch-node
24
- executor: ruby/default
25
- steps:
26
- - checkout
27
- - ruby/bundle-install
28
- - run:
29
- name: rubocop
30
- command: bundle exec rubocop
19
+ --format documentation
31
20
 
32
21
  deploy:
33
22
  docker:
@@ -60,7 +49,6 @@ workflows:
60
49
  ci:
61
50
  jobs:
62
51
  - rspec
63
- - rubocop
64
52
  rubygems-deploy:
65
53
  jobs:
66
54
  - deploy:
@@ -0,0 +1,45 @@
1
+ name: update docs
2
+ on:
3
+ push:
4
+ branches:
5
+ - master
6
+
7
+ jobs:
8
+ update-docs:
9
+ name: update docs
10
+ runs-on: ubuntu-latest
11
+
12
+ steps:
13
+ - name: Checkout
14
+ uses: actions/checkout@v2
15
+
16
+ - name: Set up Ruby
17
+ uses: ruby/setup-ruby@v1
18
+ with:
19
+ ruby-version: 2.6
20
+
21
+ - name: Install dependencies
22
+ run: |
23
+ gem uninstall bundler
24
+ gem install bundler -v 1.17
25
+ bundle install
26
+
27
+ - name: Deploy Configuration
28
+ run: |
29
+ mkdir ~/.ssh
30
+ ssh-keyscan -t rsa github.com >> ~/.ssh/known_hosts
31
+ echo "${{ secrets.DOCS_DEPLOY_SSH_RSA }}" | base64 -d > ~/.ssh/id_rsa
32
+ chmod 400 ~/.ssh/id_rsa
33
+
34
+ - name: Build and Push
35
+ run: |
36
+ git clone git@github.com:YusukeIwaki/puppeteer-ruby-docs.git docs
37
+ rm -rf docs/*
38
+ bundle exec yardoc -o docs
39
+ cp puppeteer-ruby.png docs/
40
+ cd docs/
41
+ git add -A
42
+ git config user.name github
43
+ git config user.email github@example.com
44
+ git commit -m ${{ github.sha }}
45
+ git push origin master
@@ -0,0 +1,15 @@
1
+ name: reviewdog
2
+ on: [pull_request]
3
+ jobs:
4
+ rubocop:
5
+ name: runner / rubocop
6
+ runs-on: ubuntu-latest
7
+ steps:
8
+ - name: Check out code
9
+ uses: actions/checkout@v2
10
+ - name: rubocop
11
+ uses: reviewdog/action-rubocop@v1
12
+ with:
13
+ github_token: ${{ secrets.github_token }}
14
+ reporter: github-pr-review
15
+ rubocop_version: 0.86.0
data/README.md CHANGED
@@ -47,9 +47,60 @@ end
47
47
 
48
48
  More usage examples can be found [here](https://github.com/YusukeIwaki/puppeteer-ruby-example)
49
49
 
50
+ ## Collaboration with Selenium or Capybara
51
+
52
+ It is really remarkable that we can use puppeteer functions in existing Selenium or Capybara codes, with a few configuration in advance.
53
+
54
+ ```ruby
55
+ require 'spec_helper'
56
+
57
+ RSpec.describe 'hotel.testplanisphere.dev', type: :feature do
58
+ before {
59
+ visit 'https://hotel.testplanisphere.dev/'
60
+
61
+ # acquire Puppeteer::Browser instance, by connecting Chrome with DevTools Protocol.
62
+ @browser = Puppeteer.connect(
63
+ browser_url: 'http://localhost:9222',
64
+ default_viewport: Puppeteer::Viewport.new(width: 1280, height: 800))
65
+ }
66
+
67
+ after {
68
+ # release Puppeteer::Browser reesource.
69
+ @browser.disconnect
70
+ }
71
+
72
+ it 'can be handled with puppeteer and assert with Capybara' do
73
+ # automation with puppeteer
74
+ puppeteer_page = @browser.pages.first
75
+ puppeteer_page.wait_for_selector('li.nav-item')
76
+
77
+ reservation_link = puppeteer_page.SS('li.nav-item')[1]
78
+
79
+ await_all(
80
+ puppeteer_page.async_wait_for_navigation,
81
+ reservation_link.async_click,
82
+ )
83
+
84
+ # expectation with Capybara DSL
85
+ expect(page).to have_text('宿泊プラン一覧')
86
+ end
87
+
88
+ it 'can be handled with Capybara and assert with puppeteer' do
89
+ # automation with Capybara
90
+ page.all('li.nav-item')[1].click
91
+
92
+ # expectation with puppeteer
93
+ puppeteer_page = @browser.pages.first
94
+ body_text = puppeteer_page.Seval('body', '(el) => el.textContent')
95
+ expect(body_text).to include('宿泊プラン一覧')
96
+ end
97
+ ```
98
+
99
+ The detailed step of configuration can be found [here](https://github.com/YusukeIwaki/puppeteer-ruby-example/tree/master/_with_capybara-rspec).
100
+
50
101
  ## API
51
102
 
52
- https://yusukeiwaki.github.io/puppeteer-ruby/
103
+ https://yusukeiwaki.github.io/puppeteer-ruby-docs/
53
104
 
54
105
  ## Contributing
55
106
 
@@ -2,14 +2,16 @@ require 'concurrent'
2
2
 
3
3
  class Puppeteer; end
4
4
 
5
+ require 'puppeteer/env'
6
+
5
7
  # Custom data types.
6
8
  require 'puppeteer/device'
7
9
  require 'puppeteer/errors'
8
10
  require 'puppeteer/viewport'
9
11
 
10
12
  # Modules
11
- require 'puppeteer/async_await_behavior'
12
13
  require 'puppeteer/concurrent_ruby_utils'
14
+ require 'puppeteer/define_async_method'
13
15
  require 'puppeteer/debug_print'
14
16
  require 'puppeteer/event_callbackable'
15
17
  require 'puppeteer/if_present'
@@ -36,6 +38,8 @@ require 'puppeteer/mouse'
36
38
  require 'puppeteer/network_manager'
37
39
  require 'puppeteer/page'
38
40
  require 'puppeteer/remote_object'
41
+ require 'puppeteer/request'
42
+ require 'puppeteer/response'
39
43
  require 'puppeteer/target'
40
44
  require 'puppeteer/timeout_settings'
41
45
  require 'puppeteer/touch_screen'
@@ -166,7 +170,11 @@ class Puppeteer
166
170
  }.compact
167
171
  browser = launcher.connect(options)
168
172
  if block_given?
169
- yield(browser)
173
+ begin
174
+ yield(browser)
175
+ ensure
176
+ browser.disconnect
177
+ end
170
178
  else
171
179
  browser
172
180
  end
@@ -5,7 +5,7 @@ class Puppeteer::Browser
5
5
  include Puppeteer::DebugPrint
6
6
  include Puppeteer::EventCallbackable
7
7
  include Puppeteer::IfPresent
8
- using Puppeteer::AsyncAwaitBehavior
8
+ using Puppeteer::DefineAsyncMethod
9
9
 
10
10
  # @param {!Puppeteer.Connection} connection
11
11
  # @param {!Array<string>} contextIds
@@ -43,7 +43,7 @@ class Puppeteer::Browser
43
43
  @default_context = Puppeteer::BrowserContext.new(@connection, self, nil)
44
44
  @contexts = {}
45
45
  context_ids.each do |context_id|
46
- @contexts[context_id] = Puppeteer::BrowserContext.new(@connection, self. context_id)
46
+ @contexts[context_id] = Puppeteer::BrowserContext.new(@connection, self, context_id)
47
47
  end
48
48
  @targets = {}
49
49
  @connection.on_event 'Events.Connection.Disconnected' do
@@ -70,6 +70,15 @@ class Puppeteer::Browser
70
70
  add_event_listener(EVENT_MAPPINGS[event_name.to_sym], &block)
71
71
  end
72
72
 
73
+ # @param event_name [Symbol]
74
+ def once(event_name, &block)
75
+ unless EVENT_MAPPINGS.has_key?(event_name.to_sym)
76
+ raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{EVENT_MAPPINGS.keys.join(", ")}")
77
+ end
78
+
79
+ observe_first(EVENT_MAPPINGS[event_name.to_sym], &block)
80
+ end
81
+
73
82
  # @return [Puppeteer::BrowserRunner::BrowserProcess]
74
83
  def process
75
84
  @process
@@ -94,7 +103,13 @@ class Puppeteer::Browser
94
103
  # @param context_id [String]
95
104
  def dispose_context(context_id)
96
105
  @connection.send_message('Target.disposeBrowserContext', browserContextId: context_id)
97
- @contexts.remove(context_id)
106
+ @contexts.delete(context_id)
107
+ end
108
+
109
+ class TargetAlreadyExistError < StandardError
110
+ def initialize
111
+ super('Target should not exist before targetCreated')
112
+ end
98
113
  end
99
114
 
100
115
  # @param {!Protocol.Target.targetCreatedPayload} event
@@ -108,6 +123,9 @@ class Puppeteer::Browser
108
123
  @default_context
109
124
  end
110
125
 
126
+ if @targets[target_info.target_id]
127
+ raise TargetAlreadyExistError.new
128
+ end
111
129
  target = Puppeteer::Target.new(
112
130
  target_info: target_info,
113
131
  browser_context: context,
@@ -122,13 +140,8 @@ class Puppeteer::Browser
122
140
  emit_event 'Events.Browser.TargetCreated', target
123
141
  context.emit_event 'Events.BrowserContext.TargetCreated', target
124
142
  end
125
-
126
- if_present(pending_target_info_changed_event.delete(target_info.target_id)) do |pending_event|
127
- handle_target_info_changed(pending_event)
128
- end
129
143
  end
130
144
 
131
-
132
145
  # @param {{targetId: string}} event
133
146
  def handle_target_destroyed(event)
134
147
  target_id = event['targetId']
@@ -142,24 +155,16 @@ class Puppeteer::Browser
142
155
  end
143
156
  end
144
157
 
158
+ class TargetNotExistError < StandardError
159
+ def initialize
160
+ super('target should exist before targetInfoChanged')
161
+ end
162
+ end
163
+
145
164
  # @param {!Protocol.Target.targetInfoChangedPayload} event
146
165
  def handle_target_info_changed(event)
147
166
  target_info = Puppeteer::Target::TargetInfo.new(event['targetInfo'])
148
- target = @targets[target_info.target_id]
149
- if !target
150
- # targetCreated is sometimes notified after targetInfoChanged.
151
- # We don't raise error. Instead, keep the event as a pending change,
152
- # and handle it on handle_target_created.
153
- #
154
- # D, [2020-04-22T00:22:26.630328 #79646] DEBUG -- : RECV << {"method"=>"Target.targetInfoChanged", "params"=>{"targetInfo"=>{"targetId"=>"8068CED48357B9557EEC85AA62165A8E", "type"=>"iframe", "title"=>"", "url"=>"", "attached"=>true, "browserContextId"=>"7895BFB24BF22CE40584808713D96E8D"}}}
155
- # E, [2020-04-22T00:22:26.630448 #79646] ERROR -- : target should exist before targetInfoChanged (StandardError)
156
- # D, [2020-04-22T00:22:26.630648 #79646] DEBUG -- : RECV << {"method"=>"Target.targetCreated", "params"=>{"targetInfo"=>{"targetId"=>"8068CED48357B9557EEC85AA62165A8E", "type"=>"iframe", "title"=>"", "url"=>"", "attached"=>false, "browserContextId"=>"7895BFB24BF22CE40584808713D96E8D"}}}
157
- pending_target_info_changed_event[target_info.target_id] = event
158
- return
159
- # original implementation is:
160
- #
161
- # raise StandardError.new('target should exist before targetInfoChanged')
162
- end
167
+ target = @targets[target_info.target_id] or raise TargetNotExistError.new
163
168
  previous_url = target.url
164
169
  was_initialized = target.initialized?
165
170
  target.handle_target_info_changed(target_info)
@@ -169,12 +174,8 @@ class Puppeteer::Browser
169
174
  end
170
175
  end
171
176
 
172
- private def pending_target_info_changed_event
173
- @pending_target_info_changed_event ||= {}
174
- end
175
-
176
177
  # @return [String]
177
- def websocket_endpoint
178
+ def ws_endpoint
178
179
  @connection.url
179
180
  end
180
181
 
@@ -204,7 +205,7 @@ class Puppeteer::Browser
204
205
 
205
206
  # @return {!Target}
206
207
  def target
207
- targets.first { |target| target.type == 'browser' }
208
+ targets.find { |target| target.type == 'browser' }
208
209
  end
209
210
 
210
211
  # used only in Target#opener
@@ -212,12 +213,11 @@ class Puppeteer::Browser
212
213
  @targets[target_id]
213
214
  end
214
215
 
215
- # @param {function(!Target):boolean} predicate
216
- # @param {{timeout?: number}=} options
217
- # @return {!Promise<!Target>}
216
+ # @param predicate [Proc(Puppeteer::Target -> Boolean)]
217
+ # @return [Puppeteer::Target]
218
218
  def wait_for_target(predicate:, timeout: nil)
219
219
  timeout_in_sec = (timeout || 30000).to_i / 1000.0
220
- existing_target = targets.first { |target| predicate.call(target) }
220
+ existing_target = targets.find { |target| predicate.call(target) }
221
221
  return existing_target if existing_target
222
222
 
223
223
  event_listening_ids = []
@@ -241,11 +241,18 @@ class Puppeteer::Browser
241
241
  else
242
242
  target_promise.value!
243
243
  end
244
+ rescue Timeout::Error
245
+ raise Puppeteer::TimeoutError.new("waiting for target failed: timeout #{timeout}ms exceeded")
244
246
  ensure
245
247
  remove_event_listener(*event_listening_ids)
246
248
  end
247
249
  end
248
250
 
251
+ # @!method async_wait_for_target(predicate:, timeout: nil)
252
+ #
253
+ # @param predicate [Proc(Puppeteer::Target -> Boolean)]
254
+ define_async_method :async_wait_for_target
255
+
249
256
  # @return {!Promise<!Array<!Puppeteer.Page>>}
250
257
  def pages
251
258
  browser_contexts.flat_map(&:pages)
@@ -274,7 +281,19 @@ class Puppeteer::Browser
274
281
  !@connection.closed?
275
282
  end
276
283
 
284
+ class Version
285
+ def initialize(hash)
286
+ @protocol_version = hash['protocolVersion']
287
+ @product = hash['product']
288
+ @revision = hash['revision']
289
+ @user_agent = hash['userAgent']
290
+ @js_version = hash['jsVersion']
291
+ end
292
+
293
+ attr_reader :protocol_version, :product, :revision, :user_agent, :js_version
294
+ end
295
+
277
296
  private def get_version
278
- @connection.send_message('Browser.getVersion')
297
+ Version.new(@connection.send_message('Browser.getVersion'))
279
298
  end
280
299
  end
@@ -1,5 +1,6 @@
1
1
  class Puppeteer::BrowserContext
2
2
  include Puppeteer::EventCallbackable
3
+ using Puppeteer::DefineAsyncMethod
3
4
 
4
5
  # @param {!Puppeteer.Connection} connection
5
6
  # @param {!Browser} browser
@@ -10,14 +11,38 @@ class Puppeteer::BrowserContext
10
11
  @id = context_id
11
12
  end
12
13
 
14
+ EVENT_MAPPINGS = {
15
+ disconnected: 'Events.BrowserContext.Disconnected',
16
+ targetcreated: 'Events.BrowserContext.TargetCreated',
17
+ targetchanged: 'Events.BrowserContext.TargetChanged',
18
+ targetdestroyed: 'Events.BrowserContext.TargetDestroyed',
19
+ }
20
+
21
+ # @param event_name [Symbol] either of :disconnected, :targetcreated, :targetchanged, :targetdestroyed
22
+ def on(event_name, &block)
23
+ unless EVENT_MAPPINGS.has_key?(event_name.to_sym)
24
+ raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{EVENT_MAPPINGS.keys.join(", ")}")
25
+ end
26
+
27
+ add_event_listener(EVENT_MAPPINGS[event_name.to_sym], &block)
28
+ end
29
+
30
+ # @param event_name [Symbol]
31
+ def once(event_name, &block)
32
+ unless EVENT_MAPPINGS.has_key?(event_name.to_sym)
33
+ raise ArgumentError.new("Unknown event name: #{event_name}. Known events are #{EVENT_MAPPINGS.keys.join(", ")}")
34
+ end
35
+
36
+ observe_first(EVENT_MAPPINGS[event_name.to_sym], &block)
37
+ end
38
+
13
39
  # @return {!Array<!Target>} target
14
40
  def targets
15
41
  @browser.targets.select { |target| target.browser_context == self }
16
42
  end
17
43
 
18
- # @param {function(!Target):boolean} predicate
19
- # @param {{timeout?: number}=} options
20
- # @return {!Promise<!Target>}
44
+ # @param predicate [Proc(Puppeteer::Target -> Boolean)]
45
+ # @return [Puppeteer::Target]
21
46
  def wait_for_target(predicate:, timeout: nil)
22
47
  @browser.wait_for_target(
23
48
  predicate: ->(target) { target.browser_context == self && predicate.call(target) },
@@ -25,13 +50,18 @@ class Puppeteer::BrowserContext
25
50
  )
26
51
  end
27
52
 
53
+ # @!method async_wait_for_target(predicate:, timeout: nil)
54
+ #
55
+ # @param predicate [Proc(Puppeteer::Target -> Boolean)]
56
+ define_async_method :async_wait_for_target
57
+
28
58
  # @return {!Promise<!Array<!Puppeteer.Page>>}
29
59
  def pages
30
60
  targets.select { |target| target.type == 'page' }.map(&:page).reject { |page| !page }
31
61
  end
32
62
 
33
63
  def incognito?
34
- !@id
64
+ !!@id
35
65
  end
36
66
 
37
67
  # /**
@@ -82,7 +112,7 @@ class Puppeteer::BrowserContext
82
112
  end
83
113
 
84
114
  def close
85
- if !@id
115
+ unless @id
86
116
  raise 'Non-incognito profiles cannot be closed!'
87
117
  end
88
118
  @browser.dispose_context(@id)