Reputation: 5539
How can I test rescue_from is RSpec? I'd like to make sure that if one of the exceptions is raised, that the controller correctly sets the flash and does the redirect. Is there a way to simulate the exception?
rescue_from PageAccessDenied do
flash[:alert] = "You do not have the necessary roles to access this page"
redirect_to root_url
end
rescue_from CanCan::AccessDenied do |exception|
flash[:alert] = exception.message
redirect_to root_url
end
Upvotes: 17
Views: 9819
Reputation: 788
I went with a shared_example approach:
we want to avoid stubbing / mocking the initialize
method and there are plenty of warning to remind you of that if you try. Instead we can leverage the new
or exception
methods, depending on how your error is being raised.
I have noticed that errors explicitly invoked by raise
require the check to be on the exception
method.
example code:
def validate_params
params.require(:param_key_1)
params.require(:param_key_2)
raise ExpectedError if something_wrong?
end
shared_examples_for :no_errors_raised do
it { expect { subject }.not_to raise_error }
end
shared_examples_for :rescued_from do |error_class, invocation_method: :new|
before do
# complains if the expected error is not invoked
expect(error_class).to receive(invocation_method).and_call_original
end
# complains if the error is not rescued
it_behaves_like :no_errors_raised
end
it_behaves_like :rescued_from, ActionController::ParameterMissing # => when param_key_1 or param_key_2 is missing
it_behaves_like :rescued_from, ExpectedError, method: :exception # => when something_wrong? == true
I have tested this locally and it seems to work fine when the rescue_from
approach is used, therefore you would just call the same shared_example as follows:
context "PageAccessDenied" do
# setup your test conditions
# run the request
it { expect(response).to redirect_to(root_url) }
it { expect(flash[:alert]).to eq "You do not have the necessary roles to access this page" }
it_behaves_like :rescued_from, PageAccessDenied
end
NOTE: don't forget to break up your expects into separate tests so that one failing ahead of the others doesn't hide additional test feedback / failures that can help with troubleshooting the failure.
Upvotes: 0
Reputation: 47548
Assuming that you have an authorize!
method that raises the exception, you should be able to do something like this:
describe "rescue_from exceptions" do
it "rescues from PageAccessDenied" do
controller.stub(:authorize!) { raise PageAccessDenied }
get :index
response.should redirect_to("/")
flash[:alert].should == "You do not have the necessary roles to access this page"
end
end
Upvotes: 14