Michael MacDonald

Faster Cucumbering With Pagination

In Rails, Testing on November 25, 2010 at 5:30 pm

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.

Advertisements
  1. 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 }

  2. 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.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: