module RSpecHtmlMatchers

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

Constants

DATE_FIELD_TYPES
VERSION

Public Instance Methods

but_without_text(text)
Alias for: without_text
have_empty_tag(tag, options = {}) click to toggle source

tests whether tag have any content inside

@example

expect('<div></div>').to have_empty_tag('div') # success
expect('<div>hi</div>').to have_empty_tag('div') # fail
# 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 = {}) click to toggle source

form assertion

it is a shortcut to

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

@yield block with with_<field>, see below @see have_tag

# 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 = {}) click to toggle source

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

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

@param [String] tag css selector for tag you want to match, e.g. ‘div’, ‘section#my’, ‘article.red’ @param [Hash] options options hash(see below) @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 @option options [Fixnum] :count for tag count matching(ATTENTION: do not use :count with :minimum(:min) or :maximum(:max)) @option options [Range] :count not strict tag count matching, count of tags should be in specified range @option options [Fixnum] :minimum minimum count of elements to match @option options [Fixnum] :min same as :minimum @option options [Fixnum] :maximum maximum count of elements to match @option options [Fixnum] :max same as :maximum @option options [String/Regexp] :text to match tag content, could be either String or Regexp

@example

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' })
# 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 = {}) click to toggle source
# 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) click to toggle source
# 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 = {}) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source

@TODO fix code duplications

# 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) click to toggle source
# 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 = {}) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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 = {}) click to toggle source
# 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 = {}) click to toggle source
# 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) click to toggle source
# 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 = {}) click to toggle source

with_tag matcher @yield block where you should put other with_tag or without_tag @see have_tag @note this should be used within block of have_tag matcher

# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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 = {}) click to toggle source
# 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) click to toggle source
# 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 = {}) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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 = {}) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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 = {}) click to toggle source
# 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 = {}) click to toggle source
# 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) click to toggle source
# 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 = {}) click to toggle source

without_tag matcher @yield block where you should put other with_tag or without_tag @see have_tag @note this should be used within block of have_tag matcher

# 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) click to toggle source
# 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
Also aliased as: but_without_text
without_text_area(name) click to toggle source
# 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) click to toggle source
# 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) click to toggle source
# 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

Private Instance Methods

form_tag_options(form_tag_type, form_tag_name, form_tag_value = nil) click to toggle source

form_tag in method name name mean smth. like input, submit, tags that should appear in a form

# File lib/rspec-html-matchers.rb, line 381
def form_tag_options form_tag_type, form_tag_name, form_tag_value = nil
  options = { :with => { :name => form_tag_name, :type => form_tag_type } }
  # .to_s if value is a digit or smth. else, see issue#10
  options[:with].merge!(:value => form_tag_value.to_s) if form_tag_value
  options
end
should_have_input(options) click to toggle source
# File lib/rspec-html-matchers.rb, line 368
def should_have_input options
  within_nested_tag do
    expect(@__current_scope_for_nokogiri_matcher).to have_tag('input', options)
  end
end
should_not_have_input(options) click to toggle source
# File lib/rspec-html-matchers.rb, line 374
def should_not_have_input options
  within_nested_tag do
    expect(@__current_scope_for_nokogiri_matcher).to_not have_tag('input', options)
  end
end
within_nested_tag(&block) click to toggle source
# File lib/rspec-html-matchers.rb, line 388
def within_nested_tag &block
  raise 'block needed' unless block_given?

  parent_scope = @__current_scope_for_nokogiri_matcher
  block.call
  @__current_scope_for_nokogiri_matcher = parent_scope
end