puppeteer-ruby 0.0.16 → 0.0.21
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 +25 -2
- 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 +15 -12
- data/lib/puppeteer/browser.rb +36 -9
- data/lib/puppeteer/browser_context.rb +35 -5
- data/lib/puppeteer/browser_runner.rb +1 -1
- data/lib/puppeteer/cdp_session.rb +10 -0
- data/lib/puppeteer/connection.rb +8 -3
- data/lib/puppeteer/debug_print.rb +2 -2
- 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 +37 -14
- data/lib/puppeteer/element_handle.rb +49 -20
- data/lib/puppeteer/env.rb +23 -0
- data/lib/puppeteer/frame.rb +14 -10
- data/lib/puppeteer/js_handle.rb +37 -27
- data/lib/puppeteer/keyboard.rb +3 -2
- data/lib/puppeteer/keyboard/us_keyboard_layout.rb +2 -2
- data/lib/puppeteer/launcher.rb +11 -1
- data/lib/puppeteer/launcher/base.rb +14 -4
- data/lib/puppeteer/launcher/chrome.rb +1 -1
- data/lib/puppeteer/launcher/firefox.rb +389 -0
- data/lib/puppeteer/mouse.rb +16 -0
- data/lib/puppeteer/page.rb +67 -36
- data/lib/puppeteer/remote_object.rb +28 -1
- data/lib/puppeteer/request.rb +23 -29
- data/lib/puppeteer/version.rb +1 -1
- data/lib/puppeteer/wait_task.rb +1 -1
- data/lib/puppeteer/web_socket.rb +7 -0
- data/puppeteer-ruby.gemspec +2 -1
- metadata +23 -4
data/lib/puppeteer/page.rb
CHANGED
@@ -101,7 +101,9 @@ class Puppeteer::Page
|
|
101
101
|
end
|
102
102
|
# client.on('Runtime.consoleAPICalled', event => this._onConsoleAPI(event));
|
103
103
|
# client.on('Runtime.bindingCalled', event => this._onBindingCalled(event));
|
104
|
-
|
104
|
+
@client.on_event 'Page.javascriptDialogOpening' do |event|
|
105
|
+
handle_dialog_opening(event)
|
106
|
+
end
|
105
107
|
# client.on('Runtime.exceptionThrown', exception => this._handleException(exception.exceptionDetails));
|
106
108
|
# client.on('Inspector.targetCrashed', event => this._onTargetCrashed());
|
107
109
|
# client.on('Performance.metrics', event => this._emitMetrics(event));
|
@@ -129,7 +131,7 @@ class Puppeteer::Page
|
|
129
131
|
EVENT_MAPPINGS = {
|
130
132
|
close: 'Events.Page.Close',
|
131
133
|
# console: 'Events.Page.Console',
|
132
|
-
|
134
|
+
dialog: 'Events.Page.Dialog',
|
133
135
|
domcontentloaded: 'Events.Page.DOMContentLoaded',
|
134
136
|
# error:
|
135
137
|
frameattached: 'Events.Page.FrameAttached',
|
@@ -266,7 +268,13 @@ class Puppeteer::Page
|
|
266
268
|
@frame_manager.main_frame
|
267
269
|
end
|
268
270
|
|
269
|
-
attr_reader :
|
271
|
+
attr_reader :touch_screen, :coverage, :accessibility
|
272
|
+
|
273
|
+
def keyboard(&block)
|
274
|
+
@keyboard.instance_eval(&block) unless block.nil?
|
275
|
+
|
276
|
+
@keyboard
|
277
|
+
end
|
270
278
|
|
271
279
|
def frames
|
272
280
|
@frame_manager.frames
|
@@ -626,20 +634,17 @@ class Puppeteer::Page
|
|
626
634
|
# this.emit(Events.Page.Console, message);
|
627
635
|
# }
|
628
636
|
|
629
|
-
|
630
|
-
|
631
|
-
|
632
|
-
|
633
|
-
|
634
|
-
|
635
|
-
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
640
|
-
# const dialog = new Dialog(this._client, dialogType, event.message, event.defaultPrompt);
|
641
|
-
# this.emit(Events.Page.Dialog, dialog);
|
642
|
-
# }
|
637
|
+
private def handle_dialog_opening(event)
|
638
|
+
dialog_type = event['type']
|
639
|
+
unless %w(alert confirm prompt beforeunload).include?(dialog_type)
|
640
|
+
raise ArgumentError.new("Unknown javascript dialog type: #{dialog_type}")
|
641
|
+
end
|
642
|
+
dialog = Puppeteer::Dialog.new(@client,
|
643
|
+
type: dialog_type,
|
644
|
+
message: event['message'],
|
645
|
+
default_value: event['defaultPrompt'])
|
646
|
+
emit_event('Events.Page.Dialog', dialog)
|
647
|
+
end
|
643
648
|
|
644
649
|
# @return [String]
|
645
650
|
def url
|
@@ -681,12 +686,14 @@ class Puppeteer::Page
|
|
681
686
|
).first
|
682
687
|
end
|
683
688
|
|
684
|
-
# @param timeout [number|nil]
|
685
|
-
# @param wait_until [string|nil] 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2'
|
686
689
|
private def wait_for_navigation(timeout: nil, wait_until: nil)
|
687
690
|
main_frame.send(:wait_for_navigation, timeout: timeout, wait_until: wait_until)
|
688
691
|
end
|
689
692
|
|
693
|
+
# @!method async_wait_for_navigation(timeout: nil, wait_until: nil)
|
694
|
+
#
|
695
|
+
# @param timeout [number|nil]
|
696
|
+
# @param wait_until [string|nil] 'load' | 'domcontentloaded' | 'networkidle0' | 'networkidle2'
|
690
697
|
define_async_method :async_wait_for_navigation
|
691
698
|
|
692
699
|
private def wait_for_network_manager_event(event_name, predicate:, timeout:)
|
@@ -725,13 +732,6 @@ class Puppeteer::Page
|
|
725
732
|
end
|
726
733
|
end
|
727
734
|
|
728
|
-
# - Waits until request URL matches
|
729
|
-
# `wait_for_request(url: 'https://example.com/awesome')`
|
730
|
-
# - Waits until request matches the given predicate
|
731
|
-
# `wait_for_request(predicate: -> (req){ req.url.start_with?('https://example.com/search') })`
|
732
|
-
#
|
733
|
-
# @param url [String]
|
734
|
-
# @param predicate [Proc(Puppeteer::Request -> Boolean)]
|
735
735
|
private def wait_for_request(url: nil, predicate: nil, timeout: nil)
|
736
736
|
if !url && !predicate
|
737
737
|
raise ArgumentError.new('url or predicate must be specified')
|
@@ -752,10 +752,20 @@ class Puppeteer::Page
|
|
752
752
|
)
|
753
753
|
end
|
754
754
|
|
755
|
-
|
756
|
-
|
755
|
+
# @!method async_wait_for_request(url: nil, predicate: nil, timeout: nil)
|
756
|
+
#
|
757
|
+
# Waits until request URL matches or request matches the given predicate.
|
758
|
+
#
|
759
|
+
# Waits until request URL matches
|
760
|
+
# wait_for_request(url: 'https://example.com/awesome')
|
761
|
+
#
|
762
|
+
# Waits until request matches the given predicate
|
763
|
+
# wait_for_request(predicate: -> (req){ req.url.start_with?('https://example.com/search') })
|
764
|
+
#
|
757
765
|
# @param url [String]
|
758
766
|
# @param predicate [Proc(Puppeteer::Request -> Boolean)]
|
767
|
+
define_async_method :async_wait_for_request
|
768
|
+
|
759
769
|
private def wait_for_response(url: nil, predicate: nil, timeout: nil)
|
760
770
|
if !url && !predicate
|
761
771
|
raise ArgumentError.new('url or predicate must be specified')
|
@@ -776,6 +786,10 @@ class Puppeteer::Page
|
|
776
786
|
)
|
777
787
|
end
|
778
788
|
|
789
|
+
# @!method async_wait_for_response(url: nil, predicate: nil, timeout: nil)
|
790
|
+
#
|
791
|
+
# @param url [String]
|
792
|
+
# @param predicate [Proc(Puppeteer::Request -> Boolean)]
|
779
793
|
define_async_method :async_wait_for_response
|
780
794
|
|
781
795
|
# @param timeout [number|nil]
|
@@ -1071,8 +1085,19 @@ class Puppeteer::Page
|
|
1071
1085
|
define_async_method :async_select
|
1072
1086
|
|
1073
1087
|
# @param selector [String]
|
1074
|
-
def tap(selector)
|
1075
|
-
|
1088
|
+
def tap(selector: nil, &block)
|
1089
|
+
# resolves double meaning of tap.
|
1090
|
+
if selector.nil? && block
|
1091
|
+
# Original usage of Object#tap.
|
1092
|
+
#
|
1093
|
+
# browser.new_page.tap do |page|
|
1094
|
+
# ...
|
1095
|
+
# end
|
1096
|
+
super(&block)
|
1097
|
+
else
|
1098
|
+
# Puppeteer's Page#tap.
|
1099
|
+
main_frame.tap(selector)
|
1100
|
+
end
|
1076
1101
|
end
|
1077
1102
|
|
1078
1103
|
define_async_method :async_tap
|
@@ -1096,6 +1121,11 @@ class Puppeteer::Page
|
|
1096
1121
|
|
1097
1122
|
define_async_method :async_wait_for_selector
|
1098
1123
|
|
1124
|
+
# @param milliseconds [Integer] the number of milliseconds to wait.
|
1125
|
+
def wait_for_timeout(milliseconds)
|
1126
|
+
main_frame.wait_for_timeout(milliseconds)
|
1127
|
+
end
|
1128
|
+
|
1099
1129
|
# @param xpath [String]
|
1100
1130
|
# @param visible [Boolean] Wait for element visible (not 'display: none' nor 'visibility: hidden') on true. default to false.
|
1101
1131
|
# @param hidden [Boolean] Wait for element invisible ('display: none' nor 'visibility: hidden') on true. default to false.
|
@@ -1106,12 +1136,13 @@ class Puppeteer::Page
|
|
1106
1136
|
|
1107
1137
|
define_async_method :async_wait_for_xpath
|
1108
1138
|
|
1109
|
-
# @param
|
1110
|
-
# @param
|
1111
|
-
# @param
|
1112
|
-
# @
|
1113
|
-
|
1114
|
-
|
1139
|
+
# @param page_function [String]
|
1140
|
+
# @param args [Integer|Array]
|
1141
|
+
# @param polling [String]
|
1142
|
+
# @param timeout [Integer]
|
1143
|
+
# @return [Puppeteer::JSHandle]
|
1144
|
+
def wait_for_function(page_function, args: [], polling: nil, timeout: nil)
|
1145
|
+
main_frame.wait_for_function(page_function, args: args, polling: polling, timeout: timeout)
|
1115
1146
|
end
|
1116
1147
|
|
1117
1148
|
define_async_method :async_wait_for_function
|
@@ -6,6 +6,7 @@ class Puppeteer::RemoteObject
|
|
6
6
|
# @param payload [Hash]
|
7
7
|
def initialize(payload)
|
8
8
|
@object_id = payload['objectId']
|
9
|
+
@type = payload['type']
|
9
10
|
@sub_type = payload['subtype']
|
10
11
|
@unserializable_value = payload['unserializableValue']
|
11
12
|
@value = payload['value']
|
@@ -42,6 +43,21 @@ class Puppeteer::RemoteObject
|
|
42
43
|
end
|
43
44
|
end
|
44
45
|
|
46
|
+
# @return [String]
|
47
|
+
def type_str
|
48
|
+
# used in JSHandle#to_s
|
49
|
+
# original logic:
|
50
|
+
# if (this._remoteObject.objectId) {
|
51
|
+
# const type = this._remoteObject.subtype || this._remoteObject.type;
|
52
|
+
# return 'JSHandle@' + type;
|
53
|
+
# }
|
54
|
+
if @object_id
|
55
|
+
@sub_type || @type
|
56
|
+
else
|
57
|
+
nil
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
45
61
|
# used in JSHandle#properties
|
46
62
|
def properties(client)
|
47
63
|
# original logic:
|
@@ -64,7 +80,18 @@ class Puppeteer::RemoteObject
|
|
64
80
|
|
65
81
|
# used in ElementHandle#_box_model
|
66
82
|
def box_model(client)
|
67
|
-
client.send_message('DOM.getBoxModel', objectId: @object_id)
|
83
|
+
result = client.send_message('DOM.getBoxModel', objectId: @object_id)
|
84
|
+
|
85
|
+
# Firefox returns width/height = 0, content/padding/border/margin = [nil, nil, nil, nil, nil, nil, nil, nil]
|
86
|
+
# while Chrome throws Error(Could not compute box model)
|
87
|
+
model = result['model']
|
88
|
+
if model['width'] == 0 && model['height'] == 0 &&
|
89
|
+
%w(content padding border margin).all? { |key| model[key].all?(&:nil?) }
|
90
|
+
|
91
|
+
debug_puts('Could not compute box model in Firefox.')
|
92
|
+
return nil
|
93
|
+
end
|
94
|
+
result
|
68
95
|
rescue => err
|
69
96
|
debug_puts(err)
|
70
97
|
nil
|
data/lib/puppeteer/request.rb
CHANGED
@@ -106,17 +106,15 @@ class Puppeteer::Request
|
|
106
106
|
#
|
107
107
|
# Example:
|
108
108
|
#
|
109
|
-
#
|
110
|
-
#
|
111
|
-
#
|
112
|
-
#
|
113
|
-
#
|
114
|
-
#
|
115
|
-
#
|
116
|
-
#
|
117
|
-
#
|
118
|
-
# ```
|
119
|
-
#`
|
109
|
+
# page.on 'request' do |req|
|
110
|
+
# # Override headers
|
111
|
+
# headers = req.headers.merge(
|
112
|
+
# foo: 'bar', # set "foo" header
|
113
|
+
# origin: nil, # remove "origin" header
|
114
|
+
# )
|
115
|
+
# req.continue(headers: headers)
|
116
|
+
# end
|
117
|
+
#
|
120
118
|
# @param error_code [String|Symbol]
|
121
119
|
def continue(url: nil, method: nil, post_data: nil, headers: nil)
|
122
120
|
# Request interception is not supported for data: urls.
|
@@ -152,15 +150,13 @@ class Puppeteer::Request
|
|
152
150
|
#
|
153
151
|
# Example:
|
154
152
|
#
|
155
|
-
#
|
156
|
-
#
|
157
|
-
#
|
158
|
-
#
|
159
|
-
#
|
160
|
-
#
|
161
|
-
#
|
162
|
-
# end
|
163
|
-
# ````
|
153
|
+
# page.on 'request' do |req|
|
154
|
+
# req.respond(
|
155
|
+
# status: 404,
|
156
|
+
# content_type: 'text/plain',
|
157
|
+
# body: 'Not Found!'
|
158
|
+
# )
|
159
|
+
# end
|
164
160
|
#
|
165
161
|
# @param status [Integer]
|
166
162
|
# @param headers [Hash<String, String>]
|
@@ -211,16 +207,14 @@ class Puppeteer::Request
|
|
211
207
|
#
|
212
208
|
# Example:
|
213
209
|
#
|
214
|
-
#
|
215
|
-
#
|
216
|
-
#
|
217
|
-
#
|
218
|
-
#
|
219
|
-
#
|
210
|
+
# page.on 'request' do |req|
|
211
|
+
# if req.url.include?("porn")
|
212
|
+
# req.abort
|
213
|
+
# else
|
214
|
+
# req.continue
|
215
|
+
# end
|
220
216
|
# end
|
221
|
-
#
|
222
|
-
# ```
|
223
|
-
#`
|
217
|
+
#
|
224
218
|
# @param error_code [String|Symbol]
|
225
219
|
def abort(error_code: :failed)
|
226
220
|
# Request interception is not supported for data: urls.
|
data/lib/puppeteer/version.rb
CHANGED
data/lib/puppeteer/wait_task.rb
CHANGED
@@ -25,7 +25,7 @@ class Puppeteer::WaitTask
|
|
25
25
|
@dom_world = dom_world
|
26
26
|
@polling = polling
|
27
27
|
@timeout = timeout
|
28
|
-
@predicate_body = predicate_body
|
28
|
+
@predicate_body = "return (#{predicate_body})(...args);"
|
29
29
|
@args = args
|
30
30
|
@run_count = 0
|
31
31
|
@dom_world._wait_tasks.add(self)
|
data/lib/puppeteer/web_socket.rb
CHANGED
@@ -16,10 +16,14 @@ class Puppeteer::WebSocket
|
|
16
16
|
|
17
17
|
def write(data)
|
18
18
|
@socket.write(data)
|
19
|
+
rescue Errno::EPIPE
|
20
|
+
raise EOFError.new('already closed')
|
19
21
|
end
|
20
22
|
|
21
23
|
def readpartial(maxlen = 1024)
|
22
24
|
@socket.readpartial(maxlen)
|
25
|
+
rescue Errno::ECONNRESET
|
26
|
+
raise EOFError.new('closed by remote')
|
23
27
|
end
|
24
28
|
end
|
25
29
|
|
@@ -40,6 +44,9 @@ class Puppeteer::WebSocket
|
|
40
44
|
rescue EOFError
|
41
45
|
# Google Chrome was gone.
|
42
46
|
# We have nothing todo. Just finish polling.
|
47
|
+
if @ready_state < STATE_CLOSING
|
48
|
+
handle_on_close(reason: 'Going Away', code: 1001)
|
49
|
+
end
|
43
50
|
end
|
44
51
|
end
|
45
52
|
|
data/puppeteer-ruby.gemspec
CHANGED
@@ -26,7 +26,8 @@ Gem::Specification.new do |spec|
|
|
26
26
|
spec.add_development_dependency 'rake', '~> 10.0'
|
27
27
|
spec.add_development_dependency 'rspec', '~> 3.0'
|
28
28
|
spec.add_development_dependency 'rspec_junit_formatter' # for CircleCI.
|
29
|
-
spec.add_development_dependency 'rubocop', '~> 0.
|
29
|
+
spec.add_development_dependency 'rubocop', '~> 0.90.0'
|
30
30
|
spec.add_development_dependency 'rubocop-rspec'
|
31
|
+
spec.add_development_dependency 'sinatra'
|
31
32
|
spec.add_development_dependency 'yard'
|
32
33
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: puppeteer-ruby
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.21
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- YusukeIwaki
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-10-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: concurrent-ruby
|
@@ -128,14 +128,14 @@ dependencies:
|
|
128
128
|
requirements:
|
129
129
|
- - "~>"
|
130
130
|
- !ruby/object:Gem::Version
|
131
|
-
version: 0.
|
131
|
+
version: 0.90.0
|
132
132
|
type: :development
|
133
133
|
prerelease: false
|
134
134
|
version_requirements: !ruby/object:Gem::Requirement
|
135
135
|
requirements:
|
136
136
|
- - "~>"
|
137
137
|
- !ruby/object:Gem::Version
|
138
|
-
version: 0.
|
138
|
+
version: 0.90.0
|
139
139
|
- !ruby/object:Gem::Dependency
|
140
140
|
name: rubocop-rspec
|
141
141
|
requirement: !ruby/object:Gem::Requirement
|
@@ -150,6 +150,20 @@ dependencies:
|
|
150
150
|
- - ">="
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: '0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: sinatra
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - ">="
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '0'
|
160
|
+
type: :development
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - ">="
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '0'
|
153
167
|
- !ruby/object:Gem::Dependency
|
154
168
|
name: yard
|
155
169
|
requirement: !ruby/object:Gem::Requirement
|
@@ -179,11 +193,13 @@ files:
|
|
179
193
|
- ".rspec"
|
180
194
|
- ".rubocop.yml"
|
181
195
|
- ".travis.yml"
|
196
|
+
- Dockerfile
|
182
197
|
- Gemfile
|
183
198
|
- README.md
|
184
199
|
- Rakefile
|
185
200
|
- bin/console
|
186
201
|
- bin/setup
|
202
|
+
- docker-compose.yml
|
187
203
|
- lib/puppeteer.rb
|
188
204
|
- lib/puppeteer/browser.rb
|
189
205
|
- lib/puppeteer/browser_context.rb
|
@@ -197,12 +213,14 @@ files:
|
|
197
213
|
- lib/puppeteer/define_async_method.rb
|
198
214
|
- lib/puppeteer/device.rb
|
199
215
|
- lib/puppeteer/devices.rb
|
216
|
+
- lib/puppeteer/dialog.rb
|
200
217
|
- lib/puppeteer/dom_world.rb
|
201
218
|
- lib/puppeteer/element_handle.rb
|
202
219
|
- lib/puppeteer/element_handle/bounding_box.rb
|
203
220
|
- lib/puppeteer/element_handle/box_model.rb
|
204
221
|
- lib/puppeteer/element_handle/point.rb
|
205
222
|
- lib/puppeteer/emulation_manager.rb
|
223
|
+
- lib/puppeteer/env.rb
|
206
224
|
- lib/puppeteer/errors.rb
|
207
225
|
- lib/puppeteer/event_callbackable.rb
|
208
226
|
- lib/puppeteer/execution_context.rb
|
@@ -219,6 +237,7 @@ files:
|
|
219
237
|
- lib/puppeteer/launcher/browser_options.rb
|
220
238
|
- lib/puppeteer/launcher/chrome.rb
|
221
239
|
- lib/puppeteer/launcher/chrome_arg_options.rb
|
240
|
+
- lib/puppeteer/launcher/firefox.rb
|
222
241
|
- lib/puppeteer/launcher/launch_options.rb
|
223
242
|
- lib/puppeteer/lifecycle_watcher.rb
|
224
243
|
- lib/puppeteer/mouse.rb
|