rspec2-rails-views-matchers 0.1.6 → 0.2.0
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 +1 -0
- data/.yardopts +1 -1
- data/{docs/CHANGELOG.md → CHANGELOG.md} +10 -3
- data/Gemfile +0 -2
- data/README.md +47 -24
- data/Rakefile +7 -0
- data/assets/form.html +139 -0
- data/assets/ordered_list.html +9 -0
- data/assets/paragraphs.html +3 -0
- data/assets/quotes.html +6 -0
- data/assets/search_and_submit.html +9 -0
- data/assets/special.html +22 -0
- data/lib/rspec2-rails-views-matchers.rb +469 -1
- data/{docs/mikhalok.jpg → mikhalok.jpg} +0 -0
- data/rspec2-rails-views-matchers.gemspec +6 -5
- data/spec/matchers/form_matchers_spec.rb +214 -213
- data/spec/matchers/have_tag_spec.rb +137 -166
- data/spec/spec_helper.rb +0 -11
- metadata +34 -31
- data/lib/rspec/rails/views/matchers.rb +0 -1
- data/lib/rspec/rails/views/matchers/have_tag.rb +0 -325
- data/lib/version.rb +0 -13
|
@@ -1 +0,0 @@
|
|
|
1
|
-
require 'rspec/rails/views/matchers/have_tag'
|
|
@@ -1,325 +0,0 @@
|
|
|
1
|
-
require 'nokogiri'
|
|
2
|
-
|
|
3
|
-
module RSpec
|
|
4
|
-
module Matchers
|
|
5
|
-
|
|
6
|
-
# @api
|
|
7
|
-
# @private
|
|
8
|
-
class NokogiriMatcher
|
|
9
|
-
attr_reader :failure_message
|
|
10
|
-
attr_reader :parent_scope, :current_scope
|
|
11
|
-
|
|
12
|
-
def initialize tag, options={}, &block
|
|
13
|
-
@tag, @options, @block = tag.to_s, options, block
|
|
14
|
-
|
|
15
|
-
if attrs = @options.delete(:with)
|
|
16
|
-
if classes=attrs.delete(:class)
|
|
17
|
-
classes = case classes
|
|
18
|
-
when Array
|
|
19
|
-
classes.join('.')
|
|
20
|
-
when String
|
|
21
|
-
classes.gsub("\s",'.')
|
|
22
|
-
end
|
|
23
|
-
@tag << '.'+classes
|
|
24
|
-
end
|
|
25
|
-
html_attrs_string=''
|
|
26
|
-
attrs.each_pair { |k,v| html_attrs_string << %Q{[#{k.to_s}='#{v.to_s}']} }
|
|
27
|
-
@tag << html_attrs_string
|
|
28
|
-
end
|
|
29
|
-
|
|
30
|
-
# TODO add min and max processing
|
|
31
|
-
@options[:minimum] ||= @options.delete(:min)
|
|
32
|
-
@options[:maximum] ||= @options.delete(:max)
|
|
33
|
-
end
|
|
34
|
-
|
|
35
|
-
def matches? document, &block
|
|
36
|
-
@block = block if block
|
|
37
|
-
|
|
38
|
-
case document
|
|
39
|
-
when String
|
|
40
|
-
@parent_scope = @current_scope = Nokogiri::HTML(document).css(@tag)
|
|
41
|
-
@document = document
|
|
42
|
-
else
|
|
43
|
-
@parent_scope = document.current_scope
|
|
44
|
-
@current_scope = document.parent_scope.css(@tag)
|
|
45
|
-
@document = @parent_scope.to_html
|
|
46
|
-
end
|
|
47
|
-
|
|
48
|
-
if tag_presents? and content_right? and count_right?
|
|
49
|
-
@current_scope = @parent_scope
|
|
50
|
-
@block.call if @block
|
|
51
|
-
true
|
|
52
|
-
else
|
|
53
|
-
false
|
|
54
|
-
end
|
|
55
|
-
end
|
|
56
|
-
|
|
57
|
-
private
|
|
58
|
-
|
|
59
|
-
def tag_presents?
|
|
60
|
-
if @current_scope.first
|
|
61
|
-
@count = @current_scope.count
|
|
62
|
-
true
|
|
63
|
-
else
|
|
64
|
-
@failure_message = %Q{expected following:\n#{@document}\nto have at least 1 element matching "#{@tag}", found 0.}
|
|
65
|
-
false
|
|
66
|
-
end
|
|
67
|
-
end
|
|
68
|
-
|
|
69
|
-
def count_right?
|
|
70
|
-
case @options[:count]
|
|
71
|
-
when Integer
|
|
72
|
-
@count == @options[:count] || (@failure_message=%Q{expected following:\n#{@document}\nto have #{@options[:count]} element(s) matching "#{@tag}", found #{@count}.}; false)
|
|
73
|
-
when Range
|
|
74
|
-
@options[:count].member?(@count) || (@failure_message=%Q{expected following:\n#{@document}\nto have at least #{@options[:count].min} and at most #{@options[:count].max} element(s) matching "#{@tag}", found #{@count}.}; false)
|
|
75
|
-
when nil
|
|
76
|
-
if @options[:maximum]
|
|
77
|
-
@count <= @options[:maximum] || (@failure_message=%Q{expected following:\n#{@document}\nto have at most #{@options[:maximum]} element(s) matching "#{@tag}", found #{@count}.}; false)
|
|
78
|
-
elsif @options[:minimum]
|
|
79
|
-
@count >= @options[:minimum] || (@failure_message=%Q{expected following:\n#{@document}\nto have at least #{@options[:minimum]} element(s) matching "#{@tag}", found #{@count}.}; false)
|
|
80
|
-
else
|
|
81
|
-
true
|
|
82
|
-
end
|
|
83
|
-
else
|
|
84
|
-
@failure_message = 'wrong count specified'
|
|
85
|
-
return false
|
|
86
|
-
end
|
|
87
|
-
end
|
|
88
|
-
|
|
89
|
-
def content_right?
|
|
90
|
-
return true unless @options[:text]
|
|
91
|
-
|
|
92
|
-
case text=@options[:text]
|
|
93
|
-
when Regexp
|
|
94
|
-
new_scope = @current_scope.css(":regexp('#{text}')",Class.new {
|
|
95
|
-
def regexp node_set, text
|
|
96
|
-
node_set.find_all { |node| node.content =~ Regexp.new(text) }
|
|
97
|
-
end
|
|
98
|
-
}.new)
|
|
99
|
-
unless new_scope.empty?
|
|
100
|
-
@count = new_scope.count
|
|
101
|
-
true
|
|
102
|
-
else
|
|
103
|
-
@failure_message=%Q{#{text.inspect} regexp expected within "#{@tag}" in following template:\n#{@document}}
|
|
104
|
-
false
|
|
105
|
-
end
|
|
106
|
-
else
|
|
107
|
-
css_param = text.gsub(/'/) { %q{\000027} }
|
|
108
|
-
new_scope = @current_scope.css(":content('#{css_param}')",Class.new {
|
|
109
|
-
def content node_set, text
|
|
110
|
-
match_text = text.gsub(/\\000027/, "'")
|
|
111
|
-
node_set.find_all { |node| node.content == match_text }
|
|
112
|
-
end
|
|
113
|
-
}.new)
|
|
114
|
-
unless new_scope.empty?
|
|
115
|
-
@count = new_scope.count
|
|
116
|
-
true
|
|
117
|
-
else
|
|
118
|
-
@failure_message=%Q{"#{text}" expected within "#{@tag}" in following template:\n#{@document}}
|
|
119
|
-
false
|
|
120
|
-
end
|
|
121
|
-
end
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
# have_tag matcher
|
|
126
|
-
#
|
|
127
|
-
# @yield block where you should put with_tag
|
|
128
|
-
#
|
|
129
|
-
# @param [String] tag css selector for tag you want to match
|
|
130
|
-
# @param [Hash] options options hash(see below)
|
|
131
|
-
# @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
|
|
132
|
-
# @option options [Fixnum] :count count of matched tags(DO NOT USE :count with :minimum(:min) or :maximum(:max)*)
|
|
133
|
-
# @option options [Range] :count count of matched tags should be between range minimum and maximum values
|
|
134
|
-
# @option options [Fixnum] :minimum minimum count of elements to match
|
|
135
|
-
# @option options [Fixnum] :min same as :minimum
|
|
136
|
-
# @option options [Fixnum] :maximum maximum count of elements to match
|
|
137
|
-
# @option options [Fixnum] :max same as :maximum
|
|
138
|
-
#
|
|
139
|
-
#
|
|
140
|
-
# @example
|
|
141
|
-
# rendered.should have_tag('div')
|
|
142
|
-
# rendered.should have_tag('h1.header')
|
|
143
|
-
# rendered.should have_tag('div#footer')
|
|
144
|
-
# rendered.should have_tag('input#email', :with => { :name => 'user[email]', :type => 'email' } )
|
|
145
|
-
# rendered.should have_tag('div', :count => 3) # matches exactly 3 'div' tags
|
|
146
|
-
# rendered.should have_tag('div', :count => 3..7) # something like have_tag('div', :minimum => 3, :maximum => 7)
|
|
147
|
-
# rendered.should have_tag('div', :minimum => 3) # matches more(or equal) than 3 'div' tags
|
|
148
|
-
# rendered.should have_tag('div', :maximum => 3) # matches less(or equal) than 3 'div' tags
|
|
149
|
-
# rendered.should have_tag('p', :text => 'some content') # will match "<p>some content</p>"
|
|
150
|
-
# rendered.should have_tag('p', :text => /some content/i) # will match "<p>sOme cOntEnt</p>"
|
|
151
|
-
# rendered.should have_tag('textarea', :with => {:name => 'user[description]'}, :text => "I like pie")
|
|
152
|
-
# "<html>
|
|
153
|
-
# <body>
|
|
154
|
-
# <h1>some html document</h1>
|
|
155
|
-
# </body>
|
|
156
|
-
# </html>".should have_tag('body') { with_tag('h1', :text => 'some html document') }
|
|
157
|
-
# '<div class="one two">'.should have_tag('div', :with => { :class => ['two', 'one'] })
|
|
158
|
-
# '<div class="one two">'.should have_tag('div', :with => { :class => 'two one' })
|
|
159
|
-
def have_tag tag, options={}, &block
|
|
160
|
-
@__current_scope_for_nokogiri_matcher = NokogiriMatcher.new(tag, options, &block)
|
|
161
|
-
end
|
|
162
|
-
|
|
163
|
-
# with_tag matcher
|
|
164
|
-
# @yield
|
|
165
|
-
# @see #have_tag
|
|
166
|
-
# @note this should be used within block of have_tag matcher
|
|
167
|
-
def with_tag tag, options={}, &block
|
|
168
|
-
@__current_scope_for_nokogiri_matcher.should have_tag(tag, options, &block)
|
|
169
|
-
end
|
|
170
|
-
|
|
171
|
-
# without_tag matcher
|
|
172
|
-
# @yield
|
|
173
|
-
# @see #have_tag
|
|
174
|
-
# @note this should be used within block of have_tag matcher
|
|
175
|
-
def without_tag tag, options={}, &block
|
|
176
|
-
@__current_scope_for_nokogiri_matcher.should_not have_tag(tag, options, &block)
|
|
177
|
-
end
|
|
178
|
-
|
|
179
|
-
def have_form action_url, method, options={}, &block
|
|
180
|
-
options[:with] ||= {}
|
|
181
|
-
id = options[:with].delete(:id)
|
|
182
|
-
tag = 'form'; tag += '#'+id if id
|
|
183
|
-
options[:with].merge!(:action => action_url)
|
|
184
|
-
options[:with].merge!(:method => method.to_s)
|
|
185
|
-
have_tag tag, options, &block
|
|
186
|
-
end
|
|
187
|
-
|
|
188
|
-
def with_hidden_field name, value=nil
|
|
189
|
-
options = { :with => { :name => name, :type => 'hidden' } }
|
|
190
|
-
options[:with].merge!(:value => value) if value
|
|
191
|
-
@__current_scope_for_nokogiri_matcher.should have_tag('input', options)
|
|
192
|
-
end
|
|
193
|
-
|
|
194
|
-
def without_hidden_field name, value=nil
|
|
195
|
-
options = { :with => { :name => name, :type => 'hidden' } }
|
|
196
|
-
options[:with].merge!(:value => value) if value
|
|
197
|
-
@__current_scope_for_nokogiri_matcher.should_not have_tag('input', options)
|
|
198
|
-
end
|
|
199
|
-
|
|
200
|
-
def with_text_field name, value=nil
|
|
201
|
-
options = { :with => { :name => name, :type => 'text' } }
|
|
202
|
-
options[:with].merge!(:value => value) if value
|
|
203
|
-
@__current_scope_for_nokogiri_matcher.should have_tag('input', options)
|
|
204
|
-
end
|
|
205
|
-
|
|
206
|
-
def without_text_field name, value=nil
|
|
207
|
-
options = { :with => { :name => name, :type => 'text' } }
|
|
208
|
-
options[:with].merge!(:value => value) if value
|
|
209
|
-
@__current_scope_for_nokogiri_matcher.should_not have_tag('input', options)
|
|
210
|
-
end
|
|
211
|
-
|
|
212
|
-
def with_password_field name
|
|
213
|
-
options = { :with => { :name => name, :type => 'password' } }
|
|
214
|
-
@__current_scope_for_nokogiri_matcher.should have_tag('input', options)
|
|
215
|
-
end
|
|
216
|
-
|
|
217
|
-
def without_password_field name
|
|
218
|
-
options = { :with => { :name => name, :type => 'password' } }
|
|
219
|
-
@__current_scope_for_nokogiri_matcher.should_not have_tag('input', options)
|
|
220
|
-
end
|
|
221
|
-
|
|
222
|
-
def with_file_field name
|
|
223
|
-
options = { :with => { :name => name, :type => 'file' } }
|
|
224
|
-
@__current_scope_for_nokogiri_matcher.should have_tag('input', options)
|
|
225
|
-
end
|
|
226
|
-
|
|
227
|
-
def without_file_field name
|
|
228
|
-
options = { :with => { :name => name, :type => 'file' } }
|
|
229
|
-
@__current_scope_for_nokogiri_matcher.should_not have_tag('input', options)
|
|
230
|
-
end
|
|
231
|
-
|
|
232
|
-
def with_text_area name
|
|
233
|
-
options = { :with => { :name => name } }
|
|
234
|
-
@__current_scope_for_nokogiri_matcher.should have_tag('textarea', options)
|
|
235
|
-
end
|
|
236
|
-
|
|
237
|
-
def without_text_area name
|
|
238
|
-
options = { :with => { :name => name } }
|
|
239
|
-
@__current_scope_for_nokogiri_matcher.should_not have_tag('textarea', options)
|
|
240
|
-
end
|
|
241
|
-
|
|
242
|
-
def with_checkbox name, value=nil
|
|
243
|
-
options = { :with => { :name => name, :type => 'checkbox' } }
|
|
244
|
-
options[:with].merge!(:value => value) if value
|
|
245
|
-
@__current_scope_for_nokogiri_matcher.should have_tag('input', options)
|
|
246
|
-
end
|
|
247
|
-
|
|
248
|
-
def without_checkbox name, value=nil
|
|
249
|
-
options = { :with => { :name => name, :type => 'checkbox' } }
|
|
250
|
-
options[:with].merge!(:value => value) if value
|
|
251
|
-
@__current_scope_for_nokogiri_matcher.should_not have_tag('input', options)
|
|
252
|
-
end
|
|
253
|
-
|
|
254
|
-
def with_radio_button name, value
|
|
255
|
-
options = { :with => { :name => name, :type => 'radio' } }
|
|
256
|
-
options[:with].merge!(:value => value)
|
|
257
|
-
@__current_scope_for_nokogiri_matcher.should have_tag('input', options)
|
|
258
|
-
end
|
|
259
|
-
|
|
260
|
-
def without_radio_button name, value
|
|
261
|
-
options = { :with => { :name => name, :type => 'radio' } }
|
|
262
|
-
options[:with].merge!(:value => value)
|
|
263
|
-
@__current_scope_for_nokogiri_matcher.should_not have_tag('input', options)
|
|
264
|
-
end
|
|
265
|
-
|
|
266
|
-
def with_select name, options={}, &block
|
|
267
|
-
options[:with] ||= {}
|
|
268
|
-
id = options[:with].delete(:id)
|
|
269
|
-
tag='select'; tag += '#'+id if id
|
|
270
|
-
options[:with].merge!(:name => name)
|
|
271
|
-
@__current_scope_for_nokogiri_matcher.should have_tag(tag, options, &block)
|
|
272
|
-
end
|
|
273
|
-
|
|
274
|
-
def without_select name, options={}, &block
|
|
275
|
-
options[:with] ||= {}
|
|
276
|
-
id = options[:with].delete(:id)
|
|
277
|
-
tag='select'; tag += '#'+id if id
|
|
278
|
-
options[:with].merge!(:name => name)
|
|
279
|
-
@__current_scope_for_nokogiri_matcher.should_not have_tag(tag, options, &block)
|
|
280
|
-
end
|
|
281
|
-
|
|
282
|
-
def with_option text, value=nil, options={}
|
|
283
|
-
options[:with] ||= {}
|
|
284
|
-
if value.is_a?(Hash)
|
|
285
|
-
options.merge!(value)
|
|
286
|
-
value=nil
|
|
287
|
-
end
|
|
288
|
-
tag='option'
|
|
289
|
-
options[:with].merge!(:value => value.to_s) if value
|
|
290
|
-
if options[:selected]
|
|
291
|
-
options[:with].merge!(:selected => "selected")
|
|
292
|
-
end
|
|
293
|
-
options.delete(:selected)
|
|
294
|
-
options.merge!(:text => text) if text
|
|
295
|
-
@__current_scope_for_nokogiri_matcher.should have_tag(tag, options)
|
|
296
|
-
end
|
|
297
|
-
|
|
298
|
-
def without_option text, value=nil, options={}
|
|
299
|
-
options[:with] ||= {}
|
|
300
|
-
if value.is_a?(Hash)
|
|
301
|
-
options.merge!(value)
|
|
302
|
-
value=nil
|
|
303
|
-
end
|
|
304
|
-
tag='option'
|
|
305
|
-
options[:with].merge!(:value => value.to_s) if value
|
|
306
|
-
if options[:selected]
|
|
307
|
-
options[:with].merge!(:selected => "selected")
|
|
308
|
-
end
|
|
309
|
-
options.delete(:selected)
|
|
310
|
-
options.merge!(:text => text) if text
|
|
311
|
-
@__current_scope_for_nokogiri_matcher.should_not have_tag(tag, options)
|
|
312
|
-
end
|
|
313
|
-
|
|
314
|
-
def with_submit value
|
|
315
|
-
options = { :with => { :type => 'submit', :value => value } }
|
|
316
|
-
@__current_scope_for_nokogiri_matcher.should have_tag('input', options)
|
|
317
|
-
end
|
|
318
|
-
|
|
319
|
-
def without_submit value
|
|
320
|
-
options = { :with => { :type => 'submit', :value => value } }
|
|
321
|
-
@__current_scope_for_nokogiri_matcher.should_not have_tag('input', options)
|
|
322
|
-
end
|
|
323
|
-
|
|
324
|
-
end
|
|
325
|
-
end
|