capybara 2.7.1 → 2.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -4
  2. data/History.md +22 -0
  3. data/README.md +27 -3
  4. data/lib/capybara.rb +19 -4
  5. data/lib/capybara/driver/base.rb +6 -2
  6. data/lib/capybara/driver/node.rb +13 -5
  7. data/lib/capybara/helpers.rb +2 -2
  8. data/lib/capybara/node/actions.rb +116 -17
  9. data/lib/capybara/node/base.rb +7 -1
  10. data/lib/capybara/node/element.rb +23 -3
  11. data/lib/capybara/node/finders.rb +45 -29
  12. data/lib/capybara/node/matchers.rb +13 -15
  13. data/lib/capybara/queries/selector_query.rb +22 -5
  14. data/lib/capybara/queries/text_query.rb +42 -6
  15. data/lib/capybara/rack_test/node.rb +13 -1
  16. data/lib/capybara/result.rb +80 -8
  17. data/lib/capybara/rspec/features.rb +13 -6
  18. data/lib/capybara/selector.rb +98 -71
  19. data/lib/capybara/selector/filter_set.rb +46 -0
  20. data/lib/capybara/selenium/driver.rb +22 -23
  21. data/lib/capybara/selenium/node.rb +14 -6
  22. data/lib/capybara/server.rb +20 -10
  23. data/lib/capybara/session.rb +44 -8
  24. data/lib/capybara/spec/session/all_spec.rb +4 -4
  25. data/lib/capybara/spec/session/assert_text.rb +23 -0
  26. data/lib/capybara/spec/session/check_spec.rb +66 -8
  27. data/lib/capybara/spec/session/choose_spec.rb +20 -0
  28. data/lib/capybara/spec/session/click_button_spec.rb +0 -3
  29. data/lib/capybara/spec/session/click_link_spec.rb +7 -0
  30. data/lib/capybara/spec/session/execute_script_spec.rb +6 -1
  31. data/lib/capybara/spec/session/find_button_spec.rb +19 -1
  32. data/lib/capybara/spec/session/find_field_spec.rb +21 -1
  33. data/lib/capybara/spec/session/find_link_spec.rb +19 -1
  34. data/lib/capybara/spec/session/find_spec.rb +32 -4
  35. data/lib/capybara/spec/session/first_spec.rb +4 -4
  36. data/lib/capybara/spec/session/has_field_spec.rb +4 -0
  37. data/lib/capybara/spec/session/has_text_spec.rb +2 -2
  38. data/lib/capybara/spec/session/node_spec.rb +24 -3
  39. data/lib/capybara/spec/session/reset_session_spec.rb +7 -0
  40. data/lib/capybara/spec/session/selectors_spec.rb +14 -0
  41. data/lib/capybara/spec/session/uncheck_spec.rb +39 -0
  42. data/lib/capybara/spec/session/window/switch_to_window_spec.rb +4 -2
  43. data/lib/capybara/spec/session/window/window_opened_by_spec.rb +2 -1
  44. data/lib/capybara/spec/session/window/window_spec.rb +36 -22
  45. data/lib/capybara/spec/session/within_frame_spec.rb +19 -0
  46. data/lib/capybara/spec/spec_helper.rb +3 -0
  47. data/lib/capybara/spec/views/form.erb +34 -6
  48. data/lib/capybara/spec/views/with_html.erb +5 -1
  49. data/lib/capybara/spec/views/with_unload_alert.erb +3 -1
  50. data/lib/capybara/spec/views/with_windows.erb +2 -0
  51. data/lib/capybara/version.rb +1 -1
  52. data/spec/capybara_spec.rb +34 -0
  53. data/spec/rack_test_spec.rb +24 -0
  54. data/spec/result_spec.rb +25 -0
  55. data/spec/rspec/features_spec.rb +3 -3
  56. data/spec/selenium_spec.rb +6 -3
  57. data/spec/server_spec.rb +2 -2
  58. metadata +18 -4
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 85d6a1e7f742859bc5336d455e804e941efbaffe
4
- data.tar.gz: 9235385a6473080bb3ac0cae536857a054d323fc
3
+ metadata.gz: 0cbea94168c582ba31d25ccf5f24312005b47616
4
+ data.tar.gz: 7b779b6363ffb09be883cfe71ac2fde7cd616851
5
5
  SHA512:
6
- metadata.gz: 301575ccd96eb6a4239441886571377806d911f0de5868fc3891f052518199fef15424eba03429e8bf7e7ba5d1abba62e6953ba7a171a66ba2e3a325824806a8
7
- data.tar.gz: 3339a52f863d7417eaedae85e8e556d5359f40a04f4c628dc883ddadd517a04d62c0f40b3a0d2d6cf2600842a6f3f1bb011d1df5fe88a977278273ae7055a417
6
+ metadata.gz: 132688050a792bda11f9d4054aa5bac76e6f4070668f72c10bce230060d622e306e9eeb1b2bb079de66d428ca24f2814d07102083619db4e8f53075c473727a6
7
+ data.tar.gz: dbd2d43752dad9b40b2281ca1281cd3751e774ba6b785024f98c3c7c845637cdb76c36521343d16f338af34c21439cab00a76f837b32c4a1a88115f52a99e674
data/History.md CHANGED
@@ -1,3 +1,25 @@
1
+ # Version 2.8.0
2
+ Release date: 2016-08-16
3
+
4
+ ### Fixed
5
+ * Issue with modals present when closing the page using selenium - Issue #1696 [Jonas Nicklas, Thomas Walpole]
6
+ * Server errors raised in test code have the cause set to an explanatory exception
7
+ in rubies that support Exception#cause rather than a confusing ExpectationNotMet - Issue #1719 [Thomas Walpole]
8
+ * background/given/given! RSoec aliases will work if RSpec config.shared_context_metadata_behavior == :apply_to_host_groups [Thomas Walpole]
9
+ * Fixed setting of unexpectedAlertError now that Selenium will be freezing the Capabilities::DEFAULTS [Thomas Walpole]
10
+
11
+ ### Added
12
+ * 'check', 'uncheck', and 'choose' can now optionally click the associated label if the checkbox/radio button is not visible [Thomas Walpole]
13
+ * Raise error if Capybara.app_host/default_host are specified incorrectly [Thomas Walpole]
14
+ * Capybara::Selector::FilterSet allows for sharing filter definitions between selectors [Thomas Walpole]
15
+ * Remove need to pass nil locator in most node actions when locator is not needed [Thomas Walpole]
16
+ * New frames API for drivers - Issue #1365 [Thomas Walpole]
17
+ * Deprecated Element#parent in favor of Element#query_scope to better indicate what it is [Thomas Walpole]
18
+ * Improved error messages for have_text matcher [Alex Chaffee, Thomas Walpole]
19
+ * The `:with` option for the field selector now accepts a regular expression for matching the field value [Uwe Kubosch]
20
+ * Support matching on aria-label attribute when finding fields/links/buttons - Issue #1528 [Thomas Walpole]
21
+ * Optimize Capybara::Result to only apply fields as necessary in common use-case of `.all[idx]` [Thomas Walpole]
22
+
1
23
  #Version 2.7.1
2
24
  Release date: 2016-05-01
3
25
 
data/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  [![Build Status](https://secure.travis-ci.org/jnicklas/capybara.svg)](https://travis-ci.org/jnicklas/capybara)
4
4
  [![Dependency Status](https://gemnasium.com/jnicklas/capybara.svg)](https://gemnasium.com/jnicklas/capybara)
5
5
  [![Code Climate](https://codeclimate.com/github/jnicklas/capybara.svg)](https://codeclimate.com/github/jnicklas/capybara)
6
+ [![Gitter](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/jnicklas/capybara?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
6
7
 
7
8
  Capybara helps you test web applications by simulating how a real user would
8
9
  interact with your app. It is agnostic about the driver running your tests and
@@ -12,6 +13,8 @@ through an external gem.
12
13
  **Need help?** Ask on the mailing list (please do not open an issue on
13
14
  GitHub): http://groups.google.com/group/ruby-capybara
14
15
 
16
+ **Note: Firefox 48** If you're using Firefox with selenium-webdrvier, stay on Firefox 47.0.1 and selenium-webdriver 2.53.4. Firefox 48 requires geckodriver and is not supported without selenium-webdriver 3 which currently has multiple issues and is feature incomplete
17
+
15
18
  ## Table of contents
16
19
 
17
20
  - [Key benefits](#key-benefits)
@@ -44,7 +47,7 @@ GitHub): http://groups.google.com/group/ruby-capybara
44
47
  - [Asynchronous JavaScript (Ajax and friends)](#asynchronous-javascript-ajax-and-friends)
45
48
  - [Using the DSL elsewhere](#using-the-dsl-elsewhere)
46
49
  - [Calling remote servers](#calling-remote-servers)
47
- - [Using the sessions manually](#using-the-sessions-manually)
50
+ - [Using sessions](#using-sessions)
48
51
  - [XPath, CSS and selectors](#xpath-css-and-selectors)
49
52
  - [Beware the XPath // trap](#beware-the-xpath--trap)
50
53
  - [Configuring and adding drivers](#configuring-and-adding-drivers)
@@ -69,7 +72,7 @@ Capybara requires Ruby 1.9.3 or later. To install, add this line to your
69
72
  gem 'capybara'
70
73
  ```
71
74
 
72
- **Note:** If using Ruby < 2.0 you will also need to limit the version of mime-types to < 3.0
75
+ **Note:** If using Ruby < 2.0 you will also need to limit the version of mime-types to < 3.0 and the version of rack to < 2.0
73
76
 
74
77
  If the application that you are testing is a Rails app, add this line to your test helper file:
75
78
 
@@ -818,7 +821,28 @@ remote application:
818
821
  Capybara.run_server = false
819
822
  ```
820
823
 
821
- ## <a name="using-the-sessions-manually"></a>Using the sessions manually
824
+ ## <a name="using-sessions"></a>Using sessions
825
+
826
+ Capybara manages named sessions (:default if not specified) allowing multiple sessions using the same driver and test app instance to be interacted with.
827
+ A new session will be created using the current driver if a session with the given name using the current driver and test app instance is not found.
828
+
829
+ ### Named sessions
830
+ To perform operations in a different session and then revert to the previous session
831
+
832
+ ```ruby
833
+ Capybara.using_session("Bob's session") do
834
+ #do something in Bob's browser session
835
+ end
836
+ #reverts to previous session
837
+ ```
838
+
839
+ To permanently switch the current session to a different session
840
+
841
+ ```ruby
842
+ Capybara.session_name = "some other session"
843
+ ````
844
+
845
+ ### <a name="using-sessions-manually"></a>Using sessions manually
822
846
 
823
847
  For ultimate control, you can instantiate and use a
824
848
  [Session](http://rubydoc.info/github/jnicklas/capybara/master/Capybara/Session)
@@ -20,10 +20,11 @@ module Capybara
20
20
  class ReadOnlyElementError < CapybaraError; end
21
21
 
22
22
  class << self
23
- attr_accessor :asset_host, :app_host, :run_server, :default_host, :always_include_port
24
- attr_accessor :server_port, :exact, :match, :exact_options, :visible_text_only
23
+ attr_reader :app_host, :default_host
24
+ attr_accessor :asset_host, :run_server, :always_include_port
25
+ attr_accessor :server_port, :exact, :match, :exact_options, :visible_text_only, :enable_aria_label
25
26
  attr_accessor :default_selector, :default_max_wait_time, :ignore_hidden_elements
26
- attr_accessor :save_path, :wait_on_first_by_default, :automatic_reload
27
+ attr_accessor :save_path, :wait_on_first_by_default, :automatic_label_click, :automatic_reload
27
28
  attr_accessor :reuse_server, :raise_server_errors, :server_errors
28
29
  attr_writer :default_driver, :current_driver, :javascript_driver, :session_name, :server_host
29
30
  attr_reader :save_and_open_page_path
@@ -40,7 +41,7 @@ module Capybara
40
41
  #
41
42
  # === Configurable options
42
43
  #
43
- # [app_host = String] The default host to use when giving a relative URL to visit
44
+ # [app_host = String/nil] The default host to use when giving a relative URL to visit, must be a valid URL e.g. http://www.example.com
44
45
  # [always_include_port = Boolean] Whether the Rack server's port should automatically be inserted into every visited URL (Default: false)
45
46
  # [asset_host = String] Where dynamic assets are hosted - will be prepended to relative asset locations if present (Default: nil)
46
47
  # [run_server = Boolean] Whether to start a Rack server for the given Rack app (Default: true)
@@ -52,6 +53,8 @@ module Capybara
52
53
  # [automatic_reload = Boolean] Whether to automatically reload elements as Capybara is waiting (Default: true)
53
54
  # [save_path = String] Where to put pages saved through save_(page|screenshot), save_and_open_(page|screenshot) (Default: Dir.pwd)
54
55
  # [wait_on_first_by_default = Boolean] Whether Node#first defaults to Capybara waiting behavior for at least 1 element to match (Default: false)
56
+ # [automatic_label_click = Boolean] Whether Node#choose, Node#check, Node#uncheck will attempt to click the associated label element if the checkbox/radio button are non-visible (Default: false)
57
+ # [enable_aria_label = Boolean] Whether fields, links, and buttons will match against aria-label attribute (Default: false)
55
58
  # [reuse_server = Boolean] Reuse the server thread between multiple sessions using the same app object (Default: true)
56
59
  # === DSL Options
57
60
  #
@@ -387,6 +390,16 @@ module Capybara
387
390
  @save_and_open_page_path = path
388
391
  end
389
392
 
393
+ def app_host=(url)
394
+ raise ArgumentError.new("Capybara.app_host should be set to a url (http://www.example.com)") unless url.nil? || (url =~ URI::regexp)
395
+ @app_host = url
396
+ end
397
+
398
+ def default_host=(url)
399
+ raise ArgumentError.new("Capybara.default_host should be set to a url (http://www.example.com)") unless url.nil? || (url =~ URI::regexp)
400
+ @default_host = url
401
+ end
402
+
390
403
  def included(base)
391
404
  base.send(:include, Capybara::DSL)
392
405
  warn "`include Capybara` is deprecated. Please use `include Capybara::DSL` instead."
@@ -487,6 +500,8 @@ Capybara.configure do |config|
487
500
  config.server_errors = [StandardError]
488
501
  config.visible_text_only = false
489
502
  config.wait_on_first_by_default = false
503
+ config.automatic_label_click = false
504
+ config.enable_aria_label = false
490
505
  config.reuse_server = true
491
506
  end
492
507
 
@@ -48,8 +48,12 @@ class Capybara::Driver::Base
48
48
  raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#status_code'
49
49
  end
50
50
 
51
- def within_frame(frame_handle)
52
- raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#within_frame'
51
+ ##
52
+ #
53
+ # @param frame [Capybara::Node::Element, :parent, :top] The iframe element to switch to
54
+ #
55
+ def switch_to_frame(frame)
56
+ raise Capybara::NotSupportedByDriverError, 'Capybara::Driver::Base#switch_to_frame'
53
57
  end
54
58
 
55
59
  def current_window_handle
@@ -42,23 +42,23 @@ module Capybara
42
42
  def click
43
43
  raise NotImplementedError
44
44
  end
45
-
45
+
46
46
  def right_click
47
47
  raise NotImplementedError
48
48
  end
49
-
49
+
50
50
  def double_click
51
51
  raise NotImplementedError
52
52
  end
53
-
53
+
54
54
  def send_keys(*args)
55
55
  raise NotImplementedError
56
56
  end
57
-
57
+
58
58
  def hover
59
59
  raise NotImplementedError
60
60
  end
61
-
61
+
62
62
  def drag_to(element)
63
63
  raise NotImplementedError
64
64
  end
@@ -83,6 +83,14 @@ module Capybara
83
83
  raise NotImplementedError
84
84
  end
85
85
 
86
+ def readonly?
87
+ !!self[:readonly]
88
+ end
89
+
90
+ def multiple?
91
+ !!self[:multiple]
92
+ end
93
+
86
94
  def path
87
95
  raise NotSupportedByDriverError, 'Capybara::Driver::Node#path'
88
96
  end
@@ -28,8 +28,8 @@ module Capybara
28
28
  # @param [String] text Text to escape
29
29
  # @return [String] Escaped text
30
30
  #
31
- def to_regexp(text)
32
- text.is_a?(Regexp) ? text : Regexp.new(Regexp.escape(normalize_whitespace(text)))
31
+ def to_regexp(text, options=nil)
32
+ text.is_a?(Regexp) ? text : Regexp.new(Regexp.escape(normalize_whitespace(text)), options)
33
33
  end
34
34
 
35
35
  ##
@@ -7,10 +7,19 @@ module Capybara
7
7
  #
8
8
  # Finds a button or link by id, text or value and clicks it. Also looks at image
9
9
  # alt text inside the link.
10
+ # @!macro waiting_behavior
11
+ # If the driver is capable of executing JavaScript, +$0+ will wait for a set amount of time
12
+ # and continuously retry finding the element until either the element is found or the time
13
+ # expires. The length of time +find+ will wait is controlled through {Capybara.default_max_wait_time}
10
14
  #
11
- # @param [String] locator Text, id or value of link or button
15
+ # @option options [false, Numeric] wait (Capybara.default_max_wait_time) Maximum time to wait for matching element to appear.
12
16
  #
13
- def click_link_or_button(locator, options={})
17
+ # @overload click_link_or_button([locator], options)
18
+ #
19
+ # @param [String] locator Text, id or value of link or button
20
+ #
21
+ def click_link_or_button(locator=nil, options={})
22
+ locator, options = nil, locator if locator.is_a? Hash
14
23
  find(:link_or_button, locator, options).click
15
24
  end
16
25
  alias_method :click_on, :click_link_or_button
@@ -20,10 +29,14 @@ module Capybara
20
29
  # Finds a link by id, text or title and clicks it. Also looks at image
21
30
  # alt text inside the link.
22
31
  #
23
- # @param [String] locator text, id, title or nested image's alt attribute
24
- # @param options See {Capybara::Node::Finders#find_link}
32
+ # @macro waiting_behavior
33
+ #
34
+ # @overload click_link([locator], options)
35
+ # @param [String] locator text, id, title or nested image's alt attribute
36
+ # @param options See {Capybara::Node::Finders#find_link}
25
37
  #
26
- def click_link(locator, options={})
38
+ def click_link(locator=nil, options={})
39
+ locator, options = nil, locator if locator.is_a? Hash
27
40
  find(:link, locator, options).click
28
41
  end
29
42
 
@@ -34,9 +47,13 @@ module Capybara
34
47
  # \<button> element. All buttons can be found by their id, value, or title. \<button> elements can also be found
35
48
  # by their text content, and image \<input> elements by their alt attribute
36
49
  #
37
- # @param [String] locator Which button to find
38
- # @param options See {Capybara::Node::Finders#find_button}
39
- def click_button(locator, options={})
50
+ # @macro waiting_behavior
51
+ #
52
+ # @overload click_button([locator], options)
53
+ # @param [String] locator Which button to find
54
+ # @param options See {Capybara::Node::Finders#find_button}
55
+ def click_button(locator=nil, options={})
56
+ locator, options = nil, locator if locator.is_a? Hash
40
57
  find(:button, locator, options).click
41
58
  end
42
59
 
@@ -47,18 +64,28 @@ module Capybara
47
64
  #
48
65
  # page.fill_in 'Name', :with => 'Bob'
49
66
  #
67
+ # @macro waiting_behavior
68
+ #
50
69
  # @param [String] locator Which field to fill in
51
70
  # @param [Hash] options
52
- # @option options [String] :with The value to fill in - required
53
- # @option options [Hash] :fill_options Driver specific options regarding how to fill fields
71
+ # @option options [String] :with The value to fill in - required
72
+ # @option options [Hash] :fill_options Driver specific options regarding how to fill fields
73
+ # @option options [Boolean] :multiple Match fields that can have multiple values?
74
+ # @option options [String] id Match fields that match the id attribute
75
+ # @option options [String] name Match fields that match the name attribute
76
+ # @option options [String] placeholder Match fields that match the placeholder attribute
54
77
  #
55
78
  def fill_in(locator, options={})
79
+ locator, options = nil, locator if locator.is_a? Hash
56
80
  raise "Must pass a hash containing 'with'" if not options.is_a?(Hash) or not options.has_key?(:with)
57
81
  with = options.delete(:with)
58
82
  fill_options = options.delete(:fill_options)
59
83
  find(:fillable_field, locator, options).set(with, fill_options)
60
84
  end
61
85
 
86
+ # @!macro label_click
87
+ # @option options [Boolean] :allow_label_click (Capybara.automatic_label_click) Attempt to click the label to toggle state if element is non-visible.
88
+
62
89
  ##
63
90
  #
64
91
  # Find a radio button and mark it as checked. The radio button can be found
@@ -66,10 +93,30 @@ module Capybara
66
93
  #
67
94
  # page.choose('Male')
68
95
  #
69
- # @param [String] locator Which radio button to choose
96
+ # @overload choose([locator], options)
97
+ # @param [String] locator Which radio button to choose
70
98
  #
99
+ # @option options [String] :option Value of the radio_button to choose
100
+ # @option options [String] id Match fields that match the id attribute
101
+ # @option options [String] name Match fields that match the name attribute
102
+ # @macro waiting_behavior
103
+ # @macro label_click
71
104
  def choose(locator, options={})
72
- find(:radio_button, locator, options).set(true)
105
+ locator, options = nil, locator if locator.is_a? Hash
106
+ allow_label_click = options.delete(:allow_label_click) { Capybara.automatic_label_click }
107
+
108
+ begin
109
+ find(:radio_button, locator, options).set(true)
110
+ rescue Capybara::ElementNotFound => e
111
+ raise unless allow_label_click
112
+ begin
113
+ radio = find(:radio_button, locator, options.merge({wait: 0, visible: :hidden}))
114
+ label = find(:label, for: radio, wait: 0, visible: true)
115
+ label.click unless radio.checked?
116
+ rescue
117
+ raise e
118
+ end
119
+ end
73
120
  end
74
121
 
75
122
  ##
@@ -79,10 +126,32 @@ module Capybara
79
126
  #
80
127
  # page.check('German')
81
128
  #
82
- # @param [String] locator Which check box to check
129
+ #
130
+ # @overload check([locator], options)
131
+ # @param [String] locator Which check box to check
132
+ #
133
+ # @option options [String] :option Value of the checkbox to select
134
+ # @option options [String] id Match fields that match the id attribute
135
+ # @option options [String] name Match fields that match the name attribute
136
+ # @macro label_click
137
+ # @macro waiting_behavior
83
138
  #
84
139
  def check(locator, options={})
85
- find(:checkbox, locator, options).set(true)
140
+ locator, options = nil, locator if locator.is_a? Hash
141
+ allow_label_click = options.delete(:allow_label_click) { Capybara.automatic_label_click }
142
+
143
+ begin
144
+ find(:checkbox, locator, options).set(true)
145
+ rescue Capybara::ElementNotFound => e
146
+ raise unless allow_label_click
147
+ begin
148
+ cbox = find(:checkbox, locator, options.merge({wait: 0, visible: :hidden}))
149
+ label = find(:label, for: cbox, wait: 0, visible: true)
150
+ label.click unless cbox.checked?
151
+ rescue
152
+ raise e
153
+ end
154
+ end
86
155
  end
87
156
 
88
157
  ##
@@ -92,10 +161,32 @@ module Capybara
92
161
  #
93
162
  # page.uncheck('German')
94
163
  #
95
- # @param [String] locator Which check box to uncheck
164
+ #
165
+ # @overload uncheck([locator], options)
166
+ # @param [String] locator Which check box to uncheck
167
+ #
168
+ # @option options [String] :option Value of the checkbox to deselect
169
+ # @option options [String] id Match fields that match the id attribute
170
+ # @option options [String] name Match fields that match the name attribute
171
+ # @macro label_click
172
+ # @macro waiting_behavior
96
173
  #
97
174
  def uncheck(locator, options={})
98
- find(:checkbox, locator, options).set(false)
175
+ locator, options = nil, locator if locator.is_a? Hash
176
+ allow_label_click = options.delete(:allow_label_click) { Capybara.automatic_label_click }
177
+
178
+ begin
179
+ find(:checkbox, locator, options).set(false)
180
+ rescue Capybara::ElementNotFound => e
181
+ raise unless allow_label_click
182
+ begin
183
+ cbox = find(:checkbox, locator, options.merge({wait: 0, visible: :hidden}))
184
+ label = find(:label, for: cbox, wait: 0, visible: true)
185
+ label.click if cbox.checked?
186
+ rescue
187
+ raise e
188
+ end
189
+ end
99
190
  end
100
191
 
101
192
  ##
@@ -109,6 +200,8 @@ module Capybara
109
200
  #
110
201
  # page.select 'March', :from => 'Month'
111
202
  #
203
+ # @macro waiting_behavior
204
+ #
112
205
  # @param [String] value Which option to select
113
206
  # @option options [String] :from The id, name or label of the select box
114
207
  #
@@ -129,6 +222,8 @@ module Capybara
129
222
  #
130
223
  # page.unselect 'March', :from => 'Month'
131
224
  #
225
+ # @macro waiting_behavior
226
+ #
132
227
  # @param [String] value Which option to unselect
133
228
  # @param [Hash{:from => String}] options The id, name or label of the select box
134
229
  #
@@ -148,15 +243,19 @@ module Capybara
148
243
  #
149
244
  # page.attach_file(locator, '/path/to/file.png')
150
245
  #
246
+ # @macro waiting_behavior
247
+ #
151
248
  # @param [String] locator Which field to attach the file to
152
249
  # @param [String] path The path of the file that will be attached, or an array of paths
153
250
  #
154
251
  # @option options [Symbol] match (Capybara.match) The matching strategy to use (:one, :first, :prefer_exact, :smart).
155
252
  # @option options [Boolean] exact (Capybara.exact) Match the exact label name/contents or accept a partial match.
156
- # @option options [Fixnum] wait (Capybara.default_max_wait_time) If using a Javascript driver, maximum number of seconds during which the element will be searched for.
157
253
  # @option options [Boolean] multiple Match field which allows multiple file selection
254
+ # @option options [String] id Match fields that match the id attribute
255
+ # @option options [String] name Match fields that match the name attribute
158
256
  #
159
257
  def attach_file(locator, path, options={})
258
+ locator, path, options = nil, locator, path if path.is_a? Hash
160
259
  Array(path).each do |p|
161
260
  raise Capybara::FileNotFound, "cannot attach file, #{p} does not exist" unless File.exist?(p.to_s)
162
261
  end