UNPKG

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
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() }) }) })