user2490003
user2490003

Reputation: 11890

Getting rid of repetitive rspec tests across contexts

Let's say I have various RSpec context blocks to group tests with similar data scenarios.

feature "User Profile" do
  context "user is active" do
    before(:each) {  (some setup) }

    # Various tests
    ...
  end

  context "user is pending" do
    before(:each) {  (some setup) }

    # Various tests
    ...
  end

  context "user is deactivated" do
    before(:each) {  (some setup) }

    # Various tests
    ...
  end
end

Now I'm adding a new feature and I'd like to add a simple scenario that verifies behavior when I click a certain link on the user's page

it "clicking help redirects to the user's help page" do
  click_on foo_button
  expect(response).to have('bar')
end

Ideally I'd love to add this test for all 3 contexts because I want to be sure that it performs correctly under different data scenarios. But the test itself doesn't change from context to context, so it seems repetitive to type it all out 3 times.

What are some alternatives to DRY up this test set? Can I stick the new test in some module or does RSpec have some built in functionality to let me define it once and call it from each context block?

Thanks!

Upvotes: 0

Views: 332

Answers (1)

SteveTurczyn
SteveTurczyn

Reputation: 36860

You can use shared_examples ... define them in spec/support/shared_examples.rb

shared_examples "redirect_help" do
  it "clicking help redirects to the user's help page" do
    click_on foo_button
    expect(response).to have('bar')
  end
end

Then in each of your contexts just enter...

it_behaves_like "redirect_help"

You can even pass a block to it_behaves_like and then perform that block with the action method, the block being unique to each context.

Your shared_example might look like...

shared_examples "need_sign_in" do
  it "redirects to the log in" do
    session[:current_user_id] = nil
    action
    response.should render_template 'sessions/new'
  end
end

And in your context you'd call it with the block...

  describe "GET index" do
    it_behaves_like "need_sign_in" do
      let(:action) {get :index}
    end
    ...

Upvotes: 6

Related Questions