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

824 lines (756 loc) 23.7 kB
import { mount } from '@vue/test-utils' import { waitNT } from '../../../tests/utils' import defaultSortCompare from './helpers/default-sort-compare' import { BTable } from './table' const testItems = [{ a: 3, b: 'b', c: 'x' }, { a: 1, b: 'c', c: 'y' }, { a: 2, b: 'a', c: 'z' }] const testFields = [ { key: 'a', label: 'A', sortable: true }, { key: 'b', label: 'B', sortable: true }, { key: 'c', label: 'C', sortable: false } ] describe('table > sorting', () => { it('should not be sorted by default', async () => { const wrapper = mount(BTable, { propsData: { fields: testFields, items: testItems } }) expect(wrapper).toBeDefined() expect(wrapper.findAll('tbody > tr').exists()).toBe(true) expect(wrapper.findAll('tbody > tr').length).toBe(3) await waitNT(wrapper.vm) expect(wrapper.emitted('input')).toBeDefined() expect(wrapper.emitted('input').length).toBe(1) expect(wrapper.emitted('input')[0][0]).toEqual(testItems) const $rows = wrapper.findAll('tbody > tr').wrappers expect($rows.length).toBe(3) // Map the rows to the first column text value const columnA = $rows.map(row => { return row .findAll('td') .at(0) .text() }) expect(columnA[0]).toBe('3') expect(columnA[1]).toBe('1') expect(columnA[2]).toBe('2') wrapper.destroy() }) it('should sort column descending when sortBy set and sortDesc changed, with proper attributes', async () => { const wrapper = mount(BTable, { propsData: { fields: testFields, items: testItems, sortBy: 'a', sortDesc: false } }) expect(wrapper).toBeDefined() expect(wrapper.findAll('tbody > tr').exists()).toBe(true) expect(wrapper.findAll('tbody > tr').length).toBe(3) let $rows let columnA await waitNT(wrapper.vm) expect(wrapper.emitted('input')).toBeDefined() expect(wrapper.emitted('input').length).toBe(1) $rows = wrapper.findAll('tbody > tr').wrappers expect($rows.length).toBe(3) // Map the rows to the first column text value columnA = $rows.map(row => { return row .findAll('td') .at(0) .text() }) expect(columnA[0]).toBe('1') expect(columnA[1]).toBe('2') expect(columnA[2]).toBe('3') let $ths = wrapper.findAll('thead > tr > th') // Currently sorted as ascending expect($ths.at(0).attributes('aria-sort')).toBe('ascending') // For switching to descending expect( $ths .at(0) .find('.sr-only') .text() ).toContain(wrapper.vm.labelSortDesc) // Not sorted by this column expect($ths.at(1).attributes('aria-sort')).toBe('none') // For sorting by ascending expect( $ths .at(1) .find('.sr-only') .text() ).toContain(wrapper.vm.labelSortAsc) // Not a sortable column expect($ths.at(2).attributes('aria-sort')).not.toBeDefined() // For clearing sorting expect( $ths .at(2) .find('.sr-only') .text() ).toContain(wrapper.vm.labelSortClear) // Change sort direction wrapper.setProps({ sortDesc: true }) await waitNT(wrapper.vm) expect(wrapper.emitted('input').length).toBe(2) $rows = wrapper.findAll('tbody > tr').wrappers expect($rows.length).toBe(3) // Map the rows to the first column text value columnA = $rows.map(row => { return row .findAll('td') .at(0) .text() }) expect(columnA[0]).toBe('3') expect(columnA[1]).toBe('2') expect(columnA[2]).toBe('1') $ths = wrapper.findAll('thead > tr > th') // Currently sorted as descending expect($ths.at(0).attributes('aria-sort')).toBe('descending') // For switching to ascending expect( $ths .at(0) .find('.sr-only') .text() ).toContain(wrapper.vm.labelSortAsc) // Not sorted by this column expect($ths.at(1).attributes('aria-sort')).toBe('none') // For sorting by ascending expect( $ths .at(1) .find('.sr-only') .text() ).toContain(wrapper.vm.labelSortAsc) // Not a sortable column expect($ths.at(2).attributes('aria-sort')).not.toBeDefined() // For clearing sorting expect( $ths .at(2) .find('.sr-only') .text() ).toContain(wrapper.vm.labelSortClear) // Clear sort wrapper.setProps({ sortBy: null, sortDesc: false }) await waitNT(wrapper.vm) expect(wrapper.emitted('input').length).toBe(4) $rows = wrapper.findAll('tbody > tr').wrappers expect($rows.length).toBe(3) // Map the rows to the first column text value columnA = $rows.map(row => { return row .findAll('td') .at(0) .text() }) expect(columnA[0]).toBe('3') expect(columnA[1]).toBe('1') expect(columnA[2]).toBe('2') $ths = wrapper.findAll('thead > tr > th') // Currently not sorted expect($ths.at(0).attributes('aria-sort')).toBe('none') // For sorting by ascending expect( $ths .at(0) .find('.sr-only') .text() ).toContain(wrapper.vm.labelSortAsc) // Not sorted by this column expect($ths.at(1).attributes('aria-sort')).toBe('none') // For sorting by ascending expect( $ths .at(1) .find('.sr-only') .text() ).toContain(wrapper.vm.labelSortAsc) // Not a sortable column expect($ths.at(2).attributes('aria-sort')).not.toBeDefined() // For clearing sorting expect( $ths .at(2) .find('.sr-only') .exists() ).toBe(false) wrapper.destroy() }) it('should accept custom sort compare', async () => { const wrapper = mount(BTable, { propsData: { fields: testFields, items: testItems, sortBy: 'a', sortDesc: false, sortCompare: (a, b, sortBy) => { // We just use our default sort compare to test passing a function return defaultSortCompare(a, b, sortBy) } } }) expect(wrapper).toBeDefined() expect(wrapper.findAll('tbody > tr').exists()).toBe(true) expect(wrapper.findAll('tbody > tr').length).toBe(3) await waitNT(wrapper.vm) expect(wrapper.emitted('input')).toBeDefined() expect(wrapper.emitted('input').length).toBe(1) const $rows = wrapper.findAll('tbody > tr').wrappers expect($rows.length).toBe(3) // Map the rows to the first column text value const columnA = $rows.map(row => { return row .findAll('td') .at(0) .text() }) expect(columnA[0]).toBe('1') expect(columnA[1]).toBe('2') expect(columnA[2]).toBe('3') wrapper.destroy() }) it('should sort columns when clicking headers', async () => { const wrapper = mount(BTable, { propsData: { fields: testFields, items: testItems } }) expect(wrapper).toBeDefined() expect(wrapper.findAll('tbody > tr').exists()).toBe(true) expect(wrapper.findAll('tbody > tr').length).toBe(3) let $rows let columnA // Should not be sorted await waitNT(wrapper.vm) expect(wrapper.emitted('input')).toBeDefined() expect(wrapper.emitted('sort-changed')).not.toBeDefined() $rows = wrapper.findAll('tbody > tr').wrappers expect($rows.length).toBe(3) // Map the rows to the first column text value columnA = $rows.map(row => { return row .findAll('td') .at(0) .text() }) expect(columnA[0]).toBe('3') expect(columnA[1]).toBe('1') expect(columnA[2]).toBe('2') // Sort by first column wrapper .findAll('thead > tr > th') .at(0) .trigger('click') await waitNT(wrapper.vm) expect(wrapper.emitted('sort-changed')).toBeDefined() expect(wrapper.emitted('sort-changed').length).toBe(1) expect(wrapper.emitted('sort-changed')[0][0]).toEqual(wrapper.vm.context) $rows = wrapper.findAll('tbody > tr').wrappers expect($rows.length).toBe(3) // Map the rows to the column text value columnA = $rows.map(row => { return row .findAll('td') .at(0) .text() }) expect(columnA[0]).toBe('1') expect(columnA[1]).toBe('2') expect(columnA[2]).toBe('3') // Click first column header again to reverse sort wrapper .findAll('thead > tr > th') .at(0) .trigger('click') await waitNT(wrapper.vm) expect(wrapper.emitted('sort-changed').length).toBe(2) expect(wrapper.emitted('sort-changed')[1][0]).toEqual(wrapper.vm.context) $rows = wrapper.findAll('tbody > tr').wrappers expect($rows.length).toBe(3) // Map the rows to the column text value columnA = $rows.map(row => { return row .findAll('td') .at(0) .text() }) expect(columnA[0]).toBe('3') expect(columnA[1]).toBe('2') expect(columnA[2]).toBe('1') // Click second column header to sort by it (by using keydown.enter) wrapper .findAll('thead > tr > th') .at(1) .trigger('keydown.enter') await waitNT(wrapper.vm) expect(wrapper.emitted('sort-changed').length).toBe(3) expect(wrapper.emitted('sort-changed')[2][0]).toEqual(wrapper.vm.context) $rows = wrapper.findAll('tbody > tr').wrappers expect($rows.length).toBe(3) // Map the rows to the column text value const columnB = $rows.map(row => { return row .findAll('td') .at(1) .text() }) expect(columnB[0]).toBe('a') expect(columnB[1]).toBe('b') expect(columnB[2]).toBe('c') // Click third column header to clear sort wrapper .findAll('thead > tr > th') .at(2) .trigger('click') await waitNT(wrapper.vm) expect(wrapper.emitted('sort-changed').length).toBe(4) expect(wrapper.emitted('sort-changed')[3][0]).toEqual(wrapper.vm.context) $rows = wrapper.findAll('tbody > tr').wrappers expect($rows.length).toBe(3) // Map the rows to the column text value columnA = $rows.map(row => { return row .findAll('td') .at(0) .text() }) expect(columnA[0]).toBe('3') expect(columnA[1]).toBe('1') expect(columnA[2]).toBe('2') wrapper.destroy() }) it('should sort columns when clicking footers', async () => { const wrapper = mount(BTable, { propsData: { fields: testFields, items: testItems, footClone: true } }) expect(wrapper).toBeDefined() expect(wrapper.findAll('tbody > tr').exists()).toBe(true) expect(wrapper.findAll('tbody > tr').length).toBe(3) let $rows let columnA // Should not be sorted await waitNT(wrapper.vm) expect(wrapper.emitted('input')).toBeDefined() expect(wrapper.emitted('sort-changed')).not.toBeDefined() $rows = wrapper.findAll('tbody > tr').wrappers expect($rows.length).toBe(3) // Map the rows to the first column text value columnA = $rows.map(row => { return row .findAll('td') .at(0) .text() }) expect(columnA[0]).toBe('3') expect(columnA[1]).toBe('1') expect(columnA[2]).toBe('2') // Should have aria-* labels expect(wrapper.findAll('tfoot > tr > th[aria-sort]').length).toBe(2) expect(wrapper.findAll('tfoot > tr > th > .sr-only').length).toBe(2) // Sort by first column wrapper .findAll('tfoot > tr > th') .at(0) .trigger('click') await waitNT(wrapper.vm) expect(wrapper.emitted('sort-changed')).toBeDefined() expect(wrapper.emitted('sort-changed').length).toBe(1) expect(wrapper.emitted('sort-changed')[0][0]).toEqual(wrapper.vm.context) $rows = wrapper.findAll('tbody > tr').wrappers expect($rows.length).toBe(3) // Map the rows to the column text value columnA = $rows.map(row => { return row .findAll('td') .at(0) .text() }) expect(columnA[0]).toBe('1') expect(columnA[1]).toBe('2') expect(columnA[2]).toBe('3') // Should have aria-* labels expect(wrapper.findAll('tfoot > tr > th[aria-sort]').length).toBe(2) expect(wrapper.findAll('tfoot > tr > th > .sr-only').length).toBe(3) // Click first column header again to reverse sort wrapper .findAll('tfoot > tr > th') .at(0) .trigger('click') await waitNT(wrapper.vm) expect(wrapper.emitted('sort-changed').length).toBe(2) expect(wrapper.emitted('sort-changed')[1][0]).toEqual(wrapper.vm.context) $rows = wrapper.findAll('tbody > tr').wrappers expect($rows.length).toBe(3) // Map the rows to the column text value columnA = $rows.map(row => { return row .findAll('td') .at(0) .text() }) expect(columnA[0]).toBe('3') expect(columnA[1]).toBe('2') expect(columnA[2]).toBe('1') // Should have aria-* labels expect(wrapper.findAll('tfoot > tr > th[aria-sort]').length).toBe(2) expect(wrapper.findAll('tfoot > tr > th > .sr-only').length).toBe(3) // Click second column header to sort by it (by using keydown.enter) wrapper .findAll('tfoot > tr > th') .at(1) .trigger('keydown.enter') await waitNT(wrapper.vm) expect(wrapper.emitted('sort-changed').length).toBe(3) expect(wrapper.emitted('sort-changed')[2][0]).toEqual(wrapper.vm.context) $rows = wrapper.findAll('tbody > tr').wrappers expect($rows.length).toBe(3) // Map the rows to the column text value const columnB = $rows.map(row => { return row .findAll('td') .at(1) .text() }) expect(columnB[0]).toBe('a') expect(columnB[1]).toBe('b') expect(columnB[2]).toBe('c') // Click third column header to clear sort wrapper .findAll('tfoot > tr > th') .at(2) .trigger('click') await waitNT(wrapper.vm) expect(wrapper.emitted('sort-changed').length).toBe(4) expect(wrapper.emitted('sort-changed')[3][0]).toEqual(wrapper.vm.context) $rows = wrapper.findAll('tbody > tr').wrappers expect($rows.length).toBe(3) // Map the rows to the column text value columnA = $rows.map(row => { return row .findAll('td') .at(0) .text() }) expect(columnA[0]).toBe('3') expect(columnA[1]).toBe('1') expect(columnA[2]).toBe('2') // Should have aria-* labels expect(wrapper.findAll('tfoot > tr > th[aria-sort]').length).toBe(2) expect(wrapper.findAll('tfoot > tr > th > .sr-only').length).toBe(2) wrapper.destroy() }) it('should not sort columns when clicking footers and no-footer-sorting set', async () => { const wrapper = mount(BTable, { propsData: { fields: testFields, items: testItems, footClone: true, noFooterSorting: true } }) expect(wrapper).toBeDefined() expect(wrapper.findAll('tbody > tr').exists()).toBe(true) expect(wrapper.findAll('tbody > tr').length).toBe(3) let $rows let columnA // Should not be sorted await waitNT(wrapper.vm) expect(wrapper.emitted('input')).toBeDefined() expect(wrapper.emitted('sort-changed')).not.toBeDefined() $rows = wrapper.findAll('tbody > tr').wrappers expect($rows.length).toBe(3) // Map the rows to the first column text value columnA = $rows.map(row => { return row .findAll('td') .at(0) .text() }) expect(columnA[0]).toBe('3') expect(columnA[1]).toBe('1') expect(columnA[2]).toBe('2') // Shouldn't have aria-* labels expect(wrapper.findAll('tfoot > tr > th[aria-sort]').length).toBe(0) expect(wrapper.findAll('tfoot > tr > th > .sr-only').length).toBe(0) // Click first column wrapper .findAll('tfoot > tr > th') .at(0) .trigger('click') await waitNT(wrapper.vm) expect(wrapper.emitted('sort-changed')).not.toBeDefined() $rows = wrapper.findAll('tbody > tr').wrappers expect($rows.length).toBe(3) // Map the rows to the column text value columnA = $rows.map(row => { return row .findAll('td') .at(0) .text() }) expect(columnA[0]).toBe('3') expect(columnA[1]).toBe('1') expect(columnA[2]).toBe('2') // Shouldn't have aria-* labels expect(wrapper.findAll('tfoot > tr > th[aria-sort]').length).toBe(0) expect(wrapper.findAll('tfoot > tr > th > .sr-only').length).toBe(0) // Click third column header wrapper .findAll('tfoot > tr > th') .at(2) .trigger('click') await waitNT(wrapper.vm) expect(wrapper.emitted('sort-changed')).not.toBeDefined() $rows = wrapper.findAll('tbody > tr').wrappers expect($rows.length).toBe(3) // Map the rows to the column text value columnA = $rows.map(row => { return row .findAll('td') .at(0) .text() }) expect(columnA[0]).toBe('3') expect(columnA[1]).toBe('1') expect(columnA[2]).toBe('2') // Shouldn't have aria-* labels expect(wrapper.findAll('tfoot > tr > th[aria-sort]').length).toBe(0) expect(wrapper.findAll('tfoot > tr > th > .sr-only').length).toBe(0) wrapper.destroy() }) it('should sort column descending first, when sort-direction=desc', async () => { const wrapper = mount(BTable, { propsData: { fields: testFields, items: testItems, sortDesc: false, sortDirection: 'desc' } }) expect(wrapper).toBeDefined() expect(wrapper.findAll('tbody > tr').exists()).toBe(true) expect(wrapper.findAll('tbody > tr').length).toBe(3) let $rows let columnA await waitNT(wrapper.vm) $rows = wrapper.findAll('tbody > tr').wrappers expect($rows.length).toBe(3) // Map the rows to the first column text value columnA = $rows.map(row => { return row .findAll('td') .at(0) .text() }) expect(columnA[0]).toBe('3') expect(columnA[1]).toBe('1') expect(columnA[2]).toBe('2') let $ths = wrapper.findAll('thead > tr > th') // Currently not sorted expect($ths.at(0).attributes('aria-sort')).toBe('none') // For switching to descending expect( $ths .at(0) .find('.sr-only') .text() ).toContain(wrapper.vm.labelSortDesc) // Not sorted by this column expect($ths.at(1).attributes('aria-sort')).toBe('none') // For sorting by ascending expect( $ths .at(1) .find('.sr-only') .text() ).toContain(wrapper.vm.labelSortDesc) // Not a sortable column expect($ths.at(2).attributes('aria-sort')).not.toBeDefined() // For clearing sorting expect( $ths .at(2) .find('.sr-only') .exists() ).toBe(false) // Change sort direction (should be descending first) wrapper .findAll('thead > tr > th') .at(0) .trigger('click') await waitNT(wrapper.vm) $rows = wrapper.findAll('tbody > tr').wrappers expect($rows.length).toBe(3) // Map the rows to the first column text value columnA = $rows.map(row => { return row .findAll('td') .at(0) .text() }) expect(columnA[0]).toBe('3') expect(columnA[1]).toBe('2') expect(columnA[2]).toBe('1') $ths = wrapper.findAll('thead > tr > th') // Currently sorted as descending expect($ths.at(0).attributes('aria-sort')).toBe('descending') // For switching to ascending expect( $ths .at(0) .find('.sr-only') .text() ).toContain(wrapper.vm.labelSortAsc) // Not sorted by this column expect($ths.at(1).attributes('aria-sort')).toBe('none') // For sorting by ascending expect( $ths .at(1) .find('.sr-only') .text() ).toContain(wrapper.vm.labelSortDesc) // Not a sortable column expect($ths.at(2).attributes('aria-sort')).not.toBeDefined() // For clearing sorting expect( $ths .at(2) .find('.sr-only') .text() ).toContain(wrapper.vm.labelSortClear) wrapper.destroy() }) it('non-sortable header th should not emit a sort-changed event when clicked and prop no-sort-reset is set', async () => { const wrapper = mount(BTable, { propsData: { fields: testFields, items: testItems, noSortReset: true } }) expect(wrapper).toBeDefined() expect(wrapper.findAll('tbody > tr').exists()).toBe(true) expect(wrapper.findAll('tbody > tr').length).toBe(3) let $rows let columnA // Should not be sorted await waitNT(wrapper.vm) expect(wrapper.emitted('input')).toBeDefined() expect(wrapper.emitted('sort-changed')).not.toBeDefined() $rows = wrapper.findAll('tbody > tr').wrappers expect($rows.length).toBe(3) // Map the rows to the first column text value columnA = $rows.map(row => { return row .findAll('td') .at(0) .text() }) expect(columnA[0]).toBe('3') expect(columnA[1]).toBe('1') expect(columnA[2]).toBe('2') // Click first column to sort wrapper .findAll('thead > tr > th') .at(0) .trigger('click') await waitNT(wrapper.vm) expect(wrapper.emitted('sort-changed')).toBeDefined() expect(wrapper.emitted('sort-changed').length).toBe(1) $rows = wrapper.findAll('tbody > tr').wrappers expect($rows.length).toBe(3) // Map the rows to the column text value columnA = $rows.map(row => { return row .findAll('td') .at(0) .text() }) expect(columnA[0]).toBe('1') expect(columnA[1]).toBe('2') expect(columnA[2]).toBe('3') // Click third column header (should not clear sorting) wrapper .findAll('thead > tr > th') .at(2) .trigger('click') await waitNT(wrapper.vm) expect(wrapper.emitted('sort-changed').length).toBe(1) $rows = wrapper.findAll('tbody > tr').wrappers expect($rows.length).toBe(3) // Map the rows to the column text value columnA = $rows.map(row => { return row .findAll('td') .at(0) .text() }) expect(columnA[0]).toBe('1') expect(columnA[1]).toBe('2') expect(columnA[2]).toBe('3') wrapper.destroy() }) it('sorting by virutal column formatter works', async () => { const wrapper = mount(BTable, { propsData: { items: [{ a: 5, b: 2 }, { a: 10, b: 9 }], fields: [ 'a', 'b', { key: 'c', sortable: true, formatter(value, key, item) { return item.a - item.b }, sortByFormatted: true } ], // Initialy unsorted sortBy: '' } }) expect(wrapper).toBeDefined() let $trs = wrapper.findAll('tbody > tr') expect($trs.length).toBe(2) // First Row - unsorted let $tds = $trs.at(0).findAll('td') expect($tds.length).toBe(3) expect($tds.at(0).text()).toBe('5') expect($tds.at(1).text()).toBe('2') expect($tds.at(2).text()).toBe('3') // 5 - 2 wrapper.setProps({ sortBy: 'c', sortDesc: false }) // Grab the sorted TRs $trs = wrapper.findAll('tbody > tr') expect($trs.length).toBe(2) // First Row - sorted (smallest first) $tds = $trs.at(0).findAll('td') expect($tds.length).toBe(3) expect($tds.at(0).text()).toBe('10') expect($tds.at(1).text()).toBe('9') expect($tds.at(2).text()).toBe('1') // 10 - 9 wrapper.destroy() }) })