rspec-html-matchers 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.gitignore +10 -0
- data/.rspec +1 -0
- data/.travis.yml +4 -0
- data/.yardopts +4 -0
- data/CHANGELOG.md +87 -0
- data/Gemfile +2 -0
- data/README.md +109 -0
- data/Rakefile +27 -0
- data/assets/form.html +139 -0
- data/assets/ordered_list.html +9 -0
- data/assets/paragraphs.html +3 -0
- data/assets/quotes.html +24 -0
- data/assets/search_and_submit.html +9 -0
- data/assets/special.html +22 -0
- data/lib/rspec-html-matchers.rb +486 -0
- data/mikhalok.jpg +0 -0
- data/rspec-html-matchers.gemspec +28 -0
- data/script/assets.rb +38 -0
- data/script/console +9 -0
- data/spec/matchers/form_matchers_spec.rb +310 -0
- data/spec/matchers/have_tag_spec.rb +346 -0
- data/spec/spec_helper.rb +17 -0
- data/spec/support/helpers.rb +11 -0
- metadata +123 -0
data/assets/special.html
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
<table>
|
2
|
+
<tr>
|
3
|
+
<td>user_1</td>
|
4
|
+
<td id="other-special">user_2</td>
|
5
|
+
<td>user_3</td>
|
6
|
+
</tr>
|
7
|
+
<tr>
|
8
|
+
<td>a</td>
|
9
|
+
<td id="special">a</td>
|
10
|
+
<td>a</td>
|
11
|
+
</tr>
|
12
|
+
</table>
|
13
|
+
|
14
|
+
<div class="one">text</div>
|
15
|
+
<div class="one">text</div>
|
16
|
+
<div class="one">text</div>
|
17
|
+
<div class="one">text bla</div>
|
18
|
+
<div class="one">content bla</div>
|
19
|
+
<div class="one">content</div>
|
20
|
+
<div class="two">content bla</div>
|
21
|
+
<div class="two">content</div>
|
22
|
+
<div class="two">text</div>
|
@@ -0,0 +1,486 @@
|
|
1
|
+
require 'nokogiri'
|
2
|
+
|
3
|
+
module RSpec
|
4
|
+
module Matchers
|
5
|
+
|
6
|
+
# @api
|
7
|
+
# @private
|
8
|
+
class NokogiriMatcher
|
9
|
+
attr_reader :failure_message, :negative_failure_message
|
10
|
+
attr_reader :parent_scope, :current_scope
|
11
|
+
|
12
|
+
TAG_NOT_FOUND_MSG = %Q|expected following:\n%s\nto have at least 1 element matching "%s", found 0.|
|
13
|
+
TAG_FOUND_MSG = %Q|expected following:\n%s\nto NOT have element matching "%s", found %s.|
|
14
|
+
WRONG_COUNT_MSG = %Q|expected following:\n%s\nto have %s element(s) matching "%s", found %s.|
|
15
|
+
RIGHT_COUNT_MSG = %Q|expected following:\n%s\nto NOT have %s element(s) matching "%s", but found.|
|
16
|
+
BETWEEN_COUNT_MSG = %Q|expected following:\n%s\nto have at least %s and at most %s element(s) matching "%s", found %s.|
|
17
|
+
RIGHT_BETWEEN_COUNT_MSG = %Q|expected following:\n%s\nto NOT have at least %s and at most %s element(s) matching "%s", but found %s.|
|
18
|
+
AT_MOST_MSG = %Q|expected following:\n%s\nto have at most %s element(s) matching "%s", found %s.|
|
19
|
+
RIGHT_AT_MOST_MSG = %Q|expected following:\n%s\nto NOT have at most %s element(s) matching "%s", but found %s.|
|
20
|
+
AT_LEAST_MSG = %Q|expected following:\n%s\nto have at least %s element(s) matching "%s", found %s.|
|
21
|
+
RIGHT_AT_LEAST_MSG = %Q|expected following:\n%s\nto NOT have at least %s element(s) matching "%s", but found %s.|
|
22
|
+
REGEXP_NOT_FOUND_MSG = %Q|%s regexp expected within "%s" in following template:\n%s|
|
23
|
+
REGEXP_FOUND_MSG = %Q|%s regexp unexpected within "%s" in following template:\n%s\nbut was found.|
|
24
|
+
TEXT_NOT_FOUND_MSG = %Q|"%s" expected within "%s" in following template:\n%s|
|
25
|
+
TEXT_FOUND_MSG = %Q|"%s" unexpected within "%s" in following template:\n%s\nbut was found.|
|
26
|
+
WRONG_COUNT_ERROR_MSG = %Q|:count with :minimum or :maximum has no sence!|
|
27
|
+
MIN_MAX_ERROR_MSG = %Q|:minimum shold be less than :maximum!|
|
28
|
+
BAD_RANGE_ERROR_MSG = %Q|Your :count range(%s) has no sence!|
|
29
|
+
|
30
|
+
PRESERVE_WHITESPACE_TAGS = %w( pre textarea )
|
31
|
+
|
32
|
+
def initialize tag, options={}, &block
|
33
|
+
@tag, @options, @block = tag.to_s, options, block
|
34
|
+
|
35
|
+
if attrs = @options.delete(:with)
|
36
|
+
if classes=attrs.delete(:class)
|
37
|
+
classes = case classes
|
38
|
+
when Array
|
39
|
+
classes.join('.')
|
40
|
+
when String
|
41
|
+
classes.gsub("\s",'.')
|
42
|
+
end
|
43
|
+
@tag << '.'+classes
|
44
|
+
end
|
45
|
+
html_attrs_string=''
|
46
|
+
attrs.each_pair { |k,v| html_attrs_string << %Q{[#{k.to_s}='#{v.to_s}']} }
|
47
|
+
@tag << html_attrs_string
|
48
|
+
end
|
49
|
+
|
50
|
+
validate_options!
|
51
|
+
end
|
52
|
+
|
53
|
+
def matches? document, &block
|
54
|
+
@block = block if block
|
55
|
+
|
56
|
+
case document
|
57
|
+
when String
|
58
|
+
@parent_scope = @current_scope = Nokogiri::HTML(document).css(@tag)
|
59
|
+
@document = document
|
60
|
+
else
|
61
|
+
@parent_scope = document.current_scope
|
62
|
+
@current_scope = document.parent_scope.css(@tag)
|
63
|
+
@document = @parent_scope.to_html
|
64
|
+
end
|
65
|
+
|
66
|
+
if tag_presents? and content_right? and count_right?
|
67
|
+
@current_scope = @parent_scope
|
68
|
+
@block.call if @block
|
69
|
+
true
|
70
|
+
else
|
71
|
+
false
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
private
|
76
|
+
|
77
|
+
def tag_presents?
|
78
|
+
if @current_scope.first
|
79
|
+
@count = @current_scope.count
|
80
|
+
@negative_failure_message = TAG_FOUND_MSG % [@document, @tag, @count]
|
81
|
+
true
|
82
|
+
else
|
83
|
+
@failure_message = TAG_NOT_FOUND_MSG % [@document, @tag]
|
84
|
+
false
|
85
|
+
end
|
86
|
+
end
|
87
|
+
|
88
|
+
def count_right?
|
89
|
+
case @options[:count]
|
90
|
+
when Integer
|
91
|
+
((@negative_failure_message=RIGHT_COUNT_MSG % [@document,@count,@tag]) && @count == @options[:count]) || (@failure_message=WRONG_COUNT_MSG % [@document,@options[:count],@tag,@count]; false)
|
92
|
+
when Range
|
93
|
+
((@negative_failure_message=RIGHT_BETWEEN_COUNT_MSG % [@document,@options[:count].min,@options[:count].max,@tag,@count]) && @options[:count].member?(@count)) || (@failure_message=BETWEEN_COUNT_MSG % [@document,@options[:count].min,@options[:count].max,@tag,@count]; false)
|
94
|
+
when nil
|
95
|
+
if @options[:maximum]
|
96
|
+
((@negative_failure_message=RIGHT_AT_MOST_MSG % [@document,@options[:maximum],@tag,@count]) && @count <= @options[:maximum]) || (@failure_message=AT_MOST_MSG % [@document,@options[:maximum],@tag,@count]; false)
|
97
|
+
elsif @options[:minimum]
|
98
|
+
((@negative_failure_message=RIGHT_AT_LEAST_MSG % [@document,@options[:minimum],@tag,@count]) && @count >= @options[:minimum]) || (@failure_message=AT_LEAST_MSG % [@document,@options[:minimum],@tag,@count]; false)
|
99
|
+
else
|
100
|
+
true
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def content_right?
|
106
|
+
return true unless @options[:text]
|
107
|
+
|
108
|
+
case text=@options[:text]
|
109
|
+
when Regexp
|
110
|
+
new_scope = @current_scope.css(":regexp('#{text}')",Class.new {
|
111
|
+
def regexp node_set, text
|
112
|
+
node_set.find_all { |node| node.content =~ Regexp.new(text) }
|
113
|
+
end
|
114
|
+
}.new)
|
115
|
+
unless new_scope.empty?
|
116
|
+
@count = new_scope.count
|
117
|
+
@negative_failure_message = REGEXP_FOUND_MSG % [text.inspect,@tag,@document]
|
118
|
+
true
|
119
|
+
else
|
120
|
+
@failure_message = REGEXP_NOT_FOUND_MSG % [text.inspect,@tag,@document]
|
121
|
+
false
|
122
|
+
end
|
123
|
+
else
|
124
|
+
css_param = text.gsub(/'/) { %q{\000027} }
|
125
|
+
new_scope = @current_scope.css(":content('#{css_param}')",Class.new {
|
126
|
+
def content node_set, text
|
127
|
+
match_text = text.gsub(/\\000027/, "'")
|
128
|
+
node_set.find_all do |node|
|
129
|
+
actual_content = if PRESERVE_WHITESPACE_TAGS.include?(node.name)
|
130
|
+
node.content
|
131
|
+
else
|
132
|
+
node.content.strip.squeeze(' ')
|
133
|
+
end
|
134
|
+
# remove non-braking spaces:
|
135
|
+
actual_content.gsub!("\u00a0", ' ')
|
136
|
+
actual_content.gsub!("\302\240", ' ')
|
137
|
+
actual_content == match_text
|
138
|
+
end
|
139
|
+
end
|
140
|
+
}.new)
|
141
|
+
unless new_scope.empty?
|
142
|
+
@count = new_scope.count
|
143
|
+
@negative_failure_message = TEXT_FOUND_MSG % [text,@tag,@document]
|
144
|
+
true
|
145
|
+
else
|
146
|
+
@failure_message = TEXT_NOT_FOUND_MSG % [text,@tag,@document]
|
147
|
+
false
|
148
|
+
end
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
protected
|
153
|
+
|
154
|
+
def validate_options!
|
155
|
+
raise 'wrong :count specified' unless [Range, NilClass].include?(@options[:count].class) or @options[:count].is_a?(Integer)
|
156
|
+
|
157
|
+
[:min, :minimum, :max, :maximum].each do |key|
|
158
|
+
raise WRONG_COUNT_ERROR_MSG if @options.has_key?(key) and @options.has_key?(:count)
|
159
|
+
end
|
160
|
+
|
161
|
+
begin
|
162
|
+
raise MIN_MAX_ERROR_MSG if @options[:minimum] > @options[:maximum]
|
163
|
+
rescue NoMethodError # nil > 4
|
164
|
+
rescue ArgumentError # 2 < nil
|
165
|
+
end
|
166
|
+
|
167
|
+
begin
|
168
|
+
begin
|
169
|
+
raise BAD_RANGE_ERROR_MSG % [@options[:count].to_s] if @options[:count] && @options[:count].is_a?(Range) && (@options[:count].min.nil? or @options[:count].min < 0)
|
170
|
+
rescue ArgumentError, "comparison of String with" # if @options[:count] == 'a'..'z'
|
171
|
+
raise BAD_RANGE_ERROR_MSG % [@options[:count].to_s]
|
172
|
+
end
|
173
|
+
rescue TypeError # fix for 1.8.7 for 'rescue ArgumentError, "comparison of String with"' stroke
|
174
|
+
raise BAD_RANGE_ERROR_MSG % [@options[:count].to_s]
|
175
|
+
end
|
176
|
+
|
177
|
+
@options[:minimum] ||= @options.delete(:min)
|
178
|
+
@options[:maximum] ||= @options.delete(:max)
|
179
|
+
|
180
|
+
@options[:text] = @options[:text].to_s if @options.has_key?(:text) && !@options[:text].is_a?(Regexp)
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
# have_tag matcher
|
186
|
+
#
|
187
|
+
# @yield block where you should put with_tag
|
188
|
+
#
|
189
|
+
# @param [String] tag css selector for tag you want to match
|
190
|
+
# @param [Hash] options options hash(see below)
|
191
|
+
# @option options [Hash] :with hash with other attributes, within this, key :class have special meaning, you may specify it as array of expected classes or string of classes separated by spaces, order does not matter
|
192
|
+
# @option options [Fixnum] :count count of matched tags(DO NOT USE :count with :minimum(:min) or :maximum(:max)*)
|
193
|
+
# @option options [Range] :count count of matched tags should be between range minimum and maximum values
|
194
|
+
# @option options [Fixnum] :minimum minimum count of elements to match
|
195
|
+
# @option options [Fixnum] :min same as :minimum
|
196
|
+
# @option options [Fixnum] :maximum maximum count of elements to match
|
197
|
+
# @option options [Fixnum] :max same as :maximum
|
198
|
+
#
|
199
|
+
#
|
200
|
+
# @example
|
201
|
+
# rendered.should have_tag('div')
|
202
|
+
# rendered.should have_tag('h1.header')
|
203
|
+
# rendered.should have_tag('div#footer')
|
204
|
+
# rendered.should have_tag('input#email', :with => { :name => 'user[email]', :type => 'email' } )
|
205
|
+
# rendered.should have_tag('div', :count => 3) # matches exactly 3 'div' tags
|
206
|
+
# rendered.should have_tag('div', :count => 3..7) # something like have_tag('div', :minimum => 3, :maximum => 7)
|
207
|
+
# rendered.should have_tag('div', :minimum => 3) # matches more(or equal) than 3 'div' tags
|
208
|
+
# rendered.should have_tag('div', :maximum => 3) # matches less(or equal) than 3 'div' tags
|
209
|
+
# rendered.should have_tag('p', :text => 'some content') # will match "<p>some content</p>"
|
210
|
+
# rendered.should have_tag('p', :text => /some content/i) # will match "<p>sOme cOntEnt</p>"
|
211
|
+
# rendered.should have_tag('textarea', :with => {:name => 'user[description]'}, :text => "I like pie")
|
212
|
+
# "<html>
|
213
|
+
# <body>
|
214
|
+
# <h1>some html document</h1>
|
215
|
+
# </body>
|
216
|
+
# </html>".should have_tag('body') { with_tag('h1', :text => 'some html document') }
|
217
|
+
# '<div class="one two">'.should have_tag('div', :with => { :class => ['two', 'one'] })
|
218
|
+
# '<div class="one two">'.should have_tag('div', :with => { :class => 'two one' })
|
219
|
+
def have_tag tag, options={}, &block
|
220
|
+
if options.kind_of? String
|
221
|
+
options = { :text => options }
|
222
|
+
end
|
223
|
+
@__current_scope_for_nokogiri_matcher = NokogiriMatcher.new(tag, options, &block)
|
224
|
+
end
|
225
|
+
|
226
|
+
# with_tag matcher
|
227
|
+
# @yield
|
228
|
+
# @see #have_tag
|
229
|
+
# @note this should be used within block of have_tag matcher
|
230
|
+
def with_tag tag, options={}, &block
|
231
|
+
@__current_scope_for_nokogiri_matcher.should have_tag(tag, options, &block)
|
232
|
+
end
|
233
|
+
|
234
|
+
# without_tag matcher
|
235
|
+
# @yield
|
236
|
+
# @see #have_tag
|
237
|
+
# @note this should be used within block of have_tag matcher
|
238
|
+
def without_tag tag, options={}, &block
|
239
|
+
@__current_scope_for_nokogiri_matcher.should_not have_tag(tag, options, &block)
|
240
|
+
end
|
241
|
+
|
242
|
+
def have_form action_url, method, options={}, &block
|
243
|
+
options[:with] ||= {}
|
244
|
+
id = options[:with].delete(:id)
|
245
|
+
tag = 'form'; tag += '#'+id if id
|
246
|
+
options[:with].merge!(:action => action_url)
|
247
|
+
options[:with].merge!(:method => method.to_s)
|
248
|
+
have_tag tag, options, &block
|
249
|
+
end
|
250
|
+
|
251
|
+
def with_hidden_field name, value=nil
|
252
|
+
options = { :with => { :name => name, :type => 'hidden' } }
|
253
|
+
options[:with].merge!(:value => value) if value
|
254
|
+
should_have_input(options)
|
255
|
+
end
|
256
|
+
|
257
|
+
def without_hidden_field name, value=nil
|
258
|
+
options = { :with => { :name => name, :type => 'hidden' } }
|
259
|
+
options[:with].merge!(:value => value) if value
|
260
|
+
should_not_have_input(options)
|
261
|
+
end
|
262
|
+
|
263
|
+
def with_text_field name, value=nil
|
264
|
+
options = { :with => { :name => name, :type => 'text' } }
|
265
|
+
options[:with].merge!(:value => value) if value
|
266
|
+
should_have_input(options)
|
267
|
+
end
|
268
|
+
|
269
|
+
def without_text_field name, value=nil
|
270
|
+
options = { :with => { :name => name, :type => 'text' } }
|
271
|
+
options[:with].merge!(:value => value) if value
|
272
|
+
should_not_have_input(options)
|
273
|
+
end
|
274
|
+
|
275
|
+
def with_email_field name, value=nil
|
276
|
+
options = { :with => { :name => name, :type => 'email' } }
|
277
|
+
options[:with].merge!(:value => value) if value
|
278
|
+
should_have_input(options)
|
279
|
+
end
|
280
|
+
|
281
|
+
def without_email_field name, value=nil
|
282
|
+
options = { :with => { :name => name, :type => 'email' } }
|
283
|
+
options[:with].merge!(:value => value) if value
|
284
|
+
should_not_have_input(options)
|
285
|
+
end
|
286
|
+
|
287
|
+
def with_url_field name, value=nil
|
288
|
+
options = { :with => { :name => name, :type => 'url' } }
|
289
|
+
options[:with].merge!(:value => value) if value
|
290
|
+
should_have_input(options)
|
291
|
+
end
|
292
|
+
|
293
|
+
def without_url_field name, value=nil
|
294
|
+
options = { :with => { :name => name, :type => 'url' } }
|
295
|
+
options[:with].merge!(:value => value) if value
|
296
|
+
should_not_have_input(options)
|
297
|
+
end
|
298
|
+
|
299
|
+
def with_number_field name, value=nil
|
300
|
+
options = { :with => { :name => name, :type => 'number' } }
|
301
|
+
options[:with].merge!(:value => value.to_s) if value
|
302
|
+
should_have_input(options)
|
303
|
+
end
|
304
|
+
|
305
|
+
def without_number_field name, value=nil
|
306
|
+
options = { :with => { :name => name, :type => 'number' } }
|
307
|
+
options[:with].merge!(:value => value.to_s) if value
|
308
|
+
should_not_have_input(options)
|
309
|
+
end
|
310
|
+
|
311
|
+
def with_range_field name, min, max, options={}
|
312
|
+
options = { :with => { :name => name, :type => 'range', :min => min.to_s, :max => max.to_s }.merge(options.delete(:with)||{}) }
|
313
|
+
should_have_input(options)
|
314
|
+
end
|
315
|
+
|
316
|
+
def without_range_field name, min=nil, max=nil, options={}
|
317
|
+
options = { :with => { :name => name, :type => 'range' }.merge(options.delete(:with)||{}) }
|
318
|
+
options[:with].merge!(:min => min.to_s) if min
|
319
|
+
options[:with].merge!(:max => max.to_s) if max
|
320
|
+
should_not_have_input(options)
|
321
|
+
end
|
322
|
+
|
323
|
+
DATE_FIELD_TYPES = %w( date month week time datetime datetime-local )
|
324
|
+
|
325
|
+
def with_date_field date_field_type, name=nil, options={}
|
326
|
+
date_field_type = date_field_type.to_s
|
327
|
+
raise "unknown type `#{date_field_type}` for date picker" unless DATE_FIELD_TYPES.include?(date_field_type)
|
328
|
+
options = { :with => { :type => date_field_type.to_s }.merge(options.delete(:with)||{}) }
|
329
|
+
options[:with].merge!(:name => name.to_s) if name
|
330
|
+
should_have_input(options)
|
331
|
+
end
|
332
|
+
|
333
|
+
def without_date_field date_field_type, name=nil, options={}
|
334
|
+
date_field_type = date_field_type.to_s
|
335
|
+
raise "unknown type `#{date_field_type}` for date picker" unless DATE_FIELD_TYPES.include?(date_field_type)
|
336
|
+
options = { :with => { :type => date_field_type.to_s }.merge(options.delete(:with)||{}) }
|
337
|
+
options[:with].merge!(:name => name.to_s) if name
|
338
|
+
should_not_have_input(options)
|
339
|
+
end
|
340
|
+
|
341
|
+
def with_password_field name
|
342
|
+
options = { :with => { :name => name, :type => 'password' } }
|
343
|
+
should_have_input(options)
|
344
|
+
end
|
345
|
+
|
346
|
+
def without_password_field name
|
347
|
+
options = { :with => { :name => name, :type => 'password' } }
|
348
|
+
should_not_have_input(options)
|
349
|
+
end
|
350
|
+
|
351
|
+
def with_file_field name
|
352
|
+
options = { :with => { :name => name, :type => 'file' } }
|
353
|
+
should_have_input(options)
|
354
|
+
end
|
355
|
+
|
356
|
+
def without_file_field name
|
357
|
+
options = { :with => { :name => name, :type => 'file' } }
|
358
|
+
should_not_have_input(options)
|
359
|
+
end
|
360
|
+
|
361
|
+
def with_text_area name
|
362
|
+
options = { :with => { :name => name } }
|
363
|
+
@__current_scope_for_nokogiri_matcher.should have_tag('textarea', options)
|
364
|
+
end
|
365
|
+
|
366
|
+
def without_text_area name
|
367
|
+
options = { :with => { :name => name } }
|
368
|
+
@__current_scope_for_nokogiri_matcher.should_not have_tag('textarea', options)
|
369
|
+
end
|
370
|
+
|
371
|
+
def with_checkbox name, value=nil
|
372
|
+
options = { :with => { :name => name, :type => 'checkbox' } }
|
373
|
+
options[:with].merge!(:value => value) if value
|
374
|
+
should_have_input(options)
|
375
|
+
end
|
376
|
+
|
377
|
+
def without_checkbox name, value=nil
|
378
|
+
options = { :with => { :name => name, :type => 'checkbox' } }
|
379
|
+
options[:with].merge!(:value => value) if value
|
380
|
+
should_not_have_input(options)
|
381
|
+
end
|
382
|
+
|
383
|
+
def with_radio_button name, value
|
384
|
+
options = { :with => { :name => name, :type => 'radio' } }
|
385
|
+
options[:with].merge!(:value => value)
|
386
|
+
should_have_input(options)
|
387
|
+
end
|
388
|
+
|
389
|
+
def without_radio_button name, value
|
390
|
+
options = { :with => { :name => name, :type => 'radio' } }
|
391
|
+
options[:with].merge!(:value => value)
|
392
|
+
should_not_have_input(options)
|
393
|
+
end
|
394
|
+
|
395
|
+
def with_select name, options={}, &block
|
396
|
+
options[:with] ||= {}
|
397
|
+
id = options[:with].delete(:id)
|
398
|
+
tag='select'; tag += '#'+id if id
|
399
|
+
options[:with].merge!(:name => name)
|
400
|
+
@__current_scope_for_nokogiri_matcher.should have_tag(tag, options, &block)
|
401
|
+
end
|
402
|
+
|
403
|
+
def without_select name, options={}, &block
|
404
|
+
options[:with] ||= {}
|
405
|
+
id = options[:with].delete(:id)
|
406
|
+
tag='select'; tag += '#'+id if id
|
407
|
+
options[:with].merge!(:name => name)
|
408
|
+
@__current_scope_for_nokogiri_matcher.should_not have_tag(tag, options, &block)
|
409
|
+
end
|
410
|
+
|
411
|
+
def with_option text, value=nil, options={}
|
412
|
+
options[:with] ||= {}
|
413
|
+
if value.is_a?(Hash)
|
414
|
+
options.merge!(value)
|
415
|
+
value=nil
|
416
|
+
end
|
417
|
+
tag='option'
|
418
|
+
options[:with].merge!(:value => value.to_s) if value
|
419
|
+
if options[:selected]
|
420
|
+
options[:with].merge!(:selected => "selected")
|
421
|
+
end
|
422
|
+
options.delete(:selected)
|
423
|
+
options.merge!(:text => text) if text
|
424
|
+
@__current_scope_for_nokogiri_matcher.should have_tag(tag, options)
|
425
|
+
end
|
426
|
+
|
427
|
+
def without_option text, value=nil, options={}
|
428
|
+
options[:with] ||= {}
|
429
|
+
if value.is_a?(Hash)
|
430
|
+
options.merge!(value)
|
431
|
+
value=nil
|
432
|
+
end
|
433
|
+
tag='option'
|
434
|
+
options[:with].merge!(:value => value.to_s) if value
|
435
|
+
if options[:selected]
|
436
|
+
options[:with].merge!(:selected => "selected")
|
437
|
+
end
|
438
|
+
options.delete(:selected)
|
439
|
+
options.merge!(:text => text) if text
|
440
|
+
@__current_scope_for_nokogiri_matcher.should_not have_tag(tag, options)
|
441
|
+
end
|
442
|
+
|
443
|
+
def with_button text, value=nil, options={}
|
444
|
+
options[:with] ||= {}
|
445
|
+
if value.is_a?(Hash)
|
446
|
+
options.merge!(value)
|
447
|
+
value=nil
|
448
|
+
end
|
449
|
+
options[:with].merge!(:value => value.to_s) if value
|
450
|
+
options.merge!(:text => text) if text
|
451
|
+
@__current_scope_for_nokogiri_matcher.should have_tag('button', options)
|
452
|
+
end
|
453
|
+
|
454
|
+
def without_button text, value=nil, options={}
|
455
|
+
options[:with] ||= {}
|
456
|
+
if value.is_a?(Hash)
|
457
|
+
options.merge!(value)
|
458
|
+
value=nil
|
459
|
+
end
|
460
|
+
options[:with].merge!(:value => value.to_s) if value
|
461
|
+
options.merge!(:text => text) if text
|
462
|
+
@__current_scope_for_nokogiri_matcher.should_not have_tag('button', options)
|
463
|
+
end
|
464
|
+
|
465
|
+
def with_submit value
|
466
|
+
options = { :with => { :type => 'submit', :value => value } }
|
467
|
+
should_have_input(options)
|
468
|
+
end
|
469
|
+
|
470
|
+
def without_submit value
|
471
|
+
options = { :with => { :type => 'submit', :value => value } }
|
472
|
+
should_not_have_input(options)
|
473
|
+
end
|
474
|
+
|
475
|
+
private
|
476
|
+
|
477
|
+
def should_have_input(options)
|
478
|
+
@__current_scope_for_nokogiri_matcher.should have_tag('input', options)
|
479
|
+
end
|
480
|
+
|
481
|
+
def should_not_have_input(options)
|
482
|
+
@__current_scope_for_nokogiri_matcher.should_not have_tag('input', options)
|
483
|
+
end
|
484
|
+
|
485
|
+
end
|
486
|
+
end
|