Please bear with me while I give some background to my question:
I was recently integrating CanCan into our application and found that one of the controller rspec tests failed. Turns out this was a result of the test being poorly written and invoking an action on the controller twice.
it 'only assigns users for the organisation as @users' do
xhr :get, :users, { id: first_organisation.to_param}
expect(assigns(:users).count).to eq(3)
xhr :get, :users, { id: second_organisation.to_param}
expect(assigns(:users).count).to eq(4)
end
Note, the example is cut for brevity.
Now the reason this fails is because rspec is using the same controller instance for both action calls and CanCan only loads the organisation resource if it isn't already loaded.
I can accept the reasoning behind a) rspec using a single instance of the controller for the scope of the example and b) for CanCan to be only loading the resource if it doesn't exist.
The real issue here is that of course it's a bad idea to be invoking an action twice within the same example. Now the introduction of CanCan highlighted the error in this example, but I am now concerned there may be other controller tests which are also invoking actions twice or that such examples may be written in the future, which, rather long-windedly, leads me to my question:
Is it possible to enforce that a controller rspec example can only invoke a single controller action?
Ok, it does appear I have a solution:
Create unity_helper.rb to go into spec/support
module UnityExtension
class UnityException < StandardError
end
def check_unity
if @unity
raise UnityException, message: 'Example is not a unit test!'
end
@unity = true
end
end
RSpec.configure do |config|
config.before(:all, type: :controller) do
ApplicationController.prepend UnityExtension
ApplicationController.prepend_before_action :check_unity
end
end
then in rails_helper.rb
require 'support/unity_helper'
And this has actually highlighted another rspec controller example which is invoking a controller twice.
I am open to other solutions or improvements to mine.