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.
@@ -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
- # client.on('Page.javascriptDialogOpening', event => this._onDialog(event));
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
- # dialog: 'Events.Page.Dialog',
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 :keyboard, :touch_screen, :coverage, :accessibility
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
- # _onDialog(event) {
630
- # let dialogType = null;
631
- # if (event.type === 'alert')
632
- # dialogType = Dialog.Type.Alert;
633
- # else if (event.type === 'confirm')
634
- # dialogType = Dialog.Type.Confirm;
635
- # else if (event.type === 'prompt')
636
- # dialogType = Dialog.Type.Prompt;
637
- # else if (event.type === 'beforeunload')
638
- # dialogType = Dialog.Type.BeforeUnload;
639
- # assert(dialogType, 'Unknown javascript dialog type: ' + event.type);
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
- define_async_method :async_wait_for_request
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
- main_frame.tap(selector)
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 {Function|string} pageFunction
1110
- # @param {!{polling?: string|number, timeout?: number}=} options
1111
- # @param {!Array<*>} args
1112
- # @return {!Promise<!Puppeteer.JSHandle>}
1113
- def wait_for_function(page_function, options = {}, *args)
1114
- main_frame.wait_for_function(page_function, options, *args)
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
@@ -106,17 +106,15 @@ class Puppeteer::Request
106
106
  #
107
107
  # Example:
108
108
  #
109
- # ````
110
- # page.on 'request' do |req|
111
- # # Override headers
112
- # headers = req.headers.merge(
113
- # foo: 'bar', # set "foo" header
114
- # origin: nil, # remove "origin" header
115
- # )
116
- # req.continue(headers: headers)
117
- # end
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
- # page.on 'request' do |req|
157
- # req.respond(
158
- # status: 404,
159
- # content_type: 'text/plain',
160
- # body: 'Not Found!'
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
- # page.on 'request' do |req|
216
- # if req.url.include?("porn")
217
- # req.abort
218
- # else
219
- # req.continue
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
- # end
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.
@@ -1,3 +1,3 @@
1
1
  class Puppeteer
2
- VERSION = '0.0.16'
2
+ VERSION = '0.0.21'
3
3
  end
@@ -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)
@@ -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
 
@@ -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.86.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.16
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-07-12 00:00:00.000000000 Z
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.86.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.86.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