puppeteer-ruby 0.0.13 → 0.0.14

Sign up to get free protection for your applications and to get access to all the features.
Files changed (126) hide show
  1. checksums.yaml +4 -4
  2. data/.circleci/config.yml +0 -12
  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 +1 -1
  7. data/lib/puppeteer/browser.rb +17 -25
  8. data/lib/puppeteer/cdp_session.rb +3 -19
  9. data/lib/puppeteer/concurrent_ruby_utils.rb +6 -0
  10. data/lib/puppeteer/connection.rb +3 -15
  11. data/lib/puppeteer/define_async_method.rb +23 -0
  12. data/lib/puppeteer/dom_world.rb +6 -21
  13. data/lib/puppeteer/element_handle.rb +15 -44
  14. data/lib/puppeteer/emulation_manager.rb +2 -6
  15. data/lib/puppeteer/execution_context.rb +1 -6
  16. data/lib/puppeteer/frame.rb +30 -16
  17. data/lib/puppeteer/frame_manager.rb +7 -25
  18. data/lib/puppeteer/js_handle.rb +3 -12
  19. data/lib/puppeteer/keyboard.rb +6 -27
  20. data/lib/puppeteer/mouse.rb +5 -25
  21. data/lib/puppeteer/page.rb +39 -63
  22. data/lib/puppeteer/remote_object.rb +2 -5
  23. data/lib/puppeteer/touch_screen.rb +2 -7
  24. data/lib/puppeteer/version.rb +1 -1
  25. data/lib/puppeteer/wait_task.rb +2 -4
  26. data/puppeteer-ruby.gemspec +1 -1
  27. metadata +7 -103
  28. data/docs/Puppeteer.html +0 -2338
  29. data/docs/Puppeteer/AsyncAwaitBehavior.html +0 -105
  30. data/docs/Puppeteer/Browser.html +0 -2258
  31. data/docs/Puppeteer/BrowserContext.html +0 -809
  32. data/docs/Puppeteer/BrowserFetcher.html +0 -214
  33. data/docs/Puppeteer/BrowserRunner.html +0 -914
  34. data/docs/Puppeteer/BrowserRunner/BrowserProcess.html +0 -477
  35. data/docs/Puppeteer/CDPSession.html +0 -813
  36. data/docs/Puppeteer/CDPSession/Error.html +0 -124
  37. data/docs/Puppeteer/ConcurrentRubyUtils.html +0 -438
  38. data/docs/Puppeteer/Connection.html +0 -964
  39. data/docs/Puppeteer/Connection/MessageCallback.html +0 -434
  40. data/docs/Puppeteer/Connection/ProtocolError.html +0 -216
  41. data/docs/Puppeteer/Connection/RequestDebugPrinter.html +0 -217
  42. data/docs/Puppeteer/Connection/ResponseDebugPrinter.html +0 -244
  43. data/docs/Puppeteer/ConsoleMessage.html +0 -565
  44. data/docs/Puppeteer/ConsoleMessage/Location.html +0 -433
  45. data/docs/Puppeteer/DOMWorld.html +0 -2293
  46. data/docs/Puppeteer/DOMWorld/DetachedError.html +0 -124
  47. data/docs/Puppeteer/DOMWorld/DocumentEvaluationError.html +0 -124
  48. data/docs/Puppeteer/DebugPrint.html +0 -233
  49. data/docs/Puppeteer/Device.html +0 -470
  50. data/docs/Puppeteer/Devices.html +0 -139
  51. data/docs/Puppeteer/ElementHandle.html +0 -2542
  52. data/docs/Puppeteer/ElementHandle/BoundingBox.html +0 -507
  53. data/docs/Puppeteer/ElementHandle/BoxModel.html +0 -404
  54. data/docs/Puppeteer/ElementHandle/ElementNotFoundError.html +0 -206
  55. data/docs/Puppeteer/ElementHandle/ElementNotVisibleError.html +0 -206
  56. data/docs/Puppeteer/ElementHandle/Point.html +0 -492
  57. data/docs/Puppeteer/ElementHandle/ScrollIntoViewError.html +0 -124
  58. data/docs/Puppeteer/EmulationManager.html +0 -454
  59. data/docs/Puppeteer/EventCallbackable.html +0 -499
  60. data/docs/Puppeteer/EventCallbackable/EventListeners.html +0 -435
  61. data/docs/Puppeteer/ExecutionContext.html +0 -998
  62. data/docs/Puppeteer/ExecutionContext/EvaluationError.html +0 -124
  63. data/docs/Puppeteer/ExecutionContext/JavaScriptExpression.html +0 -357
  64. data/docs/Puppeteer/ExecutionContext/JavaScriptFunction.html +0 -389
  65. data/docs/Puppeteer/FileChooser.html +0 -455
  66. data/docs/Puppeteer/Frame.html +0 -3835
  67. data/docs/Puppeteer/FrameManager.html +0 -2410
  68. data/docs/Puppeteer/FrameManager/NavigationError.html +0 -124
  69. data/docs/Puppeteer/IfPresent.html +0 -222
  70. data/docs/Puppeteer/JSHandle.html +0 -1352
  71. data/docs/Puppeteer/Keyboard.html +0 -1557
  72. data/docs/Puppeteer/Keyboard/KeyDefinition.html +0 -831
  73. data/docs/Puppeteer/Keyboard/KeyDescription.html +0 -603
  74. data/docs/Puppeteer/Launcher.html +0 -237
  75. data/docs/Puppeteer/Launcher/Base.html +0 -385
  76. data/docs/Puppeteer/Launcher/Base/ExecutablePathNotFound.html +0 -124
  77. data/docs/Puppeteer/Launcher/BrowserOptions.html +0 -441
  78. data/docs/Puppeteer/Launcher/Chrome.html +0 -674
  79. data/docs/Puppeteer/Launcher/Chrome/DefaultArgs.html +0 -382
  80. data/docs/Puppeteer/Launcher/ChromeArgOptions.html +0 -531
  81. data/docs/Puppeteer/Launcher/LaunchOptions.html +0 -893
  82. data/docs/Puppeteer/LifecycleWatcher.html +0 -834
  83. data/docs/Puppeteer/LifecycleWatcher/ExpectedLifecycle.html +0 -363
  84. data/docs/Puppeteer/LifecycleWatcher/FrameDetachedError.html +0 -206
  85. data/docs/Puppeteer/LifecycleWatcher/TerminatedError.html +0 -124
  86. data/docs/Puppeteer/Mouse.html +0 -1095
  87. data/docs/Puppeteer/Mouse/Button.html +0 -136
  88. data/docs/Puppeteer/NetworkManager.html +0 -901
  89. data/docs/Puppeteer/NetworkManager/Credentials.html +0 -385
  90. data/docs/Puppeteer/Page.html +0 -6173
  91. data/docs/Puppeteer/Page/FileChooserTimeoutError.html +0 -206
  92. data/docs/Puppeteer/Page/ScreenshotOptions.html +0 -845
  93. data/docs/Puppeteer/Page/ScriptTag.html +0 -555
  94. data/docs/Puppeteer/Page/StyleTag.html +0 -448
  95. data/docs/Puppeteer/Page/TargetCrashedError.html +0 -124
  96. data/docs/Puppeteer/RemoteObject.html +0 -1087
  97. data/docs/Puppeteer/Target.html +0 -1336
  98. data/docs/Puppeteer/Target/InitializeFailure.html +0 -124
  99. data/docs/Puppeteer/Target/TargetInfo.html +0 -729
  100. data/docs/Puppeteer/TimeoutError.html +0 -135
  101. data/docs/Puppeteer/TimeoutSettings.html +0 -496
  102. data/docs/Puppeteer/TouchScreen.html +0 -464
  103. data/docs/Puppeteer/Viewport.html +0 -837
  104. data/docs/Puppeteer/WaitTask.html +0 -637
  105. data/docs/Puppeteer/WaitTask/TerminatedError.html +0 -124
  106. data/docs/Puppeteer/WaitTask/TimeoutError.html +0 -206
  107. data/docs/Puppeteer/WebSocket.html +0 -673
  108. data/docs/Puppeteer/WebSocket/DriverImpl.html +0 -412
  109. data/docs/Puppeteer/WebSocket/TransportError.html +0 -124
  110. data/docs/Puppeteer/WebSocketTransport.html +0 -600
  111. data/docs/Puppeteer/WebSocktTransportError.html +0 -124
  112. data/docs/_index.html +0 -816
  113. data/docs/class_list.html +0 -51
  114. data/docs/css/common.css +0 -1
  115. data/docs/css/full_list.css +0 -58
  116. data/docs/css/style.css +0 -496
  117. data/docs/file.README.html +0 -125
  118. data/docs/file_list.html +0 -56
  119. data/docs/frames.html +0 -17
  120. data/docs/index.html +0 -125
  121. data/docs/js/app.js +0 -314
  122. data/docs/js/full_list.js +0 -216
  123. data/docs/js/jquery.js +0 -4
  124. data/docs/method_list.html +0 -4123
  125. data/docs/top-level-namespace.html +0 -126
  126. data/lib/puppeteer/async_await_behavior.rb +0 -38
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0c440ee3ee2c46ab3b4639855bb08497063338c8cc4458fa4e1d4eeba8fd7c65
4
- data.tar.gz: 0d380b3fc666f05402676ba85f278f42cce9b271bd713cffd938d0fefd39be71
3
+ metadata.gz: 0a500508a5a1d88ed4694c5614c7c70bdae06d4d5cb10f81c1237ebd25a6623f
4
+ data.tar.gz: 338b902e3c64d9f96e7b7822353a7b664ab112cd3993e7a7ec06cda41752521e
5
5
  SHA512:
6
- metadata.gz: a6018e2425cc73f5d3a850169041906d9f6eb50f0398690df3f4bef871960834c4aaf07ae14f439e854f7069e33691575e29c1153b379ed22dbab6120c34731c
7
- data.tar.gz: 6ba30ed2dddb60113bb6e8f1341b7e326901a4c4ebcf8c61734a93c114dcd667954ce442bcbc4d44d5f951537ff65458ac34dcedf23747182b45a86920f67245
6
+ metadata.gz: 51ea52a62c04917d5ec62c4224ffe91cacf3ccd3cfc796d94d975c309971dc0e789fdec7f4fabcc37f51619d833f070e7d6136f18cdb7113721382392456dd88
7
+ data.tar.gz: ef643098e96d3d1794470f38befb55039916c13b35d7d133596acf42d7217c302d1de4865c62c178e758aa619063ee9469bbbfcda1665c3e19fcca26aaee12ce
@@ -18,17 +18,6 @@ jobs:
18
18
  --out test_results/rspec.xml \
19
19
  --format progress
20
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
31
-
32
21
  deploy:
33
22
  docker:
34
23
  - image: circleci/ruby:2.6.3-stretch-node
@@ -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
 
@@ -8,8 +8,8 @@ require 'puppeteer/errors'
8
8
  require 'puppeteer/viewport'
9
9
 
10
10
  # Modules
11
- require 'puppeteer/async_await_behavior'
12
11
  require 'puppeteer/concurrent_ruby_utils'
12
+ require 'puppeteer/define_async_method'
13
13
  require 'puppeteer/debug_print'
14
14
  require 'puppeteer/event_callbackable'
15
15
  require 'puppeteer/if_present'
@@ -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
@@ -97,6 +97,12 @@ class Puppeteer::Browser
97
97
  @contexts.remove(context_id)
98
98
  end
99
99
 
100
+ class TargetAlreadyExistError < StandardError
101
+ def initialize
102
+ super('Target should not exist before targetCreated')
103
+ end
104
+ end
105
+
100
106
  # @param {!Protocol.Target.targetCreatedPayload} event
101
107
  def handle_target_created(event)
102
108
  target_info = Puppeteer::Target::TargetInfo.new(event['targetInfo'])
@@ -108,6 +114,9 @@ class Puppeteer::Browser
108
114
  @default_context
109
115
  end
110
116
 
117
+ if @targets[target_info.target_id]
118
+ raise TargetAlreadyExistError.new
119
+ end
111
120
  target = Puppeteer::Target.new(
112
121
  target_info: target_info,
113
122
  browser_context: context,
@@ -122,13 +131,8 @@ class Puppeteer::Browser
122
131
  emit_event 'Events.Browser.TargetCreated', target
123
132
  context.emit_event 'Events.BrowserContext.TargetCreated', target
124
133
  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
134
  end
130
135
 
131
-
132
136
  # @param {{targetId: string}} event
133
137
  def handle_target_destroyed(event)
134
138
  target_id = event['targetId']
@@ -142,24 +146,16 @@ class Puppeteer::Browser
142
146
  end
143
147
  end
144
148
 
149
+ class TargetNotExistError < StandardError
150
+ def initialize
151
+ super('target should exist before targetInfoChanged')
152
+ end
153
+ end
154
+
145
155
  # @param {!Protocol.Target.targetInfoChangedPayload} event
146
156
  def handle_target_info_changed(event)
147
157
  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
158
+ target = @targets[target_info.target_id] or raise TargetNotExistError.new
163
159
  previous_url = target.url
164
160
  was_initialized = target.initialized?
165
161
  target.handle_target_info_changed(target_info)
@@ -169,10 +165,6 @@ class Puppeteer::Browser
169
165
  end
170
166
  end
171
167
 
172
- private def pending_target_info_changed_event
173
- @pending_target_info_changed_event ||= {}
174
- end
175
-
176
168
  # @return [String]
177
169
  def websocket_endpoint
178
170
  @connection.url
@@ -1,7 +1,7 @@
1
1
  class Puppeteer::CDPSession
2
2
  include Puppeteer::DebugPrint
3
3
  include Puppeteer::EventCallbackable
4
- using Puppeteer::AsyncAwaitBehavior
4
+ using Puppeteer::DefineAsyncMethod
5
5
 
6
6
  class Error < StandardError; end
7
7
 
@@ -13,7 +13,6 @@ class Puppeteer::CDPSession
13
13
  @connection = connection
14
14
  @target_type = target_type
15
15
  @session_id = session_id
16
- @pending_messages = {}
17
16
  end
18
17
 
19
18
  attr_reader :connection
@@ -35,12 +34,7 @@ class Puppeteer::CDPSession
35
34
  id = @connection.raw_send(message: { sessionId: @session_id, method: method, params: params })
36
35
  promise = resolvable_future
37
36
  callback = Puppeteer::Connection::MessageCallback.new(method: method, promise: promise)
38
- if pending_message = @pending_messages.delete(id)
39
- debug_puts "Pending message (id: #{id}) is handled"
40
- callback_with_message(callback, pending_message)
41
- else
42
- @callbacks[id] = callback
43
- end
37
+ @callbacks[id] = callback
44
38
  promise
45
39
  end
46
40
 
@@ -50,17 +44,7 @@ class Puppeteer::CDPSession
50
44
  if callback = @callbacks.delete(message['id'])
51
45
  callback_with_message(callback, message)
52
46
  else
53
- debug_puts "unknown id: #{id}. Store it into pending message"
54
-
55
- # RECV is often notified before SEND.
56
- # Wait about 10 frames before throwing an error.
57
- message_id = message['id']
58
- @pending_messages[message_id] = message
59
- Concurrent::Promises.schedule(0.16, message_id) do |id|
60
- if @pending_messages.delete(id)
61
- raise Error.new("unknown id: #{id}")
62
- end
63
- end
47
+ raise Error.new("unknown id: #{id}")
64
48
  end
65
49
  else
66
50
  emit_event message['method'], message['params']
@@ -1,5 +1,8 @@
1
1
  # utility methods for Concurrent::Promises.
2
2
  module Puppeteer::ConcurrentRubyUtils
3
+ # wait for all promises.
4
+ # REMARK: This method doesn't assure the order of calling.
5
+ # for example, await_all(async1, async2) calls calls2 -> calls1 often.
3
6
  def await_all(*args)
4
7
  if args.length == 1 && args[0].is_a?(Enumerable)
5
8
  Concurrent::Promises.zip(*(args[0])).value!
@@ -8,6 +11,9 @@ module Puppeteer::ConcurrentRubyUtils
8
11
  end
9
12
  end
10
13
 
14
+ # wait for first promises.
15
+ # REMARK: This method doesn't assure the order of calling.
16
+ # for example, await_all(async1, async2) calls calls2 -> calls1 often.
11
17
  def await_any(*args)
12
18
  if args.length == 1 && args[0].is_a?(Enumerable)
13
19
  Concurrent::Promises.any(*(args[0])).value!
@@ -3,7 +3,7 @@ require 'json'
3
3
  class Puppeteer::Connection
4
4
  include Puppeteer::DebugPrint
5
5
  include Puppeteer::EventCallbackable
6
- using Puppeteer::AsyncAwaitBehavior
6
+ using Puppeteer::DefineAsyncMethod
7
7
 
8
8
  class ProtocolError < StandardError
9
9
  def initialize(method:, error_message:, error_data: nil)
@@ -210,9 +210,7 @@ class Puppeteer::Connection
210
210
  end
211
211
  end
212
212
 
213
- private async def async_handle_message(message)
214
- handle_message(message)
215
- end
213
+ private define_async_method :async_handle_message
216
214
 
217
215
  private def handle_close
218
216
  return if @closed
@@ -251,16 +249,6 @@ class Puppeteer::Connection
251
249
  def create_session(target_info)
252
250
  result = send_message('Target.attachToTarget', targetId: target_info.target_id, flatten: true)
253
251
  session_id = result['sessionId']
254
-
255
- # Target.attachedToTarget is often notified after the result of Target.attachToTarget.
256
- # D, [2020-04-04T23:04:30.736311 #91875] DEBUG -- : RECV << {"id"=>2, "result"=>{"sessionId"=>"DA002F8A95B04710502CB40D8430B95A"}}
257
- # D, [2020-04-04T23:04:30.736649 #91875] DEBUG -- : RECV << {"method"=>"Target.attachedToTarget", "params"=>{"sessionId"=>"DA002F8A95B04710502CB40D8430B95A", "targetInfo"=>{"targetId"=>"EBAB949A7DE63F12CB94268AD3A9976B", "type"=>"page", "title"=>"about:blank", "url"=>"about:blank", "attached"=>true, "browserContextId"=>"46D23767E9B79DD9E589101121F6DADD"}, "waitingForDebugger"=>false}}
258
- # So we have to wait for "Target.attachedToTarget" a bit.
259
- 20.times do
260
- if @sessions[session_id]
261
- return @sessions[session_id]
262
- end
263
- sleep 0.1
264
- end
252
+ @sessions[session_id]
265
253
  end
266
254
  end
@@ -0,0 +1,23 @@
1
+ module Puppeteer::DefineAsyncMethod
2
+ refine Class do
3
+ def define_async_method(async_method_name)
4
+ unless async_method_name.to_s.start_with?('async_')
5
+ raise ArgumentError.new('async method name should start with "async_"')
6
+ end
7
+
8
+ if method_defined?(async_method_name) || private_method_defined?(async_method_name)
9
+ raise ArgumentError.new("#{async_method_name} is already defined")
10
+ end
11
+
12
+ original_method = instance_method(async_method_name[6..-1])
13
+ define_method(async_method_name) do |*args|
14
+ Concurrent::Promises.future do
15
+ original_method.bind(self).call(*args)
16
+ rescue => err
17
+ Logger.new(STDERR).warn(err)
18
+ raise err
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -2,7 +2,7 @@ require 'thread'
2
2
 
3
3
  # https://github.com/puppeteer/puppeteer/blob/master/src/DOMWorld.js
4
4
  class Puppeteer::DOMWorld
5
- using Puppeteer::AsyncAwaitBehavior
5
+ using Puppeteer::DefineAsyncMethod
6
6
 
7
7
  # @param {!Puppeteer.FrameManager} frameManager
8
8
  # @param {!Puppeteer.Frame} frame
@@ -12,7 +12,6 @@ class Puppeteer::DOMWorld
12
12
  @frame = frame
13
13
  @timeout_settings = timeout_settings
14
14
  @context_promise = resolvable_future
15
- @pending_destroy = []
16
15
  @wait_tasks = Set.new
17
16
  @detached = false
18
17
  end
@@ -24,22 +23,12 @@ class Puppeteer::DOMWorld
24
23
  @wait_tasks
25
24
  end
26
25
 
27
- # @param {?Puppeteer.ExecutionContext} context
26
+ # @param context [Puppeteer::ExecutionContext]
28
27
  def context=(context)
29
- # D, [2020-04-12T22:45:03.938754 #46154] DEBUG -- : RECV << {"method"=>"Runtime.executionContextCreated", "params"=>{"context"=>{"id"=>3, "origin"=>"https://github.com", "name"=>"", "auxData"=>{"isDefault"=>true, "type"=>"default", "frameId"=>"3AD7F1E82BCBA88BFE31D03BC49FF6CB"}}}, "sessionId"=>"636CEF0C4FEAFC4FE815E9E7B5F7BA68"}
30
- # D, [2020-04-12T22:45:03.938856 #46154] DEBUG -- : RECV << {"method"=>"Runtime.executionContextCreated", "params"=>{"context"=>{"id"=>4, "origin"=>"://", "name"=>"__puppeteer_utility_world__", "auxData"=>{"isDefault"=>false, "type"=>"isolated", "frameId"=>"3AD7F1E82BCBA88BFE31D03BC49FF6CB"}}}, "sessionId"=>"636CEF0C4FEAFC4FE815E9E7B5F7BA68"}
31
- # D, [2020-04-12T22:45:03.938960 #46154] DEBUG -- : RECV << {"method"=>"Runtime.executionContextDestroyed", "params"=>{"executionContextId"=>1}, "sessionId"=>"636CEF0C4FEAFC4FE815E9E7B5F7BA68"}
32
- # D, [2020-04-12T22:45:03.939110 #46154] DEBUG -- : RECV << {"method"=>"Page.frameNavigated", "params"=>{"frame"=>{"id"=>"3AD7F1E82BCBA88BFE31D03BC49FF6CB", "loaderId"=>"301B349884E582986C502CBE020966DF", "url"=>"https://github.com/", "securityOrigin"=>"https://github.com", "mimeType"=>"text/html"}}, "sessionId"=>"636CEF0C4FEAFC4FE815E9E7B5F7BA68"}
33
- # D, [2020-04-12T22:45:03.939793 #46154] DEBUG -- : RECV << {"method"=>"Runtime.executionContextDestroyed", "params"=>{"executionContextId"=>2}, "sessionId"=>"636CEF0C4FEAFC4FE815E9E7B5F7BA68"}
34
- # executionContextDestroyed is often notified after executionContextCreated.
35
-
36
28
  if context
37
- if @context_promise.fulfilled?
38
- @pending_destroy << context._context_id
39
- @document = nil
40
- @context_promise = resolvable_future
29
+ unless @context_promise.resolved?
30
+ @context_promise.fulfill(context)
41
31
  end
42
- @context_promise.fulfill(context)
43
32
  @wait_tasks.each(&:async_rerun)
44
33
  else
45
34
  raise ArgumentError.new("context should now be nil. Use #delete_context for clearing document.")
@@ -47,12 +36,8 @@ class Puppeteer::DOMWorld
47
36
  end
48
37
 
49
38
  def delete_context(execution_context_id)
50
- if @pending_destroy.include?(execution_context_id)
51
- @pending_destroy.delete(execution_context_id)
52
- else
53
- @document = nil
54
- @context_promise = resolvable_future
55
- end
39
+ @document = nil
40
+ @context_promise = resolvable_future
56
41
  end
57
42
 
58
43
  def has_context?