I'm trying to test a presenter method using a Capybara RSpec matcher.
Lets say I have a method that renders a button. This would be the test I would write if I wasn't using capybara rspec matchers:
it "should generate a button" do
template.should_receive(:button_to).with("Vote").
and_return("THE_HTML")
subject.render_controls.should be == "THE_HTML"
end
Using capybara rspec matchers, I want to do this:
it "should render a vote button" do
subject.render_controls.should have_button('Vote')
end
This approach was proposed in this article http://devblog.avdi.org/2011/09/06/making-a-mockery-of-tdd/. In the article, the author explains it like this: "I decided to change up my spec setup a bit in order to pass in a template object which included the actual Rails tag helpers. Then I included the Capybara spec matchers for making assertions about HTML."
However, I don't understand this. How can you use capybara rspec matchers when render_controls only returns a content_tag?
Even though luacassus's answer is correct, I found what the problem was. I wasn't including capybara rspec matchers in the test. If you don't include Capybara rspec matchers, you will an error like this: undefined method has_selector? for ActiveSupport::SafeBuffer:0x9449590.
When you include the rspec matchers, there is no need to use Capybara String method, since rspec matchers match against a string already.
I leave here a more detailed example.
require_relative '../../app/presenters/some_presenter'
require 'capybara/rspec'
describe 'SomePresenter'
include Capybara::RSpecMatchers
let(:template) { ActionView::Base.new }
subject { Presenter.new(template) }
it "should render a vote button" do
subject.render_controls.should have_button('Vote')
end
end
Check out Capybara.string method: http://rubydoc.info/github/jnicklas/capybara/master/Capybara#string-class_method
With this method you should be able to write something like that:
subject { Capybara.string(presenter.render_controls }
it { should have_button('Vote') }
Related
It looks like you used to be able to write RSpec tests with the following syntax
it { should validate_presence_of :privacy }
However I'm receiving the following error
error undefined method `validate_presence_of' for #<RSpec::ExampleGroups::Review:0x007fd819c1bdc8>
I can write tests the following way but the above syntax is much simpler
it "should require privacy" do
expect(FactoryGirl.build(:review, privacy: "")).to_not be_valid
end
Is there a 1 liner to test validations using Rails 4.2 and rspec-rails 3.0? I feel like I'm missing something...
Yes there is:
it { is_expected.not_to be_valid }
You can read all about it at Relish
Edited to add clarification:
This assumes the subject is either explicitly stated, like
subject{ FactoryGirl.build(:wiget) }
or is able to be inferred.
I have run into this issue a few times, and was wondering what the proper way to deal with it is.
Basically, I am writing a simple capybara feature in rspec:
describe 'Some Feature', type: :feature do
context "when visiting the /some/page/:id" do
it "shows Desired Content" do
visit "/admin/pages/:id"
expect(page).to have_content("Desired Content")
end
end
end
In the view at views/admin/pages/show.html.erb is a call to a helper method located in the corresponding helper (Admin::PagesHelper). In normal rails, these helper module methods are automatically available for use. When i run this feature test though, I get an error stating
ActionView::Template::Error:
undefined method `some_admin_pages_method' for #<#<Class:0x007fe1ace881f0>:0x007fe1ad364d40>
What is the proper approach to getting these helper methods to be available when running my rspec features?
Not to be confused by the title, I am not asking where I can place specs that test Rails helpers, but helpers specs that test additional things in a Rails app. For example, a spec that checks whether all translations are in place. Or that FactoryGirl factories are valid.
I know the guys at FactoryGirl recommend putting this check on RSpec's before :suite, but I prefer to leave it aside in a spec file of its own (so that it doesn't get executed when I want to run a single spec, for example).
So, what's the place to put these kind of specs?
I put FactoryGirl's specs in spec/models/*_spec.rb. For example
# spec/models/user_spec.rb
describe User do
describe "factories" do
it { expect(build(:user)).to be_valid }
end
end
For other kinds of specs, say for service objects, I put them in spec/services/*_spec.rb. RSpec will automatically detect them.
Edited
For translations, I test them in view specs. Firstly, set config to raise error on translations are missing.
# config/environments/test.rb
# Raises error for missing translations
config.action_view.raise_on_missing_translations = true
Then in the view spec,
describe "pages/welcome" do
it { expect { render }.not_to raise_error }
end
I'm building a Rails application and formulating tests using RSpec.
I wrote tests for a method I'm creating called current_link_to. This method is supposed to check whether the current page corresponds to the path I pass it and add the current class to the generated link in case it does.
Here is the spec:
require "spec_helper"
describe ApplicationHelper do
describe "#current_link_to" do
let(:name) { "Products" }
let(:path) { products_path }
let(:rendered) { current_link_to(name, path) }
context "when the given path is the current path" do
before { visit(path) }
it "should return a link with the current class" do
# Uses the gem "rspec-html-matchers" (https://github.com/kucaahbe/rspec-html-matchers)
expect(rendered).to have_tag("a", with: { href: path, class: "current" }) do
with_text(name)
end
end
end
context "when the given path is not the current path" do
before { visit(about_path) }
it "should return a link without the current class" do
expect(rendered).to have_tag("a", with: { href: path }, without: { class: "current" } ) do
with_text(name)
end
end
end
end
end
I then tried implementing my method following the spec:
module ApplicationHelper
def current_link_to(name, path, options={})
options.merge!({ class: "#{options[:class]} current".strip }) if current_page?(path)
link_to(name, path, options)
end
end
However, the tests fail with the following error:
Failure/Error: let(:rendered) { current_link_to(name, path) }
RuntimeError: You cannot use helpers that need to determine the current page unless your view context provides a Request object in a #request method
Since I don't really need the current_page? helper method to perform checks on the request, I decided that it would make sense to stub it.
I tried the following methods, but none of them worked:
helper.double(:current_page? => true)
Seems to stub the helper.current_page? method, but it's not the same method that's being called by my function.
allow(ActionView::Helpers::UrlHelper).to receive(:current_page?).and_return(true)
The stub seems not to be effective at all
While writing this question I stumbled onto the solution. I managed to stub the current_page? method using this in a before block:
allow(self).to receive(:current_page?).and_return(true)
It worked, however this solution raised more questions than it really answered. I am now baffled over how this works, as it seems weird that self in a before block would respond to current_page? and that said method would in fact be exactly the same one my helper is calling.
Even after reading documentation and trying to figure out how this works by littering my code with puts calls, the following doubts still haunt me:
Why are helper methods available directly in the specs, when the RSpec docs mention that they should instead be available as methods on the helper object available in all helper specs?
How does stubbing the current_page? method on self in a RSpec before block somehow reflect onto the actual method that gets called by my helper? Does self in my helper for some reason reference the same self you can find in the before block? Is RSpec or Rails including and mixing stuff under the covers?
If the same self encompasses my spec and my helpers, what exactly does self refer to in this case and why is it the same everywhere?
It would be great if someone could help me figure this out because this is blowing my mind up, and I'm scared of using code that I don't really understand.
With respect, you're testing a little too much functionality here. The trick is to test only the bits you need to test.
In this instance, you only need to test that the current class is added when it needs to be, and isn't when it doesn't need to be.
This code should do the trick for you:
require 'rails_helper'
# Specs in this file have access to a helper object that includes
# the ApplicationHelper.
RSpec.describe ApplicationHelper, type: :helper do
describe 'current_link_to' do
let(:subject) { helper.current_link_to('some_name', 'some_path', options = {}) }
context 'where the path is current' do
before do
allow(helper).to receive(:current_page?).and_return true
end
it 'should include the current class' do
expect(subject).to match /current/
end
end
context 'where the path is not current' do
before do
allow(helper).to receive(:current_page?).and_return false
end
it 'should not include the current class' do
expect(subject).to_not match /current/
end
end
end
end
I've been a little glib and only tested for the presence of 'current' in the returned string. You could test for something like 'class="current"' if you want to be more precise.
The other key is the comment at the top of the page, which Rails inserts into blank helper specs for you:
# Specs in this file have access to a helper object that includes
# the ApplicationHelper.
That means that you can use 'helper' where in your comment above you were using 'self', which makes things a little clearer (imho)
Hope it helps!
I'm very rigorous when it comes to my HTML markup and I follow a strict coding convention for forms, lists, etc...
I would like to include reusable test in my RSpec tests that would allow for me call a form test from any other test and target it directly to the page or URL that I'm testing.
Something like this:
# spec/helpers/form_tester.rb
describe FormTester
it "should check to see if all the text fields have an ID prefix of 'input-'" do
... #form should be valid ...
should be true
end
end
# spec/requests/user_form.rb
describe UserForm
it "should validate the form" do
#form = find(:tag,'form')
# call the FormTester method
end
end
Any ideas on how todo this? I'm using Rails 3.1, with RSpec, Capybara and FactoryGirl.
Use shared examples. In you case, something like this may work:
# spec/shared_examples_for_form.rb
shared_examples 'a form' do
describe 'validation' do
it 'should be validated' do
form.should_be valid
end
end
end
# spec/requests/user_form.rb
describe UserForm
it_behaves_like 'a form' do
let(:form) { find(:tag, 'form') }
end
end
It's also possible to pass parameters to shared examples and place the shared examples inside spec/support. Just have a read at the documentation.
Shared examples are great, but you've got at least two serious problems here.
First: why are you giving your form fields IDs at all? You've already got perfectly good selectors: just use input[name='whatever']. And even if you are giving them IDs, don't put a prefix on them: input#whatever or just #whatever is probably a more sensible selector in your CSS than #input-whatever. By being overspecific on your selector names, you're most likely making your CSS and JavaScript harder to write than they have to be.
Second: don't use RSpec to test your views. RSpec is at its best when confined to models. Cucumber is better for anything user-facing.