v-datatable-light
Version:
A lightweight vue datatable component with no dependencies
511 lines (411 loc) • 22.3 kB
JavaScript
import { mount } from '@vue/test-utils'
import DataTable from '@/components/DataTable.vue'
import mock from '$/mock/datatable.mock.json'
describe('DataTable.vue', () => {
describe('Rendering tests', () => {
it('should renders table when minimun props are passed', () => {
const wrapper = mount(DataTable, { propsData: mock.minimum })
expect(wrapper.contains('.v-datatable-light')).toBe(true)
expect(wrapper.contains('.v-datatable-light thead')).toBe(true)
expect(wrapper.findAll('.v-datatable-light thead tr')).toHaveLength(1)
expect(wrapper.findAll('.v-datatable-light thead tr th')).toHaveLength(2)
expect(wrapper.contains('.v-datatable-light tbody')).toBe(true)
expect(wrapper.findAll('.v-datatable-light tbody tr')).toHaveLength(1)
expect(wrapper.findAll('.v-datatable-light tbody tr td')).toHaveLength(2)
expect(wrapper.contains('.v-datatable-light tfoot')).toBe(false)
})
it('should renders the arrows to sort when just one headerField sent sortable as true ', () => {
const wrapper = mount(DataTable, { propsData: mock.sortable })
const ths = wrapper.findAll('.v-datatable-light thead tr th')
expect(ths).toHaveLength(2)
const arrowWrapper = ths.at(1).find('.arrows-wrapper')
expect(arrowWrapper.exists()).toBe(true)
expect(arrowWrapper.contains('.arrow-up')).toBe(true)
expect(arrowWrapper.contains('.arrow-down')).toBe(true)
expect(ths.at(0).contains('.arrows-wrapper')).toBe(false)
})
it('should renders the label on th instead of name when a headerField contains a label ', () => {
const wrapper = mount(DataTable, { propsData: mock.minimum })
const ths = wrapper.findAll('.v-datatable-light thead tr th')
expect(ths).toHaveLength(2)
expect(ths.at(0).find('.th-wrapper').text()).toEqual(mock.minimum.headerFields[0].label)
})
it('should call the format function before render th content when a headerField contains a format function ', () => {
let { headerFields, data } = mock.minimum
const format = value => `${value}-formated`
headerFields = headerFields.map((item, index) => index === 1 ? { ...item, format } : item)
const wrapper = mount(DataTable, { propsData: { headerFields, data } })
const tds = wrapper.findAll('.v-datatable-light tbody tr td')
expect(tds).toHaveLength(2)
expect(tds.at(1).find('.tbody-td').text()).toEqual(format(data[0].name))
})
it('should call the format function before render th content when a headerField contains a format function ', () => {
let { headerFields, data } = mock.minimum
const format = value => `${value}-formated`
headerFields = headerFields.map((item, index) => index === 1 ? { ...item, format } : item)
const wrapper = mount(DataTable, { propsData: { headerFields, data } })
const tds = wrapper.findAll('.v-datatable-light tbody tr td')
expect(tds).toHaveLength(2)
expect(tds.at(1).find('.tbody-td').text()).toEqual(format(data[0].name))
})
it('should render a slot in the column in every row of tbody when the headerField contains customElement attribute ', () => {
const customElement = '<input class="my-custom-element">'
const wrapper = mount(
DataTable,
{
propsData: mock.customElement,
slots: { name: customElement }
}
)
const tds = wrapper.findAll('.v-datatable-light tbody tr td')
expect(tds).toHaveLength(2)
expect(tds.at(1).find('.my-custom-element').html()).toEqual(customElement)
})
it('should render a slot in the column in every row of tbody when the headerField contains customHeader attribute ', () => {
const customHeader = '<div class="my-custom-header">Foo</div>'
const wrapper = mount(
DataTable,
{
propsData: mock.customHeader,
slots: { 'name:header': customHeader }
}
)
const ths = wrapper.findAll('.v-datatable-light thead tr th')
expect(ths).toHaveLength(2)
expect(ths.at(1).contains('.my-custom-header')).toBe(true)
})
it('should render a checkbox in the column in every row of tbody when the headerField contains __slot:checkbox string ', () => {
const wrapper = mount(DataTable, {
propsData: mock.checkboxes
})
const ths = wrapper.findAll('.v-datatable-light thead tr th')
expect(ths).toHaveLength(4)
expect(ths.at(3).contains('.th-wrapper-checkboxes .checkbox-header')).toBe(true)
const tds = wrapper.findAll('.v-datatable-light tbody tr td')
expect(tds).toHaveLength(4)
expect(tds.at(3).contains('.checkbox')).toBe(true)
})
it('should render the slot actions in the column in every row of tbody when the headerField contains __slot:actions string ', () => {
const wrapper = mount(DataTable, {
propsData: mock.actions,
slots: { actions: '<input type="button" class="action-button"/>' }
})
const ths = wrapper.findAll('.v-datatable-light thead tr th')
expect(ths).toHaveLength(4)
expect(ths.at(3).find('.thead-th').text()).toBe('')
const tds = wrapper.findAll('.v-datatable-light tbody tr td')
expect(tds).toHaveLength(4)
expect(tds.at(3).contains('.action-button')).toBe(true)
})
it('should render the slot actions with the specified ID in the column in every row of tbody when the headerField contains __slot:actions:ActionID string ', () => {
const wrapper = mount(DataTable, {
propsData: mock.actionsID,
slots: {
actions: '<input type="button" class="action-button"/>',
ActionID: '<a href="#" class="my-link">Link</a>'
}
})
const ths = wrapper.findAll('.v-datatable-light thead tr th')
expect(ths).toHaveLength(5)
expect(ths.at(3).find('.thead-th').text()).toBe('')
expect(ths.at(4).find('.thead-th').text()).toBe('')
const tds = wrapper.findAll('.v-datatable-light tbody tr td')
expect(tds).toHaveLength(5)
expect(tds.at(3).contains('.my-link')).toBe(true)
expect(tds.at(4).contains('.action-button')).toBe(true)
})
it('should render the slot spinner when the isLoading attribute is true ', () => {
const spinner = '<div class="main-spinner"></div>'
const wrapper = mount(DataTable, {
propsData: mock.isLoading,
slots: { spinner }
})
const td = wrapper.findAll('.v-datatable-light tbody .tbody-tr-spinner .tbody-td-spinner')
expect(td).toHaveLength(1)
expect(td.contains('.main-spinner')).toBe(true)
expect(td.at(0).find('.main-spinner').html()).toBe(spinner)
})
it('should render the slot spinner when the isLoading attribute is true ', () => {
const spinner = '<div class="main-spinner"></div>'
const wrapper = mount(DataTable, {
propsData: mock.isLoading,
slots: { spinner }
})
const td = wrapper.findAll('.v-datatable-light tbody .tbody-tr-spinner .tbody-td-spinner')
expect(td).toHaveLength(1)
expect(td.contains('.main-spinner')).toBe(true)
expect(td.at(0).find('.main-spinner').html()).toBe(spinner)
})
it('should render no sort arrow on the thead for a sortable column when the sortField attribute is has its name and sort attribute empty', () => {
const sortField = { ...mock.sortField, sort: undefined }
const wrapper = mount(DataTable, {
propsData: sortField
})
const ths = wrapper.findAll('.v-datatable-light thead tr th')
expect(ths).toHaveLength(2)
const arrowWrapper = ths.at(1).findAll('.th-wrapper .arrows-wrapper')
expect(arrowWrapper).toHaveLength(1)
expect(arrowWrapper.contains('arrow-up')).toBe(false)
expect(arrowWrapper.contains('arrow-down')).toBe(false)
})
it('should only render the arrow-down element on the thead for a sortable column when the sortField attribute is has its name and sort attribute is "asc"', () => {
const wrapper = mount(DataTable, {
propsData: mock.sortField
})
const ths = wrapper.findAll('.v-datatable-light thead tr th')
expect(ths).toHaveLength(2)
const arrowWrapper = ths.at(1).findAll('.th-wrapper .arrows-wrapper')
expect(arrowWrapper).toHaveLength(1)
expect(arrowWrapper.contains('.arrow-down')).toBe(true)
expect(arrowWrapper.contains('.arrow-up')).toBe(false)
})
it('should only render the arrow-up element on the thead for a sortable column when the sortField attribute is has its name and sort attribute is "desc"', () => {
const sortField = { ...mock.sortField, sort: 'desc' }
const wrapper = mount(DataTable, {
propsData: sortField
})
const ths = wrapper.findAll('.v-datatable-light thead tr th')
expect(ths).toHaveLength(2)
const arrowWrapper = ths.at(1).findAll('.th-wrapper .arrows-wrapper')
expect(arrowWrapper).toHaveLength(1)
expect(arrowWrapper.contains('.arrow-down')).toBe(false)
expect(arrowWrapper.contains('.arrow-up')).toBe(true)
})
it('should only render one line and column with not found message in the tbody when empty array data attribute was sent', () => {
const wrapper = mount(DataTable, {
propsData: mock.notFoundMsg
})
const tds = wrapper.findAll('.v-datatable-light tbody .not-found-tr .not-found-td')
expect(tds).toHaveLength(1)
expect(tds.at(0).text()).toBe(mock.notFoundMsg.notFoundMsg)
})
it('should renders DataTable with css class names when css attribute sent', () => {
const wrapper = mount(DataTable, { propsData: mock.cssStructure })
const mockedData = { ...mock.cssStructure, data: [], notFoundMsg: 'not found' }
const wrapperNoData = mount(DataTable, { propsData: mockedData })
expect(wrapper.contains('.v-datatable-light.table-test')).toBe(true)
expect(wrapper.contains('.table-test .thead-test')).toBe(true)
expect(wrapper.findAll('.table-test .thead-test .thead-tr-test')).toHaveLength(1)
const theadTh = wrapper.findAll('.table-test .thead-test .thead-tr-test .thead-th-test')
expect(theadTh).toHaveLength(3)
expect(theadTh.at(0).contains('.th-wrapper-test')).toBe(true)
const arrowsWrapper = '.th-wrapper-test .arrows-wrapper-test'
expect(theadTh.at(1).contains(arrowsWrapper)).toBe(true)
expect(theadTh.at(1).contains(`${arrowsWrapper} .arrow-up-test`)).toBe(true)
expect(theadTh.at(1).contains(`${arrowsWrapper} .arrow-down-test`)).toBe(true)
expect(theadTh.at(2).contains('.th-wrapper-checkboxes-test .checkbox-header-test')).toBe(true)
expect(wrapper.contains('.table-test .tbody-test')).toBe(true)
expect(wrapper.findAll('.table-test .tbody-test .tbody-tr-test')).toHaveLength(1)
expect(wrapper.findAll('.table-test .tbody-test .tbody-tr-test .tbody-td-test')).toHaveLength(3)
expect(wrapper.contains('.table-test .tfoot-test')).toBe(false)
expect(wrapperNoData.contains('.table-test .tbody-test .not-found-tr-test .not-found-td-test')).toBe(true)
})
it('should render tbody and thead styles to fix thead and create scroll bar in the tbody when tableHeight attribute was sent', () => {
const wrapper = mount(DataTable, {
propsData: mock.tableHeight
})
const thead = wrapper.findAll('.v-datatable-light thead')
expect(thead).toHaveLength(1)
expect.anything(thead.at(0).attributes('style'))
const tbody = wrapper.findAll('.v-datatable-light tbody')
expect(tbody).toHaveLength(1)
expect.anything(tbody.at(0).attributes('style'))
})
it("should render the default width column for thead's th and tbody's td when tableHeight attribute was sent and no headerFields item sent the width attribute", () => {
const wrapper = mount(DataTable, {
propsData: mock.tableHeightWidth
})
const ths = wrapper.findAll('.v-datatable-light thead tr th')
expect(ths).toHaveLength(2)
expect(ths.at(0).attributes('style')).toBe('width: 150px;')
const tds = wrapper.findAll('.v-datatable-light tbody tr td')
expect(tds).toHaveLength(2)
expect(tds.at(0).attributes('style')).toBe('width: 150px;')
})
it("should render the width column sent on headerFields for thead's th and tbody's td when tableHeight attribute was sent and headerFields's item sent the width attribute", () => {
const wrapper = mount(DataTable, {
propsData: mock.tableHeightWidth
})
const ths = wrapper.findAll('.v-datatable-light thead tr th')
expect(ths).toHaveLength(2)
expect(ths.at(1).attributes('style')).toBe('width: 100px;')
const tds = wrapper.findAll('.v-datatable-light tbody tr td')
expect(tds).toHaveLength(2)
expect(tds.at(1).attributes('style')).toBe('width: 100px;')
})
it('should render the th class for each column', () => {
const wrapper = mount(DataTable, { propsData: mock.rowsCss })
const ths = wrapper.findAll('.v-datatable-light thead tr th')
expect(ths).toHaveLength(3)
const firstThClass = ths.at(0).find('.header-column-0')
expect(firstThClass.exists()).toBe(true)
const secondThClass = ths.at(1).find('.header-column-1')
expect(secondThClass.exists()).toBe(true)
const thirdThClass = ths.at(2).find('.header-column-2')
expect(thirdThClass.exists()).toBe(true)
})
it('should render the tr class for each line', () => {
const wrapper = mount(DataTable, { propsData: mock.rowsCss })
const trs = wrapper.findAll('.v-datatable-light tbody tr.row-0')
expect(trs).toHaveLength(1)
const tds = trs.at(0).findAll('td')
expect(tds).toHaveLength(3)
})
it('should render the tbody td class for each column using the column index to create the class name', () => {
const wrapper = mount(DataTable, { propsData: mock.rowsCss })
const tds = wrapper.findAll('.v-datatable-light tbody tr.row-0 td')
expect(tds).toHaveLength(3)
const firstTdColumn = tds.at(1).find('.column-1')
expect(firstTdColumn.exists()).toBe(true)
const secondTdColumn = tds.at(2).find('.column-2')
expect(secondTdColumn.exists()).toBe(true)
})
})
describe('Internal iteractions tests', () => {
it('should change sortedDir data when th wrapper is clicked', () => {
const wrapper = mount(DataTable, { propsData: mock.sortable })
const ths = wrapper.findAll('.v-datatable-light thead tr th')
expect(ths).toHaveLength(2)
const thWrapper = ths.at(1).find('.th-wrapper')
expect(thWrapper.exists('.th-wrapper')).toBe(true)
thWrapper.trigger('click')
expect(wrapper.vm.sortedDir).toBe('desc')
thWrapper.trigger('click')
expect(wrapper.vm.sortedDir).toBe('asc')
})
it('should set itemsChecked to the data size or 0 when checkbox header is clicked', () => {
const wrapper = mount(DataTable, { propsData: mock.checkboxes })
const ths = wrapper.findAll('.v-datatable-light thead tr th')
expect(ths).toHaveLength(4)
const checkboxHeader = ths.at(3).find('.th-wrapper-checkboxes .checkbox-header')
expect(checkboxHeader.exists()).toBe(true)
checkboxHeader.trigger('click')
expect(wrapper.vm.itemsChecked).toHaveLength(mock.checkboxes.data.length)
checkboxHeader.trigger('click')
expect(wrapper.vm.itemsChecked).toHaveLength(0)
})
it("should add item to itemsChecked array when item's checkbox is clicked", () => {
const wrapper = mount(DataTable, { propsData: mock.checkboxesSelect })
const trs = wrapper.findAll('.v-datatable-light tbody tr')
expect(trs).toHaveLength(2)
const tds1 = trs.at(0).findAll('td')
expect(tds1).toHaveLength(4)
const checkbox = tds1.at(3).findAll('input')
expect(checkbox).toHaveLength(1)
checkbox.at(0).trigger('click')
expect(wrapper.vm.itemsChecked).toHaveLength(1)
const tds2 = trs.at(1).findAll('td')
expect(tds2).toHaveLength(4)
const checkbox2 = tds2.at(3).findAll('input')
expect(checkbox2).toHaveLength(1)
checkbox2.at(0).trigger('click')
expect(wrapper.vm.itemsChecked).toHaveLength(2)
})
it("should checkItem function use trackBy prop to keep track of items checked when item's checkbox is clicked", () => {
const wrapper = mount(DataTable, { propsData: mock.checkboxesTrackBy })
const trs = wrapper.findAll('.v-datatable-light tbody tr')
expect(trs).toHaveLength(2)
const tds1 = trs.at(0).findAll('td')
expect(tds1).toHaveLength(4)
const checkbox = tds1.at(3).findAll('input')
expect(checkbox).toHaveLength(1)
checkbox.at(0).trigger('click')
expect(wrapper.vm.itemsChecked).toHaveLength(1)
expect(Object.keys(wrapper.vm.itemsChecked[0])[0]).toBe(Object.keys(mock.checkboxesTrackBy.data[0])[0])
})
})
describe('Emmited Events tests', () => {
it('should emmit onUpdate event when user change order direction or order', () => {
const wrapper = mount(DataTable, { propsData: mock.sortable })
const ths = wrapper.findAll('.v-datatable-light thead tr th')
expect(ths).toHaveLength(2)
const thWrapper = ths.at(1).find('.th-wrapper')
expect(thWrapper.exists('.th-wrapper')).toBe(true)
thWrapper.trigger('click')
const emitted = wrapper.emitted()
expect(emitted['on-update']).toBeTruthy()
expect(emitted['on-update']).toEqual([[{ sortField: 'name', sort: 'desc' }]])
})
it("should emmit onCheckAll event when user click on theader's checkbox", () => {
const wrapper = mount(DataTable, { propsData: mock.checkboxesSelect })
const ths = wrapper.findAll('.v-datatable-light thead tr th')
expect(ths).toHaveLength(4)
const checkboxHeader = ths.at(3).find('.th-wrapper-checkboxes .checkbox-header')
expect(checkboxHeader.exists()).toBe(true)
checkboxHeader.trigger('click')
const emitted = wrapper.emitted()
expect(emitted['on-check-all']).toBeTruthy()
expect(emitted['on-check-all']).toEqual([[mock.checkboxesSelect.data]])
})
it("should emmit onCheckedItem and onUncheckedItem events when user click on tbody's checkbox to check and uncheck", () => {
const wrapper = mount(DataTable, { propsData: mock.checkboxesSelect })
const trs = wrapper.findAll('.v-datatable-light tbody tr')
expect(trs).toHaveLength(2)
const tds1 = trs.at(0).findAll('td')
expect(tds1).toHaveLength(4)
const checkbox = tds1.at(3).findAll('input')
expect(checkbox).toHaveLength(1)
checkbox.at(0).trigger('click')
checkbox.at(0).trigger('click')
const emitted = wrapper.emitted()
expect(emitted['on-checked-item']).toBeTruthy()
expect(emitted['on-checked-item']).toEqual([[mock.checkboxesSelect.data[0]]])
expect(emitted['on-unchecked-item']).toBeTruthy()
expect(emitted['on-unchecked-item']).toEqual([[mock.checkboxesSelect.data[0]]])
})
it('should only exist sorted arrow in firstName column when onlyShowOrderedArrow is true and sortedField is firstColumn', () => {
const wrapper = mount(DataTable, { propsData: mock.onlyShowOrderedArrow })
const ths = wrapper.findAll('.v-datatable-light thead tr th')
expect(ths).toHaveLength(4)
// returns nothing because it is not sortable
const arrow1 = ths.at(0).findAll('.th-wrapper .arrows-wrapper')
expect(arrow1).toHaveLength(0)
const noSortable = ths.at(0).classes()
expect(noSortable).toContain('no-sortable')
const arrow2Wrapper = ths.at(1).findAll('.th-wrapper .arrows-wrapper')
expect(arrow2Wrapper).toHaveLength(1)
const arrowUp2 = arrow2Wrapper.at(0).findAll('.arrow-up')
const arrowDown2 = arrow2Wrapper.at(0).findAll('.arrow-down')
expect(arrowUp2).toHaveLength(1)
expect(arrowDown2).toHaveLength(0)
const arrowsWrapper3 = ths.at(2).findAll('.th-wrapper .arrows-wrapper')
expect(arrowsWrapper3).toHaveLength(1)
const arrowUp3 = arrowsWrapper3.at(0).findAll('.arrow-up')
const arrowDown3 = arrowsWrapper3.at(0).findAll('.arrow-down')
expect(arrowUp3).toHaveLength(0)
expect(arrowDown3).toHaveLength(0)
const arrowsWrapper4 = ths.at(3).findAll('.th-wrapper .arrows-wrapper')
expect(arrowsWrapper4).toHaveLength(1)
const arrowUp4 = arrowsWrapper4.at(0).findAll('.arrow-up')
const arrowDown4 = arrowsWrapper4.at(0).findAll('.arrow-down')
expect(arrowUp4).toHaveLength(0)
expect(arrowDown4).toHaveLength(0)
})
it('should only exist sorted arrow in lastName column when onlyShowOrderedArrow is true and sortedField is lastColumn', () => {
const wrapper = mount(DataTable, { propsData: mock.onlyShowOrderedArrowLastName })
const ths = wrapper.findAll('.v-datatable-light thead tr th')
expect(ths).toHaveLength(4)
// returns nothing because it is not sortable
const arrow1 = ths.at(0).findAll('.th-wrapper .arrows-wrapper')
expect(arrow1).toHaveLength(0)
const arrow2Wrapper = ths.at(1).findAll('.th-wrapper .arrows-wrapper')
expect(arrow2Wrapper).toHaveLength(1)
const arrowUp2 = arrow2Wrapper.at(0).findAll('.arrow-up')
const arrowDown2 = arrow2Wrapper.at(0).findAll('.arrow-down')
expect(arrowUp2).toHaveLength(0)
expect(arrowDown2).toHaveLength(0)
const arrowsWrapper3 = ths.at(2).findAll('.th-wrapper .arrows-wrapper')
expect(arrowsWrapper3).toHaveLength(1)
const arrowUp3 = arrowsWrapper3.at(0).findAll('.arrow-up')
const arrowDown3 = arrowsWrapper3.at(0).findAll('.arrow-down')
expect(arrowUp3).toHaveLength(0)
expect(arrowDown3).toHaveLength(1)
const arrowsWrapper4 = ths.at(3).findAll('.th-wrapper .arrows-wrapper')
expect(arrowsWrapper4).toHaveLength(1)
const arrowUp4 = arrowsWrapper4.at(0).findAll('.arrow-up')
const arrowDown4 = arrowsWrapper4.at(0).findAll('.arrow-down')
expect(arrowUp4).toHaveLength(0)
expect(arrowDown4).toHaveLength(0)
})
})
})