Javier Su
Javier Su

Reputation: 48

Rspec controller tests with chaining method calls

My controller looks like this:

def index
  params[:page]||1
  @stories = Story.all.page(params[:page]).per(5)
end

When I try to write controller tests for the chaining line through using RSpec, I can't seem to get the tests to pass.

My controller_spec looks something like:

describe '#index' do
  let(:story) {double(Story)}
  before do
    allow(Story).to receive(:all).and_return(story)
    allow(story).to receive(:page).and_return(story)
    allow(story).to receive(:per).and_return(story)                                                                                                         
    get :index
  end
  context 'when user is not logged in' do
    it 'should get page 1' do                                                                                                
      expect(story).to receive(:page).with(1)                                                                                                               
    end
    it 'should get 5 stories' do
      expect(story).to receive(:per).with(5)                                                                                                                
    end
  end
end 

What would be good example test to write for such a controller?

Upvotes: 2

Views: 1283

Answers (2)

Alexander Kireyev
Alexander Kireyev

Reputation: 10825

I think you can use something like this:

def index
  params[:page] ||= 1
  @stories = Story.all.page(params[:page]).per(5)
end

describe '#index' do
  let(:stories) { [double(Story)] }
  let(:index) { -> { get :index, page: 1, pre: 5 } }

  context 'when user is not logged in' do
    it 'should get 5 last stories and assign to @stories' do
      expect_any_instance_of(Story).to receive(:all).and_return(stories)
      expect_any_instance_of(Story).to receive(:page).with(1).and_return(stories)
      expect_any_instance_of(Story).to receive(:per).with(5).and_return(stories)

      index.()
    end
  end
end

Your methods returns Enum of stories, not some story. When you make it return one story it's wrong. You probably want to check the order of this methods, and you can do it with this but they don't check receiving parameters.

If you don't care about params or you should add extra check you can do it with this:

describe '#index' do
  let(:stories) { [double(Story)] }

  context 'when user is not logged in' do
    it 'should get 5 last stories and assign to @stories' do
      expect_any_instance_of(Story).to receive(:all).and_return(stories)
      expect(stories).to receive(:page).and_return(stories)
      expect(stories).to receive(:per).and_return(stories)

      # or probably just this
      expect_any_instance_of(Story).to receive_message_chain(:all, :page, :per) { stories }

      get :index
    end
  end
end

Upvotes: 1

gotva
gotva

Reputation: 5998

You should set expect(story).to receive(:page).with(1) before calling get :index

move get :index from before block to it block:

it 'should get page 1' do                                                                                                
  expect(story).to receive(:page).with(1)
  get :index
end

PS and it looks like you missed = in controller action

params[:page] ||= 1

Upvotes: 1

Related Questions