apparition 0.0.3 → 0.0.4

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: e4f76aefa6b5bebbab16d325e6f434846c2a426b74df9b8c0248465653124202
4
- data.tar.gz: e9538e39a9c912471527fc456e801f0b3cc261bf042ddc82177d0e74e0769a33
3
+ metadata.gz: 69753c37a3e00ce9d57e86847601bef5e39a820ebef96db2c4ad7a6cb922f341
4
+ data.tar.gz: 486caf74087a17e078b39e4960a0c707b090142f1831d12b9755ad8b2cbb0596
5
5
  SHA512:
6
- metadata.gz: 9f187d2d4b1185e2fe5460adf9435daec58d008789e69bca907df06bdc20f59b1b8808ac4f346ef1c7d00d4caa62a6fe7aaf033a9e3287299a007e8c9c7493fb
7
- data.tar.gz: 443d5076e6b92f8c051a261663a8dc93a3ae2b0a75d87943579b762927b0f8d4e42a527b3c047c4ae937bf001198f7e14ebd8f4ea77de7ffd1ec04d4e096ad65
6
+ metadata.gz: 2f512ba7bbaca565d304a2ac0ede0d1c2b41fd3dc38d7f00b8dbe30b75bba2bbf3c35d7bcea2b00a17bdcbdb9d1702c27efcdfb9ef082b75de3988e7e48664c6
7
+ data.tar.gz: e01438d8900cd67015e0b473e7f710528ac1d8d4597cb8d0f47c97a1971a914b63cb52013bc1958d46621be58123105e1ed1f3d8f9e033ca0d908490fb152f8f
data/README.md CHANGED
@@ -51,7 +51,7 @@ Apparition supports all Capybara features, and the following extended features:
51
51
  * `page.driver.render_base64(format, options)`
52
52
  * `page.driver.scroll_to(left, top)`
53
53
  * `page.driver.basic_authorize(user, password)`
54
- * `page.driver.set_proxy(ip, port, type, user, password)`
54
+ * `page.driver.set_proxy(host, port, type, user, password, bypass: [bypass list passed to chrome])`
55
55
  * cookie handling
56
56
  * extra headers
57
57
 
@@ -3,21 +3,31 @@
3
3
  require 'capybara/apparition/errors'
4
4
  require 'capybara/apparition/dev_tools_protocol/target_manager'
5
5
  require 'capybara/apparition/page'
6
+ require 'capybara/apparition/console'
6
7
  require 'json'
7
8
  require 'time'
8
9
 
9
10
  module Capybara::Apparition
10
11
  class Browser
11
- attr_reader :client, :logger, :paper_size, :zoom_factor
12
+ attr_reader :client, :paper_size, :zoom_factor, :console
13
+ extend Forwardable
14
+
15
+ delegate %i[visit current_url status_code
16
+ title frame_title frame_url
17
+ find scroll_to clear_network_traffic
18
+ evaluate evaluate_async execute
19
+ fullscreen maximize
20
+ response_headers
21
+ go_back go_forward refresh] => :current_page
12
22
 
13
23
  def initialize(client, logger = nil)
14
24
  @client = client
15
- @logger = logger
16
25
  @current_page_handle = nil
17
26
  @targets = Capybara::Apparition::DevToolsProtocol::TargetManager.new
18
27
  @context_id = nil
19
28
  @js_errors = true
20
29
  @ignore_https_errors = false
30
+ @console = Console.new(logger)
21
31
 
22
32
  initialize_handlers
23
33
 
@@ -39,18 +49,6 @@ module Capybara::Apparition
39
49
  current_page.clear_network_traffic
40
50
  end
41
51
 
42
- def visit(url)
43
- current_page.visit url
44
- end
45
-
46
- def current_url
47
- current_page.current_url
48
- end
49
-
50
- def status_code
51
- current_page.status_code
52
- end
53
-
54
52
  def body
55
53
  current_page.content
56
54
  end
@@ -60,40 +58,10 @@ module Capybara::Apparition
60
58
  # command 'source'
61
59
  end
62
60
 
63
- def title
64
- # Updated info doesn't have correct title when changed programmatically
65
- # current_target.title
66
- current_page.title
67
- end
68
-
69
- def frame_title
70
- current_page.frame_title
71
- end
72
-
73
- def frame_url
74
- current_page.frame_url
75
- end
76
-
77
- def find(method, selector)
78
- current_page.find(method, selector)
79
- end
80
-
81
61
  def click_coordinates(x, y)
82
62
  current_page.click_at(x, y)
83
63
  end
84
64
 
85
- def evaluate(script, *args)
86
- current_page.evaluate(script, *args)
87
- end
88
-
89
- def evaluate_async(script, wait_time, *args)
90
- current_page.evaluate_async(script, wait_time, *args)
91
- end
92
-
93
- def execute(script, *args)
94
- current_page.execute(script, *args)
95
- end
96
-
97
65
  def switch_to_frame(frame)
98
66
  case frame
99
67
  when Capybara::Node::Base
@@ -166,10 +134,6 @@ module Capybara::Apparition
166
134
  true
167
135
  end
168
136
 
169
- def scroll_to(left, top)
170
- current_page.scroll_to(left, top)
171
- end
172
-
173
137
  def render(path, options = {})
174
138
  check_render_options!(options, path)
175
139
  img_data = current_page.render(options)
@@ -197,14 +161,6 @@ module Capybara::Apparition
197
161
  current_page.set_viewport width: width, height: height, screen: screen
198
162
  end
199
163
 
200
- def fullscreen
201
- current_page.fullscreen
202
- end
203
-
204
- def maximize
205
- current_page.maximize
206
- end
207
-
208
164
  def network_traffic(type = nil)
209
165
  case type
210
166
  when :blocked
@@ -214,18 +170,6 @@ module Capybara::Apparition
214
170
  end
215
171
  end
216
172
 
217
- def clear_network_traffic
218
- current_page.clear_network_traffic
219
- end
220
-
221
- def set_proxy(ip, port, type, user, password)
222
- args = [ip, port, type]
223
- args << user if user
224
- args << password if password
225
- # TODO: Implement via CDP if possible
226
- # command('set_proxy', *args)
227
- end
228
-
229
173
  def headers
230
174
  current_page.extra_headers
231
175
  end
@@ -260,10 +204,6 @@ module Capybara::Apparition
260
204
  end
261
205
  end
262
206
 
263
- def response_headers
264
- current_page.response_headers
265
- end
266
-
267
207
  def cookies
268
208
  current_page.command('Network.getCookies')['cookies'].each_with_object({}) do |c, h|
269
209
  h[c['name']] = Cookie.new(c)
@@ -343,18 +283,6 @@ module Capybara::Apparition
343
283
  raise
344
284
  end
345
285
 
346
- def go_back
347
- current_page.go_back
348
- end
349
-
350
- def go_forward
351
- current_page.go_forward
352
- end
353
-
354
- def refresh
355
- current_page.refresh
356
- end
357
-
358
286
  def accept_alert
359
287
  current_page.add_modal(alert: true)
360
288
  end
@@ -383,6 +311,10 @@ module Capybara::Apparition
383
311
  current_target.page
384
312
  end
385
313
 
314
+ def console_messages
315
+ console.messages
316
+ end
317
+
386
318
  private
387
319
 
388
320
  def current_target
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Capybara::Apparition
4
+ class Console
5
+ def initialize(logger = nil)
6
+ @logger = logger
7
+ @messages = []
8
+ end
9
+
10
+ def log(type, message)
11
+ @messages << OpenStruct.new(type: type, message: message)
12
+ @logger&.puts message
13
+ end
14
+
15
+ def clear
16
+ @messages.clear
17
+ end
18
+
19
+ def messages
20
+ @messages
21
+ end
22
+ end
23
+ end
@@ -47,5 +47,10 @@ module Capybara::Apparition
47
47
  def expires
48
48
  Time.at @attributes['expires'] unless [nil, 0, -1].include? @attributes['expires']
49
49
  end
50
+
51
+ def ==(value)
52
+ return super unless value.is_a? String
53
+ self.value == value
54
+ end
50
55
  end
51
56
  end
@@ -22,7 +22,8 @@ module Capybara::Apparition
22
22
  headers headers= add_headers
23
23
  cookies remove_cookie clear_cookies cookies_enabled=
24
24
  clear_memory_cache
25
- go_back go_forward refresh] => :browser
25
+ go_back go_forward refresh
26
+ console_messages] => :browser
26
27
 
27
28
  def initialize(app, options = {})
28
29
  @app = app
@@ -37,9 +38,9 @@ module Capybara::Apparition
37
38
  true
38
39
  end
39
40
 
40
- def chrome_url
41
- 'ws://localhost:9223'
42
- end
41
+ # def chrome_url
42
+ # 'ws://localhost:9223'
43
+ # end
43
44
 
44
45
  def browser
45
46
  @browser ||= begin
@@ -64,6 +65,7 @@ module Capybara::Apparition
64
65
  browser_options['remote-debugging-port'] = options[:port] || 0
65
66
  browser_options['remote-debugging-address'] = options[:host] if options[:host]
66
67
  browser_options['window-size'] = options[:window_size].join(',') if options[:window_size]
68
+ browser_options.merge! @options[:browser] if @options[:browser]
67
69
  @launcher ||= Browser::Launcher.start(
68
70
  headless: options[:headless] != false,
69
71
  browser: browser_options
@@ -194,13 +196,19 @@ module Capybara::Apparition
194
196
  end
195
197
  end
196
198
 
197
- def set_proxy(ip, port, type = 'http', user = nil, password = nil)
198
- browser.set_proxy(ip, port, type, user, password)
199
+ def set_proxy(host, port, type = nil, user = nil, password = nil, bypass: [])
200
+ # TODO: Look at implementing via the CDP Fetch domain
201
+ raise ArgumentError, "Proxy auth is not yet implented" if user || password
202
+ @options[:browser] ||= {}
203
+ @options[:browser].merge!("proxy-server" => "#{type+"=" if type}#{host}:#{port}")
204
+ bypass = Array(bypass).join(';')
205
+ @options[:browser].merge!("proxy-bypass-list" => bypass) unless bypass.empty?
199
206
  end
200
207
 
201
208
  def add_header(name, value, options = {})
202
209
  browser.add_header({ name => value }, { permanent: true }.merge(options))
203
210
  end
211
+ alias_method :header, :add_header
204
212
 
205
213
  def response_headers
206
214
  browser.response_headers.each_with_object({}) do |(key, value), hsh|
@@ -208,7 +216,9 @@ module Capybara::Apparition
208
216
  end
209
217
  end
210
218
 
211
- def set_cookie(name, value, options = {})
219
+ def set_cookie(name, value=nil, options = {})
220
+ name, value, options = parse_raw_cookie(name) if value.nil?
221
+
212
222
  options[:name] ||= name
213
223
  options[:value] ||= value
214
224
  options[:domain] ||= begin
@@ -227,6 +237,7 @@ module Capybara::Apparition
227
237
  # credentials = ["#{user}:#{password}"].pack('m*').strip
228
238
  # add_header('Authorization', "Basic #{credentials}")
229
239
  end
240
+ alias_method :authenticate, :basic_authorize
230
241
 
231
242
  def debug
232
243
  if @options[:inspector]
@@ -324,8 +335,41 @@ module Capybara::Apparition
324
335
  client.timeout = sec
325
336
  end
326
337
 
338
+ def within_frame(frame_selector)
339
+ warn "Driver#within_frame is deprecated, please use Session#within_frame"
340
+
341
+ frame = case frame_selector
342
+ when Capybara::Apparition::Node
343
+ frame_selector
344
+ when Integer
345
+ find_css('iframe')[frame_selector]
346
+ when String
347
+ find_css("iframe[name='#{frame_selector}']")[0]
348
+ else
349
+ raise TypeError, 'Unknown frame selector'
350
+ command("FrameFocus")
351
+ end
352
+
353
+ switch_to_frame(frame)
354
+ begin
355
+ yield
356
+ ensure
357
+ switch_to_frame(:parent)
358
+ end
359
+ end
360
+
327
361
  private
328
362
 
363
+ def parse_raw_cookie(raw)
364
+ parts = raw.split(/;\s*/)
365
+ name, value = parts[0].split('=', 2)
366
+ options = parts[1..-1].each_with_object({}) do |part, opts|
367
+ name, value = part.split('=', 2)
368
+ opts[name.to_sym] = value
369
+ end
370
+ [name, value, options]
371
+ end
372
+
329
373
  def screen_size
330
374
  options[:screen_size] || [1366, 768]
331
375
  end
@@ -341,8 +385,9 @@ module Capybara::Apparition
341
385
  raise Capybara::ModalNotFound if modal_text.nil? || (expect_text && !modal_text.match(expect_regexp))
342
386
  rescue Capybara::ModalNotFound => e
343
387
  if timer.expired?
344
- raise e, 'Unable to find modal dialog'\
345
- "#{" with #{expect_text}" if expect_text}"\
388
+ raise e, 'Timed out waiting for modal dialog. Unable to find modal dialog.' if !found_text
389
+ raise e, 'Unable to find modal dialog' \
390
+ "#{" with #{expect_text}" if expect_text}" \
346
391
  "#{", did find modal with #{found_text}" if found_text}"
347
392
  end
348
393
  sleep(0.05)
@@ -128,12 +128,14 @@ module Capybara
128
128
  'new element.'
129
129
  end
130
130
  end
131
+ NodeNotAttachedError = ObsoleteNode
131
132
 
132
133
  class WrongWorld < ObsoleteNode
133
134
  def message
134
135
  'The element you are trying to access is not from the current page'
135
136
  end
136
137
  end
138
+ NodeNotAttachedError = ObsoleteNode
137
139
 
138
140
  class UnsupportedFeature < ClientError
139
141
  def name
@@ -186,6 +186,7 @@ module Capybara::Apparition
186
186
  'abort': { 'keyCode': 3, 'code': 'Abort', 'key': 'Cancel' },
187
187
  'help': { 'keyCode': 6, 'code': 'Help', 'key': 'Help' },
188
188
  'backspace': { 'keyCode': 8, 'code': 'Backspace', 'key': 'Backspace' },
189
+ "\b": { 'keyCode': 8, 'code': 'Backspace', 'key': 'Backspace' },
189
190
  'tab': { 'keyCode': 9, 'code': 'Tab', 'key': 'Tab' },
190
191
  'enter': { 'keyCode': 13, 'code': 'Enter', 'key': 'Enter', 'text': "\r" },
191
192
  "\r": { 'keyCode': 13, 'code': 'Enter', 'key': 'Enter', 'text': "\r" },
@@ -64,6 +64,11 @@ module Capybara::Apparition
64
64
  .tr("\u00a0", ' ')
65
65
  end
66
66
 
67
+ def text # capybara-webkit method
68
+ warn "Node#text is deprecated, please use Node#visible_text instead"
69
+ visible_text
70
+ end
71
+
67
72
  def property(name)
68
73
  evaluate_on('function(name){ return this[name] }', value: name)
69
74
  end
@@ -161,8 +166,11 @@ module Capybara::Apparition
161
166
 
162
167
  @page.mouse.click_at pos.merge(button: button, count: count, modifiers: keys)
163
168
  if ENV['DEBUG']
164
- new_pos = element_click_pos(options)
165
- puts "Element moved from #{pos} to #{new_pos}" unless pos == new_pos
169
+ begin
170
+ new_pos = element_click_pos(options)
171
+ puts "Element moved from #{pos} to #{new_pos}" unless pos == new_pos
172
+ rescue WrongWorld
173
+ end
166
174
  end
167
175
  # Wait a short time to see if click triggers page load
168
176
  sleep 0.05
@@ -430,7 +438,11 @@ module Capybara::Apparition
430
438
  # Clear field by JavaScript assignment of the value property.
431
439
  # Script can change a readonly element which user input cannot, so
432
440
  # don't execute if readonly.
433
- driver.execute_script "arguments[0].value = ''", self unless clear == :none
441
+ driver.execute_script <<~JS, self unless clear == :none
442
+ if (!arguments[0].readOnly) {
443
+ arguments[0].value = ''
444
+ }
445
+ JS
434
446
  send_keys(value)
435
447
  end
436
448
  end
@@ -706,13 +718,7 @@ module Capybara::Apparition
706
718
  GET_VALUE_JS = <<~JS
707
719
  function(){
708
720
  if ((this.tagName == 'SELECT') && this.multiple){
709
- let selected = [];
710
- for (let option of this.children) {
711
- if (option.selected) {
712
- selected.push(option.value);
713
- }
714
- }
715
- return selected;
721
+ return Array.from(this.querySelectorAll("option:checked"),e=>e.value);
716
722
  } else {
717
723
  return this.value;
718
724
  }
@@ -339,8 +339,8 @@ module Capybara::Apparition
339
339
 
340
340
  def update_headers(async: false)
341
341
  method = async ? :async_command : :command
342
- if extra_headers['User-Agent']
343
- send(method, 'Network.setUserAgentOverride', userAgent: extra_headers['User-Agent'])
342
+ if (ua = extra_headers.find { |k, _v| k=~/^User-Agent$/i })
343
+ send(method, 'Network.setUserAgentOverride', userAgent: ua[1])
344
344
  end
345
345
  send(method, 'Network.setExtraHTTPHeaders', headers: extra_headers)
346
346
  setup_network_interception
@@ -526,9 +526,8 @@ module Capybara::Apparition
526
526
  end
527
527
 
528
528
  @session.on 'Runtime.consoleAPICalled' do |params|
529
- @browser.logger&.puts(
530
- "#{params['type']}: #{params['args'].map { |arg| arg['description'] || arg['value'] }.join(' ')}"
531
- )
529
+ @browser.console.log(params['type'],
530
+ "#{params['args'].map { |arg| arg['description'] || arg['value'] }.join(' ')}")
532
531
  end
533
532
 
534
533
  # @session.on 'Security.certificateError' do |params|
@@ -603,7 +602,9 @@ module Capybara::Apparition
603
602
  entry = history['entries'][history['currentIndex'] + delta]
604
603
  return nil unless entry
605
604
 
605
+ main_frame.loading(-1)
606
606
  command('Page.navigateToHistoryEntry', entryId: entry['id'])
607
+ wait_for_loaded
607
608
  end
608
609
 
609
610
  def _execute_script(script, *args)
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Capybara
4
4
  module Apparition
5
- VERSION = '0.0.3'
5
+ VERSION = '0.0.4'
6
6
  end
7
7
  end
@@ -1,5 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'backports/2.4.0/enumerable/sum'
4
+ require 'backports/2.4.0/string/match'
3
5
  require 'capybara'
4
6
 
5
7
  module Capybara
metadata CHANGED
@@ -1,15 +1,29 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: apparition
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  platform: ruby
6
6
  authors:
7
7
  - Thomas Walpole
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-01-27 00:00:00.000000000 Z
11
+ date: 2019-01-28 00:00:00.000000000 Z
12
12
  dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: backports
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - ">="
18
+ - !ruby/object:Gem::Version
19
+ version: '0'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - ">="
25
+ - !ruby/object:Gem::Version
26
+ version: '0'
13
27
  - !ruby/object:Gem::Dependency
14
28
  name: capybara
15
29
  requirement: !ruby/object:Gem::Requirement
@@ -197,6 +211,7 @@ files:
197
211
  - lib/capybara/apparition.rb
198
212
  - lib/capybara/apparition/browser.rb
199
213
  - lib/capybara/apparition/chrome_client.rb
214
+ - lib/capybara/apparition/console.rb
200
215
  - lib/capybara/apparition/cookie.rb
201
216
  - lib/capybara/apparition/dev_tools_protocol/session.rb
202
217
  - lib/capybara/apparition/dev_tools_protocol/target.rb
@@ -232,7 +247,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
232
247
  requirements:
233
248
  - - ">="
234
249
  - !ruby/object:Gem::Version
235
- version: 2.4.0
250
+ version: 2.3.0
236
251
  required_rubygems_version: !ruby/object:Gem::Requirement
237
252
  requirements:
238
253
  - - ">="