I am writing an RSpec spec to test a Rails helper. The problem is that the helper method that I'm testing depends on a method defined in a different helper. It may be a code smell to me, but I'm adding tests for legacy code and am not at a point where I can refactor. How can I test this Rails helper?
module FancyHelper
def fancy_method
html = "hello"
html << another_fancy_method
html
end
end
module OtherHelper
def another_fancy_method
"world"
end
end
require "spec_helper"
describe FancyHelper do
describe "#fancy_method" do
it "does what it's supposed to" do
helper.fancy_method.should match("hello")
# NoMethodError: undefined method `another_fancy_method'
end
end
end
This is what stubs are for. When testing your helper that depends on the other helper, you will want to stub the other helper to get a predictable value and complete the test.
EDIT: https://www.relishapp.com/rspec/rspec-mocks/docs/method-stubs thanks grantovich for the newer link.
Related
I have a Rails (4.2) helper that I am trying to unit test with Rspec 3.
# app/helpers/nav_helper.rb
module NavHelper
def nav_link(body, url, li_class: "", html: {})
li_class += current_page?(url) ? " active" : ""
content_tag(:li, class: li_class) do
link_to(body, url, html)
end
end
end
# spec/helpers/nav_helper_spec.rb
require 'spec_helper'
describe NavHelper do
describe "#nav_link" do
it "creates a correctly formatted link" do
link = nav_link("test", "www.example.com/testing")
...
end
end
end
This throws the following error when I run the test:
Failure/Error: link = nav_link("test", "www.example.com/testing")
NoMethodError:
undefined method `content_tag' for #<RSpec::ExampleGroups::NavHelper::NavLink:0x007fe44b98fee0>
# ./app/helpers/nav_helper.rb:5:in `nav_link'
It seems like the Rails helpers aren't available, but I'm not sure how to include them. Regardless, how can I test a helper method that uses content_tag?
Update
Adding include ActionView::Helpers::TagHelper throws the following error
uninitialized constant ActionView (NameError)
You need to include the helper that contains the content_tag method in your NavHelper (in this case, TagHelper):
module NavHelper
include ActionView::Helpers::TagHelper
# ...
end
It's a good idea to include only the helpers that you need to make things work, as it makes it clear which parts of Rails/ActionView you're using in your helper.
EDIT: Why is this necessary?
When you're testing the helper, you're testing it in isolation from the rest of Rails. That's why RSpec is complaining about the method not being available - it literally isn't there!
The issue was the leading line of my spec. I changed require 'spec_helper' to require 'rails_helper' and everything works as expected.
Not the first time that's bitten me, but it was the hardest.
How is it that rspec feature tests implicitly know to use methods such as find, within, and fill_in from the page object?
I've written a helper class for some of my rspec tests and wanted to use those methods, and realized that I needed to pass the page object into the method, and then use page.find and the like.
RSpec achieves this by including Capybara::DSL in those cases where it wants those methods available. The module is pretty elegant, if you want to take a look at https://github.com/jnicklas/capybara/blob/f83edc2a515a3a4fd80eef090734d14de76580d3/lib/capybara/dsl.rb
suppose you want to include the following module:
module MailerMacros
def last_email
ActionMailer::Base.deliveries.last
end
def reset_email
ActionMailer::Base.deliveries = []
end
end
to include them, just call config.include(MailerMacros), like this:
RSpec.configure do |config|
config.include(MailerMacros)
end
now, you should be able to call reset_email() & last_email instead of MailerMacros::reset_email().
I'm a little unsure as to how to write a test for a helper method which has output that is based on the given controller and action that are requested.
Given the following helper method in my application helper...
module ApplicationHelper
def body_id
[ controller.controller_name, controller.action_name ].join("_")
end
end
... how would you write an application_helper_spec that tests this method?
Assign or mock the controller object. That will give you something to test against. (RSpec includes a very good mocking/stubbing library.)
rspec-rails has some built sugar for testing helpers as #marnen-laibow-koser mentioned. But I sometimes like to write very lightweight tests for my helpers that don't have to load in my whole rails environment. This way the tests can run in less than a second as opposed to the multiple seconds it takes to load the rails environment.
Here is an example:
require 'spec_helper_lite'
require_relative '../../app/helpers/application_helper'
describe ApplicationHelper do
let(:helper) do
class Helper
include ApplicationHelper
end
Helper.new
end
it "formats an elapsed time as a number of minutes and seconds" do
helper.elapsed_as_min_sec(90).should == "1min 30sec"
end
end
And my spec_helper_lite.rb file just looks like this:
require 'rspec'
require 'rspec/autorun'
RSpec.configure do |config|
config.order = "random"
end
I am developing a Rails app. I have a helper under app/helpers/ , that's the
db_data_helper.rb.
The methods in this db_data_helper are mainly used to execute sql dump file to load data to database. And these methods in the helper are used in some Rake task.
Some sample code of the helper:
db_data_helper.rb:
module DbDataHelper
def self.load_data
# CODE TO EXECUTE SQL dump files
end
...
...
end
Now, I would like to test this helper in Rspec but I am not sure how to implement the test in Rspec for a helper like this. Could some one help me on this?
I'd simply create a class in my spec file:
class DummyDbDataHelper
extend DbDataHelper
end
describe DummyDbDataHelper do
it "tests the load_data method" do
DummyDbDataHelper.load_data.should ...
end
end
module FooHelper
def foo
haml_tag(:div) do
haml_content("bar")
end
end
end
When I test this I get:
NoMethodError: undefined method `haml_tag'
This code is perfectly valid and works in a development/production environment.
It's something to do with having the haml helpers properly loaded in the test environment.
Thanks!
It looks like the Rails test scaffold isn't including Haml::Helpers in its context. If you're using Test::Unit, you can probably just include it yourself in the test class. You'll also want to run Haml::Helpers#init_haml_helpers in the test setup so that all the Haml stuff is properly initialized.
http://haml-lang.com/docs/yardoc/Haml/Helpers.html#init_haml_helpers-instance_method