puppeteer-ruby 0.0.13 → 0.0.14
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.circleci/config.yml +0 -12
- data/.github/workflows/docs.yml +45 -0
- data/.github/workflows/reviewdog.yml +15 -0
- data/README.md +52 -1
- data/lib/puppeteer.rb +1 -1
- data/lib/puppeteer/browser.rb +17 -25
- data/lib/puppeteer/cdp_session.rb +3 -19
- data/lib/puppeteer/concurrent_ruby_utils.rb +6 -0
- data/lib/puppeteer/connection.rb +3 -15
- data/lib/puppeteer/define_async_method.rb +23 -0
- data/lib/puppeteer/dom_world.rb +6 -21
- data/lib/puppeteer/element_handle.rb +15 -44
- data/lib/puppeteer/emulation_manager.rb +2 -6
- data/lib/puppeteer/execution_context.rb +1 -6
- data/lib/puppeteer/frame.rb +30 -16
- data/lib/puppeteer/frame_manager.rb +7 -25
- data/lib/puppeteer/js_handle.rb +3 -12
- data/lib/puppeteer/keyboard.rb +6 -27
- data/lib/puppeteer/mouse.rb +5 -25
- data/lib/puppeteer/page.rb +39 -63
- data/lib/puppeteer/remote_object.rb +2 -5
- data/lib/puppeteer/touch_screen.rb +2 -7
- data/lib/puppeteer/version.rb +1 -1
- data/lib/puppeteer/wait_task.rb +2 -4
- data/puppeteer-ruby.gemspec +1 -1
- metadata +7 -103
- data/docs/Puppeteer.html +0 -2338
- data/docs/Puppeteer/AsyncAwaitBehavior.html +0 -105
- data/docs/Puppeteer/Browser.html +0 -2258
- data/docs/Puppeteer/BrowserContext.html +0 -809
- data/docs/Puppeteer/BrowserFetcher.html +0 -214
- data/docs/Puppeteer/BrowserRunner.html +0 -914
- data/docs/Puppeteer/BrowserRunner/BrowserProcess.html +0 -477
- data/docs/Puppeteer/CDPSession.html +0 -813
- data/docs/Puppeteer/CDPSession/Error.html +0 -124
- data/docs/Puppeteer/ConcurrentRubyUtils.html +0 -438
- data/docs/Puppeteer/Connection.html +0 -964
- data/docs/Puppeteer/Connection/MessageCallback.html +0 -434
- data/docs/Puppeteer/Connection/ProtocolError.html +0 -216
- data/docs/Puppeteer/Connection/RequestDebugPrinter.html +0 -217
- data/docs/Puppeteer/Connection/ResponseDebugPrinter.html +0 -244
- data/docs/Puppeteer/ConsoleMessage.html +0 -565
- data/docs/Puppeteer/ConsoleMessage/Location.html +0 -433
- data/docs/Puppeteer/DOMWorld.html +0 -2293
- data/docs/Puppeteer/DOMWorld/DetachedError.html +0 -124
- data/docs/Puppeteer/DOMWorld/DocumentEvaluationError.html +0 -124
- data/docs/Puppeteer/DebugPrint.html +0 -233
- data/docs/Puppeteer/Device.html +0 -470
- data/docs/Puppeteer/Devices.html +0 -139
- data/docs/Puppeteer/ElementHandle.html +0 -2542
- data/docs/Puppeteer/ElementHandle/BoundingBox.html +0 -507
- data/docs/Puppeteer/ElementHandle/BoxModel.html +0 -404
- data/docs/Puppeteer/ElementHandle/ElementNotFoundError.html +0 -206
- data/docs/Puppeteer/ElementHandle/ElementNotVisibleError.html +0 -206
- data/docs/Puppeteer/ElementHandle/Point.html +0 -492
- data/docs/Puppeteer/ElementHandle/ScrollIntoViewError.html +0 -124
- data/docs/Puppeteer/EmulationManager.html +0 -454
- data/docs/Puppeteer/EventCallbackable.html +0 -499
- data/docs/Puppeteer/EventCallbackable/EventListeners.html +0 -435
- data/docs/Puppeteer/ExecutionContext.html +0 -998
- data/docs/Puppeteer/ExecutionContext/EvaluationError.html +0 -124
- data/docs/Puppeteer/ExecutionContext/JavaScriptExpression.html +0 -357
- data/docs/Puppeteer/ExecutionContext/JavaScriptFunction.html +0 -389
- data/docs/Puppeteer/FileChooser.html +0 -455
- data/docs/Puppeteer/Frame.html +0 -3835
- data/docs/Puppeteer/FrameManager.html +0 -2410
- data/docs/Puppeteer/FrameManager/NavigationError.html +0 -124
- data/docs/Puppeteer/IfPresent.html +0 -222
- data/docs/Puppeteer/JSHandle.html +0 -1352
- data/docs/Puppeteer/Keyboard.html +0 -1557
- data/docs/Puppeteer/Keyboard/KeyDefinition.html +0 -831
- data/docs/Puppeteer/Keyboard/KeyDescription.html +0 -603
- data/docs/Puppeteer/Launcher.html +0 -237
- data/docs/Puppeteer/Launcher/Base.html +0 -385
- data/docs/Puppeteer/Launcher/Base/ExecutablePathNotFound.html +0 -124
- data/docs/Puppeteer/Launcher/BrowserOptions.html +0 -441
- data/docs/Puppeteer/Launcher/Chrome.html +0 -674
- data/docs/Puppeteer/Launcher/Chrome/DefaultArgs.html +0 -382
- data/docs/Puppeteer/Launcher/ChromeArgOptions.html +0 -531
- data/docs/Puppeteer/Launcher/LaunchOptions.html +0 -893
- data/docs/Puppeteer/LifecycleWatcher.html +0 -834
- data/docs/Puppeteer/LifecycleWatcher/ExpectedLifecycle.html +0 -363
- data/docs/Puppeteer/LifecycleWatcher/FrameDetachedError.html +0 -206
- data/docs/Puppeteer/LifecycleWatcher/TerminatedError.html +0 -124
- data/docs/Puppeteer/Mouse.html +0 -1095
- data/docs/Puppeteer/Mouse/Button.html +0 -136
- data/docs/Puppeteer/NetworkManager.html +0 -901
- data/docs/Puppeteer/NetworkManager/Credentials.html +0 -385
- data/docs/Puppeteer/Page.html +0 -6173
- data/docs/Puppeteer/Page/FileChooserTimeoutError.html +0 -206
- data/docs/Puppeteer/Page/ScreenshotOptions.html +0 -845
- data/docs/Puppeteer/Page/ScriptTag.html +0 -555
- data/docs/Puppeteer/Page/StyleTag.html +0 -448
- data/docs/Puppeteer/Page/TargetCrashedError.html +0 -124
- data/docs/Puppeteer/RemoteObject.html +0 -1087
- data/docs/Puppeteer/Target.html +0 -1336
- data/docs/Puppeteer/Target/InitializeFailure.html +0 -124
- data/docs/Puppeteer/Target/TargetInfo.html +0 -729
- data/docs/Puppeteer/TimeoutError.html +0 -135
- data/docs/Puppeteer/TimeoutSettings.html +0 -496
- data/docs/Puppeteer/TouchScreen.html +0 -464
- data/docs/Puppeteer/Viewport.html +0 -837
- data/docs/Puppeteer/WaitTask.html +0 -637
- data/docs/Puppeteer/WaitTask/TerminatedError.html +0 -124
- data/docs/Puppeteer/WaitTask/TimeoutError.html +0 -206
- data/docs/Puppeteer/WebSocket.html +0 -673
- data/docs/Puppeteer/WebSocket/DriverImpl.html +0 -412
- data/docs/Puppeteer/WebSocket/TransportError.html +0 -124
- data/docs/Puppeteer/WebSocketTransport.html +0 -600
- data/docs/Puppeteer/WebSocktTransportError.html +0 -124
- data/docs/_index.html +0 -816
- data/docs/class_list.html +0 -51
- data/docs/css/common.css +0 -1
- data/docs/css/full_list.css +0 -58
- data/docs/css/style.css +0 -496
- data/docs/file.README.html +0 -125
- data/docs/file_list.html +0 -56
- data/docs/frames.html +0 -17
- data/docs/index.html +0 -125
- data/docs/js/app.js +0 -314
- data/docs/js/full_list.js +0 -216
- data/docs/js/jquery.js +0 -4
- data/docs/method_list.html +0 -4123
- data/docs/top-level-namespace.html +0 -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:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0a500508a5a1d88ed4694c5614c7c70bdae06d4d5cb10f81c1237ebd25a6623f
|
|
4
|
+
data.tar.gz: 338b902e3c64d9f96e7b7822353a7b664ab112cd3993e7a7ec06cda41752521e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 51ea52a62c04917d5ec62c4224ffe91cacf3ccd3cfc796d94d975c309971dc0e789fdec7f4fabcc37f51619d833f070e7d6136f18cdb7113721382392456dd88
|
|
7
|
+
data.tar.gz: ef643098e96d3d1794470f38befb55039916c13b35d7d133596acf42d7217c302d1de4865c62c178e758aa619063ee9469bbbfcda1665c3e19fcca26aaee12ce
|
data/.circleci/config.yml
CHANGED
|
@@ -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
|
|
data/lib/puppeteer.rb
CHANGED
|
@@ -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'
|
data/lib/puppeteer/browser.rb
CHANGED
|
@@ -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::
|
|
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::
|
|
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
|
-
|
|
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
|
-
|
|
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!
|
data/lib/puppeteer/connection.rb
CHANGED
|
@@ -3,7 +3,7 @@ require 'json'
|
|
|
3
3
|
class Puppeteer::Connection
|
|
4
4
|
include Puppeteer::DebugPrint
|
|
5
5
|
include Puppeteer::EventCallbackable
|
|
6
|
-
using Puppeteer::
|
|
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
|
|
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
|
data/lib/puppeteer/dom_world.rb
CHANGED
|
@@ -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::
|
|
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
|
|
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
|
-
|
|
38
|
-
@
|
|
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
|
-
|
|
51
|
-
|
|
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?
|