Capybara testing with RSpec in Ruby - ruby-on-rails

on my index page I have this div:
<div class="banner">
<h1 class="glow-header">Galaxy Far, Far Away? Quick Trip to Mars?<br>
Pianeta has you covered.</h1>
<div>
In my testfile this works:
RSpec.describe 'home features' do
it 'displays the name of the app and links to the index-all planets page' do
visit root_path
expect(page).to have_content('Space is full of surprises.')
click_link('Go Beyond')
expect(current_path).to eq('/planets')
expect(page).to have_content('Galaxy Far, Far Away?')
end
end
But I would like it to be working with the h1 included.
I did this:
expect(page).to have_content('<h1 class="glow-header">Galaxy Far, Far Away? Quick Trip to Mars?<br>
Pianeta has you covered.</h1>')
end
But the test failed. What did I do wrong ?

The #has_content?/#has_text? method only checks the text content of the page. It does not look at the HTML tags.
If you want to check for content within a specific HTML element there is a #within method that takes a block and will scope the Capybara lookups within it to be within the matched element. The element referenced by #within must exist or Capybara will raise an exception.
page.within('h1.glow-header') do
expect(page).to have_content('Galaxy Far, Far Away?')
end

If you don't want to deal with scoping using within for a single expectation you could do
expect(page).to have_css('h1.glow-header', text: 'Galaxy Far, Far Away?')
If you've already got a reference to the header you could also do something like
header = find('h1.glow-header')
...
expect(header).to have_text('Galaxy Far, Far Away?')
Additionally you should not be doing expect(current_path).to eq('/planets'). Using RSpecs eq matcher with Capybara will lead to flaky tests as soon as you move to using an asynchronous (JS supporting) driver, because it prevents Capybaras auto waiting/retrying behaviors. Instead you should use the Capybara provided matcher
expect(page).to have_current_path('/planets')

Related

How do I confirm a css element attribute with Capybara?

This may seem unusually basic but how do I confirm the presence of a pop up confirmation?
<a data-confirm="delete this video?" rel="nofollow" data-method="delete" href="/videos/21">Delete</a>
<a is the "tag"/"element" and data-confirm is an attribute. I want to test for the existence of the "data-confirm" attribute within the <a> element/tag
I have tried
expect(page).to have_css("a.data-confirm.delete this video?")
from
capybara assert attributes of an element
but no joy.
Edit:
I've tried the expectation from Arup's comment below
expect(page).to have_content "Content"
click_link "Delete"
expect(page).to have_css('a[data-confirm="delete this video?"]')
But it raises the following (same) error
Failures:
1) Visiting the video index page should search and save movies
Failure/Error: expect(page).to have_css('a[data-confirm="delete this video?"]')
expected #has_css?("a[data-confirm=\"delete this video?\"]") to return true, got false
but the page source shows it there and it is clearly working for the user
Any assistance would be very appreciated
You can write this expectation as:
expect(page).to have_css('a[data-confirm="delete this video?"]')
The answer by Arup is correct for the title of the question (and as he stated in the comments it's just valid CSS - https://developer.mozilla.org/en-US/docs/Web/CSS/Attribute_selectors), however it's not actually testing the more detailed part of the question "how do I confirm the presence of a pop up confirmation". All it is doing is confirming the correct data attribute is on the link element to trigger the rails provided JS that should show a confirm.
If you wanted to actually test the confirm box is shown you would need to swap to using a JS capable driver - https://github.com/teamcapybara/capybara/tree/2.17_stable#drivers - and then use something like the following in your test
expect(page).to have_content "Content"
accept_confirm "delete this video?" do
click_link "Delete" # The action that will make the system modal confirm box appear
end
See - http://www.rubydoc.info/gems/capybara/Capybara/Session#accept_confirm-instance_method

How to click the form commit button in Capybara

With Rails, rspec and capybara, I'm trying to test your typical ERB generated form:
<form action="/pages/1" id="edit_page_1" method="post">
<input id="page_title" name="page[title]" type="text">
<input name="commit" type="submit" value="Update Page">
</form>
I run two kinds of feature specs, those that are the same no matter what the language, and those that are I18N specific (for internationalization testing).
The problem is there is no clear way to click that submit button with capybara, unless I'm missing the obvious. I would expect simply click('commit') to do the trick.
Using click_button('Update Page') works but is obviously language specific and can't be used with both the New and Edit templates even though they render the same form template.
Adding an id to the submit button works, but I strongly dislike changing the code exclusively because the test requires it.
Using a css or xml matcher both looks ugly (a user would never know/care about accessing an element that way) and it is overkill.
In the end a macro was the answer I needed as apparently there is nothing native in capybara.
# spec/support/form_helpers.rb
module FormHelpers
def submit_form
find('input[name="commit"]').click
end
end
This gets included in spec_helper.rb
RSpec.configure do |config|
config.include FormHelpers, :type => :feature
...etc...
I used :type => :feature so it gets included only in the integration tests.
In the integration tests you can use it like this:
scenario 'pages can be created' do
visit new_page_path
fill_in 'page_title', with: 'A Tale of Two Cities'
submit_form # Clicks the commit button regardless of id or text
expect(page).to have_content 'The page was created'
...etc..
end
Of course submit_form can also be used inside within blocks and with :js => true.
I usually do:
within 'form#edit_page_1' do
find('input[name="page[title]"]').set "Some Value"
find('input[name="commit"]').click
end
Its tied to the html but to its semantic attributes, so I feel like its fine.
Actually I never use the magical finders.
Btw I dont understand your comment: (a user would never know/care about accessing an element that way).
Integration specs are for you, it mimics a user for sure but its just a matter of giving proper instructions.
Try to use:
find('input[name="commit"]').click
It helps

Rspec Capybara find field not functioning

I'm running Rails 4 using capybara and rspec (OS is Ubuntu 13.10). I'm having a problem -- when I run rspec my specs work, including those that use capybara's fill_in methods. However in one spec I need to use capybara's find_field method, and it is not functioning at all. It gives me the following error:
Failure/Error: page.find_field('From:').set(Date.today - 1.month)
Capybara::ElementNotFound:
Unable to find field "From:"
Now, I have inserted a "puts page.html" line immediately before the page.find_field... line and the html it prints includes the following lines:
<div class="date-range-picker">
<span class="from-date"><label for="from_date">From:</label> <input id="from_date" name="from_date" type="date" value="2013-12-23" /></span>
<span class="to-date"><label for="to_date">To:</label> <input id="to_date" name="to_date" type="date" value="2013-12-30" /></span>
</div>
So the element is there, but not being picked up by the find_field method. Any ideas?
OK, after much meandering through Capybara's source files I found the problem. It seems that the #find_field method doesn't work properly when using Capybara-webkit. The method only failed on examples that had the js: true argument, so that should have been the first clue. Anyway it seems that the cause of this is some method naming conflict between capybara and capybara-webkit, but I didn't analyze it too closely and so I can't be sure.
I changed the find_field('from_date') to find('#from_date') and everything works now. It also worked when changing to the :rack_test driver, but since I need webkit that's what I'll stick too. Is this issue documented anywhere??
As for capybara documentation:
"Find a form field on the page. The field can be found by its name, id or label text."
so use this code instead:
page.find_field('form_date').set(Date.today - 1.month)
So you are selecting the field by it's id.
I placed your HTML fragment within an HTML page and was able to successfully do a find_field('From:') on it, which suggests the problem lies within the containing HTML. My "idea" would be to strip down the page until the find_field succeeds as a means of isolating the offending content.
I found this on another site and it slightly worked for me:
Add this to "support/select_from_chosen.rb":
module SelectFromChosen
# select_from_chosen('Option', from: 'id_of_field')
def select_from_chosen(item_text, options)
field = find_field(options[:from], :visible => false)
find("##{field[:id]}_chosen").click
find("##{field[:id]}_chosen ul.chosen-results li", :text => item_text).click
end
end
RSpec.configure do |config|
config.include SelectFromChosen, type: :feature
end
I was able to do:
select_from_chosen('Blue', from: 'car_colors')
find('#submit-button').click
expect(page).to have_content 'Blue'
select_from_chosen('Red', from: 'car_colors')
find('#submit-button').click
expect(page).to have_content 'Red'
What I was actually trying to do was validate that the options in the chosen results where available for some users and not for others so I wound up using:
find('#car_colors_chosen').click
expect(page).to have_content 'Blue'
expect(page).not_to have_content 'Gold'
Just wanted to add this incase it helped someone else,

webrat have_selector content passes anything

My test suite includes RSpec2 with Capybara, Guard, and Spork. This test passes no matter what I put into :content:
it 'should something something' do
rendered.should have_selector('label', :content => "NOWHEREINMYPAGE")
end
Am I using this spec wrong? I want to see if there is a <label> tag with specific content. Whoops, note that all of the variable assignment and rendering is in a before :each block elsewhere.
Ensure you have render_views in your spec file. I just saw this. And yes that's correct it will look for a tag with NOWHEREINMYPAGE inside the tags.
Resolved. I didn't realize that I had to explicitly put Webrat in my Gemfile. Requiring Webrat resolves the issue, and render_views does not need to be present for view tests.

Capybara + Webkit: How to test client side validations - "required" input elements?

Using Rspec and Capybara, I'm trying to test a failing validation for a form, where a "required" input is not filled in, so it fails. New navigators understanding HTML5 provide built-in validations, and I understand Capybara is using that as well. Before, I was using
page.should have_error
which doesn't work for me anymore.
Someone knows how to test this now?
Many thanks!
David
HTML5 client side validations are tricky to find. I found this post with a great answer.
The code is:
describe "when I leave required field empty" do
it "I get an the correct html5 validation error" do
#Leave the field empty
click_on "Save" # or whichever button triggers the submit
message = page.find("#field_id_attr").native.attribute("validationMessage")
expect(message).to eq "Please fill out this field."
end
end
Basically the way it works is that the field element has an attribute called "validationMessage" and the process is:
Click submit - this triggers the error message
Get a reference to the native(html) attribute(as opposed to the Capybara page object attribute) called "validationMessage". This will give you the value or the message itself.
Assert that the value is as expected.
I am not familiar with RSpec so I am not sure about what does have_error.
You should think about what you want to test exactly.
You surely don't want to test the exact behavior (what message is displayed, and how) as it is specific to each browser. What you want to test, because this is not specific to the browser, is the fact that the form is not submitted.
For instance, for a basic html form at root, with a required radio button "My value".
# Check form can not be submitted without the radio button
visit '/'
click_button 'Submit'
assert_equal '/', current_path
# Check form can be submitted with the radio button
visit '/'
choose 'My value'
click_button 'Submit'
assert_equal '/next', current_path
You should also consider to test only the presence of required in your html code, as the browser is supposed to work as expected (test only your code, not other's code)
If there is an error message, you can something along the lines of
page.should have_content("error")
This depends on how you handle the errors, and whether you use javascript or not.
This is an old post, however I will try to answer it
have_error is a method provided by webkit, to check e.g. if ajax requests or javascript in general running fine
I use to test my validations in my model specs:
describe 'validations' do
it { is_expected.to validate_presence_of :competitor_name }
it { is_expected.to validate_presence_of :chassi }
it { is_expected.to validate_presence_of :auction }
it { is_expected.to validate_presence_of :car_template_id }
end
or like
expect(FactoryGirl.create(:customer)).to be_valid
to check if my Factory is valid.
If you need to check your notices by targeting invalid inputs, you could test the html of your notice by capybara with the following:
it 'searches for specific order_car by chassi and model' do
visit order_cars_search_detailed_path
fill_in 'order_car_chassi', with: '123456'
select 'Octavia', from: 'order_car_car_template_car_template_id'
click_button 'Search Order'
expect(page).to have_content('THIS IS MY NOTICE')
expect(page).to have_content('123456')
end
Hope I could help some others running into this question.

Resources