Rspec: Shared context for DRY controller tests

03 September 2018 • Tags: railsrspec

Best if I start with a confession: The number of shared context or share examples that I have in my spec is a low digit. No idea why I missed that trend, but with budget-fox.com I promise to do better and cut down on repetition in my specs.

If your controller specs are a bit like mine they might look like this:

  # ...
  let(:user) { Fabricate(:user) }
  before do
    sign_in user, scope: :user
  end
  # ...

That’s actually pretty slim but with this very same pattern repeated over a few dozen controller there’s something in rspec-core that’s useful: shared context

If you repeat the same let and before calls over and over again, it’s best to put them into your spec/support folder, in my case in sign_in_context.rb. The context is then included from the controller spec.

# only argument is:
# scope (defaults to :user)
RSpec.shared_context "sign in user", :shared_context => :metadata do |args|
  signed_in_scope = args.fetch(:model, :user)
  let(signed_in_scope) do
    Fabricate(signed_in_scope)
  end
  before :each do |c, a|
    sign_in self.send(signed_in_scope.to_sym), scope: signed_in_scope
  end
end

And in the controller spec:

RSpec.describe Admin::UsersController, type: :controller do
  include_context 'sign in user', model: :admin
  it "GET #index" do
    # ...
  end
end

Random posts