As a developer, I constantly look for improving my code. Also in terms of tests. For me, it’s important to keep tests clean in order to add new tests to be a pleasure, not a drudgery.

First time I stumbled across the shared context when I was looking for something that can help me to extract some constantly repeated variables in tests. The shared context was exactly what I was looking for.

What do we test?

Assume we have to write a few policy objects:

# lib/policies/user_settings_policy.rb

class UserSettingsPolicy
  def can_show?
    user.admin? || user.id == resource.id
  end

  private

  attr_reader :user, :resource

  def initialize(user, resource)
    @user = user
    @resource = resource
  end
end

To test the policy object we need an admin user and a user who is the owner of a resource.

It’s time for the shared context

I’ve created the shared directory inside of the spec catalogue:

# spec/shared/users.rb

RSpec.shared_context :users do
  let(:user_id) { SecureRandom.uuid }
  let(:user) do
    Models::User.new(
      id: user_id,
      first_name: 'Nick',
      last_name: 'Owen',
      email: '[email protected]'
    )
  end

  let(:admin_id) { SecureRandom.uuid }
  let(:admin) do
    Models::User.new(
      id: admin_id,
      first_name: 'Jack',
      last_name: 'Jones',
      email: '[email protected]',
      role: :admin
    )
  end
end

Load the shared context in the spec_helper.rb file:

Dir[File.expand_path('shared/**/*.rb', __dir__)].each { |f| require f }

Now the spec file is clearer:

# spec/policies/user_settings_policy_spec.rb

RSpec.describe UserSettingsPolicy do
  include_context :users

  let (:resource) { Models::UserSettings.new(user_id: user_id) }

  describe '#can_show?' do
    context 'when a user has an admin role' do
      subject { described_class.new(admin, resource) }

      it 'returns true' do
        expect(subject.can_show?).to be_truthy
      end
    end
  end
end

Summary

The shared context is a good place to put variables that we use in more than one spec file. If you need you can also put mocks in your context. I really encourage you to write small shared contexts in order to easily include just what you need and keep the proper naming of context files.