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

412 lines (335 loc) 10.1 kB
import { mount } from '@vue/test-utils' import { waitNT } from '../../../tests/utils' import { BTable } from './table' const testItems = [ { a: 1, b: 2, c: 3 }, { a: 5, b: 5, c: 6 }, { a: 7, b: 8, c: 9 }, { a: 10, b: 11, c: 12 }, { a: 13, b: 14, c: 15 } ] const testFields = Object.keys(testItems[0]).sort() describe('table > provider functions', () => { it('synchronous items provider works', async () => { const provider = () => { return testItems.slice() } const wrapper = mount(BTable, { propsData: { fields: testFields, items: provider } }) expect(wrapper).toBeDefined() await waitNT(wrapper.vm) expect(wrapper.emitted('update:busy')).toBeDefined() expect(wrapper.emitted('input')).toBeDefined() expect(wrapper.find('tbody').exists()).toBe(true) expect( wrapper .find('tbody') .findAll('tr') .exists() ).toBe(true) expect(wrapper.find('tbody').findAll('tr').length).toBe(testItems.length) wrapper.destroy() }) it('promise items provider works', async () => { let doResolve const promise = new Promise(resolve => { doResolve = resolve }) const provider = () => { return promise } const wrapper = mount(BTable, { propsData: { fields: testFields, items: provider, showEmpty: true } }) expect(wrapper).toBeDefined() await waitNT(wrapper.vm) expect(wrapper.emitted('update:busy')).toBeDefined() expect(wrapper.find('tbody').exists()).toBe(true) expect( wrapper .find('tbody') .findAll('tr') .exists() ).toBe(true) // Should have single empty row expect(wrapper.find('tbody').findAll('tr').length).toBe(1) await waitNT(wrapper.vm) expect(doResolve).toBeDefined() doResolve(testItems.slice()) await waitNT(wrapper.vm) expect( wrapper .find('tbody') .findAll('tr') .exists() ).toBe(true) expect(wrapper.find('tbody').findAll('tr').length).toBe(testItems.length) wrapper.destroy() }) it('callback items provider works', async () => { let callback const provider = (ctx, cb) => { callback = cb return null } const wrapper = mount(BTable, { propsData: { fields: testFields, items: provider, showEmpty: true } }) expect(wrapper).toBeDefined() await waitNT(wrapper.vm) expect(wrapper.emitted('update:busy')).toBeDefined() expect(wrapper.find('tbody').exists()).toBe(true) expect( wrapper .find('tbody') .findAll('tr') .exists() ).toBe(true) // Should have single empty row expect(wrapper.find('tbody').findAll('tr').length).toBe(1) await waitNT(wrapper.vm) expect(callback).toBeDefined() callback(testItems.slice()) await waitNT(wrapper.vm) expect( wrapper .find('tbody') .findAll('tr') .exists() ).toBe(true) expect(wrapper.find('tbody').findAll('tr').length).toBe(testItems.length) wrapper.destroy() }) it('callback items provider expects 2 arguments', async () => { const provider = () => { return Promise.resolve(null) } const wrapper = mount(BTable, { propsData: { fields: testFields, items: provider, showEmpty: true } }) expect(wrapper).toBeDefined() await waitNT(wrapper.vm) expect(wrapper.emitted('update:busy')).toBeDefined() expect(wrapper.find('tbody').exists()).toBe(true) expect( wrapper .find('tbody') .findAll('tr') .exists() ).toBe(true) // Should have single empty row expect(wrapper.find('tbody').findAll('tr').length).toBe(1) await waitNT(wrapper.vm) await waitNT(wrapper.vm) // Expect busy to be updated to false expect(wrapper.vm.localBusy).toBe(false) const last = wrapper.emitted('update:busy').length - 1 expect(wrapper.emitted('update:busy')[last][0]).toBe(false) expect( wrapper .find('tbody') .findAll('tr') .exists() ).toBe(true) expect(wrapper.find('tbody').findAll('tr').length).toBe(1) wrapper.destroy() }) it('provider refreshing works', async () => { const provider = () => { return testItems.slice() } const wrapper = mount(BTable, { propsData: { id: 'the-table', fields: testFields, items: provider } }) expect(wrapper).toBeDefined() await waitNT(wrapper.vm) // Always initially emits a refresh when provider used expect(wrapper.emitted('refreshed')).toBeDefined() expect(wrapper.emitted('refreshed').length).toBe(1) // Instance refresh method wrapper.vm.refresh() await waitNT(wrapper.vm) await waitNT(wrapper.vm) expect(wrapper.emitted('refreshed').length).toBe(2) // Root event refreshing wrapper.vm.$root.$emit('bv::refresh::table', 'the-table') await waitNT(wrapper.vm) await waitNT(wrapper.vm) expect(wrapper.emitted('refreshed').length).toBe(3) wrapper.destroy() }) it('refresh debouncing works', async () => { let callback const provider = (ctx, cb) => { callback = cb return null } const wrapper = mount(BTable, { propsData: { fields: testFields.map(f => ({ key: f, sortable: true })), items: provider, sortBy: null, sortDesc: true } }) expect(wrapper).toBeDefined() expect(wrapper.emitted('refreshed')).toBeUndefined() await waitNT(wrapper.vm) expect(wrapper.emitted('refreshed')).toBeUndefined() expect(wrapper.vm.localBusy).toBe(true) // No refreshing if localBusy is true wrapper.vm.refresh() wrapper.vm.refresh() // Trigger a context change that would trigger an internal _providerUpdate await wrapper.setProps({ sortBy: 'b' }) await waitNT(wrapper.vm) expect(wrapper.emitted('refreshed')).toBeUndefined() expect(callback).toBeDefined() callback(testItems.slice()) await waitNT(wrapper.vm) // Refreshed event should happen only once, even though // triggered 3 times while busy expect(wrapper.emitted('refreshed')).toBeDefined() expect(wrapper.emitted('refreshed').length).toBe(1) // Just to be sure, we wait again and re-test await waitNT(wrapper.vm) expect(wrapper.emitted('refreshed').length).toBe(1) await waitNT(wrapper.vm) expect(wrapper.emitted('refreshed').length).toBe(1) wrapper.destroy() }) it('reacts to items provider function change', async () => { const provider1 = () => { return testItems.slice() } const provider2 = () => { return testItems.slice(testItems.length - 1) } const wrapper = mount(BTable, { propsData: { fields: testFields, items: provider1 } }) expect(wrapper).toBeDefined() await waitNT(wrapper.vm) expect(wrapper.emitted('update:busy')).toBeDefined() expect(wrapper.emitted('input')).toBeDefined() expect(wrapper.find('tbody').exists()).toBe(true) expect( wrapper .find('tbody') .findAll('tr') .exists() ).toBe(true) expect(wrapper.find('tbody').findAll('tr').length).toBe(testItems.length) await wrapper.setProps({ items: provider2 }) await waitNT(wrapper.vm) await waitNT(wrapper.vm) expect(wrapper.find('tbody').exists()).toBe(true) expect( wrapper .find('tbody') .findAll('tr') .exists() ).toBe(true) expect(wrapper.find('tbody').findAll('tr').length).toBe(1) wrapper.destroy() }) it('calls provider only once when filter is pre-set object', async () => { let providerCallCount = 0 const provider = () => { providerCallCount++ return testItems.slice() } const wrapper = mount(BTable, { propsData: { filter: { a: '123' }, fields: testFields.slice(), items: provider } }) await waitNT(wrapper.vm) expect(providerCallCount).toBe(1) await waitNT(wrapper.vm) await waitNT(wrapper.vm) await waitNT(wrapper.vm) expect(providerCallCount).toBe(1) wrapper.destroy() }) it('provider is called when filter object child property is changed', async () => { let lastProviderContext = {} // We need a wrapper app to get around a "bug" in Vue test utils that // doesn't let us change a child property in an object and update // that prop with the same object reference // https://forum.vuejs.org/t/vue-test-utils-watchers-on-object-properties-not-triggered/50900/11?u=tmorehouse const App = { data() { return { filter: { a: '123' }, fields: testFields.slice() } }, methods: { provider(ctx) { lastProviderContext = ctx return testItems.slice() } }, render(h) { return h(BTable, { props: { items: this.provider, fields: this.fields, filter: this.filter } }) } } const wrapper = mount(App, { attachTo: document.body }) expect(wrapper.element.tagName).toBe('TABLE') const $table = wrapper.findComponent(BTable) expect($table.exists()).toBe(true) await waitNT(wrapper.vm) await waitNT(wrapper.vm) await waitNT(wrapper.vm) expect(lastProviderContext.filter).toEqual({ a: '123' }) // Change the filter criteria child property, but not the object reference // `setData` recursively traverses the object and only changes the leaf values await wrapper.setData({ filter: { a: '456' } }) expect(wrapper.vm.filter).toEqual({ a: '456' }) await waitNT(wrapper.vm) await waitNT(wrapper.vm) await waitNT(wrapper.vm) expect(lastProviderContext.filter).toEqual({ a: '456' }) wrapper.destroy() }) })