webrat have_selector content passes anything - ruby-on-rails

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.

Related

Capybara testing with RSpec in Ruby

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')

minitest assert_select with capybara click_link

How can I achieve checking presence of my link and then clicking on it? I tried the following:
assert_select "a", "show/hide comments"
click_link('show/hide comments')
I am using minitest, capybara, and the 'minitest-rails-capybara' gem. I have added the following include statements in my integration test:
include Capybara::DSL
include Capybara::Assertions
I get the following error:
Unused parameters passed to Capybara::Queries::SelectorQuery : ["show/hide comments"]
MethodError: NoMethodError: undefined method `failure_message' for Capybara::Helpers:Module
test/integration/user_flow_test.rb:215:in `block in <class:UserFlowTest>'
Can I use both minitest's assert link and capybara's click_link?
Thanks
Firstly there is no need to assert on the presence of an element before clicking it since click_link will wait up to Capybara.default_max_wait_time seconds for the link to appear on the page and then click it. If the link doesn't appear in that time it will raise an error, so asserting on its presence is superfluous.
The error you're getting is because minitest-capybara isn't compatible with Capybara 2.9+ - https://github.com/wojtekmach/minitest-capybara/pull/17 - and the fact that assert_select doesn't take 2 strings as parameters. It just takes the id, name, or label text of a select element. So I'm guessing that's not actually the method you mean to be calling.
To clarify the previous answer:
Wrong:
assert_select "a", "show/hide comments"
Correct:
assert_select "a", text: "show/hide comments"

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,

Using Factory Girl with Rspec Views

So I want to test some views using Rspec and Factory Girl, but I don't know how to assign a factory to a view properly. All of the information I see online uses stubbing, and although stubbing is fine, I want to keep my rspec stuff somewhat consistent.
I want to use a factory for an edition model and associate that with the page when I render the page, but everything I've considered seems to be broken. Here's sort of a ridiculous example:
require 'spec_helper'
describe "catalog/editions/rationale.html.haml" do
before do
#edition = Factory.create(:edition)
assign(:editions, #edition)
render :action => 'rationale', :id => #edition
end
context "GET rationale" do
it "should not have the preamble to the United States constitution" do
rendered.should_not contain(/We the People of the United States/)
end
end
end
In this I've tried changing render :action => 'rationale', :id => #edition to just render, and other similar tweaks to the render action. I just have no idea where to start a factory_girl helped view. Any help would be greatly appreciated.
Versions:
Rails 3.0.10
RSpec 2.7
Factory_Girl 2.2
I think the error is that #editions is expecting an array, so you should write
assign(:editions, [#edition])
or, otherwise, if it should be a single element, you should write:
assign(:edition, #edition)
Secondly, unless your view is a partial that expects variables, you should just write
render
You do not have to give the action, rspec knows which view to render from the describe, and the view does not retrieve any data (so you don't have to set the id), you just have to set the instance variables correctly using the assigns. Testing the view does nothing more than rendering the view.
Hope this helps.
Now that you've got the answer, stop writing view specs. They are needlessly hard to write, and they really don't test enough to be at all worthwhile. Do your view and controller testing with Cucumber instead.

Resources