bootstrap-vue
Version:
BootstrapVue, with more than 85 custom components, over 45 plugins, several 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 W
325 lines (276 loc) • 10.5 kB
JavaScript
import { mount } from '@vue/test-utils'
import { waitNT } from '../../../tests/utils'
import stringifyRecordValues from './helpers/stringify-record-values'
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 = ['a', 'b', 'c']
describe('table > filtering', () => {
it('should not be filtered 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 be filtered when filter is a string', async () => {
const wrapper = mount(BTable, {
propsData: {
fields: testFields,
items: testItems,
filter: 'z'
}
})
expect(wrapper).toBeDefined()
await waitNT(wrapper.vm)
expect(wrapper.findAll('tbody > tr').exists()).toBe(true)
expect(wrapper.findAll('tbody > tr').length).toBe(1)
const $rows = wrapper.findAll('tbody > tr')
expect($rows.length).toBe(1)
const $tds = $rows.at(0).findAll('td')
expect($tds.at(0).text()).toBe('2')
expect($tds.at(1).text()).toBe('a')
expect($tds.at(2).text()).toBe('z')
wrapper.destroy()
})
it('should emit filtered event when filter string is changed', async () => {
const wrapper = mount(BTable, {
propsData: {
fields: testFields,
items: testItems,
filter: ''
}
})
expect(wrapper).toBeDefined()
await waitNT(wrapper.vm)
expect(wrapper.findAll('tbody > tr').exists()).toBe(true)
expect(wrapper.findAll('tbody > tr').length).toBe(3)
expect(wrapper.emitted('filtered')).not.toBeDefined()
wrapper.setProps({
filter: 'z'
})
await waitNT(wrapper.vm)
expect(wrapper.findAll('tbody > tr').exists()).toBe(true)
expect(wrapper.findAll('tbody > tr').length).toBe(1)
expect(wrapper.emitted('filtered')).toBeDefined()
expect(wrapper.emitted('filtered').length).toBe(1)
// Copy of items matching filter
expect(wrapper.emitted('filtered')[0][0]).toEqual([testItems[2]])
// Number of rows matching filter
expect(wrapper.emitted('filtered')[0][1]).toEqual(1)
wrapper.setProps({
filter: ''
})
await waitNT(wrapper.vm)
expect(wrapper.findAll('tbody > tr').exists()).toBe(true)
expect(wrapper.findAll('tbody > tr').length).toBe(3)
expect(wrapper.emitted('filtered').length).toBe(2)
// Copy of items matching filter
expect(wrapper.emitted('filtered')[1][0]).toEqual(testItems)
// Number of rows matching filter
expect(wrapper.emitted('filtered')[1][1]).toEqual(3)
wrapper.setProps({
filter: '3'
})
await waitNT(wrapper.vm)
expect(wrapper.findAll('tbody > tr').exists()).toBe(true)
expect(wrapper.findAll('tbody > tr').length).toBe(1)
expect(wrapper.emitted('filtered').length).toBe(3)
// Copy of items matching filter
expect(wrapper.emitted('filtered')[2][0]).toEqual([testItems[0]])
// Number of rows matching filter
expect(wrapper.emitted('filtered')[2][1]).toEqual(1)
wrapper.setProps({
// Setting to null will also clear the filter
filter: null
})
await waitNT(wrapper.vm)
expect(wrapper.findAll('tbody > tr').exists()).toBe(true)
expect(wrapper.findAll('tbody > tr').length).toBe(3)
expect(wrapper.emitted('filtered').length).toBe(4)
// Copy of items matching filter
expect(wrapper.emitted('filtered')[3][0]).toEqual(testItems)
// Number of rows matching filter
expect(wrapper.emitted('filtered')[3][1]).toEqual(3)
wrapper.destroy()
})
it('should work with filter function', async () => {
const filterFn = (item, regexp) => {
// We are passing a regexp for this test
return regexp.test(stringifyRecordValues(item))
}
const wrapper = mount(BTable, {
propsData: {
fields: testFields,
items: testItems,
filter: '',
filterFunction: filterFn
}
})
expect(wrapper).toBeDefined()
await waitNT(wrapper.vm)
expect(wrapper.findAll('tbody > tr').exists()).toBe(true)
expect(wrapper.findAll('tbody > tr').length).toBe(3)
expect(wrapper.emitted('filtered')).not.toBeDefined()
wrapper.setProps({
filter: /z/
})
await waitNT(wrapper.vm)
expect(wrapper.findAll('tbody > tr').exists()).toBe(true)
expect(wrapper.findAll('tbody > tr').length).toBe(1)
expect(wrapper.emitted('filtered')).toBeDefined()
expect(wrapper.emitted('filtered').length).toBe(1)
// Copy of items matching filter
expect(wrapper.emitted('filtered')[0][0]).toEqual([testItems[2]])
// Number of rows matching filter
expect(wrapper.emitted('filtered')[0][1]).toEqual(1)
wrapper.setProps({
filter: []
})
await waitNT(wrapper.vm)
expect(wrapper.findAll('tbody > tr').exists()).toBe(true)
expect(wrapper.findAll('tbody > tr').length).toBe(3)
expect(wrapper.emitted('filtered').length).toBe(2)
// Copy of items matching filter
expect(wrapper.emitted('filtered')[1][0]).toEqual(testItems)
// Number of rows matching filter
expect(wrapper.emitted('filtered')[1][1]).toEqual(3)
wrapper.destroy()
})
it('should be filtered with no rows when no matches', async () => {
const wrapper = mount(BTable, {
propsData: {
fields: testFields,
items: testItems,
filter: 'ZZZZZZZZ'
}
})
expect(wrapper).toBeDefined()
await waitNT(wrapper.vm)
expect(wrapper.findAll('tbody > tr').length).toBe(0)
wrapper.destroy()
})
it('should show empty filtered message when no matches and show-empty=true', async () => {
const wrapper = mount(BTable, {
propsData: {
fields: testFields,
items: testItems,
filter: '',
showEmpty: true
}
})
expect(wrapper).toBeDefined()
await waitNT(wrapper.vm)
expect(wrapper.findAll('tbody > tr').length).toBe(testItems.length)
wrapper.setProps({
filter: 'ZZZZZZ'
})
await waitNT(wrapper.vm)
expect(wrapper.findAll('tbody > tr').length).toBe(1)
expect(wrapper.find('tbody > tr').text()).toBe(wrapper.vm.emptyFilteredText)
expect(wrapper.find('tbody > tr').classes()).toContain('b-table-empty-row')
expect(wrapper.find('tbody > tr').attributes('role')).toBe('row')
expect(wrapper.find('tbody > tr > td').attributes('role')).toBe('cell')
expect(wrapper.find('tbody > tr > td > div').attributes('role')).toBe('alert')
expect(wrapper.find('tbody > tr > td > div').attributes('aria-live')).toBe('polite')
wrapper.destroy()
})
describe('debouncing (deprecated)', () => {
// Wrapped in a describe to limit console.warn override
// to prevent deprecated prop warnings
const originalWarn = console.warn
afterEach(() => (console.warn = originalWarn))
beforeEach(() => (console.warn = () => {}))
it('filter debouncing works', async () => {
jest.useFakeTimers()
let lastFilterTimer = null
const wrapper = mount(BTable, {
propsData: {
fields: testFields,
items: testItems,
filterDebounce: 100 // 100ms
}
})
expect(wrapper).toBeDefined()
expect(wrapper.findAll('tbody > tr').exists()).toBe(true)
expect(wrapper.findAll('tbody > tr').length).toBe(3)
expect(wrapper.vm.$_filterTimer).toBe(null)
await waitNT(wrapper.vm)
expect(wrapper.emitted('input')).toBeDefined()
expect(wrapper.emitted('input').length).toBe(1)
expect(wrapper.emitted('input')[0][0]).toEqual(testItems)
expect(wrapper.vm.$_filterTimer).toBe(null)
lastFilterTimer = wrapper.vm.$_filterTimer
// Set filter to a single character
wrapper.setProps({
filter: '1'
})
await waitNT(wrapper.vm)
expect(wrapper.emitted('input').length).toBe(1)
expect(wrapper.vm.$_filterTimer).not.toBe(null)
expect(wrapper.vm.$_filterTimer).not.toEqual(lastFilterTimer)
lastFilterTimer = wrapper.vm.$_filterTimer
expect(wrapper.vm.localFilter).not.toEqual('1')
// Change filter
wrapper.setProps({
filter: 'z'
})
await waitNT(wrapper.vm)
expect(wrapper.emitted('input').length).toBe(1)
expect(wrapper.vm.$_filterTimer).not.toBe(null)
expect(wrapper.vm.$_filterTimer).not.toEqual(lastFilterTimer)
lastFilterTimer = wrapper.vm.$_filterTimer
expect(wrapper.vm.localFilter).not.toEqual('z')
jest.runTimersToTime(101)
await waitNT(wrapper.vm)
expect(wrapper.emitted('input').length).toBe(2)
expect(wrapper.emitted('input')[1][0]).toEqual([testItems[2]])
expect(wrapper.vm.$_filterTimer).toEqual(lastFilterTimer)
lastFilterTimer = wrapper.vm.$_filterTimer
expect(wrapper.vm.localFilter).toEqual('z')
// Change filter
wrapper.setProps({
filter: '1'
})
await waitNT(wrapper.vm)
expect(wrapper.vm.$_filterTimer).not.toBe(null)
expect(wrapper.emitted('input').length).toBe(2)
expect(wrapper.vm.$_filterTimer).not.toEqual(lastFilterTimer)
lastFilterTimer = wrapper.vm.$_filterTimer
expect(wrapper.vm.localFilter).not.toEqual('1')
expect(wrapper.vm.localFilter).toEqual('z')
// Change filter-debounce to no debouncing
wrapper.setProps({
filterDebounce: 0
})
await waitNT(wrapper.vm)
// Should clear the pending timer
expect(wrapper.vm.$_filterTimer).toBe(null)
// Should immediately filter the items
expect(wrapper.emitted('input').length).toBe(3)
expect(wrapper.emitted('input')[2][0]).toEqual([testItems[1]])
expect(wrapper.vm.localFilter).toEqual('1')
wrapper.destroy()
})
})
})