capybara 2.5.0 → 2.6.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +22 -1
  3. data/License.txt +1 -1
  4. data/README.md +21 -28
  5. data/lib/capybara.rb +44 -19
  6. data/lib/capybara/cucumber.rb +1 -1
  7. data/lib/capybara/node/finders.rb +8 -2
  8. data/lib/capybara/queries/current_path_query.rb +3 -3
  9. data/lib/capybara/rack_test/form.rb +28 -9
  10. data/lib/capybara/rails.rb +0 -1
  11. data/lib/capybara/rspec.rb +0 -1
  12. data/lib/capybara/rspec/features.rb +2 -0
  13. data/lib/capybara/selector.rb +54 -22
  14. data/lib/capybara/selenium/node.rb +18 -2
  15. data/lib/capybara/session.rb +35 -47
  16. data/lib/capybara/spec/public/jquery-ui.js +13 -791
  17. data/lib/capybara/spec/public/jquery.js +4 -9045
  18. data/lib/capybara/spec/public/test.js +15 -6
  19. data/lib/capybara/spec/session/accept_confirm_spec.rb +11 -0
  20. data/lib/capybara/spec/session/find_button_spec.rb +22 -0
  21. data/lib/capybara/spec/session/find_field_spec.rb +9 -1
  22. data/lib/capybara/spec/session/has_button_spec.rb +8 -0
  23. data/lib/capybara/spec/session/has_current_path_spec.rb +10 -0
  24. data/lib/capybara/spec/session/has_field_spec.rb +8 -0
  25. data/lib/capybara/spec/session/has_select_spec.rb +14 -0
  26. data/lib/capybara/spec/session/node_spec.rb +22 -4
  27. data/lib/capybara/spec/session/visit_spec.rb +19 -0
  28. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +1 -0
  29. data/lib/capybara/spec/views/form.erb +20 -0
  30. data/lib/capybara/spec/views/with_js.erb +6 -0
  31. data/lib/capybara/version.rb +1 -1
  32. data/spec/rspec/features_spec.rb +17 -5
  33. data/spec/rspec/scenarios_spec.rb +20 -0
  34. data/spec/selector_spec.rb +53 -0
  35. data/spec/selenium_spec.rb +19 -0
  36. data/spec/selenium_spec_chrome.rb +2 -0
  37. data/spec/server_spec.rb +1 -1
  38. metadata +22 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3213dfe8f170fe23b4374001be7b721b00ce9ff7
4
- data.tar.gz: aaebf44440aff65f3183728e404bb07660e606e5
3
+ metadata.gz: b7503b0ca48f7ee15c40c1baacb2e4147aeda674
4
+ data.tar.gz: 0da9283932e38baf19334f06cb94cd3eeaf5acdf
5
5
  SHA512:
6
- metadata.gz: 1624de546eb1f2f56b5dfc38a8a4f597aa930d1db0101ce6f712deb7d15abc31845385b4b18971cfe0d76328d45c8c478109af1de1584c86c64a4f6c30dc550c
7
- data.tar.gz: 21b3438ac351b7a70d642001fb15e429fac7ff3df7eb01f56c04141c5e603bf12dfb1368a408924ee9d6ebb0450cc8397bcab92d4eb9b9242eaac63d7390808e
6
+ metadata.gz: 388e135a8d62498ae35e0f0ae289a0f78cef7ebd2f522197926a3c0a4fa68e67f548aba020ff513dde67dba3ef899685ce7cac49246a647be432f43cdd6bf697
7
+ data.tar.gz: b31b4c8ee11655e952d746ccd44ac228b8d0f739bb684c2e5bbbc80c961219bbbb380570e1adc0e4dc272d7c6081df5f74ab03f5bdf5ca7df8b3b14df7f63d60
data/History.md CHANGED
@@ -1,3 +1,22 @@
1
+ # Version 2.6.0
2
+ Relase date: 2016-01-17
3
+
4
+ ### Fixed
5
+ * Fixed path escaping issue with current_path matchers [Tom Walpole, Luke Rollans] (Issue #1611)
6
+ * Fixed circular require [David Rodríguez]
7
+ * Capybara::RackTest::Form no longer overrides Object#method [David Rodriguez]
8
+ * options and with_options filter for :select selector have more intuitive visibility behavior [Nathan]
9
+ * Test for nested modal API method support [Tom Walpole]
10
+
11
+
12
+ ### Added
13
+ * Capybara.modify_selector [Tom Walpole]
14
+ * xfeature and ffeature aliases added when using RSpec [Filip Bartuzi]
15
+ * Selenium driver supports a :clear option to #set to handle different strategies for clearing a field [Tom Walpole]
16
+ * Support the use of rack 2.0 with the rack_test driver [Travis Grathwell, Tom Walpole]
17
+ * Disabled option for default selectors now supports true, false, or :all [Jillian Rosile, Tom Walpole]
18
+ * Modal API methods now default wait time to Capybara.max_default_wait_time [Tom Walpole]
19
+
1
20
  # Version 2.5.0
2
21
  Release date: 2015-08-25
3
22
 
@@ -12,7 +31,6 @@ Release date: 2015-08-25
12
31
  * Implement Node#path in selenium driver [Soutaro Matsumoto]
13
32
  * 'using_session' is now nestable [Tom Walpole]
14
33
  * 'switch_to_window' will now use waiting behavior for a matching window to appear [Tom Walpole]
15
- * Capybara.default_wait_time deprecated in favor of Capybara.default_max_wait_time to more clearly explain its purpose [Paul Pettengill]
16
34
  * Warning when attempting to select a disabled option
17
35
  * Capybara matchers are now available in RSpec view specs by default [Joshua Clayton]
18
36
  * 'have_link' and 'click_link' now accept Regexp for href matching [Yaniv Savir]
@@ -25,6 +43,9 @@ Release date: 2015-08-25
25
43
  * 'formmethod' attribute support in RackTest driver [Emilia Andrzejewska]
26
44
  * Clear field using backspaces in Selenium driver by using `:fill_options => { :clear => :backspace }` [Joe Lencioni]
27
45
 
46
+ ### Deprecated
47
+ * Capybara.default_wait_time deprecated in favor of Capybara.default_max_wait_time to more clearly explain its purpose [Paul Pettengill]
48
+
28
49
  #Version 2.4.4
29
50
  Release date: 2014-10-13
30
51
 
@@ -1,6 +1,6 @@
1
1
  (The MIT License)
2
2
 
3
- Copyright (c) 2009-2012 Jonas Nicklas
3
+ Copyright (c) 2009-2016 Jonas Nicklas
4
4
 
5
5
  Permission is hereby granted, free of charge, to any person obtaining
6
6
  a copy of this software and associated documentation files (the
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Capybara
2
2
 
3
- [![Build Status](https://secure.travis-ci.org/jnicklas/capybara.png)](http://travis-ci.org/jnicklas/capybara)
4
- [![Dependency Status](https://gemnasium.com/jnicklas/capybara.png)](https://gemnasium.com/jnicklas/capybara)
5
- [![Code Climate](https://codeclimate.com/github/jnicklas/capybara.png)](https://codeclimate.com/github/jnicklas/capybara)
3
+ [![Build Status](https://secure.travis-ci.org/jnicklas/capybara.svg)](https://travis-ci.org/jnicklas/capybara)
4
+ [![Dependency Status](https://gemnasium.com/jnicklas/capybara.svg)](https://gemnasium.com/jnicklas/capybara)
5
+ [![Code Climate](https://codeclimate.com/github/jnicklas/capybara.svg)](https://codeclimate.com/github/jnicklas/capybara)
6
6
 
7
7
  Capybara helps you test web applications by simulating how a real user would
8
8
  interact with your app. It is agnostic about the driver running your tests and
@@ -69,6 +69,8 @@ Capybara requires Ruby 1.9.3 or later. To install, add this line to your
69
69
  gem 'capybara'
70
70
  ```
71
71
 
72
+ **Note:** If using Ruby < 2.0 you will also need to limit the version of mime-types to < 3.0
73
+
72
74
  If the application that you are testing is a Rails app, add this line to your test helper file:
73
75
 
74
76
  ```ruby
@@ -131,7 +133,11 @@ Load RSpec 2.x support by adding the following line (typically to your
131
133
  require 'capybara/rspec'
132
134
  ```
133
135
 
134
- If you are using Rails, put your Capybara specs in `spec/features`.
136
+ If you are using Rails, put your Capybara specs in `spec/features` (only works
137
+ if [you have it configured in
138
+ rpsec](https://www.relishapp.com/rspec/rspec-rails/docs/upgrade#file-type-inference-disabled))
139
+ and if you have your Capybara specs in a different directory, then tag the
140
+ example groups with `:type => :feature`.
135
141
 
136
142
  If you are not using Rails, tag all the example groups in which you want to use
137
143
  Capybara with `:type => :feature`.
@@ -367,7 +373,7 @@ Capybara.javascript_driver = :webkit
367
373
 
368
374
  ### Poltergeist
369
375
 
370
- [Poltergeist](https://github.com/jonleighton/poltergeist) is another
376
+ [Poltergeist](https://github.com/teampoltergeist/poltergeist) is another
371
377
  headless driver which integrates Capybara with
372
378
  [PhantomJS](http://phantomjs.org/). It is truly headless, so doesn't
373
379
  require Xvfb to run on your CI server. It will also detect and report
@@ -399,12 +405,17 @@ The visit method only takes a single parameter, the request method is **always**
399
405
  GET.
400
406
 
401
407
  You can get the [current path](http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Session#current_path-instance_method)
402
- of the browsing session for test assertions:
408
+ of the browsing session, and test it using the [`have_current_path`](http://www.rubydoc.info/github/jnicklas/capybara/master/Capybara/RSpecMatchers#have_current_path-instance_method) matcher:
403
409
 
404
410
  ```ruby
405
- expect(current_path).to eq(post_comments_path(post))
411
+ expect(page).to have_current_path(post_comments_path(post))
406
412
  ```
407
413
 
414
+ **Note**: You can also assert the current path by testing the value of
415
+ `current_path` directly. However, using the `have_current_path` matcher is
416
+ safer since it uses Capybara's [waiting behaviour](#asynchronous-javascript-ajax-and-friends)
417
+ to ensure that preceding actions (such as a `click_link`) have completed.
418
+
408
419
  ### Clicking links and buttons
409
420
 
410
421
  *Full reference: [Capybara::Node::Actions](http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Node/Actions)*
@@ -682,24 +693,7 @@ your test code to be invisible to Capybara.
682
693
 
683
694
  Cucumber handles this by using truncation instead of transactions, i.e. they
684
695
  empty out the entire database after each test. You can get the same behaviour
685
- by using a gem such as [database_cleaner](https://github.com/bmabey/database_cleaner).
686
-
687
- It is also possible to force your ORM to use the same transaction for all
688
- threads. This may have thread safety implications and could cause strange
689
- failures, so use caution with this approach. It can be implemented in
690
- ActiveRecord through the following monkey patch:
691
-
692
- ```ruby
693
- class ActiveRecord::Base
694
- mattr_accessor :shared_connection
695
- @@shared_connection = nil
696
-
697
- def self.connection
698
- @@shared_connection || retrieve_connection
699
- end
700
- end
701
- ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection
702
- ```
696
+ by using a gem such as [database_cleaner](https://github.com/DatabaseCleaner/database_cleaner).
703
697
 
704
698
  ## Asynchronous JavaScript (Ajax and friends)
705
699
 
@@ -769,7 +763,6 @@ You can mix the DSL into any context by including <tt>Capybara::DSL</tt>:
769
763
 
770
764
 
771
765
  ```ruby
772
- require 'capybara'
773
766
  require 'capybara/dsl'
774
767
 
775
768
  Capybara.default_driver = :webkit
@@ -938,7 +931,7 @@ Whatever is returned from the block should conform to the API described by
938
931
  Capybara::Driver::Base, it does not however have to inherit from this class.
939
932
  Gems can use this API to add their own drivers to Capybara.
940
933
 
941
- The [Selenium wiki](http://code.google.com/p/selenium/wiki/RubyBindings) has
934
+ The [Selenium wiki](https://github.com/SeleniumHQ/selenium/wiki/Ruby-Bindings) has
942
935
  additional info about how the underlying driver can be configured.
943
936
 
944
937
  ## Gotchas:
@@ -957,7 +950,7 @@ additional info about how the underlying driver can be configured.
957
950
  since Capybara's Ajax timing uses the system time, resulting in Capybara
958
951
  never timing out and just hanging when a failure occurs. It's still possible to
959
952
  use gems which allow you to travel in time, rather than freeze time.
960
- One such gem is [Timecop](http://github.com/travisjeffery/timecop).
953
+ One such gem is [Timecop](https://github.com/travisjeffery/timecop).
961
954
 
962
955
  * When using Rack::Test, beware if attempting to visit absolute URLs. For
963
956
  example, a session might not be shared between visits to `posts_path`
@@ -37,24 +37,24 @@ module Capybara
37
37
  #
38
38
  # === Configurable options
39
39
  #
40
- # [app_host = String] The default host to use when giving a relative URL to visit
41
- # [always_include_port = Boolean] Whether the Rack server's port should automatically be inserted into every visited URL (Default: false)
42
- # [asset_host = String] Where dynamic assets are hosted - will be prepended to relative asset locations if present (Default: nil)
43
- # [run_server = Boolean] Whether to start a Rack server for the given Rack app (Default: true)
44
- # [raise_server_errors = Boolean] Should errors raised in the server be raised in the tests? (Default: true)
45
- # [server_errors = Array\<Class\>] Error classes that should be raised in the tests if they are raised in the server and Capybara.raise_server_errors is true (Default: [StandardError])
46
- # [default_selector = :css/:xpath] Methods which take a selector use the given type by default (Default: :css)
47
- # [default_max_wait_time = Numeric] The maximum number of seconds to wait for asynchronous processes to finish (Default: 2)
48
- # [ignore_hidden_elements = Boolean] Whether to ignore hidden elements on the page (Default: true)
49
- # [automatic_reload = Boolean] Whether to automatically reload elements as Capybara is waiting (Default: true)
50
- # [save_and_open_page_path = String] Where to put pages saved through save_and_open_page (Default: Dir.pwd)
51
- # [wait_on_first_by_default = Boolean] Whether Node#first defaults to Capybara waiting behavior for at least 1 element to match (Default: false)
40
+ # [app_host = String] The default host to use when giving a relative URL to visit
41
+ # [always_include_port = Boolean] Whether the Rack server's port should automatically be inserted into every visited URL (Default: false)
42
+ # [asset_host = String] Where dynamic assets are hosted - will be prepended to relative asset locations if present (Default: nil)
43
+ # [run_server = Boolean] Whether to start a Rack server for the given Rack app (Default: true)
44
+ # [raise_server_errors = Boolean] Should errors raised in the server be raised in the tests? (Default: true)
45
+ # [server_errors = Array\<Class\>] Error classes that should be raised in the tests if they are raised in the server and Capybara.raise_server_errors is true (Default: [StandardError])
46
+ # [default_selector = :css/:xpath] Methods which take a selector use the given type by default (Default: :css)
47
+ # [default_max_wait_time = Numeric] The maximum number of seconds to wait for asynchronous processes to finish (Default: 2)
48
+ # [ignore_hidden_elements = Boolean] Whether to ignore hidden elements on the page (Default: true)
49
+ # [automatic_reload = Boolean] Whether to automatically reload elements as Capybara is waiting (Default: true)
50
+ # [save_and_open_page_path = String] Where to put pages saved through save_and_open_page (Default: Dir.pwd)
51
+ # [wait_on_first_by_default = Boolean] Whether Node#first defaults to Capybara waiting behavior for at least 1 element to match (Default: false)
52
52
  # === DSL Options
53
53
  #
54
54
  # when using capybara/dsl, the following options are also available:
55
55
  #
56
- # [default_driver = Symbol] The name of the driver to use by default. (Default: :rack_test)
57
- # [javascript_driver = Symbol] The name of a driver to use for JavaScript enabled tests. (Default: :selenium)
56
+ # [default_driver = Symbol] The name of the driver to use by default. (Default: :rack_test)
57
+ # [javascript_driver = Symbol] The name of a driver to use for JavaScript enabled tests. (Default: :selenium)
58
58
  #
59
59
  def configure
60
60
  yield self
@@ -109,6 +109,23 @@ module Capybara
109
109
  Capybara::Selector.add(name, &block)
110
110
  end
111
111
 
112
+ ##
113
+ #
114
+ # Modify a selector previously craeated by {Capybara.add_selector}.
115
+ # For example modifying the :button selector to also find divs styled
116
+ # to look like buttons might look like this
117
+ #
118
+ # Capybara.modfiy_selector(:button) do
119
+ # xpath { |locator| XPath::HTML.button(locator).or(XPath::css('div.btn')[XPath::string.n.is(locator)]) }
120
+ # end
121
+ #
122
+ # @param [Symbol] name The name of the selector to modify
123
+ # @yield A block executed in the context of the existing {Capybara::Selector}
124
+ #
125
+ def modify_selector(name, &block)
126
+ Capybara::Selector.update(name, &block)
127
+ end
128
+
112
129
  def drivers
113
130
  @drivers ||= {}
114
131
  end
@@ -140,7 +157,16 @@ module Capybara
140
157
  # in a {Capybara::Node::Simple} which exposes all {Capybara::Node::Matchers},
141
158
  # {Capybara::Node::Finders} and {Capybara::Node::DocumentMatchers}. This allows you to query
142
159
  # any string containing HTML in the exact same way you would query the current document in a Capybara
143
- # session. For example:
160
+ # session.
161
+ #
162
+ # Example: A single element
163
+ #
164
+ # node = Capybara.string('<a href="foo">bar</a>')
165
+ # anchor = node.first('a')
166
+ # anchor[:href] #=> 'foo'
167
+ # anchor.text #=> 'bar'
168
+ #
169
+ # Example: Multiple elements
144
170
  #
145
171
  # node = Capybara.string <<-HTML
146
172
  # <ul>
@@ -296,13 +322,13 @@ module Capybara
296
322
  end
297
323
  end
298
324
  end
299
-
325
+
300
326
  # @deprecated Use default_max_wait_time instead
301
327
  def default_wait_time
302
328
  deprecate('default_wait_time', 'default_max_wait_time', true)
303
329
  default_max_wait_time
304
330
  end
305
-
331
+
306
332
  # @deprecated Use default_max_wait_time= instead
307
333
  def default_wait_time=(t)
308
334
  deprecate('default_wait_time=', 'default_max_wait_time=')
@@ -337,7 +363,6 @@ module Capybara
337
363
 
338
364
  require 'capybara/helpers'
339
365
  require 'capybara/session'
340
- require 'capybara/dsl'
341
366
  require 'capybara/window'
342
367
  require 'capybara/server'
343
368
  require 'capybara/selector'
@@ -349,7 +374,7 @@ module Capybara
349
374
  require 'capybara/queries/text_query'
350
375
  require 'capybara/queries/title_query'
351
376
  require 'capybara/queries/current_path_query'
352
-
377
+
353
378
  require 'capybara/node/finders'
354
379
  require 'capybara/node/matchers'
355
380
  require 'capybara/node/actions'
@@ -1,4 +1,4 @@
1
- require 'capybara'
1
+ require 'capybara/dsl'
2
2
  require 'capybara/rspec/matchers'
3
3
 
4
4
  World(Capybara::DSL)
@@ -56,7 +56,10 @@ module Capybara
56
56
  #
57
57
  # @option options [Boolean] checked Match checked field?
58
58
  # @option options [Boolean] unchecked Match unchecked field?
59
- # @option options [Boolean] disabled (false) Match disabled field?
59
+ # @option options [Boolean, Symbol] disabled (false) Match disabled field?
60
+ # * true - only finds a disabled field
61
+ # * false - only finds an enabled field
62
+ # * :all - finds either an enabled or disabled field
60
63
  # @option options [Boolean] readonly Match readonly field?
61
64
  # @option options [String] with Value of field to match on
62
65
  # @option options [String] type Type of field to match on
@@ -91,7 +94,10 @@ module Capybara
91
94
  # @macro waiting_behavior
92
95
  #
93
96
  # @param [String] locator Which button to find
94
- # @option options [Boolean] disabled (false) Match disabled button?
97
+ # @option options [Boolean, Symbol] disabled (false) Match disabled button?
98
+ # * true - only finds a disabled button
99
+ # * false - only finds an enabled button
100
+ # * :all - finds either an enabled or disabled button
95
101
  # @return [Capybara::Node::Element] The found element
96
102
  #
97
103
  def find_button(locator, options={})
@@ -15,16 +15,16 @@ module Capybara
15
15
  session.current_url
16
16
  else
17
17
  if options[:only_path]
18
- URI.parse(session.current_url).path
18
+ Addressable::URI.parse(session.current_url).path
19
19
  else
20
- URI.parse(session.current_url).request_uri
20
+ Addressable::URI.parse(session.current_url).request_uri
21
21
  end
22
22
  end
23
23
 
24
24
  if @expected_path.is_a? Regexp
25
25
  @actual_path.match(@expected_path)
26
26
  else
27
- @expected_path == @actual_path
27
+ Addressable::URI.parse(@expected_path) == Addressable::URI.parse(@actual_path)
28
28
  end
29
29
  end
30
30
 
@@ -15,15 +15,15 @@ class Capybara::RackTest::Form < Capybara::RackTest::Node
15
15
  end
16
16
 
17
17
  def params(button)
18
- params = {}
18
+ params = make_params
19
19
 
20
20
  form_element_types=[:input, :select, :textarea]
21
- form_elements_xpath=XPath.generate do |x|
21
+ form_elements_xpath=XPath.generate do |x|
22
22
  xpath=x.descendant(*form_element_types).where(~x.attr(:form))
23
23
  xpath=xpath.union(x.anywhere(*form_element_types).where(x.attr(:form) == native[:id])) if native[:id]
24
24
  xpath.where(~x.attr(:disabled))
25
25
  end.to_s
26
-
26
+
27
27
  native.xpath(form_elements_xpath).map do |field|
28
28
  case field.name
29
29
  when 'input'
@@ -31,7 +31,7 @@ class Capybara::RackTest::Form < Capybara::RackTest::Node
31
31
  if field['checked']
32
32
  node=Capybara::RackTest::Node.new(self.driver, field)
33
33
  merge_param!(params, field['name'].to_s, node.value.to_s)
34
- end
34
+ end
35
35
  elsif %w(submit image).include? field['type']
36
36
  # TO DO identify the click button here (in document order, rather
37
37
  # than leaving until the end of the params)
@@ -67,13 +67,14 @@ class Capybara::RackTest::Form < Capybara::RackTest::Node
67
67
  end
68
68
  end
69
69
  merge_param!(params, button[:name], button[:value] || "") if button[:name]
70
- params
70
+
71
+ params.to_params_hash
71
72
  end
72
73
 
73
74
  def submit(button)
74
75
  action = (button && button['formaction']) || native['action']
75
- requset_method = (button && button['formmethod']) || method
76
- driver.submit(requset_method, action.to_s, params(button))
76
+ method = (button && button['formmethod']) || request_method
77
+ driver.submit(method, action.to_s, params(button))
77
78
  end
78
79
 
79
80
  def multipart?
@@ -82,11 +83,29 @@ class Capybara::RackTest::Form < Capybara::RackTest::Node
82
83
 
83
84
  private
84
85
 
85
- def method
86
+ class ParamsHash < Hash
87
+ def to_params_hash
88
+ self
89
+ end
90
+ end
91
+
92
+ def request_method
86
93
  self[:method] =~ /post/i ? :post : :get
87
94
  end
88
95
 
89
96
  def merge_param!(params, key, value)
90
- Rack::Utils.normalize_params(params, key, value)
97
+ if Rack::Utils.respond_to?(:default_query_parser)
98
+ Rack::Utils.default_query_parser.normalize_params(params, key, value, Rack::Utils.param_depth_limit)
99
+ else
100
+ Rack::Utils.normalize_params(params, key, value)
101
+ end
102
+ end
103
+
104
+ def make_params
105
+ if Rack::Utils.respond_to?(:default_query_parser)
106
+ Rack::Utils.default_query_parser.make_params
107
+ else
108
+ ParamsHash.new
109
+ end
91
110
  end
92
111
  end
@@ -1,4 +1,3 @@
1
- require 'capybara'
2
1
  require 'capybara/dsl'
3
2
 
4
3
  Capybara.app = Rack::Builder.new do
@@ -1,4 +1,3 @@
1
- require 'capybara'
2
1
  require 'capybara/dsl'
3
2
  require 'rspec/core'
4
3
  require 'capybara/rspec/matchers'
@@ -9,6 +9,8 @@ if RSpec::Core::Version::STRING.to_f >= 3.0
9
9
 
10
10
  RSpec.configure do |config|
11
11
  config.alias_example_group_to :feature, :capybara_feature => true, :type => :feature
12
+ config.alias_example_group_to :xfeature, :capybara_feature => true, :type => :feature, :skip => "Temporarily disabled with xfeature"
13
+ config.alias_example_group_to :ffeature, :capybara_feature => true, :type => :feature, :focus => true
12
14
  config.alias_example_to :scenario
13
15
  config.alias_example_to :xscenario, :skip => "Temporarily disabled with xscenario"
14
16
  config.alias_example_to :fscenario, :focus => true
@@ -17,11 +17,25 @@ module Capybara
17
17
  end
18
18
 
19
19
  def matches?(node, value)
20
+ return true if skip?(value)
21
+
20
22
  if @options.has_key?(:valid_values) && !Array(@options[:valid_values]).include?(value)
21
- warn "Invalid value #{value.inspect} passed to filter #{@name}"
23
+ msg = "Invalid value #{value.inspect} passed to filter #{@name} - "
24
+ if default?
25
+ warn msg + "defaulting to #{default}"
26
+ value = default
27
+ else
28
+ warn msg + "skipping"
29
+ return true
30
+ end
22
31
  end
32
+
23
33
  @block.call(node, value)
24
34
  end
35
+
36
+ def skip?(value)
37
+ @options.has_key?(:skip_if) && value == @options[:skip_if]
38
+ end
25
39
  end
26
40
 
27
41
  attr_reader :name, :custom_filters, :format
@@ -35,6 +49,10 @@ module Capybara
35
49
  all[name.to_sym] = Capybara::Selector.new(name.to_sym, &block)
36
50
  end
37
51
 
52
+ def update(name, &block)
53
+ all[name.to_sym].instance_eval(&block)
54
+ end
55
+
38
56
  def remove(name)
39
57
  all.delete(name.to_sym)
40
58
  end
@@ -51,15 +69,19 @@ module Capybara
51
69
  end
52
70
 
53
71
  def xpath(&block)
54
- @format = :xpath
55
- @xpath = block if block
72
+ if block
73
+ @format = :xpath
74
+ @xpath, @css = block, nil
75
+ end
56
76
  @xpath
57
77
  end
58
78
 
59
79
  # Same as xpath, but wrap in XPath.css().
60
80
  def css(&block)
61
- @format = :css
62
- @css = block if block
81
+ if block
82
+ @format = :css
83
+ @css, @xpath = block, nil
84
+ end
63
85
  @css
64
86
  end
65
87
 
@@ -115,7 +137,7 @@ Capybara.add_selector(:field) do
115
137
  xpath { |locator| XPath::HTML.field(locator) }
116
138
  filter(:checked, boolean: true) { |node, value| not(value ^ node.checked?) }
117
139
  filter(:unchecked, boolean: true) { |node, value| (value ^ node.checked?) }
118
- filter(:disabled, default: false, boolean: true) { |node, value| not(value ^ node.disabled?) }
140
+ filter(:disabled, default: false, boolean: true, skip_if: :all) { |node, value| not(value ^ node.disabled?) }
119
141
  filter(:readonly, boolean: true) { |node, value| not(value ^ node[:readonly]) }
120
142
  filter(:with) { |node, with| node.value == with.to_s }
121
143
  filter(:type) do |node, type|
@@ -131,7 +153,7 @@ Capybara.add_selector(:field) do
131
153
  desc << " with value #{options[:with].to_s.inspect}" if options.has_key?(:with)
132
154
  states << 'checked' if options[:checked] || (options.has_key?(:unchecked) && !options[:unchecked])
133
155
  states << 'not checked' if options[:unchecked] || (options.has_key?(:checked) && !options[:checked])
134
- states << 'disabled' if options[:disabled]
156
+ states << 'disabled' if options[:disabled] == true
135
157
  desc << " that is #{states.join(' and ')}" unless states.empty?
136
158
  desc
137
159
  end
@@ -162,15 +184,15 @@ end
162
184
 
163
185
  Capybara.add_selector(:button) do
164
186
  xpath { |locator| XPath::HTML.button(locator) }
165
- filter(:disabled, default: false, boolean: true) { |node, value| not(value ^ node.disabled?) }
166
- describe { |options| " that is disabled" if options[:disabled] }
187
+ filter(:disabled, default: false, boolean: true, skip_if: :all) { |node, value| not(value ^ node.disabled?) }
188
+ describe { |options| " that is disabled" if options[:disabled] == true }
167
189
  end
168
190
 
169
191
  Capybara.add_selector(:fillable_field) do
170
192
  label "field"
171
193
  xpath { |locator| XPath::HTML.fillable_field(locator) }
172
- filter(:disabled, default: false, boolean: true) { |node, value| not(value ^ node.disabled?) }
173
- describe { |options| " that is disabled" if options[:disabled] }
194
+ filter(:disabled, default: false, boolean: true, skip_if: :all) { |node, value| not(value ^ node.disabled?) }
195
+ describe { |options| " that is disabled" if options[:disabled] == true }
174
196
  end
175
197
 
176
198
  Capybara.add_selector(:radio_button) do
@@ -179,13 +201,13 @@ Capybara.add_selector(:radio_button) do
179
201
  filter(:checked, boolean: true) { |node, value| not(value ^ node.checked?) }
180
202
  filter(:unchecked, boolean: true) { |node, value| (value ^ node.checked?) }
181
203
  filter(:option) { |node, value| node.value == value.to_s }
182
- filter(:disabled, default: false, boolean: true) { |node, value| not(value ^ node.disabled?) }
204
+ filter(:disabled, default: false, boolean: true, skip_if: :all) { |node, value| not(value ^ node.disabled?) }
183
205
  describe do |options|
184
206
  desc, states = "", []
185
207
  desc << " with value #{options[:option].inspect}" if options[:option]
186
208
  states << 'checked' if options[:checked] || (options.has_key?(:unchecked) && !options[:unchecked])
187
209
  states << 'not checked' if options[:unchecked] || (options.has_key?(:checked) && !options[:checked])
188
- states << 'disabled' if options[:disabled]
210
+ states << 'disabled' if options[:disabled] == true
189
211
  desc << " that is #{states.join(' and ')}" unless states.empty?
190
212
  desc
191
213
  end
@@ -196,13 +218,13 @@ Capybara.add_selector(:checkbox) do
196
218
  filter(:checked, boolean: true) { |node, value| not(value ^ node.checked?) }
197
219
  filter(:unchecked, boolean: true) { |node, value| (value ^ node.checked?) }
198
220
  filter(:option) { |node, value| node.value == value.to_s }
199
- filter(:disabled, default: false, boolean: true) { |node, value| not(value ^ node.disabled?) }
221
+ filter(:disabled, default: false, boolean: true, skip_if: :all) { |node, value| not(value ^ node.disabled?) }
200
222
  describe do |options|
201
223
  desc, states = "", []
202
224
  desc << " with value #{options[:option].inspect}" if options[:option]
203
225
  states << 'checked' if options[:checked] || (options.has_key?(:unchecked) && !options[:unchecked])
204
226
  states << 'not checked' if options[:unchecked] || (options.has_key?(:checked) && !options[:checked])
205
- states << 'disabled' if options[:disabled]
227
+ states << 'disabled' if options[:disabled] == true
206
228
  desc << " that is #{states.join(' and ')}" unless states.empty?
207
229
  desc
208
230
  end
@@ -212,21 +234,31 @@ Capybara.add_selector(:select) do
212
234
  label "select box"
213
235
  xpath { |locator| XPath::HTML.select(locator) }
214
236
  filter(:options) do |node, options|
215
- actual = node.all(:xpath, './/option').map { |option| option.text }
237
+ if node.visible?
238
+ actual = node.all(:xpath, './/option').map { |option| option.text }
239
+ else
240
+ actual = node.all(:xpath, './/option', visible: false).map { |option| option.text(:all) }
241
+ end
216
242
  options.sort == actual.sort
217
243
  end
218
- filter(:with_options) { |node, options| options.all? { |option| node.first(:option, option, minimum: 0) } }
244
+ filter(:with_options) do |node, options|
245
+ finder_settings = { minimum: 0 }
246
+ if !node.visible?
247
+ finder_settings[:visible] = false
248
+ end
249
+ options.all? { |option| node.first(:option, option, finder_settings) }
250
+ end
219
251
  filter(:selected) do |node, selected|
220
- actual = node.all(:xpath, './/option').select { |option| option.selected? }.map { |option| option.text }
252
+ actual = node.all(:xpath, './/option', visible: false).select { |option| option.selected? }.map { |option| option.text(:all) }
221
253
  [selected].flatten.sort == actual.sort
222
254
  end
223
- filter(:disabled, default: false, boolean: true) { |node, value| not(value ^ node.disabled?) }
255
+ filter(:disabled, default: false, boolean: true, skip_if: :all) { |node, value| not(value ^ node.disabled?) }
224
256
  describe do |options|
225
257
  desc = ""
226
258
  desc << " with options #{options[:options].inspect}" if options[:options]
227
259
  desc << " with at least options #{options[:with_options].inspect}" if options[:with_options]
228
260
  desc << " with #{options[:selected].inspect} selected" if options[:selected]
229
- desc << " that is disabled" if options[:disabled]
261
+ desc << " that is disabled" if options[:disabled] == true
230
262
  desc
231
263
  end
232
264
  end
@@ -238,8 +270,8 @@ end
238
270
  Capybara.add_selector(:file_field) do
239
271
  label "file field"
240
272
  xpath { |locator| XPath::HTML.file_field(locator) }
241
- filter(:disabled, default: false, boolean: true) { |node, value| not(value ^ node.disabled?) }
242
- describe { |options| " that is disabled" if options[:disabled] }
273
+ filter(:disabled, default: false, boolean: true, skip_if: :all) { |node, value| not(value ^ node.disabled?) }
274
+ describe { |options| " that is disabled" if options[:disabled] == true}
243
275
  end
244
276
 
245
277
  Capybara.add_selector(:table) do