puppeteer-ruby 0.0.17 → 0.0.22
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.circleci/config.yml +24 -1
- data/.github/workflows/reviewdog.yml +1 -1
- data/.rubocop.yml +49 -3
- data/Dockerfile +9 -0
- data/README.md +26 -1
- data/docker-compose.yml +34 -0
- data/lib/puppeteer.rb +12 -11
- data/lib/puppeteer/browser_runner.rb +20 -5
- data/lib/puppeteer/cdp_session.rb +10 -0
- data/lib/puppeteer/concurrent_ruby_utils.rb +18 -5
- data/lib/puppeteer/connection.rb +2 -2
- data/lib/puppeteer/debug_print.rb +1 -1
- data/lib/puppeteer/define_async_method.rb +1 -1
- data/lib/puppeteer/devices.rb +998 -849
- data/lib/puppeteer/dialog.rb +34 -0
- data/lib/puppeteer/dom_world.rb +21 -1
- data/lib/puppeteer/element_handle.rb +45 -17
- data/lib/puppeteer/env.rb +5 -0
- data/lib/puppeteer/frame.rb +14 -10
- data/lib/puppeteer/js_handle.rb +37 -27
- data/lib/puppeteer/keyboard/us_keyboard_layout.rb +2 -2
- data/lib/puppeteer/launcher.rb +11 -2
- data/lib/puppeteer/launcher/base.rb +14 -4
- data/lib/puppeteer/launcher/browser_options.rb +2 -1
- data/lib/puppeteer/launcher/chrome.rb +5 -9
- data/lib/puppeteer/launcher/firefox.rb +385 -0
- data/lib/puppeteer/page.rb +37 -26
- data/lib/puppeteer/remote_object.rb +28 -1
- data/lib/puppeteer/version.rb +1 -1
- data/lib/puppeteer/wait_task.rb +1 -1
- data/puppeteer-ruby.gemspec +1 -1
- metadata +8 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 627b2272803511db582250101edac0b5f1f0191abdf86255c6f16d0f088cc82e
|
4
|
+
data.tar.gz: 70458a316f8ecce1b784bd84595c3f0fa248c77e671e4458384c494a1471c196
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2baf0cb4769fc7100495b3dc590293085e3219c661bd164cdb28f0aad1975f18cba17890029156a08873f879ef370c196c3d995bfd040d073d42d0b49acbeef3
|
7
|
+
data.tar.gz: 67a23e46e7d439b76f438c59d062fe5daea0d216469e79ea1b4af2b8d60c4f9070455de22e51b9523fde2a67692919420bce2b05becf948120b71d426c4c560f
|
data/.circleci/config.yml
CHANGED
@@ -5,7 +5,7 @@ orbs:
|
|
5
5
|
jobs:
|
6
6
|
rspec:
|
7
7
|
docker:
|
8
|
-
- image: circleci/ruby:2.6.
|
8
|
+
- image: circleci/ruby:2.6.6-buster-node-browsers
|
9
9
|
executor: ruby/default
|
10
10
|
steps:
|
11
11
|
- checkout
|
@@ -18,6 +18,28 @@ jobs:
|
|
18
18
|
--out test_results/rspec.xml \
|
19
19
|
--format documentation
|
20
20
|
|
21
|
+
rspec_firefox:
|
22
|
+
docker:
|
23
|
+
- image: circleci/ruby:2.6.6-buster-node-browsers
|
24
|
+
executor: ruby/default
|
25
|
+
steps:
|
26
|
+
- checkout
|
27
|
+
- ruby/bundle-install
|
28
|
+
- run:
|
29
|
+
name: install firefox-nightly
|
30
|
+
command: |
|
31
|
+
wget -O nightly.tar.bz2 "https://download.mozilla.org/?product=firefox-nightly-latest-ssl&os=linux64&lang=en-US"
|
32
|
+
tar xf nightly.tar.bz2
|
33
|
+
- run:
|
34
|
+
name: rspec
|
35
|
+
command: |
|
36
|
+
DEBUG=1 PUPPETEER_PRODUCT_RSPEC=firefox \
|
37
|
+
PUPPETEER_EXECUTABLE_PATH_RSPEC=${CIRCLE_WORKING_DIRECTORY/#\~/$HOME}/firefox/firefox \
|
38
|
+
bundle exec rspec --profile 10 \
|
39
|
+
--format RspecJunitFormatter \
|
40
|
+
--out test_results/rspec.xml \
|
41
|
+
--format documentation spec/integration/
|
42
|
+
|
21
43
|
deploy:
|
22
44
|
docker:
|
23
45
|
- image: circleci/ruby:2.6.3-stretch-node
|
@@ -49,6 +71,7 @@ workflows:
|
|
49
71
|
ci:
|
50
72
|
jobs:
|
51
73
|
- rspec
|
74
|
+
- rspec_firefox
|
52
75
|
rubygems-deploy:
|
53
76
|
jobs:
|
54
77
|
- deploy:
|
data/.rubocop.yml
CHANGED
@@ -35,6 +35,9 @@ Layout/EndAlignment:
|
|
35
35
|
Layout/EmptyLineAfterMagicComment:
|
36
36
|
Enabled: true
|
37
37
|
|
38
|
+
Layout/EmptyLineAfterMultilineCondition:
|
39
|
+
Enabled: true
|
40
|
+
|
38
41
|
Layout/EmptyLinesAroundAccessModifier:
|
39
42
|
Enabled: true
|
40
43
|
EnforcedStyle: only_before
|
@@ -102,6 +105,10 @@ Layout/SpaceBeforeComment:
|
|
102
105
|
Layout/SpaceBeforeFirstArg:
|
103
106
|
Enabled: true
|
104
107
|
|
108
|
+
Style/ClassMethodsDefinitions:
|
109
|
+
Enabled: true
|
110
|
+
EnforcedStyle: def_self
|
111
|
+
|
105
112
|
Style/DefWithParentheses:
|
106
113
|
Enabled: true
|
107
114
|
|
@@ -112,6 +119,12 @@ Style/MethodDefParentheses:
|
|
112
119
|
Style/RedundantFreeze:
|
113
120
|
Enabled: true
|
114
121
|
|
122
|
+
Style/RedundantSelf:
|
123
|
+
Enabled: true
|
124
|
+
|
125
|
+
Style/RedundantSelfAssignment:
|
126
|
+
Enabled: true
|
127
|
+
|
115
128
|
# Use `foo {}` not `foo{}`.
|
116
129
|
Layout/SpaceBeforeBlockBraces:
|
117
130
|
Enabled: true
|
@@ -146,17 +159,44 @@ Lint/AmbiguousOperator:
|
|
146
159
|
Lint/AmbiguousRegexpLiteral:
|
147
160
|
Enabled: true
|
148
161
|
|
162
|
+
Lint/BinaryOperatorWithIdenticalOperands:
|
163
|
+
Enabled: true
|
164
|
+
|
165
|
+
Lint/DeprecatedClassMethods:
|
166
|
+
Enabled: true
|
167
|
+
|
168
|
+
Lint/DuplicateRescueException:
|
169
|
+
Enabled: true
|
170
|
+
|
149
171
|
Lint/ErbNewArguments:
|
150
172
|
Enabled: true
|
151
173
|
|
174
|
+
Lint/EmptyConditionalBody:
|
175
|
+
Enabled: true
|
176
|
+
|
177
|
+
Lint/FloatComparison:
|
178
|
+
Enabled: true
|
179
|
+
|
180
|
+
Lint/OutOfRangeRegexpRef:
|
181
|
+
Enabled: true
|
182
|
+
|
183
|
+
Lint/RedundantStringCoercion:
|
184
|
+
Enabled: true
|
185
|
+
|
152
186
|
# Use my_method(my_arg) not my_method( my_arg ) or my_method my_arg.
|
153
187
|
Lint/RequireParentheses:
|
154
188
|
Enabled: true
|
155
189
|
|
190
|
+
Lint/SelfAssignment:
|
191
|
+
Enabled: true
|
192
|
+
|
156
193
|
Lint/ShadowingOuterLocalVariable:
|
157
194
|
Enabled: true
|
158
195
|
|
159
|
-
Lint/
|
196
|
+
Lint/TopLevelReturnWithArgument:
|
197
|
+
Enabled: true
|
198
|
+
|
199
|
+
Lint/UnreachableLoop:
|
160
200
|
Enabled: true
|
161
201
|
|
162
202
|
Lint/UriEscapeUnescape:
|
@@ -165,15 +205,18 @@ Lint/UriEscapeUnescape:
|
|
165
205
|
Lint/UselessAssignment:
|
166
206
|
Enabled: true
|
167
207
|
|
168
|
-
|
208
|
+
Style/ParenthesesAroundCondition:
|
169
209
|
Enabled: true
|
170
210
|
|
171
|
-
Style/
|
211
|
+
Style/ExplicitBlockArgument:
|
172
212
|
Enabled: true
|
173
213
|
|
174
214
|
Style/FrozenStringLiteralComment:
|
175
215
|
Enabled: false
|
176
216
|
|
217
|
+
Style/GlobalStdStream:
|
218
|
+
Enabled: true
|
219
|
+
|
177
220
|
Style/HashEachMethods:
|
178
221
|
Enabled: true
|
179
222
|
|
@@ -198,6 +241,9 @@ Style/Semicolon:
|
|
198
241
|
Enabled: true
|
199
242
|
AllowAsExpressionSeparator: true
|
200
243
|
|
244
|
+
Style/StringConcatenation:
|
245
|
+
Enabled: true
|
246
|
+
|
201
247
|
# Prefer Foo.method over Foo::method
|
202
248
|
Style/ColonMethodCall:
|
203
249
|
Enabled: true
|
data/Dockerfile
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
FROM circleci/ruby:2.6.6-buster-node-browsers
|
2
|
+
|
3
|
+
USER root
|
4
|
+
|
5
|
+
RUN wget -O nightly.tar.bz2 "https://download.mozilla.org/?product=firefox-nightly-latest-ssl&os=linux64&lang=en-US" \
|
6
|
+
&& tar xf nightly.tar.bz2 \
|
7
|
+
&& ln -s $(pwd)/firefox/firefox /usr/bin/firefox
|
8
|
+
|
9
|
+
USER circleci
|
data/README.md
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
[![Gem Version](https://badge.fury.io/rb/puppeteer-ruby.svg)](https://badge.fury.io/rb/puppeteer-ruby)
|
2
|
+
|
1
3
|
# Puppeteer in Ruby [UNDER HEAVY DEVELOPMENT]
|
2
4
|
|
3
5
|
A Ruby port of [puppeteer](https://pptr.dev/).
|
@@ -45,9 +47,32 @@ Puppeteer.launch(headless: false, slow_mo: 50, args: ['--guest', '--window-size=
|
|
45
47
|
end
|
46
48
|
```
|
47
49
|
|
50
|
+
### Evaluate JavaScript
|
51
|
+
|
52
|
+
```ruby
|
53
|
+
Puppeteer.launch do |browser|
|
54
|
+
page = browser.pages.last || browser.new_page
|
55
|
+
page.goto 'https://github.com/YusukeIwaki'
|
56
|
+
|
57
|
+
# Get the "viewport" of the page, as reported by the page.
|
58
|
+
dimensions = page.evaluate(<<~JAVASCRIPT)
|
59
|
+
() => {
|
60
|
+
return {
|
61
|
+
width: document.documentElement.clientWidth,
|
62
|
+
height: document.documentElement.clientHeight,
|
63
|
+
deviceScaleFactor: window.devicePixelRatio
|
64
|
+
};
|
65
|
+
}
|
66
|
+
JAVASCRIPT
|
67
|
+
|
68
|
+
puts "dimensions: #{dimensions}"
|
69
|
+
# => dimensions: {"width"=>800, "height"=>600, "deviceScaleFactor"=>1}
|
70
|
+
end
|
71
|
+
```
|
72
|
+
|
48
73
|
More usage examples can be found [here](https://github.com/YusukeIwaki/puppeteer-ruby-example)
|
49
74
|
|
50
|
-
## Collaboration with Selenium or Capybara
|
75
|
+
## :bulb: Collaboration with Selenium or Capybara
|
51
76
|
|
52
77
|
It is really remarkable that we can use puppeteer functions in existing Selenium or Capybara codes, with a few configuration in advance.
|
53
78
|
|
data/docker-compose.yml
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
version: "3"
|
2
|
+
services:
|
3
|
+
chrome:
|
4
|
+
tty: true
|
5
|
+
stdin_open: true
|
6
|
+
build: .
|
7
|
+
environment:
|
8
|
+
BUNDLE_PATH: /usr/local/bundle
|
9
|
+
DEBUG: 1
|
10
|
+
CI: 1
|
11
|
+
volumes:
|
12
|
+
- .:/puppeteer-ruby
|
13
|
+
- bundle-data:/usr/local/bundle
|
14
|
+
working_dir: /puppeteer-ruby
|
15
|
+
command: bundle exec rspec
|
16
|
+
|
17
|
+
firefox:
|
18
|
+
tty: true
|
19
|
+
stdin_open: true
|
20
|
+
build: .
|
21
|
+
environment:
|
22
|
+
BUNDLE_PATH: /usr/local/bundle
|
23
|
+
PUPPETEER_PRODUCT_RSPEC: firefox
|
24
|
+
DEBUG: 1
|
25
|
+
CI: 1
|
26
|
+
volumes:
|
27
|
+
- .:/puppeteer-ruby
|
28
|
+
- bundle-data:/usr/local/bundle
|
29
|
+
working_dir: /puppeteer-ruby
|
30
|
+
command: bundle exec rspec spec/integration/
|
31
|
+
|
32
|
+
volumes:
|
33
|
+
bundle-data:
|
34
|
+
driver: local
|
data/lib/puppeteer.rb
CHANGED
@@ -24,6 +24,7 @@ require 'puppeteer/cdp_session'
|
|
24
24
|
require 'puppeteer/connection'
|
25
25
|
require 'puppeteer/console_message'
|
26
26
|
require 'puppeteer/devices'
|
27
|
+
require 'puppeteer/dialog'
|
27
28
|
require 'puppeteer/dom_world'
|
28
29
|
require 'puppeteer/emulation_manager'
|
29
30
|
require 'puppeteer/execution_context'
|
@@ -53,17 +54,17 @@ require 'puppeteer/element_handle'
|
|
53
54
|
|
54
55
|
# ref: https://github.com/puppeteer/puppeteer/blob/master/lib/Puppeteer.js
|
55
56
|
class Puppeteer
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
57
|
+
def self.method_missing(method, *args, **kwargs, &block)
|
58
|
+
@puppeteer ||= Puppeteer.new(
|
59
|
+
project_root: __dir__,
|
60
|
+
preferred_revision: '706915',
|
61
|
+
is_puppeteer_core: true,
|
62
|
+
)
|
60
63
|
|
61
|
-
|
62
|
-
@
|
63
|
-
|
64
|
-
|
65
|
-
is_puppeteer_core: true,
|
66
|
-
)
|
64
|
+
if kwargs.empty? # for Ruby < 2.7
|
65
|
+
@puppeteer.public_send(method, *args, &block)
|
66
|
+
else
|
67
|
+
@puppeteer.public_send(method, *args, **kwargs, &block)
|
67
68
|
end
|
68
69
|
end
|
69
70
|
|
@@ -130,7 +131,7 @@ class Puppeteer
|
|
130
131
|
ignore_https_errors: ignore_https_errors,
|
131
132
|
default_viewport: default_viewport,
|
132
133
|
slow_mo: slow_mo,
|
133
|
-
}
|
134
|
+
}
|
134
135
|
|
135
136
|
@product_name ||= product
|
136
137
|
browser = launcher.launch(options)
|
@@ -21,9 +21,18 @@ class Puppeteer::BrowserRunner
|
|
21
21
|
|
22
22
|
class BrowserProcess
|
23
23
|
def initialize(env, executable_path, args)
|
24
|
+
@spawnargs =
|
25
|
+
if args && !args.empty?
|
26
|
+
[executable_path] + args
|
27
|
+
else
|
28
|
+
[executable_path]
|
29
|
+
end
|
30
|
+
|
24
31
|
stdin, @stdout, @stderr, @thread = Open3.popen3(env, executable_path, *args)
|
25
32
|
stdin.close
|
26
33
|
@pid = @thread.pid
|
34
|
+
rescue Errno::ENOENT => err
|
35
|
+
raise LaunchError.new(err.message)
|
27
36
|
end
|
28
37
|
|
29
38
|
def kill
|
@@ -37,7 +46,13 @@ class Puppeteer::BrowserRunner
|
|
37
46
|
@thread.join
|
38
47
|
end
|
39
48
|
|
40
|
-
attr_reader :stdout, :stderr
|
49
|
+
attr_reader :stdout, :stderr, :spawnargs
|
50
|
+
end
|
51
|
+
|
52
|
+
class LaunchError < StandardError
|
53
|
+
def initialize(reason)
|
54
|
+
super("Failed to launch browser! #{reason}")
|
55
|
+
end
|
41
56
|
end
|
42
57
|
|
43
58
|
# @param {!(Launcher.LaunchOptions)=} options
|
@@ -123,12 +138,12 @@ class Puppeteer::BrowserRunner
|
|
123
138
|
|
124
139
|
# @return {Promise}
|
125
140
|
def kill
|
126
|
-
unless @closed
|
127
|
-
@proc.kill
|
128
|
-
end
|
129
141
|
if @temp_directory
|
130
142
|
FileUtils.rm_rf(@temp_directory)
|
131
143
|
end
|
144
|
+
unless @closed
|
145
|
+
@proc.kill
|
146
|
+
end
|
132
147
|
end
|
133
148
|
|
134
149
|
|
@@ -156,6 +171,6 @@ class Puppeteer::BrowserRunner
|
|
156
171
|
end
|
157
172
|
end
|
158
173
|
rescue Timeout::Error
|
159
|
-
raise Puppeteer::TimeoutError.new("Timed out after #{timeout} ms while trying to connect to the browser! Only Chrome at revision r#{
|
174
|
+
raise Puppeteer::TimeoutError.new("Timed out after #{timeout} ms while trying to connect to the browser! Only Chrome at revision r#{preferred_revision} is guaranteed to work.")
|
160
175
|
end
|
161
176
|
end
|
@@ -81,4 +81,14 @@ class Puppeteer::CDPSession
|
|
81
81
|
@connection = nil
|
82
82
|
emit_event 'Events.CDPSession.Disconnected'
|
83
83
|
end
|
84
|
+
|
85
|
+
# @param event_name [String]
|
86
|
+
def on(event_name, &block)
|
87
|
+
add_event_listener(event_name, &block)
|
88
|
+
end
|
89
|
+
|
90
|
+
# @param event_name [String]
|
91
|
+
def once(event_name, &block)
|
92
|
+
observe_first(event_name, &block)
|
93
|
+
end
|
84
94
|
end
|
@@ -4,9 +4,13 @@ module Puppeteer::ConcurrentRubyUtils
|
|
4
4
|
# REMARK: This method doesn't assure the order of calling.
|
5
5
|
# for example, await_all(async1, async2) calls calls2 -> calls1 often.
|
6
6
|
def await_all(*args)
|
7
|
-
if args.length == 1 && args
|
8
|
-
|
7
|
+
if args.length == 1 && args.first.is_a?(Enumerable)
|
8
|
+
await_all(*args.first)
|
9
9
|
else
|
10
|
+
if args.any? { |arg| !arg.is_a?(Concurrent::Promises::Future) }
|
11
|
+
raise ArgumentError.new("All argument must be a Future: #{args}")
|
12
|
+
end
|
13
|
+
|
10
14
|
Concurrent::Promises.zip(*args).value!
|
11
15
|
end
|
12
16
|
end
|
@@ -15,9 +19,13 @@ module Puppeteer::ConcurrentRubyUtils
|
|
15
19
|
# REMARK: This method doesn't assure the order of calling.
|
16
20
|
# for example, await_all(async1, async2) calls calls2 -> calls1 often.
|
17
21
|
def await_any(*args)
|
18
|
-
if args.length == 1 && args
|
19
|
-
|
22
|
+
if args.length == 1 && args.first.is_a?(Enumerable)
|
23
|
+
await_any(*args.first)
|
20
24
|
else
|
25
|
+
if args.any? { |arg| !arg.is_a?(Concurrent::Promises::Future) }
|
26
|
+
raise ArgumentError.new("All argument must be a Future: #{args}")
|
27
|
+
end
|
28
|
+
|
21
29
|
Concurrent::Promises.any(*args).value!
|
22
30
|
end
|
23
31
|
end
|
@@ -32,7 +40,12 @@ module Puppeteer::ConcurrentRubyUtils
|
|
32
40
|
end
|
33
41
|
|
34
42
|
def future(&block)
|
35
|
-
Concurrent::Promises.future
|
43
|
+
Concurrent::Promises.future do
|
44
|
+
block.call
|
45
|
+
rescue => err
|
46
|
+
Logger.new($stderr).warn(err)
|
47
|
+
raise err
|
48
|
+
end
|
36
49
|
end
|
37
50
|
|
38
51
|
def resolvable_future(&block)
|
data/lib/puppeteer/connection.rb
CHANGED
@@ -204,8 +204,8 @@ class Puppeteer::Connection
|
|
204
204
|
callback.reject(
|
205
205
|
ProtocolError.new(
|
206
206
|
method: callback.method,
|
207
|
-
error_message:
|
208
|
-
error_data:
|
207
|
+
error_message: message['error']['message'],
|
208
|
+
error_data: message['error']['data']))
|
209
209
|
else
|
210
210
|
callback.resolve(message['result'])
|
211
211
|
end
|