Module: RSpecHtmlMatchers

Defined in:
lib/rspec-html-matchers.rb,
lib/rspec-html-matchers/version.rb,
lib/rspec-html-matchers/have_tag.rb,
lib/rspec-html-matchers/nokogiri_text_helper.rb,
lib/rspec-html-matchers/nokogiri_regexp_helper.rb

Overview

RSpec global configuration:

RSpec.configure do |config|
  config.include RSpecHtmlMatchers
end

RSpec per-test configuration

RSpec.describe "my view spec" do
  include RSpecHtmlMatchers

  it "has tags" do
    expect(rendered).to have_tag('div')
  end
end

Cucumber configuration:

World RSpecHtmlMatchers

Constant Summary collapse

DATE_FIELD_TYPES =
%w[date month week time datetime datetime-local].freeze
VERSION =
'0.9.2'

Instance Method Summary collapse

Instance Method Details

#have_empty_tag(tag, options = {}) ⇒ Object

tests whether tag have any content inside

Examples:

expect('<div></div>').to have_empty_tag('div') # success
expect('<div>hi</div>').to have_empty_tag('div') # fail

73
74
75
# File 'lib/rspec-html-matchers.rb', line 73

def have_empty_tag tag, options = {}
  have_tag(tag, options.merge(:blank => true))
end

#have_form(action_url, method, options = {}) { ... } ⇒ Object

form assertion

it is a shortcut to

have_tag 'form', :with => { :action => action_url, :method => method ... }

Yields:

  • block with with_<field>, see below

See Also:


124
125
126
127
128
129
130
131
# File 'lib/rspec-html-matchers.rb', line 124

def have_form action_url, method, options = {}, &block
  options[:with] ||= {}
  id = options[:with].delete(:id)
  tag = 'form'; tag += '#' + id if id
  options[:with].merge!(:action => action_url)
  options[:with].merge!(:method => method.to_s)
  have_tag tag, options, &block
end

#have_tag(tag, options = {}) { ... } ⇒ Object

tag assertion, this is the core of functionality, other matchers are shortcuts to this matcher

Examples:

expect(rendered).to have_tag('div')
expect(rendered).to have_tag('h1.header')
expect(rendered).to have_tag('div#footer')
expect(rendered).to have_tag('input#email', :with => { :name => 'user[email]', :type => 'email' } )
expect(rendered).to have_tag('div', :count => 3)            # matches exactly 3 'div' tags
expect(rendered).to have_tag('div', :count => 3..7)         # shortcut for have_tag('div', :minimum => 3, :maximum => 7)
expect(rendered).to have_tag('div', :minimum => 3)          # matches more(or equal) than 3 'div' tags
expect(rendered).to have_tag('div', :maximum => 3)          # matches less(or equal) than 3 'div' tags
expect(rendered).to have_tag('p', :text => 'some content')  # will match "<p>some content</p>"
expect(rendered).to have_tag('p', :text => /some content/i) # will match "<p>sOme cOntEnt</p>"
expect(rendered).to have_tag('textarea', :with => {:name => 'user[description]'}, :text => "I like pie")
expect("<html>
  <body>
    <h1>some html document</h1>
  </body>
 </html>").to have_tag('body') { with_tag('h1', :text => 'some html document') }
expect('<div class="one two">').to have_tag('div', :with => { :class => ['two', 'one'] })
expect('<div class="one two">').to have_tag('div', :with => { :class => 'two one' })

Parameters:

  • tag (String)

    css selector for tag you want to match, e.g. 'div', 'section#my', 'article.red'

  • options (Hash) (defaults to: {})

    options hash(see below)

Options Hash (options):

  • :with (Hash)

    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

  • :count (Fixnum)

    for tag count matching(ATTENTION: do not use :count with :minimum(:min) or :maximum(:max))

  • :count (Range)

    not strict tag count matching, count of tags should be in specified range

  • :minimum (Fixnum)

    minimum count of elements to match

  • :min (Fixnum)

    same as :minimum

  • :maximum (Fixnum)

    maximum count of elements to match

  • :max (Fixnum)

    same as :maximum

  • :text (String/Regexp)

    to match tag content, could be either String or Regexp

Yields:

  • block where you should put with_tag, without_tag and/or other matchers


62
63
64
65
66
# File 'lib/rspec-html-matchers.rb', line 62

def have_tag tag, options = {}, &block
  # for backwards compatibility with rpecs have tag:
  options = { :text => options } if options.is_a?(String) || options.is_a?(Regexp)
  @__current_scope_for_nokogiri_matcher = HaveTag.new(tag, options, &block)
end

#with_button(text, value = nil, options = {}) ⇒ Object


328
329
330
331
332
333
334
335
336
337
338
339
# File 'lib/rspec-html-matchers.rb', line 328

def with_button text, value = nil, options = {}
  options[:with] ||= {}
  if value.is_a?(Hash)
    options.merge!(value)
    value = nil
  end
  options[:with].merge!(:value => value.to_s) if value
  options.merge!(:text => text) if text
  within_nested_tag do
    expect(@__current_scope_for_nokogiri_matcher).to have_tag('button', options)
  end
end

#with_checkbox(name, value = nil) ⇒ Object


256
257
258
259
# File 'lib/rspec-html-matchers.rb', line 256

def with_checkbox name, value = nil
  options = form_tag_options('checkbox', name, value)
  should_have_input(options)
end

#with_date_field(date_field_type, name = nil, options = {}) ⇒ Object


199
200
201
202
203
204
205
206
# File 'lib/rspec-html-matchers.rb', line 199

def with_date_field date_field_type, name = nil, options = {}
  date_field_type = date_field_type.to_s
  raise "unknown type `#{date_field_type}` for date picker" unless DATE_FIELD_TYPES.include?(date_field_type)

  options = { :with => { :type => date_field_type.to_s }.merge(options.delete(:with) || {}) }
  options[:with].merge!(:name => name.to_s) if name
  should_have_input(options)
end

#with_email_field(name, value = nil) ⇒ Object


155
156
157
158
# File 'lib/rspec-html-matchers.rb', line 155

def with_email_field name, value = nil
  options = form_tag_options('email', name, value)
  should_have_input(options)
end

#with_file_field(name, value = nil) ⇒ Object


228
229
230
231
# File 'lib/rspec-html-matchers.rb', line 228

def with_file_field name, value = nil
  options = form_tag_options('file', name, value)
  should_have_input(options)
end

#with_hidden_field(name, value = nil) ⇒ Object


135
136
137
138
# File 'lib/rspec-html-matchers.rb', line 135

def with_hidden_field name, value = nil
  options = form_tag_options('hidden', name, value)
  should_have_input(options)
end

#with_number_field(name, value = nil) ⇒ Object


175
176
177
178
# File 'lib/rspec-html-matchers.rb', line 175

def with_number_field name, value = nil
  options = form_tag_options('number', name, value)
  should_have_input(options)
end

#with_option(text, value = nil, options = {}) ⇒ Object


296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
# File 'lib/rspec-html-matchers.rb', line 296

def with_option text, value = nil, options = {}
  options[:with] ||= {}
  if value.is_a?(Hash)
    options.merge!(value)
    value = nil
  end
  tag = 'option'
  options[:with].merge!(:value => value.to_s) if value
  options[:with].merge!(:selected => 'selected') if options[:selected]
  options.delete(:selected)
  options.merge!(:text => text) if text
  within_nested_tag do
    expect(@__current_scope_for_nokogiri_matcher).to have_tag(tag, options)
  end
end

#with_password_field(name, value = nil) ⇒ Object


217
218
219
220
221
# File 'lib/rspec-html-matchers.rb', line 217

def with_password_field name, value = nil
  # TODO: add ability to explicitly say that value should be empty
  options = form_tag_options('password', name, value)
  should_have_input(options)
end

#with_radio_button(name, value) ⇒ Object


266
267
268
269
# File 'lib/rspec-html-matchers.rb', line 266

def with_radio_button name, value
  options = form_tag_options('radio', name, value)
  should_have_input(options)
end

#with_range_field(name, min, max, options = {}) ⇒ Object


185
186
187
188
# File 'lib/rspec-html-matchers.rb', line 185

def with_range_field name, min, max, options = {}
  options = { :with => { :name => name, :type => 'range', :min => min.to_s, :max => max.to_s }.merge(options.delete(:with) || {}) }
  should_have_input(options)
end

#with_select(name, options = {}, &block) ⇒ Object


276
277
278
279
280
281
282
283
284
# File 'lib/rspec-html-matchers.rb', line 276

def with_select name, options = {}, &block
  options[:with] ||= {}
  id = options[:with].delete(:id)
  tag = 'select'; tag += '#' + id if id
  options[:with].merge!(:name => name)
  within_nested_tag do
    expect(@__current_scope_for_nokogiri_matcher).to have_tag(tag, options, &block)
  end
end

#with_submit(value) ⇒ Object


354
355
356
357
358
# File 'lib/rspec-html-matchers.rb', line 354

def with_submit value
  options = { :with => { :type => 'submit', :value => value } }
  # options = form_tag_options('text',name,value)
  should_have_input(options)
end

#with_tag(tag, options = {}) { ... } ⇒ Object

Note:

this should be used within block of have_tag matcher

with_tag matcher

Yields:

  • block where you should put other with_tag or without_tag

See Also:


102
103
104
105
106
# File 'lib/rspec-html-matchers.rb', line 102

def with_tag tag, options = {}, &block
  within_nested_tag do
    expect(@__current_scope_for_nokogiri_matcher).to have_tag(tag, options, &block)
  end
end

#with_text(text) ⇒ Object

Raises:

  • (StandardError)

77
78
79
80
81
82
83
84
85
# File 'lib/rspec-html-matchers.rb', line 77

def with_text text
  raise StandardError, 'this matcher should be used inside "have_tag" matcher block' unless defined?(@__current_scope_for_nokogiri_matcher)
  raise ArgumentError, 'this matcher does not accept block' if block_given?

  tag = @__current_scope_for_nokogiri_matcher.instance_variable_get(:@tag)
  within_nested_tag do
    expect(@__current_scope_for_nokogiri_matcher).to have_tag(tag, :text => text)
  end
end

#with_text_area(name) ⇒ Object


238
239
240
241
242
243
244
245
# File 'lib/rspec-html-matchers.rb', line 238

def with_text_area name
  # TODO, should be: with_text_area name, text=nil
  # options = form_tag_options('text',name,value)
  options = { :with => { :name => name } }
  within_nested_tag do
    expect(@__current_scope_for_nokogiri_matcher).to have_tag('textarea', options)
  end
end

#with_text_field(name, value = nil) ⇒ Object


145
146
147
148
# File 'lib/rspec-html-matchers.rb', line 145

def with_text_field name, value = nil
  options = form_tag_options('text', name, value)
  should_have_input(options)
end

#with_url_field(name, value = nil) ⇒ Object


165
166
167
168
# File 'lib/rspec-html-matchers.rb', line 165

def with_url_field name, value = nil
  options = form_tag_options('url', name, value)
  should_have_input(options)
end

#without_button(text, value = nil, options = {}) ⇒ Object


341
342
343
344
345
346
347
348
349
350
351
352
# File 'lib/rspec-html-matchers.rb', line 341

def without_button text, value = nil, options = {}
  options[:with] ||= {}
  if value.is_a?(Hash)
    options.merge!(value)
    value = nil
  end
  options[:with].merge!(:value => value.to_s) if value
  options.merge!(:text => text) if text
  within_nested_tag do
    expect(@__current_scope_for_nokogiri_matcher).to_not have_tag('button', options)
  end
end

#without_checkbox(name, value = nil) ⇒ Object


261
262
263
264
# File 'lib/rspec-html-matchers.rb', line 261

def without_checkbox name, value = nil
  options = form_tag_options('checkbox', name, value)
  should_not_have_input(options)
end

#without_date_field(date_field_type, name = nil, options = {}) ⇒ Object


208
209
210
211
212
213
214
215
# File 'lib/rspec-html-matchers.rb', line 208

def without_date_field date_field_type, name = nil, options = {}
  date_field_type = date_field_type.to_s
  raise "unknown type `#{date_field_type}` for date picker" unless DATE_FIELD_TYPES.include?(date_field_type)

  options = { :with => { :type => date_field_type.to_s }.merge(options.delete(:with) || {}) }
  options[:with].merge!(:name => name.to_s) if name
  should_not_have_input(options)
end

#without_email_field(name, value = nil) ⇒ Object


160
161
162
163
# File 'lib/rspec-html-matchers.rb', line 160

def without_email_field name, value = nil
  options = form_tag_options('email', name, value)
  should_not_have_input(options)
end

#without_file_field(name, value = nil) ⇒ Object


233
234
235
236
# File 'lib/rspec-html-matchers.rb', line 233

def without_file_field name, value = nil
  options = form_tag_options('file', name, value)
  should_not_have_input(options)
end

#without_hidden_field(name, value = nil) ⇒ Object


140
141
142
143
# File 'lib/rspec-html-matchers.rb', line 140

def without_hidden_field name, value = nil
  options = form_tag_options('hidden', name, value)
  should_not_have_input(options)
end

#without_number_field(name, value = nil) ⇒ Object


180
181
182
183
# File 'lib/rspec-html-matchers.rb', line 180

def without_number_field name, value = nil
  options = form_tag_options('number', name, value)
  should_not_have_input(options)
end

#without_option(text, value = nil, options = {}) ⇒ Object


312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
# File 'lib/rspec-html-matchers.rb', line 312

def without_option text, value = nil, options = {}
  options[:with] ||= {}
  if value.is_a?(Hash)
    options.merge!(value)
    value = nil
  end
  tag = 'option'
  options[:with].merge!(:value => value.to_s) if value
  options[:with].merge!(:selected => 'selected') if options[:selected]
  options.delete(:selected)
  options.merge!(:text => text) if text
  within_nested_tag do
    expect(@__current_scope_for_nokogiri_matcher).to_not have_tag(tag, options)
  end
end

#without_password_field(name, value = nil) ⇒ Object


223
224
225
226
# File 'lib/rspec-html-matchers.rb', line 223

def without_password_field name, value = nil
  options = form_tag_options('password', name, value)
  should_not_have_input(options)
end

#without_radio_button(name, value) ⇒ Object


271
272
273
274
# File 'lib/rspec-html-matchers.rb', line 271

def without_radio_button name, value
  options = form_tag_options('radio', name, value)
  should_not_have_input(options)
end

#without_range_field(name, min = nil, max = nil, options = {}) ⇒ Object


190
191
192
193
194
195
# File 'lib/rspec-html-matchers.rb', line 190

def without_range_field name, min = nil, max = nil, options = {}
  options = { :with => { :name => name, :type => 'range' }.merge(options.delete(:with) || {}) }
  options[:with].merge!(:min => min.to_s) if min
  options[:with].merge!(:max => max.to_s) if max
  should_not_have_input(options)
end

#without_select(name, options = {}, &block) ⇒ Object


286
287
288
289
290
291
292
293
294
# File 'lib/rspec-html-matchers.rb', line 286

def without_select name, options = {}, &block
  options[:with] ||= {}
  id = options[:with].delete(:id)
  tag = 'select'; tag += '#' + id if id
  options[:with].merge!(:name => name)
  within_nested_tag do
    expect(@__current_scope_for_nokogiri_matcher).to_not have_tag(tag, options, &block)
  end
end

#without_submit(value) ⇒ Object


360
361
362
363
364
# File 'lib/rspec-html-matchers.rb', line 360

def without_submit value
  # options = form_tag_options('text',name,value)
  options = { :with => { :type => 'submit', :value => value } }
  should_not_have_input(options)
end

#without_tag(tag, options = {}) { ... } ⇒ Object

Note:

this should be used within block of have_tag matcher

without_tag matcher

Yields:

  • block where you should put other with_tag or without_tag

See Also:


112
113
114
115
116
# File 'lib/rspec-html-matchers.rb', line 112

def without_tag tag, options = {}, &block
  within_nested_tag do
    expect(@__current_scope_for_nokogiri_matcher).to_not have_tag(tag, options, &block)
  end
end

#without_text(text) ⇒ Object Also known as: but_without_text

Raises:

  • (StandardError)

87
88
89
90
91
92
93
94
95
# File 'lib/rspec-html-matchers.rb', line 87

def without_text text
  raise StandardError, 'this matcher should be used inside "have_tag" matcher block' unless defined?(@__current_scope_for_nokogiri_matcher)
  raise ArgumentError, 'this matcher does not accept block' if block_given?

  tag = @__current_scope_for_nokogiri_matcher.instance_variable_get(:@tag)
  within_nested_tag do
    expect(@__current_scope_for_nokogiri_matcher).to_not have_tag(tag, :text => text)
  end
end

#without_text_area(name) ⇒ Object


247
248
249
250
251
252
253
254
# File 'lib/rspec-html-matchers.rb', line 247

def without_text_area name
  # TODO, should be: without_text_area name, text=nil
  # options = form_tag_options('text',name,value)
  options = { :with => { :name => name } }
  within_nested_tag do
    expect(@__current_scope_for_nokogiri_matcher).to_not have_tag('textarea', options)
  end
end

#without_text_field(name, value = nil) ⇒ Object


150
151
152
153
# File 'lib/rspec-html-matchers.rb', line 150

def without_text_field name, value = nil
  options = form_tag_options('text', name, value)
  should_not_have_input(options)
end

#without_url_field(name, value = nil) ⇒ Object


170
171
172
173
# File 'lib/rspec-html-matchers.rb', line 170

def without_url_field name, value = nil
  options = form_tag_options('url', name, value)
  should_not_have_input(options)
end