bootstrap-vue
Version:
With more than 85 components, over 45 available plugins, several directives, and 1000+ icons, BootstrapVue provides one of the most comprehensive implementations of the Bootstrap v4 component and grid system available for Vue.js v2.6, complete with extens
1,199 lines (1,065 loc) • 37.5 kB
JavaScript
import { mount } from '@vue/test-utils'
import { waitNT } from '../../../tests/utils'
import { isVisible, getBCR, contains } from '../../utils/dom'
import { BPagination } from './pagination'
const wrapperArrayToArray = wrapperArray => {
const array = []
for (let i = 0; i < wrapperArray.length; i++) {
array.push(wrapperArray.at(i))
}
return array
}
describe('pagination', () => {
it('renders with correct basic structure for root element', async () => {
const wrapper = mount(BPagination, {
propsData: {
totalRows: 1,
perPage: 1
}
})
expect(wrapper.element.tagName).toBe('UL')
// Classes
expect(wrapper.classes()).toContain('pagination')
expect(wrapper.classes()).toContain('b-pagination')
expect(wrapper.classes()).not.toContain('pagination-sm')
expect(wrapper.classes()).not.toContain('pagination-lg')
expect(wrapper.classes()).not.toContain('justify-content-center')
expect(wrapper.classes()).not.toContain('justify-content-end')
expect(wrapper.classes()).not.toContain('b-pagination-pills')
// Attributes
expect(wrapper.attributes('role')).toBe('menubar')
expect(wrapper.attributes('aria-disabled')).toBe('false')
expect(wrapper.attributes('aria-label')).toBe('Pagination')
wrapper.destroy()
})
it('renders with correct basic inner structure', async () => {
const wrapper = mount(BPagination, {
propsData: {
totalRows: 1,
perPage: 1,
value: 1
}
})
expect(wrapper.element.tagName).toBe('UL')
const lis = wrapper.findAll('li')
expect(lis).toBeDefined()
expect(lis.length).toBe(5)
lis.wrappers.forEach((li, index) => {
expect(li.classes()).toContain('page-item')
const pageLink = li.find('.page-link')
expect(pageLink).toBeDefined()
if (index === 2) {
expect(li.classes()).toContain('active')
expect(li.classes()).not.toContain('disabled')
expect(pageLink.element.tagName).toBe('BUTTON')
} else {
expect(li.classes()).not.toContain('active')
expect(li.classes()).toContain('disabled')
expect(pageLink.element.tagName).toBe('SPAN')
}
})
const first = lis.at(0)
const prev = lis.at(1)
const page = lis.at(2)
const next = lis.at(3)
const last = lis.at(4)
// Button content
expect(first.find('.page-link').text()).toEqual('«')
expect(prev.find('.page-link').text()).toEqual('‹')
expect(page.find('.page-link').text()).toEqual('1')
expect(next.find('.page-link').text()).toEqual('›')
expect(last.find('.page-link').text()).toEqual('»')
// Page button attrs
expect(page.find('.page-link').attributes('type')).toEqual('button')
expect(page.find('.page-link').attributes('role')).toEqual('menuitemradio')
expect(page.find('.page-link').attributes('aria-checked')).toEqual('true')
expect(page.find('.page-link').attributes('aria-posinset')).toEqual('1')
expect(page.find('.page-link').attributes('aria-setsize')).toEqual('1')
expect(page.find('.page-link').attributes('tabindex')).toEqual('0')
expect(page.find('.page-link').attributes('aria-label')).toEqual('Go to page 1')
wrapper.destroy()
})
it('renders scopedSlot page', async () => {
const scopes = []
const wrapper = mount(BPagination, {
propsData: {
totalRows: 3,
perPage: 1,
limit: 10,
value: 1
},
scopedSlots: {
page: scope => {
const pageNum = scope.page
scopes[pageNum - 1] = scope
return `Page ${scope.page}`
}
}
})
expect(wrapper).toBeDefined()
await waitNT(wrapper.vm)
expect(scopes.length).toBe(3)
expect(scopes[0]).toEqual({
page: 1,
content: '1',
active: true,
index: 0,
disabled: false
})
expect(scopes[1]).toEqual({
page: 2,
content: '2',
active: false,
index: 1,
disabled: false
})
expect(scopes[2]).toEqual({
page: 3,
content: '3',
active: false,
index: 2,
disabled: false
})
const $links = wrapper.findAll('button.page-link')
expect($links.length).toBe(5)
expect($links.at(0).text()).toBe('Page 1')
expect($links.at(1).text()).toBe('Page 2')
expect($links.at(2).text()).toBe('Page 3')
wrapper.destroy()
})
it('renders correct number of elements when total-rows changes', async () => {
const wrapper = mount(BPagination, {
propsData: {
size: 'sm',
totalRows: 1,
perPage: 1,
limit: 10
}
})
expect(wrapper.element.tagName).toBe('UL')
expect(wrapper.findAll('li').length).toBe(5)
await wrapper.setProps({
totalRows: 4
})
await waitNT(wrapper.vm)
expect(wrapper.element.tagName).toBe('UL')
expect(wrapper.findAll('li').length).toBe(8)
await wrapper.setProps({
perPage: 2
})
await waitNT(wrapper.vm)
expect(wrapper.element.tagName).toBe('UL')
expect(wrapper.findAll('li').length).toBe(6)
wrapper.destroy()
})
it('has class "b-pagination-pills" when prop pills is set', async () => {
const wrapper = mount(BPagination, {
propsData: {
pills: true,
totalRows: 1,
perPage: 1
}
})
expect(wrapper.element.tagName).toBe('UL')
// Classes
expect(wrapper.classes()).toContain('pagination')
expect(wrapper.classes()).toContain('b-pagination')
expect(wrapper.classes()).toContain('b-pagination-pills')
expect(wrapper.classes()).not.toContain('pagination-lg')
expect(wrapper.classes()).not.toContain('justify-content-center')
expect(wrapper.classes()).not.toContain('justify-content-end')
// Attributes
expect(wrapper.attributes('role')).toBe('menubar')
expect(wrapper.attributes('aria-disabled')).toBe('false')
expect(wrapper.attributes('aria-label')).toBe('Pagination')
wrapper.destroy()
})
it('has class "pagination-sm" when prop size="sm"', async () => {
const wrapper = mount(BPagination, {
propsData: {
size: 'sm',
totalRows: 1,
perPage: 1
}
})
expect(wrapper.element.tagName).toBe('UL')
// Classes
expect(wrapper.classes()).toContain('pagination')
expect(wrapper.classes()).toContain('b-pagination')
expect(wrapper.classes()).toContain('pagination-sm')
expect(wrapper.classes()).not.toContain('pagination-lg')
expect(wrapper.classes()).not.toContain('justify-content-center')
expect(wrapper.classes()).not.toContain('justify-content-end')
expect(wrapper.classes()).not.toContain('b-pagination-pills')
// Attributes
expect(wrapper.attributes('role')).toBe('menubar')
expect(wrapper.attributes('aria-disabled')).toBe('false')
expect(wrapper.attributes('aria-label')).toBe('Pagination')
wrapper.destroy()
})
it('has class "pagination-lg" when prop size="lg"', async () => {
const wrapper = mount(BPagination, {
propsData: {
size: 'lg',
totalRows: 1,
perPage: 1
}
})
expect(wrapper.element.tagName).toBe('UL')
// Classes
expect(wrapper.classes()).toContain('pagination')
expect(wrapper.classes()).toContain('b-pagination')
expect(wrapper.classes()).not.toContain('pagination-sm')
expect(wrapper.classes()).toContain('pagination-lg')
expect(wrapper.classes()).not.toContain('justify-content-center')
expect(wrapper.classes()).not.toContain('justify-content-end')
expect(wrapper.classes()).not.toContain('b-pagination-pills')
// Attributes
expect(wrapper.attributes('role')).toBe('menubar')
expect(wrapper.attributes('aria-disabled')).toBe('false')
expect(wrapper.attributes('aria-label')).toBe('Pagination')
wrapper.destroy()
})
it('has class "pagination-foo" when prop size="foo"', async () => {
const wrapper = mount(BPagination, {
propsData: {
size: 'foo',
totalRows: 1,
perPage: 1
}
})
expect(wrapper.element.tagName).toBe('UL')
// Classes
expect(wrapper.classes()).toContain('pagination-foo')
expect(wrapper.classes()).toContain('pagination')
expect(wrapper.classes()).toContain('b-pagination')
expect(wrapper.classes()).not.toContain('pagination-sm')
expect(wrapper.classes()).not.toContain('pagination-lg')
expect(wrapper.classes()).not.toContain('justify-content-center')
expect(wrapper.classes()).not.toContain('justify-content-end')
expect(wrapper.classes()).not.toContain('b-pagination-pills')
// Attributes
expect(wrapper.attributes('role')).toBe('menubar')
expect(wrapper.attributes('aria-disabled')).toBe('false')
expect(wrapper.attributes('aria-label')).toBe('Pagination')
wrapper.destroy()
})
it('has class "justify-content-center" when prop align="center"', async () => {
const wrapper = mount(BPagination, {
propsData: {
align: 'center',
totalRows: 1,
perPage: 1
}
})
expect(wrapper.element.tagName).toBe('UL')
// Classes
expect(wrapper.classes()).toContain('pagination')
expect(wrapper.classes()).toContain('b-pagination')
expect(wrapper.classes()).not.toContain('pagination-sm')
expect(wrapper.classes()).not.toContain('pagination-lg')
expect(wrapper.classes()).toContain('justify-content-center')
expect(wrapper.classes()).not.toContain('justify-content-end')
expect(wrapper.classes()).not.toContain('b-pagination-pills')
// Attributes
expect(wrapper.attributes('role')).toBe('menubar')
expect(wrapper.attributes('aria-disabled')).toBe('false')
expect(wrapper.attributes('aria-label')).toBe('Pagination')
wrapper.destroy()
})
it('has class "justify-content-end" when prop align="right"', async () => {
const wrapper = mount(BPagination, {
propsData: {
align: 'right',
totalRows: 1,
perPage: 1
}
})
expect(wrapper.element.tagName).toBe('UL')
// Classes
expect(wrapper.classes()).toContain('pagination')
expect(wrapper.classes()).toContain('b-pagination')
expect(wrapper.classes()).not.toContain('pagination-sm')
expect(wrapper.classes()).not.toContain('pagination-lg')
expect(wrapper.classes()).not.toContain('justify-content-center')
expect(wrapper.classes()).toContain('justify-content-end')
expect(wrapper.classes()).not.toContain('b-pagination-pills')
// Attributes
expect(wrapper.attributes('role')).toBe('menubar')
expect(wrapper.attributes('aria-disabled')).toBe('false')
expect(wrapper.attributes('aria-label')).toBe('Pagination')
wrapper.destroy()
})
it('has class "justify-content-end" when prop align="end"', async () => {
const wrapper = mount(BPagination, {
propsData: {
align: 'end',
totalRows: 1,
perPage: 1
}
})
expect(wrapper.element.tagName).toBe('UL')
// Classes
expect(wrapper.classes()).toContain('pagination')
expect(wrapper.classes()).toContain('b-pagination')
expect(wrapper.classes()).not.toContain('pagination-sm')
expect(wrapper.classes()).not.toContain('pagination-lg')
expect(wrapper.classes()).not.toContain('justify-content-center')
expect(wrapper.classes()).toContain('justify-content-end')
expect(wrapper.classes()).not.toContain('b-pagination-pills')
// Attributes
expect(wrapper.attributes('role')).toBe('menubar')
expect(wrapper.attributes('aria-disabled')).toBe('false')
expect(wrapper.attributes('aria-label')).toBe('Pagination')
wrapper.destroy()
})
it('has class "text-center" and "flex-fill" when prop align="fill"', async () => {
const wrapper = mount(BPagination, {
propsData: {
align: 'fill',
totalRows: 5,
perPage: 1,
limit: 4,
value: 3
}
})
expect(wrapper.element.tagName).toBe('UL')
// Classes
expect(wrapper.classes()).toContain('text-center')
expect(wrapper.classes()).toContain('pagination')
expect(wrapper.classes()).toContain('b-pagination')
expect(wrapper.classes()).not.toContain('pagination-sm')
expect(wrapper.classes()).not.toContain('pagination-lg')
expect(wrapper.classes()).not.toContain('justify-content-center')
expect(wrapper.classes()).not.toContain('justify-content-end')
expect(wrapper.classes()).not.toContain('b-pagination-pills')
expect(wrapper.findAll('li.flex-fill').length).toBe(8)
wrapper.destroy()
})
it('has correct number of links when `hide-ellipsis` is enabled', async () => {
const wrapper = mount(BPagination, {
propsData: {
hideEllipsis: true,
totalRows: 100,
perPage: 10,
value: 1
}
})
expect(wrapper.element.tagName).toBe('UL')
expect(wrapper.findAll('li').length).toBe(9)
await wrapper.setProps({ value: 5 })
await waitNT(wrapper.vm)
expect(wrapper.findAll('li').length).toBe(9)
wrapper.destroy()
})
it('has attribute aria-controls on page links when prop aria-controls is set', async () => {
const wrapper = mount(BPagination, {
propsData: {
hideGotoEndButtons: true,
hideEllipsis: true,
totalRows: 3,
perPage: 1,
value: 1,
ariaControls: 'foo'
}
})
expect(wrapper.element.tagName).toBe('UL')
expect(wrapper.findAll('li').length).toBe(5)
expect(wrapper.findAll('button.page-link').length).toBe(4)
expect(
wrapper
.findAll('button.page-link')
.wrappers.every(w => w.element.matches('[aria-controls="foo"]'))
).toBe(true)
await wrapper.setProps({
ariaControls: null
})
await waitNT(wrapper.vm)
expect(wrapper.findAll('li').length).toBe(5)
expect(wrapper.findAll('button.page-link').length).toBe(4)
expect(
wrapper.findAll('button.page-link').wrappers.every(w => w.find('[aria-controls]').exists())
).toBe(false)
wrapper.destroy()
})
it('has attribute aria-label on page links', async () => {
const wrapper = mount(BPagination, {
propsData: {
hideGotoEndButtons: true,
hideEllipsis: true,
totalRows: 3,
perPage: 1,
value: 1
}
})
expect(wrapper.element.tagName).toBe('UL')
expect(wrapper.findAll('li').length).toBe(5)
expect(wrapper.findAll('button').length).toBe(4)
expect(
wrapper
.findAll('button')
.at(0)
.attributes('aria-label')
).toBe('Go to page 1')
expect(
wrapper
.findAll('button')
.at(1)
.attributes('aria-label')
).toBe('Go to page 2')
expect(
wrapper
.findAll('button')
.at(2)
.attributes('aria-label')
).toBe('Go to page 3')
expect(
wrapper
.findAll('button')
.at(3)
.attributes('aria-label')
).toBe('Go to next page')
wrapper.destroy()
})
it('has all links disabled when prop disabled set', async () => {
const wrapper = mount(BPagination, {
propsData: {
totalRows: 3,
perPage: 1,
value: 1,
disabled: true
}
})
expect(wrapper.element.tagName).toBe('UL')
expect(wrapper.findAll('li').length).toBe(7)
expect(wrapper.findAll('.page-item').length).toBe(7)
expect(
wrapper.findAll('.page-item').wrappers.every(w => w.element.matches('li.page-item.disabled'))
).toBe(true)
expect(
wrapper.findAll('.page-link').wrappers.every(w => w.element.matches('span.page-link'))
).toBe(true)
expect(
wrapper
.findAll('.page-link')
.at(2)
.attributes('aria-disabled')
).toBe('true')
expect(
wrapper
.findAll('.page-link')
.at(3)
.attributes('aria-disabled')
).toBe('true')
expect(
wrapper
.findAll('.page-link')
.at(4)
.attributes('aria-disabled')
).toBe('true')
wrapper.destroy()
})
it('renders classes bv-d-xs-down-none when more than 3 pages', async () => {
const wrapper = mount(BPagination, {
propsData: {
totalRows: 70,
perPage: 10,
limit: 7,
value: 1
}
})
expect(wrapper.element.tagName).toBe('UL')
const lis = wrapper.findAll('li')
expect(lis).toBeDefined()
// Including bookend buttons
expect(lis.length).toBe(11)
// Should have the last 4 page buttons with the
// display classes when currentPage = 0
expect(wrapper.vm.computedCurrentPage).toBe(1)
// Grab the page buttons (includes bookends)
wrapper.findAll('li').wrappers.forEach((li, index) => {
expect(li.classes()).toContain('page-item')
if (index === 0) {
// First button
expect(li.classes()).toContain('disabled')
} else if (index === 1) {
// Prev button
expect(li.classes()).toContain('disabled')
} else if (index === 9) {
// Next button
expect(li.classes()).not.toContain('disabled')
} else if (index === 10) {
// Last button
expect(li.classes()).not.toContain('disabled')
} else {
// Page number buttons
if (index === 2) {
expect(li.classes()).toContain('active')
} else {
expect(li.classes()).not.toContain('active')
}
if (index < 5) {
expect(li.classes()).not.toContain('bv-d-xs-down-none')
} else if (index > 4) {
expect(li.classes()).toContain('bv-d-xs-down-none')
}
}
})
// Should have the first and last 2 pages buttons with the
// display classes when currentPage = 4
await wrapper.setProps({
value: '4'
})
await waitNT(wrapper.vm)
expect(wrapper.vm.computedCurrentPage).toBe(4)
// Grab the page buttons (including bookends)
wrapper.findAll('li').wrappers.forEach((li, index) => {
expect(li.classes()).toContain('page-item')
if (index === 0) {
// First button
expect(li.classes()).not.toContain('disabled')
} else if (index === 1) {
// Prev button
expect(li.classes()).not.toContain('disabled')
} else if (index === 9) {
// Next button
expect(li.classes()).not.toContain('disabled')
} else if (index === 10) {
// Last button
expect(li.classes()).not.toContain('disabled')
} else {
// Page number buttons
if (index === 5) {
expect(li.classes()).toContain('active')
} else {
expect(li.classes()).not.toContain('active')
}
if (index > 3 && index < 7) {
expect(li.classes()).not.toContain('bv-d-xs-down-none')
} else if (index < 4 || index > 6) {
expect(li.classes()).toContain('bv-d-xs-down-none')
}
}
})
// Should have the first 4 pages buttons with the
// display classes when currentPage = 4
await wrapper.setProps({
value: '7'
})
await waitNT(wrapper.vm)
expect(wrapper.vm.computedCurrentPage).toBe(7)
// Grab the page buttons (including bookends)
wrapper.findAll('li').wrappers.forEach((li, index) => {
expect(li.classes()).toContain('page-item')
// Page number buttons
if (index >= 2 && index <= 5) {
// Pages 1 to 4
expect(li.classes()).toContain('bv-d-xs-down-none')
} else if (index >= 6 && index <= 8) {
// Pages 5 to 7
expect(li.classes()).not.toContain('bv-d-xs-down-none')
}
})
wrapper.destroy()
})
it('places ellipsis in correct places', async () => {
const wrapper = mount(BPagination, {
propsData: {
totalRows: 70,
perPage: 10,
limit: 5,
value: 1
}
})
expect(wrapper.element.tagName).toBe('UL')
// Should have ellipsis in place of last button
// When currentPage = 0
expect(wrapper.vm.computedCurrentPage).toBe(1)
// Grab the page buttons
let lis = wrapper.findAll('li')
expect(lis.length).toBe(9)
expect(lis.at(2).attributes('role')).not.toBe('separator')
expect(lis.at(6).attributes('role')).toBe('separator')
// Should have both ellipsis showing when currentPage = 4
await wrapper.setProps({
value: '4'
})
await waitNT(wrapper.vm)
expect(wrapper.vm.computedCurrentPage).toBe(4)
lis = wrapper.findAll('li')
expect(lis.length).toBe(9)
expect(lis.at(2).attributes('role')).toBe('separator')
expect(lis.at(6).attributes('role')).toBe('separator')
// Should have first ellipsis showing when currentPage = 5
await wrapper.setProps({
value: 5
})
await waitNT(wrapper.vm)
expect(wrapper.vm.computedCurrentPage).toBe(5)
lis = wrapper.findAll('li')
expect(lis.length).toBe(9)
expect(lis.at(2).attributes('role')).toBe('separator')
expect(lis.at(6).attributes('role')).not.toBe('separator')
wrapper.destroy()
})
it('clicking buttons updates the v-model', async () => {
const App = {
methods: {
onPageClick(bvEvent, page) {
// Prevent 3rd page from being selected
if (page === 3) {
bvEvent.preventDefault()
}
}
},
render(h) {
return h(BPagination, {
props: {
totalRows: 5,
perPage: 1,
value: 1
},
on: { 'page-click': this.onPageClick }
})
}
}
const wrapper = mount(App)
expect(wrapper).toBeDefined()
const pagination = wrapper.findComponent(BPagination)
expect(pagination).toBeDefined()
expect(pagination.element.tagName).toBe('UL')
// Grab the page buttons
const lis = pagination.findAll('li')
expect(lis.length).toBe(9)
expect(pagination.vm.computedCurrentPage).toBe(1)
expect(pagination.emitted('input')).not.toBeDefined()
expect(pagination.emitted('change')).not.toBeDefined()
expect(pagination.emitted('page-click')).not.toBeDefined()
// Click on current (1st) page button (does nothing)
await lis
.at(2)
.find('button')
.trigger('click')
expect(pagination.vm.computedCurrentPage).toBe(1)
expect(pagination.emitted('input')).not.toBeDefined()
expect(pagination.emitted('change')).not.toBeDefined()
expect(pagination.emitted('page-click')).not.toBeDefined()
// Click on 2nd button
await lis
.at(3)
.find('button')
.trigger('click')
expect(pagination.vm.computedCurrentPage).toBe(2)
expect(pagination.emitted('input')).toBeDefined()
expect(pagination.emitted('change')).toBeDefined()
expect(pagination.emitted('page-click')).toBeDefined()
expect(pagination.emitted('input')[0][0]).toBe(2)
expect(pagination.emitted('change')[0][0]).toBe(2)
expect(pagination.emitted('page-click').length).toBe(1)
// Click goto last button
await lis
.at(8)
.find('button')
.trigger('keydown.space') // Generates a click event
expect(pagination.vm.computedCurrentPage).toBe(5)
expect(pagination.emitted('input')[1][0]).toBe(5)
expect(pagination.emitted('change')[1][0]).toBe(5)
expect(pagination.emitted('page-click').length).toBe(2)
// Click prev button
await lis
.at(1)
.find('button')
.trigger('click')
expect(pagination.vm.computedCurrentPage).toBe(4)
expect(pagination.emitted('input')[2][0]).toBe(4)
expect(pagination.emitted('change')[2][0]).toBe(4)
expect(pagination.emitted('page-click').length).toBe(3)
// Click on 3rd button (prevented)
await lis
.at(4)
.find('button')
.trigger('click')
expect(pagination.vm.computedCurrentPage).toBe(4)
expect(pagination.emitted('input').length).toBe(3)
expect(pagination.emitted('change').length).toBe(3)
expect(pagination.emitted('page-click').length).toBe(4)
wrapper.destroy()
})
it('changing the limit changes the number of buttons shown', async () => {
const wrapper = mount(BPagination, {
propsData: {
totalRows: 9,
perPage: 1,
value: 5,
limit: 10
}
})
expect(wrapper.element.tagName).toBe('UL')
// Should be 13 <li> total
expect(wrapper.findAll('li').length).toBe(13)
await wrapper.setProps({
limit: 4
})
await waitNT(wrapper.vm)
// Should be 8 <li> total
expect(wrapper.findAll('li').length).toBe(8)
wrapper.destroy()
})
it('changing the number of pages to less than current page number resets to page 1', async () => {
// https://github.com/bootstrap-vue/bootstrap-vue/issues/3716
const wrapper = mount(BPagination, {
propsData: {
totalRows: 10,
perPage: 1,
value: 10, // Set to last page
limit: 20
}
})
expect(wrapper.vm).toBeDefined()
expect(wrapper.vm.currentPage).toBe(10)
expect(wrapper.emitted('input')).not.toBeDefined()
// Change total rows to larger value. Should not change page number
await wrapper.setProps({
totalRows: 20
})
await waitNT(wrapper.vm)
expect(wrapper.vm.currentPage).toBe(10)
expect(wrapper.emitted('input')).not.toBeDefined()
// Change to page 20
await wrapper.setProps({
value: 20
})
await waitNT(wrapper.vm)
expect(wrapper.vm.currentPage).toBe(20)
expect(wrapper.emitted('input')).toBeDefined()
expect(wrapper.emitted('input').length).toBe(1)
expect(wrapper.emitted('input')[0][0]).toBe(20)
// Decrease number of pages should reset to page 1
await wrapper.setProps({
totalRows: 10
})
await waitNT(wrapper.vm)
expect(wrapper.vm.currentPage).toBe(1)
expect(wrapper.emitted('input').length).toBe(2)
expect(wrapper.emitted('input')[1][0]).toBe(1)
// Change to page 3
await wrapper.setProps({
value: 3
})
await waitNT(wrapper.vm)
expect(wrapper.vm.currentPage).toBe(3)
expect(wrapper.emitted('input').length).toBe(3)
expect(wrapper.emitted('input')[2][0]).toBe(3)
// Decrease number of pages to 5 should not reset to page 1
await wrapper.setProps({
totalRows: 5
})
await waitNT(wrapper.vm)
expect(wrapper.vm.currentPage).toBe(3)
expect(wrapper.emitted('input').length).toBe(3)
wrapper.destroy()
})
it('changing per-page resets to page 1', async () => {
// https://github.com/bootstrap-vue/bootstrap-vue/issues/2987
const wrapper = mount(BPagination, {
propsData: {
totalRows: 10,
perPage: 1,
value: 4,
limit: 20
}
})
expect(wrapper.vm).toBeDefined()
expect(wrapper.vm.currentPage).toBe(4)
expect(wrapper.emitted('input')).not.toBeDefined()
// Change perPage
await wrapper.setProps({
perPage: 2
})
await waitNT(wrapper.vm)
expect(wrapper.vm.currentPage).toBe(1)
expect(wrapper.emitted('input')).toBeDefined()
expect(wrapper.emitted('input').length).toBe(1)
expect(wrapper.emitted('input')[0][0]).toBe(1)
// Change page to 3
await wrapper.setProps({
value: 3
})
await waitNT(wrapper.vm)
expect(wrapper.vm.currentPage).toBe(3)
expect(wrapper.emitted('input').length).toBe(2)
expect(wrapper.emitted('input')[1][0]).toBe(3)
// Change perPage. Should reset to page 1, even though
// current page is within range of numberOfPages
await wrapper.setProps({
perPage: 1
})
await waitNT(wrapper.vm)
expect(wrapper.vm.currentPage).toBe(1)
expect(wrapper.emitted('input').length).toBe(3)
expect(wrapper.emitted('input')[2][0]).toBe(1)
wrapper.destroy()
})
it('fist-number and last-number props work', async () => {
const selector = '.page-item .page-link'
let items = []
const wrapper = mount(BPagination, {
propsData: {
value: 1,
totalRows: 10,
perPage: 1,
limit: 5,
firstNumber: true,
lastNumber: true
}
})
expect(wrapper.vm).toBeDefined()
await waitNT(wrapper.vm)
expect(wrapper.findAll(selector).length).toBe(9)
items = wrapperArrayToArray(wrapper.findAll(selector)).map(w => w.text())
expect(items).toEqual(['‹', '1', '2', '3', '4', '5', '…', '10', '›'])
await wrapper.setProps({
value: 2
})
await waitNT(wrapper.vm)
items = wrapperArrayToArray(wrapper.findAll(selector)).map(w => w.text())
expect(items).toEqual(['‹', '1', '2', '3', '4', '5', '…', '10', '›'])
await wrapper.setProps({
value: 3
})
await waitNT(wrapper.vm)
items = wrapperArrayToArray(wrapper.findAll(selector)).map(w => w.text())
expect(items).toEqual(['‹', '1', '2', '3', '4', '5', '…', '10', '›'])
await wrapper.setProps({
value: 4
})
await waitNT(wrapper.vm)
items = wrapperArrayToArray(wrapper.findAll(selector)).map(w => w.text())
expect(items).toEqual(['‹', '1', '2', '3', '4', '5', '…', '10', '›'])
await wrapper.setProps({
value: 5
})
await waitNT(wrapper.vm)
items = wrapperArrayToArray(wrapper.findAll(selector)).map(w => w.text())
expect(items).toEqual(['‹', '1', '…', '4', '5', '6', '…', '10', '›'])
await wrapper.setProps({
value: 6
})
await waitNT(wrapper.vm)
items = wrapperArrayToArray(wrapper.findAll(selector)).map(w => w.text())
expect(items).toEqual(['‹', '1', '…', '5', '6', '7', '…', '10', '›'])
await wrapper.setProps({
value: 7
})
await waitNT(wrapper.vm)
items = wrapperArrayToArray(wrapper.findAll(selector)).map(w => w.text())
expect(items).toEqual(['‹', '1', '…', '6', '7', '8', '9', '10', '›'])
await wrapper.setProps({
value: 8
})
await waitNT(wrapper.vm)
items = wrapperArrayToArray(wrapper.findAll(selector)).map(w => w.text())
expect(items).toEqual(['‹', '1', '…', '6', '7', '8', '9', '10', '›'])
await wrapper.setProps({
value: 9
})
await waitNT(wrapper.vm)
items = wrapperArrayToArray(wrapper.findAll(selector)).map(w => w.text())
expect(items).toEqual(['‹', '1', '…', '6', '7', '8', '9', '10', '›'])
await wrapper.setProps({
value: 10
})
await waitNT(wrapper.vm)
items = wrapperArrayToArray(wrapper.findAll(selector)).map(w => w.text())
expect(items).toEqual(['‹', '1', '…', '6', '7', '8', '9', '10', '›'])
wrapper.destroy()
})
it('fist-number and last-number props work with limit <=3', async () => {
const selector = '.page-item .page-link'
let items = []
const wrapper = mount(BPagination, {
propsData: {
value: 1,
totalRows: 10,
perPage: 1,
limit: 3,
firstNumber: true,
lastNumber: true
}
})
expect(wrapper.vm).toBeDefined()
await waitNT(wrapper.vm)
expect(wrapper.findAll(selector).length).toBe(7)
items = wrapperArrayToArray(wrapper.findAll(selector)).map(w => w.text())
expect(items).toEqual(['‹', '1', '2', '3', '4', '10', '›'])
await wrapper.setProps({
value: 2
})
await waitNT(wrapper.vm)
items = wrapperArrayToArray(wrapper.findAll(selector)).map(w => w.text())
expect(items).toEqual(['‹', '1', '2', '3', '4', '10', '›'])
await wrapper.setProps({
value: 3
})
await waitNT(wrapper.vm)
items = wrapperArrayToArray(wrapper.findAll(selector)).map(w => w.text())
expect(items).toEqual(['‹', '1', '2', '3', '4', '10', '›'])
await wrapper.setProps({
value: 4
})
await waitNT(wrapper.vm)
items = wrapperArrayToArray(wrapper.findAll(selector)).map(w => w.text())
expect(items).toEqual(['‹', '1', '3', '4', '5', '10', '›'])
await wrapper.setProps({
value: 5
})
await waitNT(wrapper.vm)
items = wrapperArrayToArray(wrapper.findAll(selector)).map(w => w.text())
expect(items).toEqual(['‹', '1', '4', '5', '6', '10', '›'])
await wrapper.setProps({
value: 6
})
await waitNT(wrapper.vm)
items = wrapperArrayToArray(wrapper.findAll(selector)).map(w => w.text())
expect(items).toEqual(['‹', '1', '5', '6', '7', '10', '›'])
await wrapper.setProps({
value: 7
})
await waitNT(wrapper.vm)
items = wrapperArrayToArray(wrapper.findAll(selector)).map(w => w.text())
expect(items).toEqual(['‹', '1', '6', '7', '8', '10', '›'])
await wrapper.setProps({
value: 8
})
await waitNT(wrapper.vm)
items = wrapperArrayToArray(wrapper.findAll(selector)).map(w => w.text())
expect(items).toEqual(['‹', '1', '7', '8', '9', '10', '›'])
await wrapper.setProps({
value: 9
})
await waitNT(wrapper.vm)
items = wrapperArrayToArray(wrapper.findAll(selector)).map(w => w.text())
expect(items).toEqual(['‹', '1', '7', '8', '9', '10', '›'])
await wrapper.setProps({
value: 10
})
await waitNT(wrapper.vm)
items = wrapperArrayToArray(wrapper.findAll(selector)).map(w => w.text())
expect(items).toEqual(['‹', '1', '7', '8', '9', '10', '›'])
wrapper.destroy()
})
// These tests are wrapped in a new describe to limit the scope of the getBCR Mock
describe('pagination keyboard navigation', () => {
const origGetBCR = Element.prototype.getBoundingClientRect
beforeEach(() => {
// Mock `getBoundingClientRect()` so that the `isVisible(el)` test returns `true`
// In our test below, all pagination buttons would normally be visible
Element.prototype.getBoundingClientRect = jest.fn(() => ({
width: 24,
height: 24,
top: 0,
left: 0,
bottom: 0,
right: 0
}))
})
afterEach(() => {
// Restore prototype
Element.prototype.getBoundingClientRect = origGetBCR
})
it('keyboard navigation works', async () => {
const wrapper = mount(BPagination, {
propsData: {
totalRows: 3,
perPage: 1,
value: 2,
limit: 3
},
attachTo: document.body
})
await waitNT(wrapper.vm)
expect(wrapper.element.tagName).toBe('UL')
await waitNT(wrapper.vm)
// Grab the button links (2 bookends + 3 pages + 2 bookends)
const links = wrapper.findAll('button.page-link')
expect(links.length).toBe(7)
// Sanity check for getBCR override
expect(wrapper.element.getBoundingClientRect().width).toBe(24)
expect(getBCR(links.at(3).element).width).toBe(24)
expect(contains(document.body, links.at(3).element)).toBe(true)
expect(isVisible(links.at(3).element)).toBe(true)
// Focus the active button
links.at(3).element.focus()
await waitNT(wrapper.vm)
expect(document.activeElement).toEqual(links.at(3).element)
// LEFT
await wrapper.trigger('keydown.left')
expect(document.activeElement).toEqual(links.at(2).element)
// RIGHT
await links.at(2).trigger('keydown.right')
expect(document.activeElement).toEqual(links.at(3).element)
// UP (same as LEFT)
await wrapper.trigger('keydown.up')
expect(document.activeElement).toEqual(links.at(2).element)
// DOWN (same as RIGHT)
await links.at(2).trigger('keydown.down')
expect(document.activeElement).toEqual(links.at(3).element)
// SHIFT-RIGHT
await links.at(2).trigger('keydown.right', { shiftKey: true })
expect(document.activeElement).toEqual(links.at(6).element)
// SHIFT-LEFT
await links.at(6).trigger('keydown.left', { shiftKey: true })
expect(document.activeElement).toEqual(links.at(0).element)
wrapper.destroy()
})
it('internal method focusCurrent() works', async () => {
const wrapper = mount(BPagination, {
propsData: {
totalRows: 3,
perPage: 1,
value: 2,
limit: 3
},
attachTo: document.body
})
await waitNT(wrapper.vm)
expect(wrapper.element.tagName).toBe('UL')
// Grab the button links (2 bookends + 3 pages + 2 bookends)
const links = wrapper.findAll('button.page-link')
expect(links.length).toBe(7)
// Focus the last button
links.at(6).element.focus()
await waitNT(wrapper.vm)
expect(document.activeElement).toEqual(links.at(6).element)
wrapper.vm.focusCurrent()
await waitNT(wrapper.vm)
expect(document.activeElement).toEqual(links.at(3).element)
wrapper.destroy()
})
it('Current page button is focused when button display changes', async () => {
const wrapper = mount(BPagination, {
propsData: {
totalRows: 10,
perPage: 1,
value: 1,
limit: 5
},
attachTo: document.body
})
let links
await waitNT(wrapper.vm)
expect(wrapper.element.tagName).toBe('UL')
// Grab the button links (2 disabled bookends + 4 pages + (-ellipsis) + 2 bookends)
links = wrapper.findAll('button.page-link')
expect(links.length).toBe(6)
// Click on the 4th button (page 4, index 3)
links.at(3).element.click()
await waitNT(wrapper.vm)
// Links re-rendered with first bookends enabled and an ellipsis
links = wrapper.findAll('button.page-link')
// The 4th link should be page 4, and retain focus
expect(document.activeElement).toEqual(links.at(3).element)
wrapper.destroy()
})
})
})