UNPKG

bootstrap-vue

Version:

BootstrapVue, with over 40 plugins and more than 80 custom components, custom directives, and over 300 icons, provides one of the most comprehensive implementations of Bootstrap v4 components and grid system for Vue.js. With extensive and automated WAI-AR

1,139 lines (1,012 loc) 35.2 kB
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.is('ul')).toBe(true) // 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.is('ul')).toBe(true) 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.is('a')).toBe(true) } else { expect(li.classes()).not.toContain('active') expect(li.classes()).toContain('disabled') expect(pageLink.is('span')).toBe(true) } }) 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('href')).toEqual('#') 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') expect(page.find('.page-link').attributes('target')).toEqual('_self') 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('a.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.is('ul')).toBe(true) expect(wrapper.findAll('li').length).toBe(5) wrapper.setProps({ totalRows: 4 }) await waitNT(wrapper.vm) expect(wrapper.is('ul')).toBe(true) expect(wrapper.findAll('li').length).toBe(8) wrapper.setProps({ perPage: 2 }) await waitNT(wrapper.vm) expect(wrapper.is('ul')).toBe(true) 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.is('ul')).toBe(true) // 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.is('ul')).toBe(true) // 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.is('ul')).toBe(true) // 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.is('ul')).toBe(true) // 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.is('ul')).toBe(true) // 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.is('ul')).toBe(true) // 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.is('ul')).toBe(true) // 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.is('ul')).toBe(true) // 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 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.is('ul')).toBe(true) expect(wrapper.findAll('li').length).toBe(5) expect(wrapper.findAll('a.page-link').length).toBe(4) expect(wrapper.findAll('a.page-link').is('[aria-controls="foo"]')).toBe(true) wrapper.setProps({ ariaControls: null }) await waitNT(wrapper.vm) expect(wrapper.findAll('li').length).toBe(5) expect(wrapper.findAll('a.page-link').length).toBe(4) expect(wrapper.findAll('a.page-link').is('[aria-controls]')).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.is('ul')).toBe(true) expect(wrapper.findAll('li').length).toBe(5) expect(wrapper.findAll('a').length).toBe(4) expect( wrapper .findAll('a') .at(0) .attributes('aria-label') ).toBe('Go to page 1') expect( wrapper .findAll('a') .at(1) .attributes('aria-label') ).toBe('Go to page 2') expect( wrapper .findAll('a') .at(2) .attributes('aria-label') ).toBe('Go to page 3') expect( wrapper .findAll('a') .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.is('ul')).toBe(true) expect(wrapper.findAll('li').length).toBe(7) expect(wrapper.findAll('.page-item').length).toBe(7) expect(wrapper.findAll('.page-item').is('li.page-item.disabled')).toBe(true) expect(wrapper.findAll('.page-link').is('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.is('ul')).toBe(true) 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 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 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.is('ul')).toBe(true) // 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 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 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 wrapper = mount(BPagination, { propsData: { totalRows: 3, perPage: 1, value: 1 } }) expect(wrapper.is('ul')).toBe(true) // Grab the page buttons const lis = wrapper.findAll('li') expect(lis.length).toBe(7) expect(wrapper.vm.computedCurrentPage).toBe(1) expect(wrapper.emitted('input')).not.toBeDefined() expect(wrapper.emitted('change')).not.toBeDefined() // Click on 2nd button wrapper .findAll('li') .at(3) .find('a') .trigger('click') await waitNT(wrapper.vm) expect(wrapper.vm.computedCurrentPage).toBe(2) expect(wrapper.emitted('input')).toBeDefined() expect(wrapper.emitted('change')).toBeDefined() expect(wrapper.emitted('input')[0][0]).toBe(2) expect(wrapper.emitted('change')[0][0]).toBe(2) // Click goto last button wrapper .findAll('li') .at(6) .find('a') .trigger('keydown.space') // Generates a click event await waitNT(wrapper.vm) expect(wrapper.vm.computedCurrentPage).toBe(3) expect(wrapper.emitted('input')[1][0]).toBe(3) expect(wrapper.emitted('change')[1][0]).toBe(3) // Click prev button wrapper .findAll('li') .at(1) .find('a') .trigger('click') await waitNT(wrapper.vm) expect(wrapper.vm.computedCurrentPage).toBe(2) expect(wrapper.emitted('input')[2][0]).toBe(2) expect(wrapper.emitted('change')[2][0]).toBe(2) 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.is('ul')).toBe(true) // Should be 13 <li> total expect(wrapper.findAll('li').length).toBe(13) 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.isVueInstance()).toBe(true) expect(wrapper.vm.currentPage).toBe(10) expect(wrapper.emitted('input')).not.toBeDefined() // Change total rows to larger value. Should not change page number wrapper.setProps({ totalRows: 20 }) await waitNT(wrapper.vm) expect(wrapper.vm.currentPage).toBe(10) expect(wrapper.emitted('input')).not.toBeDefined() // Change to page 20 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 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 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 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.isVueInstance()).toBe(true) expect(wrapper.vm.currentPage).toBe(4) expect(wrapper.emitted('input')).not.toBeDefined() // Change perPage 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 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 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.isVueInstance()).toBe(true) 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', '›']) 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', '›']) 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', '›']) 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', '›']) 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', '›']) 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', '›']) 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', '›']) 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', '›']) 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', '›']) 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.isVueInstance()).toBe(true) 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', '›']) 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', '›']) 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', '›']) 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', '›']) 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', '›']) 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', '›']) 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', '›']) 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', '›']) 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', '›']) 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 getBCR 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 }, attachToDocument: true }) await waitNT(wrapper.vm) expect(wrapper.is('ul')).toBe(true) await waitNT(wrapper.vm) // Grab the button links (2 bookends + 3 pages + 2 bookends) const links = wrapper.findAll('a.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 wrapper.trigger('keydown.left') await waitNT(wrapper.vm) expect(document.activeElement).toEqual(links.at(2).element) // RIGHT links.at(2).trigger('keydown.right') await waitNT(wrapper.vm) expect(document.activeElement).toEqual(links.at(3).element) // UP (same as LEFT) wrapper.trigger('keydown.up') await waitNT(wrapper.vm) expect(document.activeElement).toEqual(links.at(2).element) // DOWN (same as RIGHT) links.at(2).trigger('keydown.down') await waitNT(wrapper.vm) expect(document.activeElement).toEqual(links.at(3).element) // SHIFT-RIGHT links.at(2).trigger('keydown.right', { shiftKey: true }) await waitNT(wrapper.vm) expect(document.activeElement).toEqual(links.at(6).element) // SHIFT-LEFT links.at(6).trigger('keydown.left', { shiftKey: true }) await waitNT(wrapper.vm) 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 }, attachToDocument: true }) await waitNT(wrapper.vm) expect(wrapper.is('ul')).toBe(true) // Grab the button links (2 bookends + 3 pages + 2 bookends) const links = wrapper.findAll('a.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 }, attachToDocument: true }) let links await waitNT(wrapper.vm) expect(wrapper.is('ul')).toBe(true) // Grab the button links (2 disabled bookends + 4 pages + (-ellipsis) + 2 bookends) links = wrapper.findAll('a.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('a.page-link') // The 4th link should be page 4, and retain focus expect(document.activeElement).toEqual(links.at(3).element) wrapper.destroy() }) }) })