frameworks-capybara 0.3.0.rc1 → 0.3.0.rc2

Sign up to get free protection for your applications and to get access to all the features.
data/.travis.yml ADDED
@@ -0,0 +1,12 @@
1
+ before_install:
2
+ - sudo apt-get update
3
+ - sudo apt-get install xvfb
4
+ language: ruby
5
+ rvm:
6
+ - 1.8.7
7
+ - 1.9.2
8
+ - 1.9.3
9
+ - jruby-18mode # JRuby in 1.8 mode
10
+ - jruby-19mode # JRuby in 1.9 mode
11
+ # uncomment this line if your project needs to run something other than `rake`:
12
+ # # script: bundle exec rspec spec
data/Gemfile CHANGED
@@ -1,3 +1,7 @@
1
1
  source :rubygems
2
2
 
3
+ platforms :jruby do
4
+ gem "jruby-openssl"
5
+ end
6
+
3
7
  gemspec
data/Gemfile.lock CHANGED
@@ -1,16 +1,20 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- frameworks-capybara (0.3.0.rc1)
4
+ frameworks-capybara (0.3.0.rc2)
5
5
  capybara (>= 1.0.0)
6
6
  capybara-celerity
7
7
  capybara-mechanize (>= 0.3.0)
8
+ capybara-webkit
9
+ cucumber (>= 0.10.5)
10
+ headless
11
+ json
8
12
  w3c_validators
9
13
 
10
14
  GEM
11
15
  remote: http://rubygems.org/
12
16
  specs:
13
- addressable (2.2.7)
17
+ addressable (2.2.8)
14
18
  builder (3.0.0)
15
19
  capybara (1.1.2)
16
20
  mime-types (>= 1.16)
@@ -25,25 +29,28 @@ GEM
25
29
  capybara-mechanize (0.3.0)
26
30
  capybara (~> 1.1)
27
31
  mechanize (~> 2.3)
32
+ capybara-webkit (0.12.1)
33
+ capybara (>= 1.0.0, < 1.2)
34
+ json
28
35
  celerity (0.9.2)
29
- childprocess (0.3.1)
36
+ childprocess (0.3.3)
30
37
  ffi (~> 1.0.6)
31
- cucumber (1.1.9)
38
+ cucumber (1.2.1)
32
39
  builder (>= 2.1.2)
33
- diff-lcs (>= 1.1.2)
34
- gherkin (~> 2.9.0)
40
+ diff-lcs (>= 1.1.3)
41
+ gherkin (~> 2.11.0)
35
42
  json (>= 1.4.6)
36
- term-ansicolor (>= 1.0.6)
37
43
  diff-lcs (1.1.3)
38
44
  domain_name (0.5.3)
39
45
  unf (~> 0.0.3)
40
46
  ffi (1.0.11)
41
- gherkin (2.9.3)
47
+ gherkin (2.11.1)
42
48
  json (>= 1.4.6)
43
- json (1.6.6)
44
- libwebsocket (0.1.3)
49
+ headless (0.3.1)
50
+ json (1.7.3)
51
+ libwebsocket (0.1.4)
45
52
  addressable
46
- mechanize (2.3)
53
+ mechanize (2.5.1)
47
54
  domain_name (~> 0.5, >= 0.5.1)
48
55
  mime-types (~> 1.17, >= 1.17.2)
49
56
  net-http-digest_auth (~> 1.1, >= 1.1.1)
@@ -51,35 +58,33 @@ GEM
51
58
  nokogiri (~> 1.4)
52
59
  ntlm-http (~> 0.1, >= 0.1.1)
53
60
  webrobots (~> 0.0, >= 0.0.9)
54
- mime-types (1.18)
55
- multi_json (1.3.2)
56
- net-http-digest_auth (1.2)
57
- net-http-persistent (2.6)
58
- nokogiri (1.5.2)
61
+ mime-types (1.19)
62
+ multi_json (1.3.6)
63
+ net-http-digest_auth (1.2.1)
64
+ net-http-persistent (2.7)
65
+ nokogiri (1.5.5)
59
66
  ntlm-http (0.1.1)
60
67
  rack (1.4.1)
61
68
  rack-test (0.6.1)
62
69
  rack (>= 1.0)
63
70
  rake (0.9.2.2)
64
- rspec (2.9.0)
65
- rspec-core (~> 2.9.0)
66
- rspec-expectations (~> 2.9.0)
67
- rspec-mocks (~> 2.9.0)
68
- rspec-core (2.9.0)
69
- rspec-expectations (2.9.1)
71
+ rspec (2.10.0)
72
+ rspec-core (~> 2.10.0)
73
+ rspec-expectations (~> 2.10.0)
74
+ rspec-mocks (~> 2.10.0)
75
+ rspec-core (2.10.1)
76
+ rspec-expectations (2.10.0)
70
77
  diff-lcs (~> 1.1.3)
71
- rspec-mocks (2.9.0)
72
- rubyzip (0.9.7)
73
- selenium-webdriver (2.21.2)
78
+ rspec-mocks (2.10.1)
79
+ rubyzip (0.9.9)
80
+ selenium-webdriver (2.24.0)
74
81
  childprocess (>= 0.2.5)
75
- ffi (~> 1.0)
76
82
  libwebsocket (~> 0.1.3)
77
83
  multi_json (~> 1.0)
78
84
  rubyzip
79
- term-ansicolor (1.0.7)
80
85
  unf (0.0.5)
81
86
  unf_ext
82
- unf_ext (0.0.4)
87
+ unf_ext (0.0.5)
83
88
  w3c_validators (1.2)
84
89
  json
85
90
  nokogiri
@@ -91,7 +96,7 @@ PLATFORMS
91
96
  ruby
92
97
 
93
98
  DEPENDENCIES
94
- cucumber (>= 0.10.5)
95
99
  frameworks-capybara!
100
+ jruby-openssl
96
101
  rake
97
102
  rspec (>= 1.0.0)
data/README.rdoc CHANGED
@@ -1,3 +1,5 @@
1
+ = Build Status {<img src="https://secure.travis-ci.org/mcrmfc/frameworks-capybara.png"/>}[https://secure.travis-ci.org/mcrmfc/frameworks-capybara]
2
+
1
3
  = frameworks-capybara
2
4
 
3
5
  Gem to simplify the configuration of Capybara when using multiple drivers, also exposes other useful utility methods.
@@ -34,6 +36,8 @@ The following environment variables can be set to configure your tests:
34
36
  REMOTE_BROWSER_VERSION - used when specifying remote test on a grid the provides a choice of browser versions for a given browser
35
37
  REMOTE_URL - URL of remote Selenium-Webdriver server e.g. http://yourremotehost:4444/wd/hub
36
38
  FIREFOX_PROFILE - specify a firefox profile to use when running in-browser tests (local or remote)
39
+ FIREFOX_PREFS - specify a json string of additional preferences e.g. FIREFOX_PREFS='{"javascript.enabled": false}'
40
+ CREATE_NEW_FF_PROFILE - create a new Firefox profile with name provided by FIREFOX_PROFILE
37
41
  CELERITY_JS_ENABLED (string - 'true', 'false') - determines whether Celerity (HTMLUnit) attempts to execute javascript
38
42
  XVFB - (string - 'true', 'false') - determines whether XVFB is used to run browser (i.e. headless Firefox on *nix platform)
39
43
  FW_CERT_LOCATION - path to client certificate (combined pem)
@@ -22,10 +22,12 @@ Gem::Specification.new do |s|
22
22
 
23
23
  s.add_runtime_dependency("capybara", [">=1.0.0"])
24
24
  s.add_runtime_dependency("capybara-mechanize", [">=0.3.0"])
25
+ s.add_runtime_dependency("capybara-webkit")
26
+ s.add_runtime_dependency("json")
27
+ s.add_runtime_dependency("headless")
25
28
  s.add_runtime_dependency("capybara-celerity")
26
29
  s.add_runtime_dependency("w3c_validators")
27
- s.add_development_dependency("cucumber", [">= 0.10.5"])
30
+ s.add_runtime_dependency("cucumber", [">= 0.10.5"])
28
31
  s.add_development_dependency("rake")
29
32
  s.add_development_dependency("rspec", [">=1.0.0"])
30
-
31
33
  end
@@ -4,15 +4,18 @@ require 'monkey-patches/capybara-patches'
4
4
  require 'monkey-patches/capybara-mechanize-patches'
5
5
  require 'monkey-patches/mechanize-patches'
6
6
  require 'monkey-patches/send-keys'
7
+ require 'monkey-patches/net-http-persistent-patches'
7
8
  require 'selenium-webdriver'
8
9
  require 'capybara/mechanize/cucumber'
9
10
  require 'capybara/celerity'
11
+ require 'capybara-webkit'
10
12
 
11
13
  class CapybaraSetup
12
14
 
13
15
  attr_reader :driver
14
16
 
15
17
  def initialize
18
+
16
19
  http_proxy = ENV['HTTP_PROXY'] || ENV['http_proxy']
17
20
 
18
21
  capybara_opts = {:environment => ENV['ENVIRONMENT'],
@@ -22,7 +25,8 @@ class CapybaraSetup
22
25
  :javascript_enabled => ENV['CELERITY_JS_ENABLED'],
23
26
  :proxy_on => ENV['PROXY_ON'],
24
27
  :url => ENV['REMOTE_URL'],
25
- :chrome_switches => ENV['CHROME_SWITCHES']}
28
+ :chrome_switches => ENV['CHROME_SWITCHES'],
29
+ :firefox_prefs => ENV['FIREFOX_PREFS']}
26
30
 
27
31
  selenium_remote_opts = {:platform => ENV['PLATFORM'],
28
32
  :browser_name => ENV['REMOTE_BROWSER'],
@@ -41,6 +45,7 @@ class CapybaraSetup
41
45
  Capybara.run_server = false #Disable rack server
42
46
 
43
47
  [capybara_opts, selenium_remote_opts, custom_opts].each do |opts| #delete nil options and environment (which is only used for validation)
48
+
44
49
  opts.delete_if {|k,v| (v.nil? or k == :environment)}
45
50
  end
46
51
 
@@ -49,6 +54,8 @@ class CapybaraSetup
49
54
  @driver = register_celerity_driver(capybara_opts)
50
55
  when :mechanize then
51
56
  @driver = register_mechanize_driver(capybara_opts)
57
+ when :webkit then
58
+ @driver = register_webkit_driver(capybara_opts)
52
59
  else
53
60
  @driver = register_selenium_driver(capybara_opts, selenium_remote_opts, custom_opts)
54
61
  end
@@ -77,7 +84,10 @@ class CapybaraSetup
77
84
  def register_selenium_driver(opts,remote_opts,custom_opts)
78
85
  Capybara.register_driver :selenium do |app|
79
86
 
80
- opts[:profile] = create_profile(opts[:profile]) if(opts[:profile])
87
+ if opts[:firefox_prefs] || opts[:profile]
88
+ opts[:profile] = create_profile(opts[:profile], opts[:firefox_prefs])
89
+ end
90
+
81
91
  opts[:switches] = [opts.delete(:chrome_switches)] if(opts[:chrome_switches])
82
92
 
83
93
  if opts[:browser] == :remote
@@ -93,7 +103,8 @@ class CapybaraSetup
93
103
  opts[:desired_capabilities] = caps
94
104
  opts[:http_client] = client
95
105
  end
96
- clean_opts(opts, :proxy, :proxy_on)
106
+
107
+ clean_opts(opts, :proxy, :proxy_on, :firefox_prefs)
97
108
  Capybara::Selenium::Driver.new(app,opts)
98
109
  end
99
110
  :selenium
@@ -108,8 +119,12 @@ class CapybaraSetup
108
119
  Selenium::WebDriver::Proxy.new(:http => opts[:proxy]) if opts[:proxy] && opts[:proxy_on] != 'false' #set proxy on client connection if required, note you may use ENV['HTTP_PROXY'] for setting in browser (ff profile) but not for client conection, hence allow for PROXY_ON=false
109
120
  end
110
121
 
111
- def create_profile(profile_name)
112
- if(profile_name == 'BBC_INTERNAL')
122
+ def create_profile(profile_name = nil, additional_prefs = nil)
123
+ additional_prefs = JSON.parse(additional_prefs) if additional_prefs
124
+ if(additional_prefs && !profile_name)
125
+ profile = Selenium::WebDriver::Firefox::Profile.new
126
+ profile.native_events = true
127
+ elsif(profile_name == 'BBC_INTERNAL')
113
128
  profile = Selenium::WebDriver::Firefox::Profile.new
114
129
  profile["network.proxy.type"] = 1
115
130
  profile["network.proxy.no_proxies_on"] = "*.sandbox.dev.bbc.co.uk"
@@ -118,14 +133,17 @@ class CapybaraSetup
118
133
  profile["network.proxy.http_port"] = 80
119
134
  profile["network.proxy.ssl_port"] = 80
120
135
  profile.native_events = true
121
- elsif(profile_name == 'DISABLED_REFERER')
122
- profile = Selenium::WebDriver::Firefox::Profile.new
123
- profile["network.http.sendRefererHeader"] = 0
124
- profile.native_events = true
125
136
  else
126
137
  profile = Selenium::WebDriver::Firefox::Profile.from_name profile_name
127
138
  profile.native_events = true
128
139
  end
140
+
141
+ if additional_prefs
142
+ additional_prefs.each do |k, v|
143
+ profile[k] = v
144
+ end
145
+ end
146
+
129
147
  profile
130
148
  end
131
149
 
@@ -147,6 +165,13 @@ class CapybaraSetup
147
165
  :mechanize
148
166
  end
149
167
 
168
+ def register_webkit_driver(opts)
169
+ Capybara.register_driver :webkit do |app|
170
+ Capybara::Driver::Webkit.new(app)
171
+ end
172
+ :webkit
173
+ end
174
+
150
175
  def clean_opts(opts, *args)
151
176
  args.each do |arg|
152
177
  opts.delete arg
@@ -2,7 +2,8 @@ require 'frameworks/capybara'
2
2
  require 'w3c_validators'
3
3
  require 'monkey-patches/cucumber-patches'
4
4
 
5
- if(ENV['XVFB']=='true')
5
+ #This is hackish but means we only run once in cucumber and not every scenario
6
+ if(ENV['XVFB']=='true' || ENV['BROWSER'] == 'webkit')
6
7
  puts "You have chosen to use XVFB - ensure you have yum installed Xvfb Xorg and firefox"
7
8
  require 'headless'
8
9
  headless = Headless.new
@@ -18,24 +19,37 @@ module Frameworks
18
19
  #Generate base urls to use in Cucumber step defs
19
20
  def generate_base_urls
20
21
  environment = ENV['ENVIRONMENT'].downcase #be defensive
21
- set_scheme
22
+
23
+ prepare_host
24
+
22
25
  if(environment =='sandbox')
23
26
  @base_url = @sandbox + @bbc_domain
27
+ @pal_base_url = @sandbox + @bbc_domain
28
+ @ssl_base_url = @sslsandbox + @bbc_domain
24
29
  @static_base_url = @static_sandbox + @bbc_domain
30
+ @mobile_base_url = @mobiledot_prefix + "sandbox.dev.bbc.co.uk"
31
+ @m_base_url = @mdot_prefix + "sandbox.dev.bbc.co.uk"
25
32
  elsif (environment =='live' && ENV['WWW_LIVE']=='false')
26
33
  @base_url = @www_prefix.chop + @bbc_domain
34
+ @pal_base_url = @pal_prefix + environment + @bbc_domain
35
+ @ssl_base_url = @ssl_prefix.chop + @bbc_domain
27
36
  @static_base_url = @static_prefix.chop + @bbci_domain
28
37
  @open_base_url = @open_prefix.chop + @bbc_domain
29
- elsif (environment.split('.')[0].include? 'pal') #address specific box
30
- @base_url = "#{scheme}://#{ENV['ENVIRONMENT']}"
38
+ @mobile_base_url = @mobiledot_prefix.chop + @bbc_domain
39
+ @m_base_url = @mdot_prefix.chop + @bbc_domain
31
40
  else
32
41
  @base_url = @www_prefix + environment + @bbc_domain
42
+ @pal_base_url = @pal_prefix + environment + @bbc_domain
43
+ @ssl_base_url = @ssl_prefix + environment + @bbc_domain
33
44
  @static_base_url = @static_prefix + environment + @bbci_domain
34
45
  @static_base_url = @static_prefix.chop + @bbci_domain if environment == 'live'
35
46
  @open_base_url = @open_prefix + environment + @bbc_domain
47
+ @mobile_base_url = @mobiledot_prefix + environment + @bbc_domain
48
+ @m_base_url = @mdot_prefix + environment + @bbc_domain
36
49
  end
50
+
37
51
  proxy = ENV['http_proxy'] || ENV['HTTP_PROXY']
38
- @proxy_host = proxy.scan(/http:\/\/(.*):80/).to_s if proxy
52
+ @proxy_host = proxy.scan(/http:\/\/(.*):80/)[0][0] if proxy
39
53
  end
40
54
 
41
55
  def validate_online(src)
@@ -44,28 +58,34 @@ module Frameworks
44
58
 
45
59
  @validator.set_doctype!(:xhtml)
46
60
  begin
61
+
47
62
  results = @validator.validate_text(src)
48
- rescue Net::HTTPFatalError => e
49
- puts "WARNING - OUTGOING NETWORK ERROR FROM FORGE TO W3C - Validation Not Performed"
50
- end
51
63
 
52
- if results.errors.length > 0
53
- results.errors.each do |err|
54
- puts err.to_s
64
+ if results.errors.length > 0
65
+ results.errors.each do |err|
66
+ puts err.to_s
67
+ end
68
+ raise "W3C Validation of " + current_url + " failed."
55
69
  end
56
- raise "W3C Validation of " + current_url + " failed."
70
+
71
+ rescue Net::HTTPFatalError => e
72
+ puts "WARNING - OUTGOING NETWORK ERROR FROM FORGE TO W3C - Validation Not Performed"
57
73
  end
58
74
  end
59
75
 
60
-
61
- def set_scheme
76
+ def prepare_host
62
77
  ENV['SCHEME']=='https' ? scheme = 'https' : scheme = 'http'
63
78
  @www_prefix = "#{scheme}://www."
79
+ @pal_prefix = "#{scheme}://pal."
80
+ @ssl_prefix = "https://ssl."
64
81
  @static_prefix = "#{scheme}://static."
65
82
  @open_prefix = "#{scheme}://open."
66
83
  @bbc_domain = '.bbc.co.uk'
67
84
  @bbci_domain = '.bbci.co.uk'
68
85
  @sandbox = "#{scheme}://pal.sandbox.dev"
86
+ @mobiledot_prefix = "#{scheme}://mobile."
87
+ @mdot_prefix = "#{scheme}://m."
88
+ @sslsandbox = "https://ssl.sandbox.dev"
69
89
  @static_sandbox = "#{scheme}://static.sandbox.dev"
70
90
  end
71
91
 
@@ -82,14 +102,27 @@ Before do
82
102
  #it was either this or a monkey patch - need to think about pushing a softer reset change to capybara-mechanize to override this
83
103
  http_proxy = ENV['HTTP_PROXY'] || ENV['http_proxy']
84
104
  if page.driver.class == Capybara::Mechanize::Driver
85
- page.driver.browser.agent.cert, page.driver.browser.agent.key = ENV['FW_CERT_LOCATION'], ENV['FW_CERT_LOCATION'] if ENV['FW_CERT_LOCATION']
105
+
106
+ if ENV['FW_CERT_LOCATION']
107
+ page.driver.browser.agent.cert, page.driver.browser.agent.key =
108
+ ENV['FW_CERT_LOCATION'],
109
+ ENV['FW_CERT_LOCATION']
110
+ end
111
+
86
112
  page.driver.browser.agent.ca_file = ENV['CA_CERT_LOCATION'] if ENV['CA_CERT_LOCATION']
87
- #TODO: Fix proxy logic globally...use system proxy instead of PROXY_URL
113
+
88
114
  page.driver.browser.agent.set_proxy(http_proxy.scan(/http:\/\/(.*):80/).to_s,80) if http_proxy
115
+
89
116
  #This is necessary because Mech2 does not ship with root certs like Mech1 did and boxes may not have the OpenSSL set installed
90
117
  page.driver.browser.agent.verify_mode = OpenSSL::SSL::VERIFY_NONE
91
118
  end
92
119
 
120
+ #TODO: See if this can be set at the driver level rather than in before do - and only want to start headless once
121
+ if page.driver.class == Capybara::Driver::Webkit
122
+ page.driver.browser.set_proxy(:host => http_proxy.scan(/http:\/\/(.*):80/).to_s,:port => '80') if http_proxy
123
+ end
124
+
125
+
93
126
  generate_base_urls
94
127
  end
95
128
 
@@ -61,6 +61,12 @@ class Capybara::Mechanize::Driver
61
61
  browser.agent.cookie_jar.clear!
62
62
  end
63
63
 
64
+ def delete_cookies_in_domain(domain)
65
+ cookies.each do |cookie|
66
+ delete_cookie(cookie[:name]) if cookie[:domain].include?(domain)
67
+ end
68
+ end
69
+
64
70
  FakeURI = Struct.new(:host)
65
71
  def add_cookie(attribs)
66
72
  c = Mechanize::Cookie.new(attribs[:name],attribs[:value])
@@ -43,6 +43,10 @@ class Capybara::Selenium::Driver
43
43
  def add_cookie(attribs)
44
44
  browser.manage.add_cookie(attribs)
45
45
  end
46
+
47
+ def delete_cookies_in_domain(domain)
48
+ browser.manage.delete_cookies_in_domain(domain)
49
+ end
46
50
  end
47
51
 
48
52
  module Capybara
@@ -78,6 +82,8 @@ module Capybara
78
82
  driver.add_cookie(attribs)
79
83
  end
80
84
 
85
+ def delete_cookies_in_domain(domain)
86
+ driver.delete_cookies_in_domain(domain)
87
+ end
81
88
  end
82
-
83
89
  end
@@ -57,3 +57,111 @@ end
57
57
  end
58
58
  =end
59
59
 
60
+ # This patch prevents Mechanize from raising a Mechanize::ResponseCodeError
61
+ # when the HTTP Response Code is 503 or 404. This lets capybara continue the journey.
62
+ class Mechanize::HTTP::Agent
63
+ def fetch uri, method = :get, headers = {}, params = [],
64
+ referer = current_page, redirects = 0
65
+ referer_uri = referer ? referer.uri : nil
66
+
67
+ uri = resolve uri, referer
68
+
69
+ uri, params = resolve_parameters uri, method, params
70
+
71
+ request = http_request uri, method, params
72
+
73
+ connection = connection_for uri
74
+
75
+ request_auth request, uri
76
+
77
+ disable_keep_alive request
78
+ enable_gzip request
79
+
80
+ request_language_charset request
81
+ request_cookies request, uri
82
+ request_host request, uri
83
+ request_referer request, uri, referer_uri
84
+ request_user_agent request
85
+ request_add_headers request, headers
86
+
87
+ pre_connect request
88
+
89
+ # Consult robots.txt
90
+ if robots && uri.is_a?(URI::HTTP)
91
+ robots_allowed?(uri) or raise Mechanize::RobotsDisallowedError.new(uri)
92
+ end
93
+
94
+ # Add If-Modified-Since if page is in history
95
+ page = visited_page(uri)
96
+
97
+ if (page = visited_page(uri)) and page.response['Last-Modified']
98
+ request['If-Modified-Since'] = page.response['Last-Modified']
99
+ end if(@conditional_requests)
100
+
101
+ # Specify timeouts if given
102
+ connection.open_timeout = @open_timeout if @open_timeout
103
+ connection.read_timeout = @read_timeout if @read_timeout
104
+
105
+ request_log request
106
+
107
+ response_body_io = nil
108
+
109
+ # Send the request
110
+ begin
111
+ response = connection.request(uri, request) { |res|
112
+ response_log res
113
+
114
+ response_body_io = response_read res, request, uri
115
+
116
+ res
117
+ }
118
+ rescue Mechanize::ChunkedTerminationError => e
119
+ raise unless @ignore_bad_chunking
120
+
121
+ response = e.response
122
+ response_body_io = e.body_io
123
+ end
124
+
125
+ hook_content_encoding response, uri, response_body_io
126
+
127
+ response_body_io = response_content_encoding response, response_body_io if
128
+ request.response_body_permitted?
129
+
130
+ post_connect uri, response, response_body_io
131
+
132
+ page = response_parse response, response_body_io, uri
133
+
134
+ response_cookies response, uri, page
135
+
136
+ meta = response_follow_meta_refresh response, uri, page, redirects
137
+
138
+ return meta if meta
139
+
140
+ case response
141
+ when Net::HTTPSuccess
142
+ if robots && page.is_a?(Mechanize::Page)
143
+ page.parser.noindex? and raise Mechanize::RobotsDisallowedError.new(uri)
144
+ end
145
+
146
+ page
147
+ when Mechanize::FileResponse
148
+ page
149
+ when Net::HTTPNotModified
150
+ log.debug("Got cached page") if log
151
+ visited_page(uri) || page
152
+ when Net::HTTPRedirection
153
+ response_redirect response, method, page, redirects, headers, referer
154
+ when Net::HTTPUnauthorized
155
+ response_authenticate(response, page, uri, request, headers, params,
156
+ referer)
157
+ else
158
+ # BEGIN PATCH
159
+ if page.code == "503" or page.code == "404"
160
+ page
161
+ else
162
+ raise Mechanize::ResponseCodeError.new(page, 'unhandled response')
163
+ end
164
+ # END PATCH
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,72 @@
1
+ #Adding no_proxy_host logic for Mechanize2 which uses this
2
+ #gem for it's HTTP client logic
3
+ #TODO: Grab from envirnment variable optionally, or provide list
4
+ class Net::HTTP::Persistent
5
+
6
+ ##
7
+ # Creates a new connection for +uri+
8
+ def connection_for uri
9
+ Thread.current[@generation_key] ||= Hash.new { |h,k| h[k] = {} }
10
+ Thread.current[@ssl_generation_key] ||= Hash.new { |h,k| h[k] = {} }
11
+ Thread.current[@request_key] ||= Hash.new 0
12
+ Thread.current[@timeout_key] ||= Hash.new EPOCH
13
+
14
+ use_ssl = uri.scheme.downcase == 'https'
15
+
16
+ if use_ssl then
17
+ ssl_generation = @ssl_generation
18
+
19
+ ssl_cleanup ssl_generation
20
+
21
+ connections = Thread.current[@ssl_generation_key][ssl_generation]
22
+ else
23
+ generation = @generation
24
+
25
+ cleanup generation
26
+
27
+ connections = Thread.current[@generation_key][generation]
28
+ end
29
+
30
+ net_http_args = [uri.host, uri.port]
31
+ connection_id = net_http_args.join ':'
32
+ #
33
+ #Frameworks patch (and condition)
34
+ if @proxy_uri and !uri.host.include? 'sandbox' then
35
+ connection_id << @proxy_connection_id
36
+ net_http_args.concat @proxy_args
37
+ end
38
+
39
+ connection = connections[connection_id]
40
+
41
+ unless connection = connections[connection_id] then
42
+ connections[connection_id] = http_class.new(*net_http_args)
43
+ connection = connections[connection_id]
44
+ ssl connection if use_ssl
45
+ else
46
+ reset connection if expired? connection
47
+ end
48
+
49
+ unless connection.started? then
50
+ connection.set_debug_output @debug_output if @debug_output
51
+ connection.open_timeout = @open_timeout if @open_timeout
52
+ connection.read_timeout = @read_timeout if @read_timeout
53
+
54
+ connection.start
55
+
56
+ socket = connection.instance_variable_get :@socket
57
+
58
+ if socket then # for fakeweb
59
+ @socket_options.each do |option|
60
+ socket.io.setsockopt(*option)
61
+ end
62
+ end
63
+ end
64
+
65
+ connection
66
+ rescue Errno::ECONNREFUSED
67
+ raise Error, "connection refused: #{connection.address}:#{connection.port}"
68
+ rescue Errno::EHOSTDOWN
69
+ raise Error, "host down: #{connection.address}:#{connection.port}"
70
+ end
71
+ end
72
+
@@ -7,7 +7,6 @@ module Selenium
7
7
  module WebDriver
8
8
  module Remote
9
9
  class Capabilities
10
-
11
10
  def custom_capabilities(opts)
12
11
  @custom_capabilities = opts
13
12
  end
@@ -15,7 +14,6 @@ module Selenium
15
14
  #hopefuly this alias approach will mean we capture changes in the webdriver method
16
15
  alias_method :old_as_json, :as_json
17
16
  def as_json(opts = nil)
18
-
19
17
  hash = old_as_json
20
18
  if @custom_capabilities
21
19
  @custom_capabilities.each do |key, value|
@@ -24,9 +22,40 @@ module Selenium
24
22
  end
25
23
  hash
26
24
  end
25
+ end
26
+ end
27
27
 
28
+ class Options
29
+ def delete_cookies_in_domain(domain)
30
+ delete_all_cookies #proxy to this method as WebDriver only deletes
31
+ #by domain
28
32
  end
29
33
  end
30
34
  end
31
35
  end
32
36
 
37
+ #Workaround for http://code.google.com/p/selenium/issues/detail?id=4007
38
+ module Selenium
39
+ module WebDriver
40
+ module Remote
41
+ module Http
42
+ class Default
43
+ def new_http_client
44
+ if @proxy
45
+ unless @proxy.respond_to?(:http) && url = @proxy.http
46
+ raise Error::WebDriverError, "expected HTTP proxy, got #{@proxy.inspect}"
47
+ end
48
+
49
+ proxy = URI.parse(url)
50
+
51
+ clazz = Net::HTTP::Proxy(proxy.host, proxy.port, proxy.user, proxy.password)
52
+ clazz.new(server_url.host, server_url.port)
53
+ else
54
+ Net::HTTP.new server_url.host, server_url.port
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+ end
61
+ end
data/lib/version.rb CHANGED
@@ -1,4 +1,3 @@
1
1
  module FrameworksCapybara
2
- VERSION = '0.3.0.rc1'
2
+ VERSION = '0.3.0.rc2'
3
3
  end
4
-
@@ -18,7 +18,6 @@ shared_examples_for "Selenium Driver Options Array" do
18
18
  it "should contain no nil values for unset options" do
19
19
  #TODO: Test for nil elements in options - there shouldn't be any that we insert
20
20
  #i.e. anything in our ENV options should not end up being nil in Selenium
21
-
22
21
  Capybara.current_session.driver.options[:environment].should == nil
23
22
  Capybara.current_session.driver.options[:proxy].should == nil
24
23
  Capybara.current_session.driver.options[:proxy_on].should == nil
@@ -27,6 +26,7 @@ shared_examples_for "Selenium Driver Options Array" do
27
26
  Capybara.current_session.driver.options[:version].should == nil
28
27
  Capybara.current_session.driver.options[:job_name].should == nil
29
28
  Capybara.current_session.driver.options[:chrome_switches].should == nil
29
+ Capybara.current_session.driver.options[:firefox_prefs].should == nil
30
30
  Capybara.current_session.driver.options[:max_duration].should == nil
31
31
  Capybara.current_session.driver.options[:profile].should_not be_a_kind_of String
32
32
  Capybara.current_session.driver.options[:browser].should_not be_a_kind_of String
@@ -136,24 +136,6 @@ describe CapybaraSetup do
136
136
  it_behaves_like "Selenium Driver Options Array"
137
137
  end
138
138
 
139
-
140
- context "with Selenium driver and programtically created profile with referer disabled" do
141
- before do
142
- ENV['BROWSER'] = 'firefox'
143
- ENV['FIREFOX_PROFILE'] = 'DISABLED_REFERER'
144
- end
145
-
146
- it "should be initialized correctly" do
147
- Capybara.delete_session
148
- CapybaraSetup.new.driver.should == :selenium
149
- Capybara.current_session.driver.should be_a_kind_of Capybara::Selenium::Driver
150
- Capybara.current_session.driver.options[:browser].should == :firefox
151
- Capybara.current_session.driver.options[:profile].should be_a_kind_of Selenium::WebDriver::Firefox::Profile
152
- Capybara.current_session.driver.options[:profile].instance_variable_get(:@additional_prefs)['network.http.sendRefererHeader'].should == 0
153
- end
154
- it_behaves_like "Selenium Driver Options Array"
155
- end
156
-
157
139
  context "with Selenium driver and custom chrome options" do
158
140
  before do
159
141
  ENV['BROWSER'] = 'chrome'
@@ -275,6 +257,62 @@ describe CapybaraSetup do
275
257
  it_behaves_like "Selenium Driver Options Array"
276
258
  end
277
259
 
260
+ context "with Selenium driver and hardcoded bbc internal profile and additional firefox preferences" do
261
+ before do
262
+ ENV['BROWSER'] = 'firefox'
263
+ ENV['HTTP_PROXY'] = 'http://example.cache.co.uk:80'
264
+ ENV['FIREFOX_PROFILE'] = 'BBC_INTERNAL'
265
+ ENV['FIREFOX_PREFS'] = '{"javascript.enabled":false}'
266
+ end
267
+
268
+ it "should be initialized correctly" do
269
+ Capybara.delete_session
270
+ CapybaraSetup.new.driver.should == :selenium
271
+ Capybara.current_session.driver.should be_a_kind_of Capybara::Selenium::Driver
272
+ Capybara.current_session.driver.options[:browser].should == :firefox
273
+ Capybara.current_session.driver.options[:profile].should be_a_kind_of Selenium::WebDriver::Firefox::Profile
274
+ Capybara.current_session.driver.options[:profile].instance_variable_get(:@additional_prefs)['javascript.enabled'].should == false
275
+ end
276
+ it_behaves_like "Selenium Driver Options Array"
277
+ end
278
+
279
+
280
+ context "with Selenium driver and additional firefox preferences" do
281
+ before do
282
+ ENV['BROWSER'] = 'firefox'
283
+ ENV['FIREFOX_PROFILE'] = 'default'
284
+ ENV['FIREFOX_PREFS'] = '{"javascript.enabled":false}'
285
+ end
286
+
287
+ it "should be initialized correctly" do
288
+ Capybara.delete_session
289
+ CapybaraSetup.new.driver.should == :selenium
290
+ Capybara.current_session.driver.should be_a_kind_of Capybara::Selenium::Driver
291
+ Capybara.current_session.driver.options[:browser].should == :firefox
292
+ Capybara.current_session.driver.options[:profile].should be_a_kind_of Selenium::WebDriver::Firefox::Profile
293
+ Capybara.current_session.driver.options[:profile].instance_variable_get(:@additional_prefs)['javascript.enabled'].should == false
294
+ end
295
+ it_behaves_like "Selenium Driver Options Array"
296
+ end
297
+
298
+
299
+ context "with Selenium driver and new profile and custom prefs" do
300
+ before do
301
+ ENV['BROWSER'] = 'firefox'
302
+ ENV['FIREFOX_PREFS'] = '{"javascript.enabled":false}'
303
+ end
304
+
305
+ it "should be initialized correctly" do
306
+ Capybara.delete_session
307
+ CapybaraSetup.new.driver.should == :selenium
308
+ Capybara.current_session.driver.should be_a_kind_of Capybara::Selenium::Driver
309
+ Capybara.current_session.driver.options[:browser].should == :firefox
310
+ Capybara.current_session.driver.options[:profile].should be_a_kind_of Selenium::WebDriver::Firefox::Profile
311
+ Capybara.current_session.driver.options[:profile].instance_variable_get(:@additional_prefs)['javascript.enabled'].should == false
312
+ end
313
+ it_behaves_like "Selenium Driver Options Array"
314
+ end
315
+
278
316
  context "with Remote Selenium driver and specified Chrome Switches" do
279
317
  before do
280
318
  ENV['BROWSER'] = 'remote'
@@ -411,6 +449,22 @@ describe CapybaraSetup do
411
449
  end
412
450
 
413
451
  end
452
+
453
+
454
+ describe "should allow Webkit driver to be created" do
455
+ context "with minimal Webkit driver" do
456
+ before do
457
+ ENV['BROWSER'] = 'webkit'
458
+ end
459
+
460
+ it "should be initialized correctly" do
461
+ Capybara.delete_session
462
+ CapybaraSetup.new.driver.should == :webkit
463
+ Capybara.current_session.driver.should be_a_kind_of Capybara::Driver::Webkit
464
+ end
465
+ end
466
+ end
467
+
414
468
  end
415
469
  end
416
470
  end
@@ -14,39 +14,54 @@ describe Frameworks::EnvHelper do
14
14
  ENV['ENVIRONMENT'] = 'sandbox'
15
15
  generate_base_urls
16
16
  @base_url.should == 'http://pal.sandbox.dev.bbc.co.uk'
17
+ @ssl_base_url.should == 'https://ssl.sandbox.dev.bbc.co.uk'
17
18
  @static_base_url.should == 'http://static.sandbox.dev.bbc.co.uk'
19
+ @m_base_url.should == 'http://m.sandbox.dev.bbc.co.uk'
20
+ @mobile_base_url.should == 'http://mobile.sandbox.dev.bbc.co.uk'
18
21
  end
19
22
 
20
23
  it "should be able to set a base url" do
21
24
  ENV['ENVIRONMENT'] = 'foo'
22
25
  generate_base_urls
23
26
  @base_url.should == 'http://www.foo.bbc.co.uk'
27
+ @ssl_base_url.should == 'https://ssl.foo.bbc.co.uk'
24
28
  @static_base_url.should == 'http://static.foo.bbci.co.uk'
25
29
  @open_base_url.should == 'http://open.foo.bbc.co.uk'
30
+ @m_base_url.should == 'http://m.foo.bbc.co.uk'
31
+ @mobile_base_url.should == 'http://mobile.foo.bbc.co.uk'
26
32
  end
27
33
 
28
34
  it "should set correct static base for www.live.bbc.co.uk" do
29
35
  ENV['ENVIRONMENT'] = 'live'
30
36
  generate_base_urls
31
37
  @base_url.should == 'http://www.live.bbc.co.uk'
38
+ @ssl_base_url.should == 'https://ssl.live.bbc.co.uk'
32
39
  @static_base_url.should == 'http://static.bbci.co.uk'
33
40
  @open_base_url.should == 'http://open.live.bbc.co.uk'
41
+ @m_base_url.should == 'http://m.live.bbc.co.uk'
42
+ @mobile_base_url.should == 'http://mobile.live.bbc.co.uk'
34
43
  end
35
44
 
36
45
  it "should be able to set a base url and not be case sensitive" do
37
46
  ENV['ENVIRONMENT'] = 'fOo'
38
47
  generate_base_urls
39
48
  @base_url.should == 'http://www.foo.bbc.co.uk'
49
+ @ssl_base_url.should == 'https://ssl.foo.bbc.co.uk'
40
50
  @static_base_url.should == 'http://static.foo.bbci.co.uk'
41
51
  @open_base_url.should == 'http://open.foo.bbc.co.uk'
52
+ @m_base_url.should == 'http://m.foo.bbc.co.uk'
53
+ @mobile_base_url.should == 'http://mobile.foo.bbc.co.uk'
42
54
  end
43
55
 
44
56
  it "should set correct static base for www.live.bbc.co.uk and not be case sensitive" do
45
57
  ENV['ENVIRONMENT'] = 'LiVe'
46
58
  generate_base_urls
47
59
  @base_url.should == 'http://www.live.bbc.co.uk'
60
+ @ssl_base_url.should == 'https://ssl.live.bbc.co.uk'
48
61
  @static_base_url.should == 'http://static.bbci.co.uk'
49
62
  @open_base_url.should == 'http://open.live.bbc.co.uk'
63
+ @m_base_url.should == 'http://m.live.bbc.co.uk'
64
+ @mobile_base_url.should == 'http://mobile.live.bbc.co.uk'
50
65
  end
51
66
 
52
67
 
@@ -55,15 +70,46 @@ describe Frameworks::EnvHelper do
55
70
  ENV['WWW_LIVE'] = 'false'
56
71
  generate_base_urls
57
72
  @base_url.should == 'http://www.bbc.co.uk'
73
+ @ssl_base_url.should == 'https://ssl.bbc.co.uk'
58
74
  @static_base_url.should == 'http://static.bbci.co.uk'
59
75
  @open_base_url.should == 'http://open.bbc.co.uk'
76
+ @m_base_url.should == 'http://m.bbc.co.uk'
77
+ @mobile_base_url.should == 'http://mobile.bbc.co.uk'
60
78
  end
61
79
 
80
+ it "should be able to set pal url and not be case sensitive" do
81
+ ENV['ENVIRONMENT'] = 'Live'
82
+ generate_base_urls
83
+ @base_url.should == 'http://www.live.bbc.co.uk'
84
+ @pal_base_url.should == 'http://pal.live.bbc.co.uk'
85
+ @ssl_base_url.should == 'https://ssl.live.bbc.co.uk'
86
+ @static_base_url.should == 'http://static.bbci.co.uk'
87
+ @open_base_url.should == 'http://open.live.bbc.co.uk'
88
+ @m_base_url.should == 'http://m.live.bbc.co.uk'
89
+ @mobile_base_url.should == 'http://mobile.live.bbc.co.uk'
90
+ end
91
+
92
+ it "pal url should still have environment even if asking for classic live url" do
93
+ ENV['ENVIRONMENT'] = 'Live'
94
+ ENV['WWW_LIVE'] = 'false'
95
+ generate_base_urls
96
+ @base_url.should == 'http://www.bbc.co.uk'
97
+ @pal_base_url.should == 'http://pal.live.bbc.co.uk'
98
+ @ssl_base_url.should == 'https://ssl.bbc.co.uk'
99
+ @static_base_url.should == 'http://static.bbci.co.uk'
100
+ @open_base_url.should == 'http://open.bbc.co.uk'
101
+ @m_base_url.should == 'http://m.bbc.co.uk'
102
+ @mobile_base_url.should == 'http://mobile.bbc.co.uk'
103
+ end
104
+
105
+
106
+
62
107
  it "should be able to set scheme to ssl" do
63
108
  ENV['SCHEME'] = 'https'
64
109
  ENV['ENVIRONMENT'] = 'foo'
65
110
  generate_base_urls
66
111
  @base_url.should == 'https://www.foo.bbc.co.uk'
112
+ @ssl_base_url.should == 'https://ssl.foo.bbc.co.uk'
67
113
  @static_base_url.should == 'https://static.foo.bbci.co.uk'
68
114
  @open_base_url.should == 'https://open.foo.bbc.co.uk'
69
115
  end
@@ -0,0 +1,10 @@
1
+ # Mozilla User Preferences
2
+
3
+ /* Do not edit this file.
4
+ *
5
+ * If you make changes to this file while the application is running,
6
+ * the changes will be overwritten when the application exits.
7
+ *
8
+ * To make a manual change to preferences, you can visit the URL about:config
9
+ * For more information, see http://www.mozilla.org/unix/customizing.html#prefs
10
+ */
data/spec/profiles.ini ADDED
@@ -0,0 +1,8 @@
1
+ [General]
2
+ StartWithLastProfile=1
3
+
4
+ [Profile0]
5
+ Name=default
6
+ IsRelative=1
7
+ Path=mock.default
8
+ Default=1
data/spec/spec_helper.rb CHANGED
@@ -13,3 +13,4 @@ Cucumber::RbSupport::RbLanguage.new(Cucumber::Runtime.new) #Need to load Cucumbe
13
13
 
14
14
  require 'frameworks/capybara'
15
15
  require 'frameworks/cucumber'
16
+ require 'unit_test_monkeypatches.rb'
@@ -0,0 +1,17 @@
1
+ module Selenium
2
+ module WebDriver
3
+ module Firefox
4
+
5
+ # @api private
6
+ module Util
7
+ module_function
8
+
9
+ def app_data_path
10
+ File.dirname(__FILE__)
11
+ end
12
+
13
+ end # Util
14
+ end # Firefox
15
+ end # WebDriver
16
+ end # Selenium
17
+
metadata CHANGED
@@ -1,15 +1,15 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: frameworks-capybara
3
3
  version: !ruby/object:Gem::Version
4
- hash: 15424039
4
+ hash: 15424033
5
5
  prerelease: 6
6
6
  segments:
7
7
  - 0
8
8
  - 3
9
9
  - 0
10
10
  - rc
11
- - 1
12
- version: 0.3.0.rc1
11
+ - 2
12
+ version: 0.3.0.rc2
13
13
  platform: ruby
14
14
  authors:
15
15
  - matt robbins
@@ -17,7 +17,7 @@ autorequire:
17
17
  bindir: bin
18
18
  cert_chain: []
19
19
 
20
- date: 2012-04-24 00:00:00 +01:00
20
+ date: 2012-07-18 00:00:00 +01:00
21
21
  default_executable:
22
22
  dependencies:
23
23
  - !ruby/object:Gem::Dependency
@@ -63,7 +63,7 @@ dependencies:
63
63
  segments:
64
64
  - 0
65
65
  version: "0"
66
- name: capybara-celerity
66
+ name: capybara-webkit
67
67
  version_requirements: *id003
68
68
  prerelease: false
69
69
  - !ruby/object:Gem::Dependency
@@ -77,12 +77,54 @@ dependencies:
77
77
  segments:
78
78
  - 0
79
79
  version: "0"
80
- name: w3c_validators
80
+ name: json
81
81
  version_requirements: *id004
82
82
  prerelease: false
83
83
  - !ruby/object:Gem::Dependency
84
- type: :development
84
+ type: :runtime
85
85
  requirement: &id005 !ruby/object:Gem::Requirement
86
+ none: false
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ hash: 3
91
+ segments:
92
+ - 0
93
+ version: "0"
94
+ name: headless
95
+ version_requirements: *id005
96
+ prerelease: false
97
+ - !ruby/object:Gem::Dependency
98
+ type: :runtime
99
+ requirement: &id006 !ruby/object:Gem::Requirement
100
+ none: false
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ hash: 3
105
+ segments:
106
+ - 0
107
+ version: "0"
108
+ name: capybara-celerity
109
+ version_requirements: *id006
110
+ prerelease: false
111
+ - !ruby/object:Gem::Dependency
112
+ type: :runtime
113
+ requirement: &id007 !ruby/object:Gem::Requirement
114
+ none: false
115
+ requirements:
116
+ - - ">="
117
+ - !ruby/object:Gem::Version
118
+ hash: 3
119
+ segments:
120
+ - 0
121
+ version: "0"
122
+ name: w3c_validators
123
+ version_requirements: *id007
124
+ prerelease: false
125
+ - !ruby/object:Gem::Dependency
126
+ type: :runtime
127
+ requirement: &id008 !ruby/object:Gem::Requirement
86
128
  none: false
87
129
  requirements:
88
130
  - - ">="
@@ -94,11 +136,11 @@ dependencies:
94
136
  - 5
95
137
  version: 0.10.5
96
138
  name: cucumber
97
- version_requirements: *id005
139
+ version_requirements: *id008
98
140
  prerelease: false
99
141
  - !ruby/object:Gem::Dependency
100
142
  type: :development
101
- requirement: &id006 !ruby/object:Gem::Requirement
143
+ requirement: &id009 !ruby/object:Gem::Requirement
102
144
  none: false
103
145
  requirements:
104
146
  - - ">="
@@ -108,11 +150,11 @@ dependencies:
108
150
  - 0
109
151
  version: "0"
110
152
  name: rake
111
- version_requirements: *id006
153
+ version_requirements: *id009
112
154
  prerelease: false
113
155
  - !ruby/object:Gem::Dependency
114
156
  type: :development
115
- requirement: &id007 !ruby/object:Gem::Requirement
157
+ requirement: &id010 !ruby/object:Gem::Requirement
116
158
  none: false
117
159
  requirements:
118
160
  - - ">="
@@ -124,7 +166,7 @@ dependencies:
124
166
  - 0
125
167
  version: 1.0.0
126
168
  name: rspec
127
- version_requirements: *id007
169
+ version_requirements: *id010
128
170
  prerelease: false
129
171
  description: Gem to ease the pain of managing capybara driver config and provide a home for common utils and patches
130
172
  email:
@@ -139,6 +181,7 @@ files:
139
181
  - .document
140
182
  - .gitignore
141
183
  - .rspec
184
+ - .travis.yml
142
185
  - Gemfile
143
186
  - Gemfile.lock
144
187
  - LICENSE.txt
@@ -152,13 +195,17 @@ files:
152
195
  - lib/monkey-patches/capybara-patches.rb
153
196
  - lib/monkey-patches/cucumber-patches.rb
154
197
  - lib/monkey-patches/mechanize-patches.rb
198
+ - lib/monkey-patches/net-http-persistent-patches.rb
155
199
  - lib/monkey-patches/send-keys.rb
156
200
  - lib/monkey-patches/webdriver-patches.rb
157
201
  - lib/tasks/frameworks-tasks.rb
158
202
  - lib/version.rb
159
203
  - spec/frameworks_capybara_spec.rb
160
204
  - spec/frameworks_cucumber_spec.rb
205
+ - spec/mock.default/prefs.js
206
+ - spec/profiles.ini
161
207
  - spec/spec_helper.rb
208
+ - spec/unit_test_monkeypatches.rb
162
209
  has_rdoc: true
163
210
  homepage:
164
211
  licenses: []