Problem with stubbing "will_paginate" in rspec-view

353 views
Skip to first unread message

netzfisch

unread,
May 18, 2013, 8:59:49 AM5/18/13
to rs...@googlegroups.com
Hi,
I aim to test for

expect(rendered).to have_selector "div.pagination"

in a view spec - using rspec. I did the following:

describe "recurrences/index" do
  let(:recurrences) do 
      [ FactoryGirl.create(:recurrence, scheduled_to: "2012-07-05"),
      FactoryGirl.create(:recurrence, scheduled_to: "2012-07-12"),
      FactoryGirl.create(:recurrence, scheduled_to: "2012-07-19") ]
  end

  before :each do
    assign(:recurrences, recurrences)
    view.stub(:will_paginate)
    render
  end

  it "should have a pagination bar" do
    expect(rendered).to have_selector('div', class: 'pagination') 
  end
end

but got an error

           expected to find css "div.pagination" but there were no matches

How do I have to stub the 'will_paginate' method, I tried something like

view.stub(:paginate).with(page: 1).and_return(recurrences.paginate(per_page: 2))

which brought me a no-method error for 'paginate'! I had a look at


But were no successful until now. Any Ideas or could some one provide/point me a working example?

Thanks in advance, h-(

David Chelimsky

unread,
May 18, 2013, 9:55:45 AM5/18/13
to rs...@googlegroups.com
If I'm reading it correctly, there is a bit of contradiction in Mislav's blog. He says "You should not test the outcome of paginating finders or the will_paginate helper. These are will_paginate features and are already tested in the plugin’s extensive test suite.", but the examples check for the presence of "div.paginate", which is an outcome of the will_paginate helper.

That said, assuming you still want to specify this outcome of will_paginate, I see several differences between your example and Mislav's:

First, yours stubs :will_paginate. You definitely don't want to do that if your specifying outcomes of will_paginate. Remove

    view.stub(:will_paginate)

Next, Mislav's examples stub :paginate on the model, but yours stub :paginate on the view. I'm assuming that your view code has something like:

  <%= will_paginate @recurrences %>

and the controller code has something like:

  def index
    @recurrences = Recurrence.paginate :page => params[:page]
  end 

If that's correct, then you want to replace this:

  view.stub(:paginate).with(page: 1).and_return(recurrences.paginate(per_page: 2))

with

  Recurrence.stub(:paginate).with(page: 1).and_return(recurrences.paginate(per_page: 2))

Next, Mislav's examples do not interact with the database, but yours does by using FactoryGirl.create. The whole point of stubbing the data returned by paginate is to keep the examples running fast, so I'd replace

  let(:recurrences) do 
    [ FactoryGirl.create(:recurrence, scheduled_to: "2012-07-05"),
      FactoryGirl.create(:recurrence, scheduled_to: "2012-07-12"),
      FactoryGirl.create(:recurrence, scheduled_to: "2012-07-19") ]
  end

with

  let(:recurrences) do 
    [ FactoryGirl.build(:recurrence, scheduled_to: "2012-07-05"),
      FactoryGirl.build(:recurrence, scheduled_to: "2012-07-12"),
      FactoryGirl.build(:recurrence, scheduled_to: "2012-07-19") ]
  end

Lastly, if all you care about in this example is that div.paginate gets rendered, I'd simplify the whole thing to this:

describe "recurrences/index" do
  it "should have a pagination bar" do
    assign(:recurrences, [ FactoryGirl.create(:recurrence, scheduled_to: "2012-07-05") ])
    render
    expect(rendered).to have_selector('div', class: 'pagination') 
  end
end

It's much easier to read because everything is in 3 lines in one example, and there is no reason to have the extra instances of Recurrence to specify that the 'div.pagination' selector appears (you may not need any, in which case an empty array will do the job).

HTH,
David

netzfisch

unread,
May 18, 2013, 5:29:15 PM5/18/13
to rs...@googlegroups.com
Hi David,
thanks for your really fast and comprehensive answer, which helped me a lot. Especially your last - simplyfing - hint, lead to folllowing solution (see full version at https://gist.github.com/netzfisch/5605792)

it "should have a pagination bar" do
assign(:recurrences, recurrences.paginate(per_page: 2))
render
 
expect(rendered).to have_selector('div.pagination')
end

"will_paginate" only shows up, if you have more objects to show (here three recurrences) than fit at one page! Therefore I set the parameter "per_page: 2". Furthermore you have to explicit "require will_paginate/array"

I couldn't get the stubbed version https://gist.github.com/netzfisch/5605721 to work, because of the following error:

    ActionView::Template::Error:
    undefined method `total_pages' for #<Array:0xa18ba8c>

"Google" tells me, I can't call the paginate method on an array and should call it on a collection **or**

    require 'will_paginate/array

which I did, but not helped. I asked therefore Mislav at https://groups.google.com/d/msg/will_paginate/i2LCboRZWfs/DpGHi5Msc74J

Anyway I am happy - it's working,
thx h-)
Reply all
Reply to author
Forward
0 new messages