Webrat has unexpected outcome when 'if' statement is used - ruby-on-rails

I have been using webrat with my rails 3.0.7 project and have been trying to write a test that uses regular expressions. It should fail, yet the if statement seems to corrupt the outcome.
it "should have 'microposts' if 0 posted" do
visit root_path
response.should have_selector('span.microposts') do |span|
if span =~ /\d/
span.should contain('hello')
end
end
end
The test is trying to confirm that the test, yet it still succeeds when an 'if' statement is used. It is trying to match the content '0 microposts'.
When I use these lines in replacement of the 'if' statement:
response.should have_selector('span.microposts') do |counter|
counter.should contain(/hello/)
end
I get the test to finally fail like it is supposed to, but then I don't get to verify the number in front of the content inside of the span like I was trying to above.
Does webrat not hand if statements well, or am I doing something wrong?
Thanks in advance!

It seems you are missing an end but I don't see how that wouldn't bomb.
it "should have 'microposts' if 0 posted" do
visit root_path
response.should have_selector('span.microposts') do |span|
if span =~ /\d/
span.should contain('hello')
end
end
end

Related

Rspec/capybara - test presence of a class OR another class

In my ruby on Rails 4.2 app, on a page I have a conditional back end rule that translates into the page front end in a change in class
<div id="content">
<i class='<% if x=true %>glyphicon glyphicon-thumbs-down<% else> glyphicon glyphicon-thumbs-up ><% end %>' </i>
this is the message.
</div>
How to check presence with rspec 3/capybara that the page contains the class glyphicon-thumbs-down OR the class glyphicon-thumbs-up ?
I tried the code below but it fails:
it "should sheck one of the 2 classes presence" do
expect(page).to have_css '.glyphicon-thumbs-down' || expect(page).to have_css '.glyphicon-thumbs-up'
end
I am getting the following error message:
syntax error, unexpected tIDENTIFIER, expecting keyword_end (SyntaxError)
Multiple OR-ed css selectors can be specified separated by a comma. Try the following:
it "should sheck one of the 2 classes presence" do
expect(page).to have_css '#content i.glyphicon-thumbs-down,#content i.glyphicon-thumbs-up'
end
(I added the #content and i selectors so that the query is more specific.)
However, instead of doing this I would recommend trying to make the test behave in a precisely defined way and test for just a single class in the spec. Have a look at this SO question and its answers for various ways to stub or preset the random number generator in tests.
Firstly, you're checking for a class name so you need a . in front of the class names to make it a CSS class selector. Then, you could use the RSpec or matcher combinator
expect(page).to have_css('.glyphicon-thumbs-down').or(have_css '.glyphicon-thumbs-up')
but it has the downside of the first one retrying/waiting for Capybara.default_max_wait_time seconds before checking the second. You could specify a 0/false wait time if you know the page is already loaded and therefore don't need retrying/waiting
expect(page).to have_css('.glyphicon-thumbs-down', wait: false).or(have_css '.glyphicon-thumbs-up', wait: false)
However, it's probably fine to just check for either element using the normal CSS ,
expect(page).to have_css('.glyphicon-thumbs-down, .glyphicon-thumbs-up')
Maybe you can try to use option :count, in expect method like this:
it 'should contains 2 same selector' do
expect(page).to have_css '.some-class', count: 2
end
Your error is from this line:
expect(page).to have_css 'glyphicon-thumbs-down' || expect(page).to have_css 'glyphicon-thumbs-up'
You just need to add some parens then it will be valid syntax:
expect(page).to(have_css('glyphicon-thumbs-down')) || expect(page).to(have_css('glyphicon-thumbs-up'))
that won't fix your issue though, because if the left condition fails then rspec will exit and not run the second half.
A working approach could be to evaluate the condition to a boolean variable, then pass it to a single rspec expectation. Doing this requires using the core Capybara method has_css to test for css presence, not have_css? from the rspec matchers package:
selectors = ['.glyphicon-thumbs-down', '.glyphicon-thumbs-up']
glyph_exists = selectors.any? do |selector|
page.has_css? selector
end
expect(glyph_exists).to be true
Note also that I've added . to the selector strings which is necessary since it's a css class.

RSpec: Force error within negated custom matcher

I have a custom matcher, that has an expect within:
RSpec::Matchers.define :have_access_to do |action|
match do |user|
allow(controller).to receive(:authorize!)
# perform GET request...
expect(controller).to have_received(:authorize!)
response.code == "200"
end
end
This works, as long as I call it this way
it { expect(shop_manager).to have_access_to(:index) }
But when I try to use the negated form not_to, and the expect within the customer matcher fails, the test passes:
it { expect(shop_manager).not_to have_access_to(:index) }
I understand RSpec logic here: When you want the test to fail with not_to and it fails, everything is fine.
But this expect serves as a side condition: I want to check if the whole request has passed the authorize! step.
I know that a matcher should only test one thing, but I use it a lot and it would lead to a lot of code duplication when I add the have_received(:authorize!) check to every single test.
Is there a way to force RSpec to fail, no matter if the call is negated or not?
You could do
RSpec::Matchers.define :have_access_to do |action|
match do |user|
allow(controller).to receive(:authorize!)
# perform GET request...
fail "failed to receive authorize" unless controller.received_message?(:authorize!)
response.code == "200"
end
end
Using old rspec shoulda syntax. However, I get a deprecation warning for this
Using received_message? from rspec-mocks' old :should syntax without explicitly enabling the syntax is deprecated.

Problems matching class with Capybara/RSpec

I'm trying to match a class attribute using Capybara with RSpec.
I can very clearly see the elements and their classes but no matter what I try, Capybara seems to know nothing about the classes. But it can find id's no problem. Any clues, please? https://gist.github.com/1428472
visit "/admin/staff?mobile=1"
page.should have_selector("ul") #works
page.should have_selector("body#page") #works
page.should have_selector("html.ui-mobile") #fails
page.should have_selector("body.ui-mobile-viewport") #fails
save_and_open_page # this launches the page so I can see it and verify these attributes are indeed there.
The html:
< html class="ui-mobile" >
< body class="ui-mobile-viewport" id="page" >
I also set a breakpoint and did this stuff which also didn't work right.
#works
p find('body')[:id]
p find(:xpath, '//body[#id="page"]')
# doesn't work
p find('body')[:class]
p find(:xpath, '//html[#class="ui-mobile"]')
What's going on?
UPDATE: It turns out that it does actually work, however the problem here is that the html displayed by save_and_open_page differs from what capybara sees. When I break right after save_and_open_page and puts page.html, it's different. It's generally the same but a bunch of class attributes are gone as well as some other stuff. Very odd.

Add I18n translations to rspec tests

How can i add a translation test to my specs ? Something like :
flash[:error].should == I18n.translate 'error.discovered'
this does not work of course. How to make it work ?
I want to make sure that i get a certain error back.
In my code, a Rails 3 project, using RSpec 2, that is exactly the line I write:
describe "GET 'index'" do
before do
get 'index'
end
it "should be successful" do
response.should be_redirect
end
it "should show appropriate flash" do
flash[:warning].should == I18n.t('authorisation.not_authorized')
end
end
So I am not sure why you say it is not possible?
Not sure if this is optimal, but in my Rails3/RSpec2 apps, I test all my locale translations in RSpec in the following way:
I set the available locales in my config/initializers/i18n.rb file:
I18n.available_locales = [:en, :it, :ja]
and in my spec files that need translation checking I have tests that looks something like:
describe "Example Pages" do
subject { page }
I18n.available_locales.each do |locale|
describe "example page" do
let(:example_text) { t('example.translation') }
before { visit example_path(locale) }
it { should have_selector('h1', text: example_text) }
...
end
...
end
end
I wasn't sure how to get just the t() method to be usable in the specs without needing I18n.t so I just added a small convenience method to spec/support/utilities.rb:
def t(string, options={})
I18n.t(string, options)
end
Update: These days I tend to use the i18n-tasks gem to handle testing related to i18n, and not what I wrote above or have answered on StackOverflow previously.
I wanted to use i18n in my RSpec tests primarily to make sure that I had translations for everything ie there were no translations missed. i18n-tasks can do that and more through static analysis of my code, so I don't need to run tests for all I18n.available_locales anymore (apart from when testing very locale-specific functionality, like, for example, switching from any locale to any other locale in the system).
Doing this has meant I can confirm that all i18n keys in the system actually have values (and that none are unused or obsolete), while keeping the number of repetitive tests, and consequently the suite running time, down.
Assuming the code in the controller is:
flash[:error] = I18n.translate 'error.discovered'
You could stub 'translate':
it "translates the error message" do
I18n.stub(:translate) { 'error_message' }
get :index # replace with appropriate action/params
flash[:error].should == 'error_message'
end

Testing view helpers in Rails with RSpec

I need to test the following helper:
def display_all_courses
#courses = Course.all
output = ""
for course in #courses do
output << content_tag(:li, :id => course.title.gsub(" ", "-").downcase.strip) do
concat content_tag(:h1, course.title)
concat link_to("Edit", edit_course_path(course))
end
end
return output
end
and I'm wondering if there is a way that I can test the output of this. Basically, I just want to test that the helper gets me the correct number of li elements, and maybe the case when there aren't any courses.
My first thought is to do something like this:
describe DashboardHelper do
describe display_all_courses do
it "should return an list of all the courses" do
7.times{Factory(:course)
html = helper.display_all_courses
html.should have_selector(:li)
end
end
end
and this works just fine. However, if I add the :count option to the have_selector call it suddenly fails, can anybody help me figure out why that is?
I believe what you were looking for was have_tag and with_tag RSpec helpers
describe DashboardHelper do
describe display_all_courses do
it "should return an list of all the courses" do
7.times{ Factory(:course) }
helper.display_all_courses.should have_tag('ul') do
with_tag('li', 3)
end
end
end
end
Maybe it could help to treat the html as xml?
In that case this link could help.
It defines a matcher have_xml which could be just what you need.
Although i understand it would be nicer if the have_tag would just work on strings too.
Clearly a template is the best way to do this.

Resources