When writing a cucumber feature that involves pagination, the easiest thing to do is to create the required number of objects to generate pagination.
Given 31 tasks exist # pagination defaults to 30
The downside of course is speed. Creating a large number of complex objects can add a lot of extra wait time to your cucumber runs. In my case, although I only had a few scenarios that involved pagination, my per_page setting was 50 and the objects I was creating were complex. The end result was a extra couple of (unnecessary) minutes. It wasn’t too bad so I left myself a TODO to fix it one day and that day finally came.
What I wanted to do was to simply change the default per_page setting for pagination across my entire project when running my cucumber suite so that I could rewrite my steps like this:
Given 3 tasks exist # pagination defaults to 2
This is how I set it all up:
- DRYed up my code by pulling out explicit settings for the per_page option and setting a project-wide per_page setting for will_paginate as a constant in my environment.rb file
- set a different value for this constant in my test.rb file and allow it to override the default setting above
- modify my cucumber scenarios to use the new (smaller) per_page value
More specifically, I added the following to the end of config/environment.rb:
unless defined? DEFAULT_PER_PAGE
# see: http://groups.google.com/group/will_paginate/browse_thread/thread/eda47114e3127709
ActiveRecord::Base.instance_eval do
def per_page; 50; end
end
DEFAULT_PER_PAGE = ActiveRecord::Base.per_page
end
Then in config/environments/test.rb:
ActiveRecord::Base.instance_eval do def per_page; 2; end end DEFAULT_PER_PAGE = ActiveRecord::Base.per_page
This solution was specific to my needs. In particular, I needed a DEFAULT_PER_PAGE constant within my code. This meant I could also use it as the conditional in my environment.rb to only set the override if it hadn’t already been set. One alternative was to take this code out of environment.rb and into the specific environment files eg development.rb, production.rb. But I also have a training.rb and a staging.rb so for me I preferred to put it into the generic environment file and change the setting specifically in the test environment.
Also, if you want to silence the “already initialized constant” warnings, simply use the silence_warnings rails method to wrap your constant assignment:
silence_warnings { DEFAULT_PER_PAGE = ActiveRecord::Base.per_page }
I later had the need to turn off pagination entirely for some features. I did this by redefining the DEFAULT_PER_PAGE constant in a tagged before/after hook and setting it to a very large number. I initially used a class variable to keep track of the original DEFAULT_PER_PAGE value but this generated a “warning: class variable access from toplevel”. It worked but I didn’t like seeing this warning throughout my output.
The solution was to simply define another constant to hold the original default per page value.
In features/support/hooks.rb:
Before(‘@no-pagination’) do
ActiveRecord::Base.instance_eval do
def per_page; 1_000_000; end
end
silence_warnings { DEFAULT_PER_PAGE = ActiveRecord::Base.per_page }
end
After(‘@no-pagination’) do
ActiveRecord::Base.instance_eval do
def per_page; ORIGINAL_PER_PAGE; end
end
silence_warnings { DEFAULT_PER_PAGE = ActiveRecord::Base.per_page }
end
And modified my config/environments/test.rb:
DEFAULT_PER_PAGE = ORIGINAL_PER_PAGE = ActiveRecord::Base.per_page
So now for the features and scenarios that I require no pagination, I tag them with @no-pagination and it all works.