puppeteer-ruby 0.0.16 → 0.0.21

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 38a6ae4190bd04cbacb863d04f9862ebc8a37c6811fbfd690426ba051d5ea5d4
4
- data.tar.gz: 60b61e143e63ed5e42b0bb6f3d9e5c27262fd2f51064c185e491056a5081707d
3
+ metadata.gz: f429910f146a926bd830400269da848120ca070da2a64d5dfec0c9861a6c46f4
4
+ data.tar.gz: e0ba66f60e283d7d0cc6263f7750dc7ddc6f9cd17ceaaaf4ae247c524f8986f8
5
5
  SHA512:
6
- metadata.gz: fc3ab652476ee319fab2d691173a0175d4b03d72346329f2fb855a142c3090693f1fb5cfa52abb4badbfbadc7d4eec5028a295f63fb7ddd3e362321564a96b7c
7
- data.tar.gz: 6de2484b1b939c3cab1bfa48bb2225c54686f13e7901f3df086d8e5c7b18aa9fc62afb5fd9a785a3fbbf12d2aef50cde1d085f3564ce9afab996f80a39c64936
6
+ metadata.gz: 1251d762934da872f78028c12c33e9e025ab331c3e09abe4bb80191e82fa1d09681c204fd1da8c1b86668cf9f317f9f7030d65c6d4aa078355afe8089ffce4eb
7
+ data.tar.gz: 2a28ea494da354c5658c1618806ddb291d53d4a2f2bde0579c5aefc01da523ddc17511cfa5ff6315761c09b7a83b6d9526ff0020cc2275b871788c88a19e70ed
@@ -5,7 +5,7 @@ orbs:
5
5
  jobs:
6
6
  rspec:
7
7
  docker:
8
- - image: circleci/ruby:2.6.3-stretch-node-browsers
8
+ - image: circleci/ruby:2.6.6-buster-node-browsers
9
9
  executor: ruby/default
10
10
  steps:
11
11
  - checkout
@@ -13,10 +13,32 @@ jobs:
13
13
  - run:
14
14
  name: rspec
15
15
  command: |
16
+ DEBUG=1 bundle exec rspec --profile 10 \
17
+ --format RspecJunitFormatter \
18
+ --out test_results/rspec.xml \
19
+ --format documentation
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 \
16
38
  bundle exec rspec --profile 10 \
17
39
  --format RspecJunitFormatter \
18
40
  --out test_results/rspec.xml \
19
- --format progress
41
+ --format documentation spec/integration/
20
42
 
21
43
  deploy:
22
44
  docker:
@@ -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:
@@ -12,4 +12,4 @@ jobs:
12
12
  with:
13
13
  github_token: ${{ secrets.github_token }}
14
14
  reporter: github-pr-review
15
- rubocop_version: 0.86.0
15
+ rubocop_version: 0.90.0
@@ -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/RedundantStringCoercion:
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
- Lint/DeprecatedClassMethods:
208
+ Style/ParenthesesAroundCondition:
169
209
  Enabled: true
170
210
 
171
- Style/ParenthesesAroundCondition:
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
@@ -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
 
@@ -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
@@ -2,6 +2,8 @@ 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'
@@ -22,6 +24,7 @@ require 'puppeteer/cdp_session'
22
24
  require 'puppeteer/connection'
23
25
  require 'puppeteer/console_message'
24
26
  require 'puppeteer/devices'
27
+ require 'puppeteer/dialog'
25
28
  require 'puppeteer/dom_world'
26
29
  require 'puppeteer/emulation_manager'
27
30
  require 'puppeteer/execution_context'
@@ -51,18 +54,14 @@ require 'puppeteer/element_handle'
51
54
 
52
55
  # ref: https://github.com/puppeteer/puppeteer/blob/master/lib/Puppeteer.js
53
56
  class Puppeteer
54
- class << self
55
- def method_missing(method, *args, **kwargs, &block)
56
- instance.send(method, *args, **kwargs, &block)
57
- end
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
+ )
58
63
 
59
- def instance
60
- @instance ||= Puppeteer.new(
61
- project_root: __dir__,
62
- preferred_revision: '706915',
63
- is_puppeteer_core: true,
64
- )
65
- end
64
+ @puppeteer.send(method, *args, **kwargs, &block)
66
65
  end
67
66
 
68
67
  # @param project_root [String]
@@ -168,7 +167,11 @@ class Puppeteer
168
167
  }.compact
169
168
  browser = launcher.connect(options)
170
169
  if block_given?
171
- yield(browser)
170
+ begin
171
+ yield(browser)
172
+ ensure
173
+ browser.disconnect
174
+ end
172
175
  else
173
176
  browser
174
177
  end
@@ -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,7 @@ 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)
98
107
  end
99
108
 
100
109
  class TargetAlreadyExistError < StandardError
@@ -166,7 +175,7 @@ class Puppeteer::Browser
166
175
  end
167
176
 
168
177
  # @return [String]
169
- def websocket_endpoint
178
+ def ws_endpoint
170
179
  @connection.url
171
180
  end
172
181
 
@@ -196,7 +205,7 @@ class Puppeteer::Browser
196
205
 
197
206
  # @return {!Target}
198
207
  def target
199
- targets.first { |target| target.type == 'browser' }
208
+ targets.find { |target| target.type == 'browser' }
200
209
  end
201
210
 
202
211
  # used only in Target#opener
@@ -204,12 +213,11 @@ class Puppeteer::Browser
204
213
  @targets[target_id]
205
214
  end
206
215
 
207
- # @param {function(!Target):boolean} predicate
208
- # @param {{timeout?: number}=} options
209
- # @return {!Promise<!Target>}
216
+ # @param predicate [Proc(Puppeteer::Target -> Boolean)]
217
+ # @return [Puppeteer::Target]
210
218
  def wait_for_target(predicate:, timeout: nil)
211
219
  timeout_in_sec = (timeout || 30000).to_i / 1000.0
212
- existing_target = targets.first { |target| predicate.call(target) }
220
+ existing_target = targets.find { |target| predicate.call(target) }
213
221
  return existing_target if existing_target
214
222
 
215
223
  event_listening_ids = []
@@ -233,11 +241,18 @@ class Puppeteer::Browser
233
241
  else
234
242
  target_promise.value!
235
243
  end
244
+ rescue Timeout::Error
245
+ raise Puppeteer::TimeoutError.new("waiting for target failed: timeout #{timeout}ms exceeded")
236
246
  ensure
237
247
  remove_event_listener(*event_listening_ids)
238
248
  end
239
249
  end
240
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
+
241
256
  # @return {!Promise<!Array<!Puppeteer.Page>>}
242
257
  def pages
243
258
  browser_contexts.flat_map(&:pages)
@@ -266,7 +281,19 @@ class Puppeteer::Browser
266
281
  !@connection.closed?
267
282
  end
268
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
+
269
296
  private def get_version
270
- @connection.send_message('Browser.getVersion')
297
+ Version.new(@connection.send_message('Browser.getVersion'))
271
298
  end
272
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)