rspec-html-matchers 0.6.1 → 0.7.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 6f28ddf0ddc2a0e321f8b3b291cfb2e3aa0b0e81
4
- data.tar.gz: a4dedc6075e05857f5d97b9e133e3fa8ec8d230b
3
+ metadata.gz: ed044ed780b0ef4fefc403e3d644e6759b45232e
4
+ data.tar.gz: 3a9a74c22ee2c89bfae15fd3de267b3cf048604e
5
5
  SHA512:
6
- metadata.gz: d66ca882d21fbba2ef260bdc3a5cebb5669568536583f1cdb10dac6a9c63068b3b46608def542c9960f3b90123a335048871aa49ed243fa92ae227683041cccf
7
- data.tar.gz: b838ba419b4e5150ffc08944fe1faa3babaf9b9926340b8aa3654f54c1368f8678ed5b457257cbf646116ebaa1c003b2deb2f6ff90ab535ea5309916ae445594
6
+ metadata.gz: 52855bb634b6ccf3a31995e7d3a7730410d3f7c3209b9bfe9a42b9c924db3b7eb7d028d95a5523d1c02e87eab4929aad565a5483e7e1f1101a8eee8bad55cc2c
7
+ data.tar.gz: ecedc6b4e6791348db17d86a0338ccdeccfa3aa35e97a99a641358247cae14c89a39c6f2a56f026eba9b0f1d94b8f3757cc87b3186d8aa59a96ddfcb58fa3cac
data/CHANGELOG.md CHANGED
@@ -11,6 +11,18 @@ unreleased(TODO)
11
11
  * order matching
12
12
  * improve documentation, add more usage examples (look at changelog and code!)
13
13
 
14
+ 0.7.0
15
+ -----
16
+
17
+ * new, explicit configuration, refer to README
18
+ * added ruby 2.2.0 to CI
19
+
20
+ 0.6.1
21
+ -----
22
+
23
+ * rspec 3 version update
24
+ * added ruby 2.1.2 to CI
25
+
14
26
  0.6.0
15
27
  -----
16
28
 
data/README.md CHANGED
@@ -28,6 +28,33 @@ Add to your Gemfile in the `:test` group:
28
28
  gem 'rspec-html-matchers'
29
29
  ```
30
30
 
31
+ and somewhere in RSpec configuration:
32
+
33
+ ```ruby
34
+ RSpec.configure do |config|
35
+ config.include RSpecHtmlMatchers
36
+ end
37
+ ```
38
+
39
+ or just in you spec(s):
40
+
41
+ ```ruby
42
+ describe "my view spec" do
43
+ include RSpecHtmlMatchers
44
+
45
+ it "has tags" do
46
+ expect(rendered).to have_tag('div')
47
+ end
48
+
49
+ end
50
+ ```
51
+
52
+ Cucumber configuration:
53
+
54
+ ```ruby
55
+ World RSpecHtmlMatchers
56
+ ```
57
+
31
58
  as this gem requires **nokogiri**, here [instructions for installing it](http://nokogiri.org/tutorials/installing_nokogiri.html).
32
59
 
33
60
  Usage
@@ -195,6 +222,7 @@ Contributors
195
222
  - [Felix Tjandrawibawa](https://github.com/cemenghttps://github.com/cemeng)
196
223
  - [Szymon Przybył](https://github.com/apocalyptiq)
197
224
  - [Manuel Meurer](https://github.com/manuelmeurer)
225
+ - [Andreas Riemer](https://github.com/arfl)
198
226
 
199
227
  MIT Licensed
200
228
  ============
@@ -5,6 +5,8 @@ require 'sinatra/base'
5
5
  require 'capybara/cucumber'
6
6
  require 'rspec-html-matchers'
7
7
 
8
+ World RSpecHtmlMatchers
9
+
8
10
  $ASSETS_DIR = File.expand_path('../tmp',__FILE__)
9
11
  $INDEX_HTML = File.join($ASSETS_DIR,'index.html')
10
12
 
@@ -2,568 +2,558 @@
2
2
  require 'rspec'
3
3
  require 'nokogiri'
4
4
 
5
- module RSpec
6
- module HtmlMatchers
7
-
8
- # @api
9
- # @private
10
- # for nokogiri regexp matching
11
- class NokogiriRegexpHelper
12
- def initialize(regex)
13
- @regex = regex
14
- end
5
+ module RSpecHtmlMatchers
15
6
 
16
- def regexp node_set
17
- node_set.find_all { |node| node.content =~ @regex }
18
- end
7
+ # @api
8
+ # @private
9
+ # for nokogiri regexp matching
10
+ class NokogiriRegexpHelper
11
+ def initialize(regex)
12
+ @regex = regex
19
13
  end
20
14
 
21
- # @api
22
- # @private
23
- class NokogiriTextHelper
24
- NON_BREAKING_SPACE = "\u00a0"
15
+ def regexp node_set
16
+ node_set.find_all { |node| node.content =~ @regex }
17
+ end
18
+ end
25
19
 
26
- def initialize text
27
- @text = text
28
- end
20
+ # @api
21
+ # @private
22
+ class NokogiriTextHelper
23
+ NON_BREAKING_SPACE = "\u00a0"
29
24
 
30
- def content node_set
31
- node_set.find_all do |node|
32
- actual_content = node.content.gsub(NON_BREAKING_SPACE, ' ')
25
+ def initialize text
26
+ @text = text
27
+ end
33
28
 
34
- actual_content == @text
35
- end
29
+ def content node_set
30
+ node_set.find_all do |node|
31
+ actual_content = node.content.gsub(NON_BREAKING_SPACE, ' ')
32
+
33
+ actual_content == @text
36
34
  end
37
35
  end
36
+ end
38
37
 
39
- # @api
40
- # @private
41
- class HaveTag
42
- attr_reader :failure_message, :failure_message_when_negated
43
- attr_reader :parent_scope, :current_scope
38
+ # @api
39
+ # @private
40
+ class HaveTag
41
+ attr_reader :failure_message, :failure_message_when_negated
42
+ attr_reader :parent_scope, :current_scope
44
43
 
45
- DESCRIPTIONS = {
46
- :have_at_least_1 => %Q|have at least 1 element matching "%s"|,
47
- :have_n => %Q|have %i element(s) matching "%s"|
48
- }
44
+ DESCRIPTIONS = {
45
+ :have_at_least_1 => %Q|have at least 1 element matching "%s"|,
46
+ :have_n => %Q|have %i element(s) matching "%s"|
47
+ }
49
48
 
50
- MESSAGES = {
51
- :expected_tag => %Q|expected following:\n%s\nto #{DESCRIPTIONS[:have_at_least_1]}, found 0.|,
52
- :unexpected_tag => %Q|expected following:\n%s\nto NOT have element matching "%s", found %s.|,
49
+ MESSAGES = {
50
+ :expected_tag => %Q|expected following:\n%s\nto #{DESCRIPTIONS[:have_at_least_1]}, found 0.|,
51
+ :unexpected_tag => %Q|expected following:\n%s\nto NOT have element matching "%s", found %s.|,
53
52
 
54
- :expected_count => %Q|expected following:\n%s\nto #{DESCRIPTIONS[:have_n]}, found %s.|,
55
- :unexpected_count => %Q|expected following:\n%s\nto NOT have %i element(s) matching "%s", but found.|,
53
+ :expected_count => %Q|expected following:\n%s\nto #{DESCRIPTIONS[:have_n]}, found %s.|,
54
+ :unexpected_count => %Q|expected following:\n%s\nto NOT have %i element(s) matching "%s", but found.|,
56
55
 
57
- :expected_btw_count => %Q|expected following:\n%s\nto have at least %i and at most %i element(s) matching "%s", found %i.|,
58
- :unexpected_btw_count => %Q|expected following:\n%s\nto NOT have at least %i and at most %i element(s) matching "%s", but found %i.|,
56
+ :expected_btw_count => %Q|expected following:\n%s\nto have at least %i and at most %i element(s) matching "%s", found %i.|,
57
+ :unexpected_btw_count => %Q|expected following:\n%s\nto NOT have at least %i and at most %i element(s) matching "%s", but found %i.|,
59
58
 
60
- :expected_at_most => %Q|expected following:\n%s\nto have at most %i element(s) matching "%s", found %i.|,
61
- :unexpected_at_most => %Q|expected following:\n%s\nto NOT have at most %i element(s) matching "%s", but found %i.|,
59
+ :expected_at_most => %Q|expected following:\n%s\nto have at most %i element(s) matching "%s", found %i.|,
60
+ :unexpected_at_most => %Q|expected following:\n%s\nto NOT have at most %i element(s) matching "%s", but found %i.|,
62
61
 
63
- :expected_at_least => %Q|expected following:\n%s\nto have at least %i element(s) matching "%s", found %i.|,
64
- :unexpected_at_least => %Q|expected following:\n%s\nto NOT have at least %i element(s) matching "%s", but found %i.|,
62
+ :expected_at_least => %Q|expected following:\n%s\nto have at least %i element(s) matching "%s", found %i.|,
63
+ :unexpected_at_least => %Q|expected following:\n%s\nto NOT have at least %i element(s) matching "%s", but found %i.|,
65
64
 
66
- :expected_regexp => %Q|%s regexp expected within "%s" in following template:\n%s|,
67
- :unexpected_regexp => %Q|%s regexp unexpected within "%s" in following template:\n%s\nbut was found.|,
65
+ :expected_regexp => %Q|%s regexp expected within "%s" in following template:\n%s|,
66
+ :unexpected_regexp => %Q|%s regexp unexpected within "%s" in following template:\n%s\nbut was found.|,
68
67
 
69
- :expected_text => %Q|"%s" expected within "%s" in following template:\n%s|,
70
- :unexpected_text => %Q|"%s" unexpected within "%s" in following template:\n%s\nbut was found.|,
68
+ :expected_text => %Q|"%s" expected within "%s" in following template:\n%s|,
69
+ :unexpected_text => %Q|"%s" unexpected within "%s" in following template:\n%s\nbut was found.|,
71
70
 
72
- :wrong_count_error => %Q|:count with :minimum or :maximum has no sence!|,
73
- :min_max_error => %Q|:minimum should be less than :maximum!|,
74
- :bad_range_error => %Q|Your :count range(%s) has no sence!|,
75
- }
71
+ :wrong_count_error => %Q|:count with :minimum or :maximum has no sence!|,
72
+ :min_max_error => %Q|:minimum should be less than :maximum!|,
73
+ :bad_range_error => %Q|Your :count range(%s) has no sence!|,
74
+ }
76
75
 
77
76
 
78
- def initialize tag, options={}, &block
79
- @tag, @options, @block = tag.to_s, options, block
77
+ def initialize tag, options={}, &block
78
+ @tag, @options, @block = tag.to_s, options, block
80
79
 
81
- if with_attrs = @options.delete(:with)
82
- if classes = with_attrs.delete(:class)
83
- @tag << '.' + classes_to_selector(classes)
84
- end
85
- selector = with_attrs.inject('') do |html_attrs_string, (k, v)|
86
- html_attrs_string << "[#{k}='#{v}']"
87
- html_attrs_string
88
- end
89
- @tag << selector
80
+ if with_attrs = @options.delete(:with)
81
+ if classes = with_attrs.delete(:class)
82
+ @tag << '.' + classes_to_selector(classes)
90
83
  end
91
-
92
- if without_attrs = @options.delete(:without)
93
- if classes = without_attrs.delete(:class)
94
- @tag << ":not(.#{classes_to_selector(classes)})"
95
- end
84
+ selector = with_attrs.inject('') do |html_attrs_string, (k, v)|
85
+ html_attrs_string << "[#{k}='#{v}']"
86
+ html_attrs_string
96
87
  end
88
+ @tag << selector
89
+ end
97
90
 
98
- validate_options!
91
+ if without_attrs = @options.delete(:without)
92
+ if classes = without_attrs.delete(:class)
93
+ @tag << ":not(.#{classes_to_selector(classes)})"
94
+ end
99
95
  end
100
96
 
101
- def matches? document, &block
102
- @block = block if block
97
+ validate_options!
98
+ end
103
99
 
104
- document = document.html if defined?(Capybara::Session) && document.is_a?(Capybara::Session)
100
+ def matches? document, &block
101
+ @block = block if block
105
102
 
106
- case document
107
- when String
108
- @parent_scope = @current_scope = Nokogiri::HTML(document).css(@tag)
109
- @document = document
110
- else
111
- @parent_scope = document.current_scope
112
- @current_scope = begin
113
- document.parent_scope.css(@tag)
114
- # on jruby this produce exception if css was not found:
115
- # undefined method `decorate' for nil:NilClass
116
- rescue NoMethodError
117
- Nokogiri::XML::NodeSet.new(Nokogiri::XML::Document.new)
118
- end
119
- @document = @parent_scope.to_html
120
- end
103
+ document = document.html if defined?(Capybara::Session) && document.is_a?(Capybara::Session)
121
104
 
122
- if tag_presents? and text_right? and count_right?
123
- @current_scope = @parent_scope
124
- @block.call if @block
125
- true
126
- else
127
- false
128
- end
105
+ case document
106
+ when String
107
+ @parent_scope = @current_scope = Nokogiri::HTML(document).css(@tag)
108
+ @document = document
109
+ else
110
+ @parent_scope = document.current_scope
111
+ @current_scope = begin
112
+ document.parent_scope.css(@tag)
113
+ # on jruby this produce exception if css was not found:
114
+ # undefined method `decorate' for nil:NilClass
115
+ rescue NoMethodError
116
+ Nokogiri::XML::NodeSet.new(Nokogiri::XML::Document.new)
117
+ end
118
+ @document = @parent_scope.to_html
129
119
  end
130
120
 
131
- def description
132
- # TODO should it be more complicated?
133
- if @options.has_key?(:count)
134
- DESCRIPTIONS[:have_n] % [@options[:count],@tag]
135
- else
136
- DESCRIPTIONS[:have_at_least_1] % @tag
137
- end
121
+ if tag_presents? and text_right? and count_right?
122
+ @current_scope = @parent_scope
123
+ @block.call if @block
124
+ true
125
+ else
126
+ false
138
127
  end
128
+ end
139
129
 
140
- private
130
+ def description
131
+ # TODO should it be more complicated?
132
+ if @options.has_key?(:count)
133
+ DESCRIPTIONS[:have_n] % [@options[:count],@tag]
134
+ else
135
+ DESCRIPTIONS[:have_at_least_1] % @tag
136
+ end
137
+ end
141
138
 
142
- def classes_to_selector(classes)
143
- case classes
144
- when Array
145
- classes.join('.')
146
- when String
147
- classes.gsub(/\s+/, '.')
148
- end
139
+ private
140
+
141
+ def classes_to_selector(classes)
142
+ case classes
143
+ when Array
144
+ classes.join('.')
145
+ when String
146
+ classes.gsub(/\s+/, '.')
149
147
  end
148
+ end
150
149
 
151
- def tag_presents?
152
- if @current_scope.first
153
- @count = @current_scope.count
154
- @failure_message_when_negated = MESSAGES[:unexpected_tag] % [@document, @tag, @count]
155
- true
156
- else
157
- @failure_message = MESSAGES[:expected_tag] % [@document, @tag]
158
- false
159
- end
150
+ def tag_presents?
151
+ if @current_scope.first
152
+ @count = @current_scope.count
153
+ @failure_message_when_negated = MESSAGES[:unexpected_tag] % [@document, @tag, @count]
154
+ true
155
+ else
156
+ @failure_message = MESSAGES[:expected_tag] % [@document, @tag]
157
+ false
160
158
  end
159
+ end
161
160
 
162
- def count_right?
163
- case @options[:count]
164
- when Integer
165
- ((@failure_message_when_negated=MESSAGES[:unexpected_count] % [@document,@count,@tag]) && @count == @options[:count]) || (@failure_message=MESSAGES[:expected_count] % [@document,@options[:count],@tag,@count]; false)
166
- when Range
167
- ((@failure_message_when_negated=MESSAGES[:unexpected_btw_count] % [@document,@options[:count].min,@options[:count].max,@tag,@count]) && @options[:count].member?(@count)) || (@failure_message=MESSAGES[:expected_btw_count] % [@document,@options[:count].min,@options[:count].max,@tag,@count]; false)
168
- when nil
169
- if @options[:maximum]
170
- ((@failure_message_when_negated=MESSAGES[:unexpected_at_most] % [@document,@options[:maximum],@tag,@count]) && @count <= @options[:maximum]) || (@failure_message=MESSAGES[:expected_at_most] % [@document,@options[:maximum],@tag,@count]; false)
171
- elsif @options[:minimum]
172
- ((@failure_message_when_negated=MESSAGES[:unexpected_at_least] % [@document,@options[:minimum],@tag,@count]) && @count >= @options[:minimum]) || (@failure_message=MESSAGES[:expected_at_least] % [@document,@options[:minimum],@tag,@count]; false)
173
- else
174
- true
175
- end
161
+ def count_right?
162
+ case @options[:count]
163
+ when Integer
164
+ ((@failure_message_when_negated=MESSAGES[:unexpected_count] % [@document,@count,@tag]) && @count == @options[:count]) || (@failure_message=MESSAGES[:expected_count] % [@document,@options[:count],@tag,@count]; false)
165
+ when Range
166
+ ((@failure_message_when_negated=MESSAGES[:unexpected_btw_count] % [@document,@options[:count].min,@options[:count].max,@tag,@count]) && @options[:count].member?(@count)) || (@failure_message=MESSAGES[:expected_btw_count] % [@document,@options[:count].min,@options[:count].max,@tag,@count]; false)
167
+ when nil
168
+ if @options[:maximum]
169
+ ((@failure_message_when_negated=MESSAGES[:unexpected_at_most] % [@document,@options[:maximum],@tag,@count]) && @count <= @options[:maximum]) || (@failure_message=MESSAGES[:expected_at_most] % [@document,@options[:maximum],@tag,@count]; false)
170
+ elsif @options[:minimum]
171
+ ((@failure_message_when_negated=MESSAGES[:unexpected_at_least] % [@document,@options[:minimum],@tag,@count]) && @count >= @options[:minimum]) || (@failure_message=MESSAGES[:expected_at_least] % [@document,@options[:minimum],@tag,@count]; false)
172
+ else
173
+ true
176
174
  end
177
175
  end
176
+ end
177
+
178
+ def text_right?
179
+ return true unless @options[:text]
178
180
 
179
- def text_right?
180
- return true unless @options[:text]
181
-
182
- case text=@options[:text]
183
- when Regexp
184
- new_scope = @current_scope.css(':regexp()',NokogiriRegexpHelper.new(text))
185
- unless new_scope.empty?
186
- @count = new_scope.count
187
- @failure_message_when_negated = MESSAGES[:unexpected_regexp] % [text.inspect,@tag,@document]
188
- true
189
- else
190
- @failure_message = MESSAGES[:expected_regexp] % [text.inspect,@tag,@document]
191
- false
192
- end
181
+ case text=@options[:text]
182
+ when Regexp
183
+ new_scope = @current_scope.css(':regexp()',NokogiriRegexpHelper.new(text))
184
+ unless new_scope.empty?
185
+ @count = new_scope.count
186
+ @failure_message_when_negated = MESSAGES[:unexpected_regexp] % [text.inspect,@tag,@document]
187
+ true
193
188
  else
194
- new_scope = @current_scope.css(':content()',NokogiriTextHelper.new(text))
195
- unless new_scope.empty?
196
- @count = new_scope.count
197
- @failure_message_when_negated = MESSAGES[:unexpected_text] % [text,@tag,@document]
198
- true
199
- else
200
- @failure_message = MESSAGES[:expected_text] % [text,@tag,@document]
201
- false
202
- end
189
+ @failure_message = MESSAGES[:expected_regexp] % [text.inspect,@tag,@document]
190
+ false
191
+ end
192
+ else
193
+ new_scope = @current_scope.css(':content()',NokogiriTextHelper.new(text))
194
+ unless new_scope.empty?
195
+ @count = new_scope.count
196
+ @failure_message_when_negated = MESSAGES[:unexpected_text] % [text,@tag,@document]
197
+ true
198
+ else
199
+ @failure_message = MESSAGES[:expected_text] % [text,@tag,@document]
200
+ false
203
201
  end
204
202
  end
203
+ end
205
204
 
206
- protected
205
+ protected
207
206
 
208
- def validate_options!
209
- raise 'wrong :count specified' unless [Range, NilClass].include?(@options[:count].class) or @options[:count].is_a?(Integer)
207
+ def validate_options!
208
+ raise 'wrong :count specified' unless [Range, NilClass].include?(@options[:count].class) or @options[:count].is_a?(Integer)
210
209
 
211
- [:min, :minimum, :max, :maximum].each do |key|
212
- raise MESSAGES[:wrong_count_error] if @options.has_key?(key) and @options.has_key?(:count)
213
- end
210
+ [:min, :minimum, :max, :maximum].each do |key|
211
+ raise MESSAGES[:wrong_count_error] if @options.has_key?(key) and @options.has_key?(:count)
212
+ end
214
213
 
215
- begin
216
- raise MESSAGES[:min_max_error] if @options[:minimum] > @options[:maximum]
217
- rescue NoMethodError # nil > 4
218
- rescue ArgumentError # 2 < nil
219
- end
214
+ begin
215
+ raise MESSAGES[:min_max_error] if @options[:minimum] > @options[:maximum]
216
+ rescue NoMethodError # nil > 4
217
+ rescue ArgumentError # 2 < nil
218
+ end
220
219
 
220
+ begin
221
221
  begin
222
- begin
223
- raise MESSAGES[:bad_range_error] % [@options[:count].to_s] if @options[:count] && @options[:count].is_a?(Range) && (@options[:count].min.nil? or @options[:count].min < 0)
224
- rescue ArgumentError, "comparison of String with" # if @options[:count] == 'a'..'z'
225
- raise MESSAGES[:bad_range_error] % [@options[:count].to_s]
226
- end
227
- rescue TypeError # fix for 1.8.7 for 'rescue ArgumentError, "comparison of String with"' stroke
222
+ raise MESSAGES[:bad_range_error] % [@options[:count].to_s] if @options[:count] && @options[:count].is_a?(Range) && (@options[:count].min.nil? or @options[:count].min < 0)
223
+ rescue ArgumentError, "comparison of String with" # if @options[:count] == 'a'..'z'
228
224
  raise MESSAGES[:bad_range_error] % [@options[:count].to_s]
229
225
  end
230
-
231
- @options[:minimum] ||= @options.delete(:min)
232
- @options[:maximum] ||= @options.delete(:max)
233
-
234
- @options[:text] = @options[:text].to_s if @options.has_key?(:text) && !@options[:text].is_a?(Regexp)
226
+ rescue TypeError # fix for 1.8.7 for 'rescue ArgumentError, "comparison of String with"' stroke
227
+ raise MESSAGES[:bad_range_error] % [@options[:count].to_s]
235
228
  end
236
229
 
237
- end
230
+ @options[:minimum] ||= @options.delete(:min)
231
+ @options[:maximum] ||= @options.delete(:max)
238
232
 
239
- # tag assertion, this is the core of functionality, other matchers are shortcuts to this matcher
240
- #
241
- # @yield block where you should put with_tag, without_tag and/or other matchers
242
- #
243
- # @param [String] tag css selector for tag you want to match, e.g. 'div', 'section#my', 'article.red'
244
- # @param [Hash] options options hash(see below)
245
- # @option options [Hash] :with hash with html attributes, within this, *:class* option have special meaning, you may specify it as array of expected classes or string of classes separated by spaces, order does not matter
246
- # @option options [Fixnum] :count for tag count matching(*ATTENTION:* do not use :count with :minimum(:min) or :maximum(:max))
247
- # @option options [Range] :count not strict tag count matching, count of tags should be in specified range
248
- # @option options [Fixnum] :minimum minimum count of elements to match
249
- # @option options [Fixnum] :min same as :minimum
250
- # @option options [Fixnum] :maximum maximum count of elements to match
251
- # @option options [Fixnum] :max same as :maximum
252
- # @option options [String/Regexp] :text to match tag content, could be either String or Regexp
253
- #
254
- # @example
255
- # expect(rendered).to have_tag('div')
256
- # expect(rendered).to have_tag('h1.header')
257
- # expect(rendered).to have_tag('div#footer')
258
- # expect(rendered).to have_tag('input#email', :with => { :name => 'user[email]', :type => 'email' } )
259
- # expect(rendered).to have_tag('div', :count => 3) # matches exactly 3 'div' tags
260
- # expect(rendered).to have_tag('div', :count => 3..7) # shortcut for have_tag('div', :minimum => 3, :maximum => 7)
261
- # expect(rendered).to have_tag('div', :minimum => 3) # matches more(or equal) than 3 'div' tags
262
- # expect(rendered).to have_tag('div', :maximum => 3) # matches less(or equal) than 3 'div' tags
263
- # expect(rendered).to have_tag('p', :text => 'some content') # will match "<p>some content</p>"
264
- # expect(rendered).to have_tag('p', :text => /some content/i) # will match "<p>sOme cOntEnt</p>"
265
- # expect(rendered).to have_tag('textarea', :with => {:name => 'user[description]'}, :text => "I like pie")
266
- # expect("<html>
267
- # <body>
268
- # <h1>some html document</h1>
269
- # </body>
270
- # </html>").to have_tag('body') { with_tag('h1', :text => 'some html document') }
271
- # expect('<div class="one two">').to have_tag('div', :with => { :class => ['two', 'one'] })
272
- # expect('<div class="one two">').to have_tag('div', :with => { :class => 'two one' })
273
- def have_tag tag, options={}, &block
274
- # for backwards compatibility with rpecs have tag:
275
- options = { :text => options } if options.kind_of?(String) || options.kind_of?(Regexp)
276
- @__current_scope_for_nokogiri_matcher = HaveTag.new(tag, options, &block)
233
+ @options[:text] = @options[:text].to_s if @options.has_key?(:text) && !@options[:text].is_a?(Regexp)
277
234
  end
278
235
 
279
- def with_text text
280
- raise StandardError, 'this matcher should be used inside "have_tag" matcher block' unless defined?(@__current_scope_for_nokogiri_matcher)
281
- raise ArgumentError, 'this matcher does not accept block' if block_given?
282
- tag = @__current_scope_for_nokogiri_matcher.instance_variable_get(:@tag)
283
- expect(@__current_scope_for_nokogiri_matcher).to have_tag(tag, :text => text)
284
- end
236
+ end
285
237
 
286
- def without_text text
287
- raise StandardError, 'this matcher should be used inside "have_tag" matcher block' unless defined?(@__current_scope_for_nokogiri_matcher)
288
- raise ArgumentError, 'this matcher does not accept block' if block_given?
289
- tag = @__current_scope_for_nokogiri_matcher.instance_variable_get(:@tag)
290
- expect(@__current_scope_for_nokogiri_matcher).to_not have_tag(tag, :text => text)
291
- end
292
- alias :but_without_text :without_text
293
-
294
- # with_tag matcher
295
- # @yield block where you should put other with_tag or without_tag
296
- # @see #have_tag
297
- # @note this should be used within block of have_tag matcher
298
- def with_tag tag, options={}, &block
299
- expect(@__current_scope_for_nokogiri_matcher).to have_tag(tag, options, &block)
300
- end
238
+ # tag assertion, this is the core of functionality, other matchers are shortcuts to this matcher
239
+ #
240
+ # @yield block where you should put with_tag, without_tag and/or other matchers
241
+ #
242
+ # @param [String] tag css selector for tag you want to match, e.g. 'div', 'section#my', 'article.red'
243
+ # @param [Hash] options options hash(see below)
244
+ # @option options [Hash] :with hash with html attributes, within this, *:class* option have special meaning, you may specify it as array of expected classes or string of classes separated by spaces, order does not matter
245
+ # @option options [Fixnum] :count for tag count matching(*ATTENTION:* do not use :count with :minimum(:min) or :maximum(:max))
246
+ # @option options [Range] :count not strict tag count matching, count of tags should be in specified range
247
+ # @option options [Fixnum] :minimum minimum count of elements to match
248
+ # @option options [Fixnum] :min same as :minimum
249
+ # @option options [Fixnum] :maximum maximum count of elements to match
250
+ # @option options [Fixnum] :max same as :maximum
251
+ # @option options [String/Regexp] :text to match tag content, could be either String or Regexp
252
+ #
253
+ # @example
254
+ # expect(rendered).to have_tag('div')
255
+ # expect(rendered).to have_tag('h1.header')
256
+ # expect(rendered).to have_tag('div#footer')
257
+ # expect(rendered).to have_tag('input#email', :with => { :name => 'user[email]', :type => 'email' } )
258
+ # expect(rendered).to have_tag('div', :count => 3) # matches exactly 3 'div' tags
259
+ # expect(rendered).to have_tag('div', :count => 3..7) # shortcut for have_tag('div', :minimum => 3, :maximum => 7)
260
+ # expect(rendered).to have_tag('div', :minimum => 3) # matches more(or equal) than 3 'div' tags
261
+ # expect(rendered).to have_tag('div', :maximum => 3) # matches less(or equal) than 3 'div' tags
262
+ # expect(rendered).to have_tag('p', :text => 'some content') # will match "<p>some content</p>"
263
+ # expect(rendered).to have_tag('p', :text => /some content/i) # will match "<p>sOme cOntEnt</p>"
264
+ # expect(rendered).to have_tag('textarea', :with => {:name => 'user[description]'}, :text => "I like pie")
265
+ # expect("<html>
266
+ # <body>
267
+ # <h1>some html document</h1>
268
+ # </body>
269
+ # </html>").to have_tag('body') { with_tag('h1', :text => 'some html document') }
270
+ # expect('<div class="one two">').to have_tag('div', :with => { :class => ['two', 'one'] })
271
+ # expect('<div class="one two">').to have_tag('div', :with => { :class => 'two one' })
272
+ def have_tag tag, options={}, &block
273
+ # for backwards compatibility with rpecs have tag:
274
+ options = { :text => options } if options.kind_of?(String) || options.kind_of?(Regexp)
275
+ @__current_scope_for_nokogiri_matcher = HaveTag.new(tag, options, &block)
276
+ end
301
277
 
302
- # without_tag matcher
303
- # @yield block where you should put other with_tag or without_tag
304
- # @see #have_tag
305
- # @note this should be used within block of have_tag matcher
306
- def without_tag tag, options={}, &block
307
- expect(@__current_scope_for_nokogiri_matcher).to_not have_tag(tag, options, &block)
308
- end
278
+ def with_text text
279
+ raise StandardError, 'this matcher should be used inside "have_tag" matcher block' unless defined?(@__current_scope_for_nokogiri_matcher)
280
+ raise ArgumentError, 'this matcher does not accept block' if block_given?
281
+ tag = @__current_scope_for_nokogiri_matcher.instance_variable_get(:@tag)
282
+ expect(@__current_scope_for_nokogiri_matcher).to have_tag(tag, :text => text)
283
+ end
309
284
 
310
- # form assertion
311
- #
312
- # it is a shortcut to
313
- # have_tag 'form', :with => { :action => action_url, :method => method ... }
314
- # @yield block with with_<field>, see below
315
- # @see #have_tag
316
- def have_form action_url, method, options={}, &block
317
- options[:with] ||= {}
318
- id = options[:with].delete(:id)
319
- tag = 'form'; tag << '#'+id if id
320
- options[:with].merge!(:action => action_url)
321
- options[:with].merge!(:method => method.to_s)
322
- have_tag tag, options, &block
323
- end
285
+ def without_text text
286
+ raise StandardError, 'this matcher should be used inside "have_tag" matcher block' unless defined?(@__current_scope_for_nokogiri_matcher)
287
+ raise ArgumentError, 'this matcher does not accept block' if block_given?
288
+ tag = @__current_scope_for_nokogiri_matcher.instance_variable_get(:@tag)
289
+ expect(@__current_scope_for_nokogiri_matcher).to_not have_tag(tag, :text => text)
290
+ end
291
+ alias :but_without_text :without_text
292
+
293
+ # with_tag matcher
294
+ # @yield block where you should put other with_tag or without_tag
295
+ # @see #have_tag
296
+ # @note this should be used within block of have_tag matcher
297
+ def with_tag tag, options={}, &block
298
+ expect(@__current_scope_for_nokogiri_matcher).to have_tag(tag, options, &block)
299
+ end
324
300
 
325
- #TODO fix code duplications
301
+ # without_tag matcher
302
+ # @yield block where you should put other with_tag or without_tag
303
+ # @see #have_tag
304
+ # @note this should be used within block of have_tag matcher
305
+ def without_tag tag, options={}, &block
306
+ expect(@__current_scope_for_nokogiri_matcher).to_not have_tag(tag, options, &block)
307
+ end
326
308
 
327
- def with_hidden_field name, value=nil
328
- options = form_tag_options('hidden',name,value)
329
- should_have_input(options)
330
- end
309
+ # form assertion
310
+ #
311
+ # it is a shortcut to
312
+ # have_tag 'form', :with => { :action => action_url, :method => method ... }
313
+ # @yield block with with_<field>, see below
314
+ # @see #have_tag
315
+ def have_form action_url, method, options={}, &block
316
+ options[:with] ||= {}
317
+ id = options[:with].delete(:id)
318
+ tag = 'form'; tag << '#'+id if id
319
+ options[:with].merge!(:action => action_url)
320
+ options[:with].merge!(:method => method.to_s)
321
+ have_tag tag, options, &block
322
+ end
331
323
 
332
- def without_hidden_field name, value=nil
333
- options = form_tag_options('hidden',name,value)
334
- should_not_have_input(options)
335
- end
324
+ #TODO fix code duplications
336
325
 
337
- def with_text_field name, value=nil
338
- options = form_tag_options('text',name,value)
339
- should_have_input(options)
340
- end
326
+ def with_hidden_field name, value=nil
327
+ options = form_tag_options('hidden',name,value)
328
+ should_have_input(options)
329
+ end
341
330
 
342
- def without_text_field name, value=nil
343
- options = form_tag_options('text',name,value)
344
- should_not_have_input(options)
345
- end
331
+ def without_hidden_field name, value=nil
332
+ options = form_tag_options('hidden',name,value)
333
+ should_not_have_input(options)
334
+ end
346
335
 
347
- def with_email_field name, value=nil
348
- options = form_tag_options('email',name,value)
349
- should_have_input(options)
350
- end
336
+ def with_text_field name, value=nil
337
+ options = form_tag_options('text',name,value)
338
+ should_have_input(options)
339
+ end
351
340
 
352
- def without_email_field name, value=nil
353
- options = form_tag_options('email',name,value)
354
- should_not_have_input(options)
355
- end
341
+ def without_text_field name, value=nil
342
+ options = form_tag_options('text',name,value)
343
+ should_not_have_input(options)
344
+ end
356
345
 
357
- def with_url_field name, value=nil
358
- options = form_tag_options('url',name,value)
359
- should_have_input(options)
360
- end
346
+ def with_email_field name, value=nil
347
+ options = form_tag_options('email',name,value)
348
+ should_have_input(options)
349
+ end
361
350
 
362
- def without_url_field name, value=nil
363
- options = form_tag_options('url',name,value)
364
- should_not_have_input(options)
365
- end
351
+ def without_email_field name, value=nil
352
+ options = form_tag_options('email',name,value)
353
+ should_not_have_input(options)
354
+ end
366
355
 
367
- def with_number_field name, value=nil
368
- options = form_tag_options('number',name,value)
369
- should_have_input(options)
370
- end
356
+ def with_url_field name, value=nil
357
+ options = form_tag_options('url',name,value)
358
+ should_have_input(options)
359
+ end
371
360
 
372
- def without_number_field name, value=nil
373
- options = form_tag_options('number',name,value)
374
- should_not_have_input(options)
375
- end
361
+ def without_url_field name, value=nil
362
+ options = form_tag_options('url',name,value)
363
+ should_not_have_input(options)
364
+ end
376
365
 
377
- def with_range_field name, min, max, options={}
378
- options = { :with => { :name => name, :type => 'range', :min => min.to_s, :max => max.to_s }.merge(options.delete(:with)||{}) }
379
- should_have_input(options)
380
- end
366
+ def with_number_field name, value=nil
367
+ options = form_tag_options('number',name,value)
368
+ should_have_input(options)
369
+ end
381
370
 
382
- def without_range_field name, min=nil, max=nil, options={}
383
- options = { :with => { :name => name, :type => 'range' }.merge(options.delete(:with)||{}) }
384
- options[:with].merge!(:min => min.to_s) if min
385
- options[:with].merge!(:max => max.to_s) if max
386
- should_not_have_input(options)
387
- end
371
+ def without_number_field name, value=nil
372
+ options = form_tag_options('number',name,value)
373
+ should_not_have_input(options)
374
+ end
388
375
 
389
- DATE_FIELD_TYPES = %w( date month week time datetime datetime-local )
376
+ def with_range_field name, min, max, options={}
377
+ options = { :with => { :name => name, :type => 'range', :min => min.to_s, :max => max.to_s }.merge(options.delete(:with)||{}) }
378
+ should_have_input(options)
379
+ end
390
380
 
391
- def with_date_field date_field_type, name=nil, options={}
392
- date_field_type = date_field_type.to_s
393
- raise "unknown type `#{date_field_type}` for date picker" unless DATE_FIELD_TYPES.include?(date_field_type)
394
- options = { :with => { :type => date_field_type.to_s }.merge(options.delete(:with)||{}) }
395
- options[:with].merge!(:name => name.to_s) if name
396
- should_have_input(options)
397
- end
381
+ def without_range_field name, min=nil, max=nil, options={}
382
+ options = { :with => { :name => name, :type => 'range' }.merge(options.delete(:with)||{}) }
383
+ options[:with].merge!(:min => min.to_s) if min
384
+ options[:with].merge!(:max => max.to_s) if max
385
+ should_not_have_input(options)
386
+ end
398
387
 
399
- def without_date_field date_field_type, name=nil, options={}
400
- date_field_type = date_field_type.to_s
401
- raise "unknown type `#{date_field_type}` for date picker" unless DATE_FIELD_TYPES.include?(date_field_type)
402
- options = { :with => { :type => date_field_type.to_s }.merge(options.delete(:with)||{}) }
403
- options[:with].merge!(:name => name.to_s) if name
404
- should_not_have_input(options)
405
- end
388
+ DATE_FIELD_TYPES = %w( date month week time datetime datetime-local )
406
389
 
407
- # TODO add ability to explicitly say that value should be empty
408
- def with_password_field name, value=nil
409
- options = form_tag_options('password',name,value)
410
- should_have_input(options)
411
- end
390
+ def with_date_field date_field_type, name=nil, options={}
391
+ date_field_type = date_field_type.to_s
392
+ raise "unknown type `#{date_field_type}` for date picker" unless DATE_FIELD_TYPES.include?(date_field_type)
393
+ options = { :with => { :type => date_field_type.to_s }.merge(options.delete(:with)||{}) }
394
+ options[:with].merge!(:name => name.to_s) if name
395
+ should_have_input(options)
396
+ end
412
397
 
413
- def without_password_field name, value=nil
414
- options = form_tag_options('password',name,value)
415
- should_not_have_input(options)
416
- end
398
+ def without_date_field date_field_type, name=nil, options={}
399
+ date_field_type = date_field_type.to_s
400
+ raise "unknown type `#{date_field_type}` for date picker" unless DATE_FIELD_TYPES.include?(date_field_type)
401
+ options = { :with => { :type => date_field_type.to_s }.merge(options.delete(:with)||{}) }
402
+ options[:with].merge!(:name => name.to_s) if name
403
+ should_not_have_input(options)
404
+ end
417
405
 
418
- def with_file_field name, value=nil
419
- options = form_tag_options('file',name,value)
420
- should_have_input(options)
421
- end
406
+ # TODO add ability to explicitly say that value should be empty
407
+ def with_password_field name, value=nil
408
+ options = form_tag_options('password',name,value)
409
+ should_have_input(options)
410
+ end
422
411
 
423
- def without_file_field name, value=nil
424
- options = form_tag_options('file',name,value)
425
- should_not_have_input(options)
426
- end
412
+ def without_password_field name, value=nil
413
+ options = form_tag_options('password',name,value)
414
+ should_not_have_input(options)
415
+ end
427
416
 
428
- def with_text_area name#TODO, text=nil
429
- #options = form_tag_options('text',name,value)
430
- options = { :with => { :name => name } }
431
- expect(@__current_scope_for_nokogiri_matcher).to have_tag('textarea', options)
432
- end
417
+ def with_file_field name, value=nil
418
+ options = form_tag_options('file',name,value)
419
+ should_have_input(options)
420
+ end
433
421
 
434
- def without_text_area name#TODO, text=nil
435
- #options = form_tag_options('text',name,value)
436
- options = { :with => { :name => name } }
437
- expect(@__current_scope_for_nokogiri_matcher).to_not have_tag('textarea', options)
438
- end
422
+ def without_file_field name, value=nil
423
+ options = form_tag_options('file',name,value)
424
+ should_not_have_input(options)
425
+ end
439
426
 
440
- def with_checkbox name, value=nil
441
- options = form_tag_options('checkbox',name,value)
442
- should_have_input(options)
443
- end
427
+ def with_text_area name#TODO, text=nil
428
+ #options = form_tag_options('text',name,value)
429
+ options = { :with => { :name => name } }
430
+ expect(@__current_scope_for_nokogiri_matcher).to have_tag('textarea', options)
431
+ end
444
432
 
445
- def without_checkbox name, value=nil
446
- options = form_tag_options('checkbox',name,value)
447
- should_not_have_input(options)
448
- end
433
+ def without_text_area name#TODO, text=nil
434
+ #options = form_tag_options('text',name,value)
435
+ options = { :with => { :name => name } }
436
+ expect(@__current_scope_for_nokogiri_matcher).to_not have_tag('textarea', options)
437
+ end
449
438
 
450
- def with_radio_button name, value
451
- options = form_tag_options('radio',name,value)
452
- should_have_input(options)
453
- end
439
+ def with_checkbox name, value=nil
440
+ options = form_tag_options('checkbox',name,value)
441
+ should_have_input(options)
442
+ end
454
443
 
455
- def without_radio_button name, value
456
- options = form_tag_options('radio',name,value)
457
- should_not_have_input(options)
458
- end
444
+ def without_checkbox name, value=nil
445
+ options = form_tag_options('checkbox',name,value)
446
+ should_not_have_input(options)
447
+ end
459
448
 
460
- def with_select name, options={}, &block
461
- options[:with] ||= {}
462
- id = options[:with].delete(:id)
463
- tag='select'; tag << '#'+id if id
464
- options[:with].merge!(:name => name)
465
- expect(@__current_scope_for_nokogiri_matcher).to have_tag(tag, options, &block)
466
- end
449
+ def with_radio_button name, value
450
+ options = form_tag_options('radio',name,value)
451
+ should_have_input(options)
452
+ end
467
453
 
468
- def without_select name, options={}, &block
469
- options[:with] ||= {}
470
- id = options[:with].delete(:id)
471
- tag='select'; tag << '#'+id if id
472
- options[:with].merge!(:name => name)
473
- expect(@__current_scope_for_nokogiri_matcher).to_not have_tag(tag, options, &block)
474
- end
454
+ def without_radio_button name, value
455
+ options = form_tag_options('radio',name,value)
456
+ should_not_have_input(options)
457
+ end
475
458
 
476
- def with_option text, value=nil, options={}
477
- options[:with] ||= {}
478
- if value.is_a?(Hash)
479
- options.merge!(value)
480
- value=nil
481
- end
482
- tag='option'
483
- options[:with].merge!(:value => value.to_s) if value
484
- if options[:selected]
485
- options[:with].merge!(:selected => "selected")
486
- end
487
- options.delete(:selected)
488
- options.merge!(:text => text) if text
489
- expect(@__current_scope_for_nokogiri_matcher).to have_tag(tag, options)
490
- end
459
+ def with_select name, options={}, &block
460
+ options[:with] ||= {}
461
+ id = options[:with].delete(:id)
462
+ tag='select'; tag << '#'+id if id
463
+ options[:with].merge!(:name => name)
464
+ expect(@__current_scope_for_nokogiri_matcher).to have_tag(tag, options, &block)
465
+ end
491
466
 
492
- def without_option text, value=nil, options={}
493
- options[:with] ||= {}
494
- if value.is_a?(Hash)
495
- options.merge!(value)
496
- value=nil
497
- end
498
- tag='option'
499
- options[:with].merge!(:value => value.to_s) if value
500
- if options[:selected]
501
- options[:with].merge!(:selected => "selected")
502
- end
503
- options.delete(:selected)
504
- options.merge!(:text => text) if text
505
- expect(@__current_scope_for_nokogiri_matcher).to_not have_tag(tag, options)
506
- end
467
+ def without_select name, options={}, &block
468
+ options[:with] ||= {}
469
+ id = options[:with].delete(:id)
470
+ tag='select'; tag << '#'+id if id
471
+ options[:with].merge!(:name => name)
472
+ expect(@__current_scope_for_nokogiri_matcher).to_not have_tag(tag, options, &block)
473
+ end
507
474
 
508
- def with_button text, value=nil, options={}
509
- options[:with] ||= {}
510
- if value.is_a?(Hash)
511
- options.merge!(value)
512
- value=nil
513
- end
514
- options[:with].merge!(:value => value.to_s) if value
515
- options.merge!(:text => text) if text
516
- expect(@__current_scope_for_nokogiri_matcher).to have_tag('button', options)
475
+ def with_option text, value=nil, options={}
476
+ options[:with] ||= {}
477
+ if value.is_a?(Hash)
478
+ options.merge!(value)
479
+ value=nil
480
+ end
481
+ tag='option'
482
+ options[:with].merge!(:value => value.to_s) if value
483
+ if options[:selected]
484
+ options[:with].merge!(:selected => "selected")
517
485
  end
486
+ options.delete(:selected)
487
+ options.merge!(:text => text) if text
488
+ expect(@__current_scope_for_nokogiri_matcher).to have_tag(tag, options)
489
+ end
518
490
 
519
- def without_button text, value=nil, options={}
520
- options[:with] ||= {}
521
- if value.is_a?(Hash)
522
- options.merge!(value)
523
- value=nil
524
- end
525
- options[:with].merge!(:value => value.to_s) if value
526
- options.merge!(:text => text) if text
527
- expect(@__current_scope_for_nokogiri_matcher).to_not have_tag('button', options)
491
+ def without_option text, value=nil, options={}
492
+ options[:with] ||= {}
493
+ if value.is_a?(Hash)
494
+ options.merge!(value)
495
+ value=nil
496
+ end
497
+ tag='option'
498
+ options[:with].merge!(:value => value.to_s) if value
499
+ if options[:selected]
500
+ options[:with].merge!(:selected => "selected")
528
501
  end
502
+ options.delete(:selected)
503
+ options.merge!(:text => text) if text
504
+ expect(@__current_scope_for_nokogiri_matcher).to_not have_tag(tag, options)
505
+ end
529
506
 
530
- def with_submit value
531
- options = { :with => { :type => 'submit', :value => value } }
532
- #options = form_tag_options('text',name,value)
533
- should_have_input(options)
507
+ def with_button text, value=nil, options={}
508
+ options[:with] ||= {}
509
+ if value.is_a?(Hash)
510
+ options.merge!(value)
511
+ value=nil
534
512
  end
513
+ options[:with].merge!(:value => value.to_s) if value
514
+ options.merge!(:text => text) if text
515
+ expect(@__current_scope_for_nokogiri_matcher).to have_tag('button', options)
516
+ end
535
517
 
536
- def without_submit value
537
- #options = form_tag_options('text',name,value)
538
- options = { :with => { :type => 'submit', :value => value } }
539
- should_not_have_input(options)
518
+ def without_button text, value=nil, options={}
519
+ options[:with] ||= {}
520
+ if value.is_a?(Hash)
521
+ options.merge!(value)
522
+ value=nil
540
523
  end
524
+ options[:with].merge!(:value => value.to_s) if value
525
+ options.merge!(:text => text) if text
526
+ expect(@__current_scope_for_nokogiri_matcher).to_not have_tag('button', options)
527
+ end
541
528
 
542
- private
529
+ def with_submit value
530
+ options = { :with => { :type => 'submit', :value => value } }
531
+ #options = form_tag_options('text',name,value)
532
+ should_have_input(options)
533
+ end
543
534
 
544
- def should_have_input(options)
545
- expect(@__current_scope_for_nokogiri_matcher).to have_tag('input', options)
546
- end
535
+ def without_submit value
536
+ #options = form_tag_options('text',name,value)
537
+ options = { :with => { :type => 'submit', :value => value } }
538
+ should_not_have_input(options)
539
+ end
547
540
 
548
- def should_not_have_input(options)
549
- expect(@__current_scope_for_nokogiri_matcher).to_not have_tag('input', options)
550
- end
541
+ private
551
542
 
552
- # form_tag in method name name mean smth. like input, submit, tags that should appear in a form
553
- def form_tag_options form_tag_type, form_tag_name, form_tag_value=nil
554
- options = { :with => { :name => form_tag_name, :type => form_tag_type } }
555
- # .to_s if value is a digit or smth. else, see issue#10
556
- options[:with].merge!(:value => form_tag_value.to_s) if form_tag_value
557
- return options
558
- end
543
+ def should_have_input(options)
544
+ expect(@__current_scope_for_nokogiri_matcher).to have_tag('input', options)
545
+ end
559
546
 
547
+ def should_not_have_input(options)
548
+ expect(@__current_scope_for_nokogiri_matcher).to_not have_tag('input', options)
560
549
  end
561
- end
562
550
 
563
- if defined? Cucumber
564
- World RSpec::HtmlMatchers
565
- else
566
- RSpec.configure do |config|
567
- config.include(RSpec::HtmlMatchers)
551
+ # form_tag in method name name mean smth. like input, submit, tags that should appear in a form
552
+ def form_tag_options form_tag_type, form_tag_name, form_tag_value=nil
553
+ options = { :with => { :name => form_tag_name, :type => form_tag_type } }
554
+ # .to_s if value is a digit or smth. else, see issue#10
555
+ options[:with].merge!(:value => form_tag_value.to_s) if form_tag_value
556
+ return options
568
557
  end
558
+
569
559
  end