puppeteer-ruby 0.0.17 → 0.0.22
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 +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
|
+
[](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
|