Testing ActiveRecord Pagination Scopes in Kaminari
This test suite validates pagination functionality in the Kaminari gem, focusing on ActiveRecord model extensions and scoping behaviors. It comprehensively tests page navigation, per-page limits, and pagination state management across different model types.
Test Coverage Overview
Implementation Analysis
Technical Details
Best Practices Demonstrated
kaminari/kaminari
kaminari-core/test/models/active_record/scopes_test.rb
# frozen_string_literal: true
require 'test_helper'
if defined? ActiveRecord
class ActiveRecordModelExtensionTest < ActiveSupport::TestCase
test 'Changing page_method_name' do
begin
Kaminari.configure {|config| config.page_method_name = :per_page_kaminari }
model = Class.new ActiveRecord::Base
assert_respond_to model, :per_page_kaminari
assert_not_respond_to model, :page
ensure
Kaminari.configure {|config| config.page_method_name = :page }
end
end
end
class ActiveRecordExtensionTest < ActiveSupport::TestCase
def assert_first_page(relation)
assert_equal 25, relation.count
assert_equal 'user001', relation.first.name
end
def assert_blank_page(relation)
assert_equal 0, relation.count
end
class << self
def startup
[User, GemDefinedModel, Device].each do |m|
1.upto(100) {|i| m.create! name: "user#{'%03d' % i}", age: (i / 10)}
end
super
end
def shutdown
[User, GemDefinedModel, Device].each(&:delete_all)
super
end
end
[User, Admin, GemDefinedModel, Device].each do |model_class|
sub_test_case "for #{model_class}" do
sub_test_case '#page' do
test 'page 1' do
assert_first_page model_class.page(1)
end
test 'page 2' do
relation = model_class.page 2
assert_equal 25, relation.count
assert_equal 'user026', relation.first.name
end
test 'page without an argument' do
assert_first_page model_class.page
end
test 'page < 1' do
assert_first_page model_class.page(0)
end
test 'page > max page' do
assert_blank_page model_class.page(5)
end
test 'invalid page as a Hash' do
assert_first_page model_class.page(page: { hacked: 100 })
end
test 'invalid page as a Array' do
assert_first_page model_class.page(page: [2, 3])
end
test 'ensure #order_values is preserved' do
relation = model_class.order('id').page 1
assert_equal ['id'], relation.order_values.uniq
end
end
sub_test_case '#per' do
test 'page 1 per 5' do
relation = model_class.page(1).per(5)
assert_equal 5, relation.count
assert_equal 'user001', relation.first.name
end
test 'page 1 per 5 with max_per_page < 5' do
begin
model_class.max_paginates_per 4
relation = model_class.page(1).per(5)
assert_equal 4, relation.count
ensure
model_class.max_paginates_per nil
end
end
test 'page 1 per nil (using default)' do
assert_equal model_class.default_per_page, model_class.page(1).per(nil).count
end
test 'page 1 per nil with max_per_page > default_per_page' do
begin
model_class.max_paginates_per(30)
assert_equal 25, model_class.page(1).per(nil).count
ensure
model_class.max_paginates_per(nil)
end
end
test 'page 1 per nil with max_per_page < default_per_page' do
begin
model_class.max_paginates_per(10)
assert_equal 10, model_class.page(1).per(nil).count
ensure
model_class.max_paginates_per(nil)
end
end
test 'page 1 per 0' do
assert_equal 0, model_class.page(1).per(0).count
end
# I know it's a bit strange to have this here, but I couldn't find any better place for this case
sub_test_case 'when max_per_page is given via model class, and `per` is not actually called' do
test 'with max_per_page > default_per_page' do
begin
model_class.max_paginates_per(200)
assert_equal 25, model_class.page(1).count
ensure
model_class.max_paginates_per(nil)
end
end
test 'with max_per_page < default_per_page' do
begin
model_class.max_paginates_per(5)
assert_equal 5, model_class.page(1).count
ensure
model_class.max_paginates_per(nil)
end
end
end
end
sub_test_case '#max_paginates_per' do
setup do
model_class.max_paginates_per(10)
end
teardown do
model_class.max_paginates_per(nil)
end
sub_test_case 'calling max_paginates_per() after per()' do
test 'when #max_paginates_per is greater than #per' do
assert_equal 15, model_class.page(1).per(15).max_paginates_per(20).count
end
test 'when #per is greater than #max_paginates_per' do
assert_equal 20, model_class.page(1).per(30).max_paginates_per(20).count
end
test 'when nil is given to #per and #max_paginates_per is specified' do
assert_equal 20, model_class.page(1).per(nil).max_paginates_per(20).count
end
end
sub_test_case 'calling max_paginates_per() before per()' do
test 'when #max_paginates_per is greater than #per' do
assert_equal 15, model_class.page(1).max_paginates_per(20).per(15).count
end
test 'when #per is greater than #max_paginates_per' do
assert_equal 20, model_class.page(1).max_paginates_per(20).per(30).count
end
test 'when nil is given to #per and #max_paginates_per is specified' do
assert_equal 20, model_class.page(1).max_paginates_per(20).per(nil).count
end
end
sub_test_case 'calling max_paginates_per() without per()' do
test 'when #max_paginates_per is greater than the default per_page' do
assert_equal 20, model_class.page(1).max_paginates_per(20).count
end
test 'when #max_paginates_per is less than the default per_page' do
assert_equal 25, model_class.page(1).max_paginates_per(30).count
end
end
end
sub_test_case '#padding' do
test 'page 1 per 5 padding 1' do
relation = model_class.page(1).per(5).padding(1)
assert_equal 5, relation.count
assert_equal 'user002', relation.first.name
end
test 'page 1 per 5 padding "1" (as string)' do
relation = model_class.page(1).per(5).padding('1')
assert_equal 5, relation.count
assert_equal 'user002', relation.first.name
end
test 'page 19 per 5 padding 5' do
relation = model_class.page(19).per(5).padding(5)
assert_equal 19, relation.current_page
assert_equal 19, relation.total_pages
end
test 'Negative padding' do
assert_raise(ArgumentError) { model_class.page(1).per(5).padding(-1) }
end
end
sub_test_case '#total_pages' do
test 'per 25 (default)' do
assert_equal 4, model_class.page.total_pages
end
test 'per 7' do
assert_equal 15, model_class.page(2).per(7).total_pages
end
test 'per 65536' do
assert_equal 1, model_class.page(50).per(65536).total_pages
end
test 'per 0' do
assert_raise Kaminari::ZeroPerPageOperation do
model_class.page(50).per(0).total_pages
end
end
test 'per -1 (using default)' do
assert_equal 4, model_class.page(5).per(-1).total_pages
end
test 'per "String value that can not be converted into Number" (using default)' do
assert_equal 4, model_class.page(5).per('aho').total_pages
end
test 'with max_pages < total pages count from database' do
begin
model_class.max_pages 3
assert_equal 3, model_class.page.total_pages
ensure
model_class.max_pages nil
end
end
test 'with max_pages > total pages count from database' do
begin
model_class.max_pages 11
assert_equal 4, model_class.page.total_pages
ensure
model_class.max_pages nil
end
end
test 'with max_pages is nil (default)' do
model_class.max_pages nil
assert_equal 4, model_class.page.total_pages
end
test 'with per(nil) using default' do
assert_equal 4, model_class.page.per(nil).total_pages
end
end
sub_test_case '#current_page' do
test 'any page, per 0' do
assert_raise Kaminari::ZeroPerPageOperation do
model_class.page.per(0).current_page
end
end
test 'page 1' do
assert_equal 1, model_class.page.current_page
end
test 'page 2' do
assert_equal 2, model_class.page(2).per(3).current_page
end
end
sub_test_case '#current_per_page' do
test 'per 0' do
assert_equal 0, model_class.page.per(0).current_per_page
end
test 'no per specified' do
assert_equal model_class.default_per_page, model_class.page.current_per_page
end
test 'per specified as 42' do
assert_equal 42, model_class.page.per(42).current_per_page
end
end
sub_test_case '#next_page' do
test 'page 1' do
assert_equal 2, model_class.page.next_page
end
test 'page 5' do
assert_nil model_class.page(5).next_page
end
end
sub_test_case '#prev_page' do
test 'page 1' do
assert_nil model_class.page.prev_page
end
test 'page 3' do
assert_equal 2, model_class.page(3).prev_page
end
test 'page 5' do
assert_nil model_class.page(5).prev_page
end
end
sub_test_case '#first_page?' do
test 'on first page' do
assert_true model_class.page(1).per(10).first_page?
end
test 'not on first page' do
assert_false model_class.page(5).per(10).first_page?
end
end
sub_test_case '#last_page?' do
test 'on last page' do
assert_true model_class.page(10).per(10).last_page?
end
test 'within range' do
assert_false model_class.page(1).per(10).last_page?
end
test 'out of range' do
assert_false model_class.page(11).per(10).last_page?
end
end
sub_test_case '#out_of_range?' do
test 'on last page' do
assert_false model_class.page(10).per(10).out_of_range?
end
test 'within range' do
assert_false model_class.page(1).per(10).out_of_range?
end
test 'out of range' do
assert_true model_class.page(11).per(10).out_of_range?
end
end
sub_test_case '#count' do
test 'page 1' do
assert_equal 25, model_class.page.count
end
test 'page 2' do
assert_equal 25, model_class.page(2).count
end
end
test 'chained with .group' do
relation = model_class.group('age').page(2).per 5
# 0..10
assert_equal 11, relation.total_count
assert_equal 3, relation.total_pages
end
test 'activerecord descendants' do
assert_not_equal 0, ActiveRecord::Base.descendants.length
end
end
end
end
end