capybara-rails-2-2 0.4.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (100) hide show
  1. data/History.txt +202 -0
  2. data/README.rdoc +540 -0
  3. data/lib/capybara.rb +231 -0
  4. data/lib/capybara/cucumber.rb +32 -0
  5. data/lib/capybara/driver/base.rb +60 -0
  6. data/lib/capybara/driver/celerity_driver.rb +164 -0
  7. data/lib/capybara/driver/culerity_driver.rb +26 -0
  8. data/lib/capybara/driver/node.rb +74 -0
  9. data/lib/capybara/driver/rack_test_driver.rb +303 -0
  10. data/lib/capybara/driver/selenium_driver.rb +161 -0
  11. data/lib/capybara/dsl.rb +109 -0
  12. data/lib/capybara/node/actions.rb +160 -0
  13. data/lib/capybara/node/base.rb +47 -0
  14. data/lib/capybara/node/document.rb +17 -0
  15. data/lib/capybara/node/element.rb +178 -0
  16. data/lib/capybara/node/finders.rb +201 -0
  17. data/lib/capybara/node/matchers.rb +391 -0
  18. data/lib/capybara/node/simple.rb +116 -0
  19. data/lib/capybara/rails.rb +16 -0
  20. data/lib/capybara/rspec.rb +18 -0
  21. data/lib/capybara/selector.rb +70 -0
  22. data/lib/capybara/server.rb +90 -0
  23. data/lib/capybara/session.rb +281 -0
  24. data/lib/capybara/spec/driver.rb +243 -0
  25. data/lib/capybara/spec/fixtures/capybara.jpg +0 -0
  26. data/lib/capybara/spec/fixtures/test_file.txt +1 -0
  27. data/lib/capybara/spec/public/jquery-ui.js +35 -0
  28. data/lib/capybara/spec/public/jquery.js +19 -0
  29. data/lib/capybara/spec/public/test.js +33 -0
  30. data/lib/capybara/spec/session.rb +110 -0
  31. data/lib/capybara/spec/session/all_spec.rb +78 -0
  32. data/lib/capybara/spec/session/attach_file_spec.rb +70 -0
  33. data/lib/capybara/spec/session/check_spec.rb +65 -0
  34. data/lib/capybara/spec/session/choose_spec.rb +26 -0
  35. data/lib/capybara/spec/session/click_button_spec.rb +252 -0
  36. data/lib/capybara/spec/session/click_link_or_button_spec.rb +36 -0
  37. data/lib/capybara/spec/session/click_link_spec.rb +113 -0
  38. data/lib/capybara/spec/session/current_url_spec.rb +15 -0
  39. data/lib/capybara/spec/session/fill_in_spec.rb +119 -0
  40. data/lib/capybara/spec/session/find_button_spec.rb +18 -0
  41. data/lib/capybara/spec/session/find_by_id_spec.rb +18 -0
  42. data/lib/capybara/spec/session/find_field_spec.rb +26 -0
  43. data/lib/capybara/spec/session/find_link_spec.rb +19 -0
  44. data/lib/capybara/spec/session/find_spec.rb +121 -0
  45. data/lib/capybara/spec/session/first_spec.rb +72 -0
  46. data/lib/capybara/spec/session/has_button_spec.rb +32 -0
  47. data/lib/capybara/spec/session/has_content_spec.rb +106 -0
  48. data/lib/capybara/spec/session/has_css_spec.rb +213 -0
  49. data/lib/capybara/spec/session/has_field_spec.rb +156 -0
  50. data/lib/capybara/spec/session/has_link_spec.rb +37 -0
  51. data/lib/capybara/spec/session/has_select_spec.rb +129 -0
  52. data/lib/capybara/spec/session/has_selector_spec.rb +129 -0
  53. data/lib/capybara/spec/session/has_table_spec.rb +96 -0
  54. data/lib/capybara/spec/session/has_xpath_spec.rb +123 -0
  55. data/lib/capybara/spec/session/headers.rb +19 -0
  56. data/lib/capybara/spec/session/javascript.rb +223 -0
  57. data/lib/capybara/spec/session/response_code.rb +19 -0
  58. data/lib/capybara/spec/session/select_spec.rb +105 -0
  59. data/lib/capybara/spec/session/uncheck_spec.rb +21 -0
  60. data/lib/capybara/spec/session/unselect_spec.rb +61 -0
  61. data/lib/capybara/spec/session/within_spec.rb +160 -0
  62. data/lib/capybara/spec/test_app.rb +117 -0
  63. data/lib/capybara/spec/views/buttons.erb +4 -0
  64. data/lib/capybara/spec/views/fieldsets.erb +29 -0
  65. data/lib/capybara/spec/views/form.erb +348 -0
  66. data/lib/capybara/spec/views/frame_one.erb +8 -0
  67. data/lib/capybara/spec/views/frame_two.erb +8 -0
  68. data/lib/capybara/spec/views/popup_one.erb +8 -0
  69. data/lib/capybara/spec/views/popup_two.erb +8 -0
  70. data/lib/capybara/spec/views/postback.erb +13 -0
  71. data/lib/capybara/spec/views/tables.erb +122 -0
  72. data/lib/capybara/spec/views/with_html.erb +69 -0
  73. data/lib/capybara/spec/views/with_js.erb +39 -0
  74. data/lib/capybara/spec/views/with_scope.erb +36 -0
  75. data/lib/capybara/spec/views/with_simple_html.erb +1 -0
  76. data/lib/capybara/spec/views/within_frames.erb +10 -0
  77. data/lib/capybara/spec/views/within_popups.erb +25 -0
  78. data/lib/capybara/util/save_and_open_page.rb +40 -0
  79. data/lib/capybara/util/timeout.rb +27 -0
  80. data/lib/capybara/version.rb +3 -0
  81. data/spec/basic_node_spec.rb +77 -0
  82. data/spec/capybara_spec.rb +46 -0
  83. data/spec/driver/celerity_driver_spec.rb +13 -0
  84. data/spec/driver/culerity_driver_spec.rb +14 -0
  85. data/spec/driver/rack_test_driver_spec.rb +84 -0
  86. data/spec/driver/remote_culerity_driver_spec.rb +22 -0
  87. data/spec/driver/remote_selenium_driver_spec.rb +16 -0
  88. data/spec/driver/selenium_driver_spec.rb +14 -0
  89. data/spec/dsl_spec.rb +157 -0
  90. data/spec/rspec_spec.rb +47 -0
  91. data/spec/save_and_open_page_spec.rb +159 -0
  92. data/spec/server_spec.rb +85 -0
  93. data/spec/session/celerity_session_spec.rb +24 -0
  94. data/spec/session/culerity_session_spec.rb +26 -0
  95. data/spec/session/rack_test_session_spec.rb +44 -0
  96. data/spec/session/selenium_session_spec.rb +26 -0
  97. data/spec/spec_helper.rb +40 -0
  98. data/spec/string_spec.rb +77 -0
  99. data/spec/timeout_spec.rb +28 -0
  100. metadata +360 -0
@@ -0,0 +1,201 @@
1
+ module Capybara
2
+ module Node
3
+ module Finders
4
+
5
+ ##
6
+ #
7
+ # Find an {Capybara::Element} based on the given arguments. +find+ will raise an error if the element
8
+ # is not found. The error message can be customized through the +:message+ option.
9
+ #
10
+ # If the driver is capable of executing JavaScript, +find+ will wait for a set amount of time
11
+ # and continuously retry finding the element until either the element is found or the time
12
+ # expires. The length of time +find+ will wait is controlled through {Capybara.default_wait_time}
13
+ # and defaults to 2 seconds.
14
+ #
15
+ # +find+ takes the same options as +all+.
16
+ #
17
+ # page.find('#foo').find('.bar')
18
+ # page.find(:xpath, '//div[contains("bar")]')
19
+ # page.find('li', :text => 'Quox').click_link('Delete')
20
+ #
21
+ # @param (see Capybara::Node::Finders#all)
22
+ # @option options [String] :message An error message in case the element can't be found
23
+ # @return [Capybara::Element] The found element
24
+ # @raise [Capybara::ElementNotFound] If the element can't be found before time expires
25
+ #
26
+ def find(*args)
27
+ begin
28
+ node = wait_conditionally_until { first(*args) }
29
+ rescue TimeoutError
30
+ end
31
+ unless node
32
+ options = if args.last.is_a?(Hash) then args.last else {} end
33
+ raise Capybara::ElementNotFound, options[:message] || "Unable to find '#{args[1] || args[0]}'"
34
+ end
35
+ return node
36
+ end
37
+
38
+ ##
39
+ #
40
+ # Find a form field on the page. The field can be found by its name, id or label text.
41
+ #
42
+ # @param [String] locator Which field to find
43
+ # @return [Capybara::Element] The found element
44
+ #
45
+ def find_field(locator)
46
+ find(:xpath, XPath::HTML.field(locator))
47
+ end
48
+ alias_method :field_labeled, :find_field
49
+
50
+ ##
51
+ #
52
+ # Find a link on the page. The link can be found by its id or text.
53
+ #
54
+ # @param [String] locator Which link to find
55
+ # @return [Capybara::Element] The found element
56
+ #
57
+ def find_link(locator)
58
+ find(:xpath, XPath::HTML.link(locator))
59
+ end
60
+
61
+ ##
62
+ #
63
+ # Find a button on the page. The link can be found by its id, name or value.
64
+ #
65
+ # @param [String] locator Which button to find
66
+ # @return [Capybara::Element] The found element
67
+ #
68
+ def find_button(locator)
69
+ find(:xpath, XPath::HTML.button(locator))
70
+ end
71
+
72
+ ##
73
+ #
74
+ # Find a element on the page, given its id.
75
+ #
76
+ # @param [String] locator Which element to find
77
+ # @return [Capybara::Element] The found element
78
+ #
79
+ def find_by_id(id)
80
+ find(:css, "##{id}")
81
+ end
82
+
83
+ ##
84
+ #
85
+ # Find all elements on the page matching the given selector
86
+ # and options.
87
+ #
88
+ # Both XPath and CSS expressions are supported, but Capybara
89
+ # does not try to automatically distinguish between them. The
90
+ # following statements are equivalent:
91
+ #
92
+ # page.all(:css, 'a#person_123')
93
+ # page.all(:xpath, '//a[@id="person_123"]')
94
+ #
95
+ #
96
+ # If the type of selector is left out, Capybara uses
97
+ # {Capybara.default_selector}. It's set to :css by default.
98
+ #
99
+ # page.all("a#person_123")
100
+ #
101
+ # Capybara.default_selector = :xpath
102
+ # page.all('//a[@id="person_123"]')
103
+ #
104
+ # The set of found elements can further be restricted by specifying
105
+ # options. It's possible to select elements by their text or visibility:
106
+ #
107
+ # page.all('a', :text => 'Home')
108
+ # page.all('#menu li', :visible => true)
109
+ #
110
+ # @param [:css, :xpath, String] kind_or_locator Either the kind of selector or the selector itself
111
+ # @param [String] locator The selector
112
+ # @param [Hash{Symbol => Object}] options Additional options
113
+ # @option options [String, Regexp] text Only find elements which contain this text or match this regexp
114
+ # @option options [Boolean] visible Only find elements that are visible on the page
115
+ # @return [Capybara::Element] The found elements
116
+ #
117
+ def all(*args)
118
+ options = extract_normalized_options(args)
119
+
120
+ Capybara::Selector.normalize(*args).
121
+ map { |path| find_in_base(path) }.flatten.
122
+ select { |node| matches_options(node, options) }.
123
+ map { |node| convert_element(node) }
124
+ end
125
+
126
+ ##
127
+ #
128
+ # Find the first element on the page matching the given selector
129
+ # and options, or nil if no element matches.
130
+ #
131
+ # When only the first matching element is needed, this method can
132
+ # be faster than all(*args).first.
133
+ #
134
+ # @param [:css, :xpath, String] kind_or_locator Either the kind of selector or the selector itself
135
+ # @param [String] locator The selector
136
+ # @param [Hash{Symbol => Object}] options Additional options; see {all}
137
+ # @return Capybara::Element The found element
138
+ #
139
+ def first(*args)
140
+ options = extract_normalized_options(args)
141
+
142
+ Capybara::Selector.normalize(*args).each do |path|
143
+ find_in_base(path).each do |node|
144
+ if matches_options(node, options)
145
+ return convert_element(node)
146
+ end
147
+ end
148
+ end
149
+
150
+ nil
151
+ end
152
+
153
+ protected
154
+
155
+ def find_in_base(xpath)
156
+ base.find(xpath)
157
+ end
158
+
159
+ def convert_element(element)
160
+ Capybara::Node::Element.new(session, element)
161
+ end
162
+
163
+ def wait_conditionally_until
164
+ if wait? then session.wait_until { yield } else yield end
165
+ end
166
+
167
+ def extract_normalized_options(args)
168
+ options = if args.last.is_a?(Hash) then args.pop.dup else {} end
169
+
170
+ if text = options[:text]
171
+ options[:text] = Regexp.escape(text) unless text.kind_of?(Regexp)
172
+ end
173
+
174
+ if !options.has_key?(:visible)
175
+ options[:visible] = Capybara.ignore_hidden_elements
176
+ end
177
+
178
+ if selected = options[:selected]
179
+ options[:selected] = [selected].flatten
180
+ end
181
+
182
+ options
183
+ end
184
+
185
+ def matches_options(node, options)
186
+ return false if options[:text] and not node.text.match(options[:text])
187
+ return false if options[:visible] and not node.visible?
188
+ return false if options[:with] and not node.value == options[:with]
189
+ return false if options[:checked] and not node.checked?
190
+ return false if options[:unchecked] and node.checked?
191
+ return false if options[:selected] and not has_selected_options?(node, options[:selected])
192
+ true
193
+ end
194
+
195
+ def has_selected_options?(node, expected)
196
+ actual = node.find('.//option').select { |option| option.selected? }.map { |option| option.text }
197
+ (expected - actual).empty?
198
+ end
199
+ end
200
+ end
201
+ end
@@ -0,0 +1,391 @@
1
+ module Capybara
2
+ module Node
3
+ module Matchers
4
+
5
+ ##
6
+ #
7
+ # Checks if a given selector is on the page or current node.
8
+ #
9
+ # page.has_selector?('p#foo')
10
+ # page.has_selector?(:xpath, './/p[@id="foo"]')
11
+ # page.has_selector?(:foo)
12
+ #
13
+ # By default it will check if the expression occurs at least once,
14
+ # but a different number can be specified.
15
+ #
16
+ # page.has_selector?('p#foo', :count => 4)
17
+ #
18
+ # This will check if the expression occurs exactly 4 times.
19
+ #
20
+ # It also accepts all options that {Capybara::Node::Finders#all} accepts,
21
+ # such as :text and :visible.
22
+ #
23
+ # page.has_selector?('li', :text => 'Horse', :visible => true)
24
+ #
25
+ # has_selector? can also accept XPath expressions generated by the
26
+ # XPath gem:
27
+ #
28
+ # xpath = XPath.generate { |x| x.descendant(:p) }
29
+ # page.has_selector?(:xpath, xpath)
30
+ #
31
+ # @param (see Capybara::Node::Finders#all)
32
+ # @option options [Integer] :count (nil) Number of times the expression should occur
33
+ # @return [Boolean] If the expression exists
34
+ #
35
+ def has_selector?(*args)
36
+ options = if args.last.is_a?(Hash) then args.last else {} end
37
+ wait_conditionally_until do
38
+ results = all(*args)
39
+
40
+ case
41
+ when results.empty?
42
+ false
43
+ when options[:between]
44
+ options[:between] === results.size
45
+ when options[:count]
46
+ options[:count] == results.size
47
+ when options[:maximum]
48
+ options[:maximum] >= results.size
49
+ when options[:minimum]
50
+ options[:minimum] <= results.size
51
+ else
52
+ results.size > 0
53
+ end
54
+ end
55
+ rescue Capybara::TimeoutError
56
+ return false
57
+ end
58
+
59
+ ##
60
+ #
61
+ # Checks if a given selector is not on the page or current node.
62
+ # Usage is identical to Capybara::Node::Matchers#has_selector?
63
+ #
64
+ # @param (see Capybara::Node::Finders#has_selector?)
65
+ # @return [Boolean]
66
+ #
67
+ def has_no_selector?(*args)
68
+ options = if args.last.is_a?(Hash) then args.last else {} end
69
+ wait_conditionally_until do
70
+ results = all(*args)
71
+
72
+ case
73
+ when results.empty?
74
+ true
75
+ when options[:between]
76
+ not(options[:between] === results.size)
77
+ when options[:count]
78
+ not(options[:count] == results.size)
79
+ when options[:maximum]
80
+ not(options[:maximum] >= results.size)
81
+ when options[:minimum]
82
+ not(options[:minimum] <= results.size)
83
+ else
84
+ results.empty?
85
+ end
86
+ end
87
+ rescue Capybara::TimeoutError
88
+ return false
89
+ end
90
+
91
+ ##
92
+ #
93
+ # Checks if a given XPath expression is on the page or current node.
94
+ #
95
+ # page.has_xpath?('.//p[@id="foo"]')
96
+ #
97
+ # By default it will check if the expression occurs at least once,
98
+ # but a different number can be specified.
99
+ #
100
+ # page.has_xpath?('.//p[@id="foo"]', :count => 4)
101
+ #
102
+ # This will check if the expression occurs exactly 4 times.
103
+ #
104
+ # It also accepts all options that {Capybara::Node::Finders#all} accepts,
105
+ # such as :text and :visible.
106
+ #
107
+ # page.has_xpath?('.//li', :text => 'Horse', :visible => true)
108
+ #
109
+ # has_xpath? can also accept XPath expressions generate by the
110
+ # XPath gem:
111
+ #
112
+ # xpath = XPath.generate { |x| x.descendant(:p) }
113
+ # page.has_xpath?(xpath)
114
+ #
115
+ # @param [String] path An XPath expression
116
+ # @param options (see Capybara::Node::Finders#all)
117
+ # @option options [Integer] :count (nil) Number of times the expression should occur
118
+ # @return [Boolean] If the expression exists
119
+ #
120
+ def has_xpath?(path, options={})
121
+ has_selector?(:xpath, path, options)
122
+ end
123
+
124
+ ##
125
+ #
126
+ # Checks if a given XPath expression is not on the page or current node.
127
+ # Usage is identical to Capybara::Node::Matchers#has_xpath?
128
+ #
129
+ # @param (see Capybara::Node::Finders#has_xpath?)
130
+ # @return [Boolean]
131
+ #
132
+ def has_no_xpath?(path, options={})
133
+ has_no_selector?(:xpath, path, options)
134
+ end
135
+
136
+ ##
137
+ #
138
+ # Checks if a given CSS selector is on the page or current node.
139
+ #
140
+ # page.has_css?('p#foo')
141
+ #
142
+ # By default it will check if the selector occurs at least once,
143
+ # but a different number can be specified.
144
+ #
145
+ # page.has_css?('p#foo', :count => 4)
146
+ #
147
+ # This will check if the selector occurs exactly 4 times.
148
+ #
149
+ # It also accepts all options that {Capybara::Node::Finders#all} accepts,
150
+ # such as :text and :visible.
151
+ #
152
+ # page.has_css?('li', :text => 'Horse', :visible => true)
153
+ #
154
+ # @param [String] path A CSS selector
155
+ # @param options (see Capybara::Node::Finders#all)
156
+ # @option options [Integer] :count (nil) Number of times the selector should occur
157
+ # @return [Boolean] If the selector exists
158
+ #
159
+ def has_css?(path, options={})
160
+ has_xpath?(XPath.css(path), options)
161
+ end
162
+
163
+ ##
164
+ #
165
+ # Checks if a given CSS selector is not on the page or current node.
166
+ # Usage is identical to Capybara::Node::Matchers#has_css?
167
+ #
168
+ # @param (see Capybara::Node::Finders#has_css?)
169
+ # @return [Boolean]
170
+ #
171
+ def has_no_css?(path, options={})
172
+ has_no_xpath?(XPath.css(path), options)
173
+ end
174
+
175
+ ##
176
+ #
177
+ # Checks if the page or current node has the given text content,
178
+ # ignoring any HTML tags and normalizing whitespace.
179
+ #
180
+ # @param [String] content The text to check for
181
+ # @return [Boolean] Whether it exists
182
+ #
183
+ def has_content?(content)
184
+ has_xpath?(XPath::HTML.content(content))
185
+ end
186
+
187
+ ##
188
+ #
189
+ # Checks if the page or current node does not have the given text
190
+ # content, ignoring any HTML tags and normalizing whitespace.
191
+ #
192
+ # @param [String] content The text to check for
193
+ # @return [Boolean] Whether it exists
194
+ #
195
+ def has_no_content?(content)
196
+ has_no_xpath?(XPath::HTML.content(content))
197
+ end
198
+
199
+ ##
200
+ #
201
+ # Checks if the page or current node has a link with the given
202
+ # text or id.
203
+ #
204
+ # @param [String] locator The text or id of a link to check for
205
+ # @param options
206
+ # @option options [String] :href The value the href attribute must be
207
+ # @return [Boolean] Whether it exists
208
+ #
209
+ def has_link?(locator, options={})
210
+ has_xpath?(XPath::HTML.link(locator, options))
211
+ end
212
+
213
+ ##
214
+ #
215
+ # Checks if the page or current node has no link with the given
216
+ # text or id.
217
+ #
218
+ # @param (see Capybara::Node::Finders#has_link?)
219
+ # @return [Boolean] Whether it doesn't exist
220
+ #
221
+ def has_no_link?(locator, options={})
222
+ has_no_xpath?(XPath::HTML.link(locator, options))
223
+ end
224
+
225
+ ##
226
+ #
227
+ # Checks if the page or current node has a button with the given
228
+ # text, value or id.
229
+ #
230
+ # @param [String] locator The text, value or id of a button to check for
231
+ # @return [Boolean] Whether it exists
232
+ #
233
+ def has_button?(locator)
234
+ has_xpath?(XPath::HTML.button(locator))
235
+ end
236
+
237
+ ##
238
+ #
239
+ # Checks if the page or current node has no button with the given
240
+ # text, value or id.
241
+ #
242
+ # @param [String] locator The text, value or id of a button to check for
243
+ # @return [Boolean] Whether it doesn't exist
244
+ #
245
+ def has_no_button?(locator)
246
+ has_no_xpath?(XPath::HTML.button(locator))
247
+ end
248
+
249
+ ##
250
+ #
251
+ # Checks if the page or current node has a form field with the given
252
+ # label, name or id.
253
+ #
254
+ # For text fields and other textual fields, such as textareas and
255
+ # HTML5 email/url/etc. fields, it's possible to specify a :with
256
+ # option to specify the text the field should contain:
257
+ #
258
+ # page.has_field?('Name', :with => 'Jonas')
259
+ #
260
+ # @param [String] locator The label, name or id of a field to check for
261
+ # @option options [String] :with The text content of the field
262
+ # @return [Boolean] Whether it exists
263
+ #
264
+ def has_field?(locator, options={})
265
+ options, with = split_options(options, :with)
266
+ has_xpath?(XPath::HTML.field(locator, options), with)
267
+ end
268
+
269
+ ##
270
+ #
271
+ # Checks if the page or current node has no form field with the given
272
+ # label, name or id. See {Capybara::Node::Matchers#has_field?}.
273
+ #
274
+ # @param [String] locator The label, name or id of a field to check for
275
+ # @option options [String] :with The text content of the field
276
+ # @return [Boolean] Whether it doesn't exist
277
+ #
278
+ def has_no_field?(locator, options={})
279
+ options, with = split_options(options, :with)
280
+ has_no_xpath?(XPath::HTML.field(locator, options), with)
281
+ end
282
+
283
+ ##
284
+ #
285
+ # Checks if the page or current node has a radio button or
286
+ # checkbox with the given label, value or id, that is currently
287
+ # checked.
288
+ #
289
+ # @param [String] locator The label, name or id of a checked field
290
+ # @return [Boolean] Whether it exists
291
+ #
292
+ def has_checked_field?(locator)
293
+ has_xpath?(XPath::HTML.field(locator), :checked => true)
294
+ end
295
+
296
+ ##
297
+ #
298
+ # Checks if the page or current node has a radio button or
299
+ # checkbox with the given label, value or id, that is currently
300
+ # unchecked.
301
+ #
302
+ # @param [String] locator The label, name or id of an unchecked field
303
+ # @return [Boolean] Whether it exists
304
+ #
305
+ def has_unchecked_field?(locator)
306
+ has_xpath?(XPath::HTML.field(locator), :unchecked => true)
307
+ end
308
+
309
+ ##
310
+ #
311
+ # Checks if the page or current node has a select field with the
312
+ # given label, name or id.
313
+ #
314
+ # It can be specified which option should currently be selected:
315
+ #
316
+ # page.has_select?('Language', :selected => 'German')
317
+ #
318
+ # For multiple select boxes, several options may be specified:
319
+ #
320
+ # page.has_select?('Language', :selected => ['English', 'German'])
321
+ #
322
+ # It's also possible to check if a given set of options exists for
323
+ # this select box:
324
+ #
325
+ # page.has_select?('Language', :options => ['English', 'German'])
326
+ #
327
+ # @param [String] locator The label, name or id of a select box
328
+ # @option options [Array] :options Options which should be contained in this select box
329
+ # @option options [String, Array] :selected Options which should be selected
330
+ # @return [Boolean] Whether it exists
331
+ #
332
+ def has_select?(locator, options={})
333
+ options, selected = split_options(options, :selected)
334
+ has_xpath?(XPath::HTML.select(locator, options), selected)
335
+ end
336
+
337
+ ##
338
+ #
339
+ # Checks if the page or current node has no select field with the
340
+ # given label, name or id. See {Capybara::Node::Matchers#has_select?}.
341
+ #
342
+ # @param (see Capybara::Node::Matchers#has_select?)
343
+ # @return [Boolean] Whether it doesn't exist
344
+ #
345
+ def has_no_select?(locator, options={})
346
+ options, selected = split_options(options, :selected)
347
+ has_no_xpath?(XPath::HTML.select(locator, options), selected)
348
+ end
349
+
350
+ ##
351
+ #
352
+ # Checks if the page or current node has a table with the given id
353
+ # or caption.
354
+ #
355
+ # If the options :rows is given, it will check that the table contains
356
+ # the rows and columns given:
357
+ #
358
+ # page.has_table?('People', :rows => [['Jonas', '24'], ['Peter', '32']])
359
+ #
360
+ # Note that this option is quite strict, the order needs to be correct
361
+ # and the text needs to match exactly.
362
+ #
363
+ # @param [String] locator The id or caption of a table
364
+ # @option options [Array[Array[String]]] :rows A set of rows the table should contain
365
+ # @return [Boolean] Whether it exist
366
+ #
367
+ def has_table?(locator, options={})
368
+ has_xpath?(XPath::HTML.table(locator, options))
369
+ end
370
+
371
+ ##
372
+ #
373
+ # Checks if the page or current node has no table with the given id
374
+ # or caption. See {Capybara::Node::Matchers#has_table?}.
375
+ #
376
+ # @param (see Capybara::Node::Matchers#has_table?)
377
+ # @return [Boolean] Whether it doesn't exist
378
+ #
379
+ def has_no_table?(locator, options={})
380
+ has_no_xpath?(XPath::HTML.table(locator, options))
381
+ end
382
+
383
+ protected
384
+
385
+ def split_options(options, key)
386
+ options = options.dup
387
+ [options, if options.has_key?(key) then {key => options.delete(key)} else {} end]
388
+ end
389
+ end
390
+ end
391
+ end