RSpec matchers for testing your html (for RSpec 2 use 0.5.x version).
Goals
- designed for testing complex html output. If you plan to perform simple matching, consider using:
- developer-friendly output in error messages
- built on top of nokogiri
- has support for capybara, see below
- syntax is similar to
have_tag
matcher from rspec-rails 1.x, but with own syntactic sugar - framework agnostic, as input should be
String
(or capybara's page, see below)
Install
Add to your Gemfile in the :test
group:
gem 'rspec-html-matchers'
Include it in your RSpec configuration:
RSpec.configure do |config|
config.include RSpecHtmlMatchers
end
or just in your spec(s):
describe "my view spec" do
include RSpecHtmlMatchers
it "has tags" do
expect(rendered).to have_tag('div')
end
end
Cucumber configuration:
World RSpecHtmlMatchers
as this gem requires nokogiri, here are instructions for installing it.
Usage
so perhaps your code produces following output:
<h1>Simple Form</h1>
<form action="/users" method="post">
<p>
<input type="email" name="user[email]" />
</p>
<p>
<input type="submit" id="special_submit" />
</p>
</form>
so you test it with the following:
expect(rendered).to have_tag('form', :with => { :action => '/users', :method => 'post' }) do
with_tag "input", :with => { :name => "user[email]", :type => 'email' }
with_tag "input#special_submit", :count => 1
without_tag "h1", :text => 'unneeded tag'
without_tag "p", :text => /content/i
end
Example above should be self-descriptive, if not, please refer to the have_tag
documentation
Input can be any html string. Let's take a look at these examples:
-
matching tags by css:
# simple examples: expect('<p class="qwe rty" id="qwerty">Paragraph</p>').to have_tag('p') expect('<p class="qwe rty" id="qwerty">Paragraph</p>').to have_tag(:p) expect('<p class="qwe rty" id="qwerty">Paragraph</p>').to have_tag('p#qwerty') expect('<p class="qwe rty" id="qwerty">Paragraph</p>').to have_tag('p.qwe.rty') # more complicated examples: expect('<p class="qwe rty" id="qwerty"><strong>Para</strong>graph</p>').to have_tag('p strong') expect('<p class="qwe rty" id="qwerty"><strong>Para</strong>graph</p>').to have_tag('p#qwerty strong') expect('<p class="qwe rty" id="qwerty"><strong>Para</strong>graph</p>').to have_tag('p.qwe.rty strong') # or you can use another syntax for examples above expect('<p class="qwe rty" id="qwerty"><strong>Para</strong>graph</p>').to have_tag('p') do with_tag('strong') end expect('<p class="qwe rty" id="qwerty"><strong>Para</strong>graph</p>').to have_tag('p#qwerty') do with_tag('strong') end expect('<p class="qwe rty" id="qwerty"><strong>Para</strong>graph</p>').to have_tag('p.qwe.rty') do with_tag('strong') end
-
special case for classes matching:
# all of this are equivalent: expect('<p class="qwe rty" id="qwerty">Paragraph</p>').to have_tag('p', :with => { :class => 'qwe rty' }) expect('<p class="qwe rty" id="qwerty">Paragraph</p>').to have_tag('p', :with => { :class => 'rty qwe' }) expect('<p class="qwe rty" id="qwerty">Paragraph</p>').to have_tag('p', :with => { :class => ['rty', 'qwe'] }) expect('<p class="qwe rty" id="qwerty">Paragraph</p>').to have_tag('p', :with => { :class => ['qwe', 'rty'] })
The same works with
:without
:# all of this are equivalent: expect('<p class="qwe rty" id="qwerty">Paragraph</p>').to have_tag('p', :without => { :class => 'qwe rty' }) expect('<p class="qwe rty" id="qwerty">Paragraph</p>').to have_tag('p', :without => { :class => 'rty qwe' }) expect('<p class="qwe rty" id="qwerty">Paragraph</p>').to have_tag('p', :without => { :class => ['rty', 'qwe'] }) expect('<p class="qwe rty" id="qwerty">Paragraph</p>').to have_tag('p', :without => { :class => ['qwe', 'rty'] })
-
content matching:
expect('<p> Some content here</p>').to have_tag('p', :text => ' Some content here') # or expect('<p> Some content here</p>').to have_tag('p') do with_text ' Some content here' end expect('<p> Some content here</p>').to have_tag('p', :text => /Some content here/) # or expect('<p> Some content here</p>').to have_tag('p') do with_text /Some content here/ end # mymock.text == 'Some content here' expect('<p> Some content here</p>').to have_tag('p', :text => mymock.text) # or expect('<p> Some content here</p>').to have_tag('p') do with_text mymock.text end # matching text content as it's seen by user: rendered = <<HTML <p> content with ignored spaces around </p> HTML expect(rendered).to have_tag('p', :seen => 'content with ignored spaces around')
-
usage with capybara and cucumber:
expect(page).to have_tag( ... )
where page
is an instance of Capybara::Session
-
also included shorthand matchers for form inputs:
- have_form
- with_checkbox
- with_email_field
- with_file_field
- with_hidden_field
- with_option
- with_password_field
- with_radio_button
- with_button
- with_select
- with_submit
- with_text_area
- with_text_field
- with_url_field
- with_number_field
- with_range_field
- with_date_field
and of course you can use the without_
matchers,
for more info take a look at documentation
rspec 1 partial backwards compatibility:
you can match:
expect(response).to have_tag('div', 'expected content')
expect(response).to have_tag('div', /regexp matching expected content/)
RSpec 1 have_tag
documentation
Matching Tag Attributes
You can also match the content of attributes by using selectors. For example, to ensure an img
tag has an alt
attribute, you can match:
expect(index).to have_tag("img[alt!='']")
More info
You can find more on documentation
Also, please read CHANGELOG and issues, might be helpful.
Contribution
- Fork the repository
- Add tests for your feature
- Write the code
- Add documentation for your contribution
- Send a pull request