Reputation: 4237
I'm having trouble using a defined variable for a shared example in RSpec. Here's my test:
RSpec.shared_examples "check user logged in" do |method, action, params|
it "redirects to the sign in page if the user is not logged in" do
send(method, action, params)
expect(response).to redirect_to(signin_url)
end
end
RSpec.describe UsersController, type: :controller do
describe "GET #show" do
let(:user) { FactoryGirl.create(:user) }
let!(:show_params) do
return { id: user.id }
end
context "navigation" do
include_examples "check user logged in", :get, :show, show_params
end
end
end
In the test, I'm checking to make sure the user needs to be logged in before the action can be performed. I am receiving the following error message:
method_missing': show_params is not available on an example group
What do I need to change to make show_params
accessible? I've tried using it_behaves_like
instead of include_examples
with no luck. I've also tried removing the context "navigation"
block to no avail. I need to perform this check across multiple controllers and actions, so it seems a shared example might be the correct way to reuse code.
Upvotes: 2
Views: 1944
Reputation: 101811
The problem here is that the memoized let helper show_params
is called outside of an example.
Instead of passing the params you can simply reference a let
from the outer scope where you are including the example:
RSpec.describe UsersController, type: :controller do
let(:user) { FactoryGirl.create(:user) }
describe "GET #show" do
let(:action) { get :show, id: user }
it_should_behave_like "an authorized action"
end
end
RSpec.shared_examples "an authorized action" do
it "denies access" do
action
expect(response).to redirect_to(signin_url)
end
end
This is a pretty powerful pattern that lets you use a convention over configuration approach since the last let always wins.
RSpec.describe UsersController, type: :controller do
let(:user) { FactoryGirl.create(:user) }
describe "GET #show" do
let(:action) { get :show, id: user }
it_should_behave_like "an authorized action"
context "when signed in" do
before { sign_in user }
let(:action) { get :show, id: other_user }
context 'when viewing another user' do
it_should_behave_like "an authorized action"
end
end
end
end
Upvotes: 3