Skip to content

Commit 831934e

Browse files
committed
Add unit tests
1 parent c83a9ac commit 831934e

File tree

4 files changed

+254
-10
lines changed

4 files changed

+254
-10
lines changed

src/components/DataTable.vue

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -311,14 +311,22 @@ const emits = defineEmits([
311311
312312
const serverOptionsComputed = computed({
313313
get: (): ServerOptionsComputed => {
314-
const {
315-
page, rowsPerPage, sortBy, sortType,
316-
} = props.serverOptions;
314+
if (props.serverOptions) {
315+
const {
316+
page, rowsPerPage, sortBy, sortType,
317+
} = props.serverOptions;
318+
return {
319+
page,
320+
rowsPerPage,
321+
sortBy: sortBy ?? null,
322+
sortType: sortType ?? null,
323+
};
324+
}
317325
return {
318-
page,
319-
rowsPerPage,
320-
sortBy: sortBy ?? null,
321-
sortType: sortType ?? null,
326+
page: 1,
327+
rowsPerPage: 25,
328+
sortBy: null,
329+
sortType: null,
322330
};
323331
},
324332
set: (value) => {
@@ -365,7 +373,7 @@ const headerColumns = computed((): string[] => headersForRender.value.map((heade
365373
366374
// multiple select
367375
const selectItemsComputed = computed({
368-
get: () => props.itemsSelected,
376+
get: () => props.itemsSelected ?? [],
369377
set: (value) => {
370378
emits('update:itemsSelected', value);
371379
},
@@ -438,7 +446,7 @@ const itemsSorting = computed((): Item[] => {
438446
if (isServerSideMode.value) return props.items;
439447
if (clientSortOptions.value === null) return itemsSearching.value;
440448
const { sortBy, sortDesc } = clientSortOptions.value;
441-
const itemsSearchingSorted = structuredClone(itemsSearching.value);
449+
const itemsSearchingSorted = [...itemsSearching.value];
442450
// eslint-disable-next-line vue/no-side-effects-in-computed-properties
443451
return itemsSearchingSorted.sort((a, b) => {
444452
if (a[sortBy] < b[sortBy]) return sortDesc ? 1 : -1;

src/mock.ts

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,17 @@
1-
import { Item, ServerOptions } from './types/main';
1+
import { Item, ServerOptions, Header } from './types/main';
2+
3+
export const headersMocked: Header[] = [
4+
{ text: 'Name', value: 'name' },
5+
{ text: 'Address', value: 'address' },
6+
{ text: 'Height', value: 'height', sortable: true },
7+
{ text: 'Weight', value: 'weight', sortable: true },
8+
{ text: 'Age', value: 'calories', sortable: true },
9+
{ text: 'Calories', value: 'calories' },
10+
{ text: 'Fat (g)', value: 'fat' },
11+
{ text: 'Carbs (g)', value: 'carbs' },
12+
{ text: 'Protein (g)', value: 'protein' },
13+
{ text: 'Iron (%)', value: 'iron' },
14+
];
215

316
export const mockClientItems = (itemsNumber = 100): Item[] => {
417
const mockItems: Item[] = [];

src/modes/Client.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
:rows-per-page="25"
88
:rows-items="[25, 50]"
99
:body-font-size="15"
10+
sort-by="height"
11+
sort-type="desc"
1012
:buttons-pagination="true"
1113
show-index
1214
>

test/DataTable.spec.js

Lines changed: 221 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,221 @@
1+
/**
2+
* @vitest-environment happy-dom
3+
*/
4+
import { describe, it, expect } from 'vitest';
5+
import { mount } from '@vue/test-utils';
6+
import DataTable from '../src/components/DataTable.vue';
7+
import { mockClientItems, headersMocked, mockServerItems } from "../src/mock";
8+
9+
// Button Pagination
10+
describe('Button Pagination', () => {
11+
it('should render', () => {
12+
const wrapper = mount(DataTable, {
13+
props: {
14+
items: mockClientItems(200),
15+
buttonsPagination: true,
16+
headers: headersMocked,
17+
rowsPerPage: 5,
18+
},
19+
});
20+
expect(wrapper.find('.data-table').exists()).toBe(true);
21+
});
22+
23+
/**
24+
* conditions:
25+
* 1. total items count is 200
26+
* 2. rows per page is 5
27+
* expection:
28+
* max pagination number should be 40
29+
*/
30+
it('Max pagination number should be 40', () => {
31+
const wrapper = mount(DataTable, {
32+
props: {
33+
items: mockClientItems(200),
34+
buttonsPagination: true,
35+
headers: headersMocked,
36+
rowsPerPage: 5,
37+
},
38+
});
39+
expect(wrapper.find('.item.button:last-of-type').exists()).toBe(true);
40+
expect(wrapper.find('.item.button:last-of-type').text()).toBe('40');
41+
});
42+
43+
it('Prev arrow button unavailable in first page', () => {
44+
const wrapper = mount(DataTable, {
45+
props: {
46+
items: mockClientItems(200),
47+
buttonsPagination: true,
48+
headers: headersMocked,
49+
rowsPerPage: 5,
50+
},
51+
});
52+
expect(wrapper.find('.previous-page__click-button').classes()).include('first-page');
53+
});
54+
55+
it('Click the second pagination button to nagivate to the second page', async () => {
56+
const wrapper = mount(DataTable, {
57+
props: {
58+
items: mockClientItems(200),
59+
buttonsPagination: true,
60+
headers: headersMocked,
61+
rowsPerPage: 5,
62+
},
63+
});
64+
const buttonArr = wrapper.findAll('.item.button');
65+
const secondButton = buttonArr.at(1);
66+
await secondButton.trigger('click');
67+
expect(secondButton.classes()).include('active');
68+
69+
const tdArr = wrapper.findAll('td');
70+
const firstTd = tdArr.at(0);
71+
expect(firstTd.text()).toBe(mockClientItems(200)[5].name);
72+
const trArr = wrapper.findAll('tbody tr');
73+
expect(trArr.length).equal(5);
74+
});
75+
});
76+
77+
// Multiple selecting
78+
describe('Multiple selecting', () => {
79+
it('Gather data of the the top two row items', async () => {
80+
const mockItems = mockClientItems(200);
81+
const wrapper = mount(DataTable, {
82+
props: {
83+
itemsSelected: [],
84+
items: mockItems,
85+
headers: headersMocked,
86+
rowsPerPage: 5,
87+
},
88+
});
89+
const singleCheckboxArr = wrapper.findAll('.single-select__checkbox');
90+
const firstSingleCheckbox = singleCheckboxArr.at(0);
91+
const secondSingleCheckbox = singleCheckboxArr.at(1);
92+
await firstSingleCheckbox.trigger('click');
93+
await secondSingleCheckbox.trigger('click');
94+
const updateItemsSelecedEvent = wrapper.emitted('update:itemsSelected');
95+
expect(updateItemsSelecedEvent).toHaveLength(2);
96+
expect(updateItemsSelecedEvent[1]).toEqual([[mockItems[1], mockItems[0]]]);
97+
});
98+
99+
it('Gather data of the the first and sixth row items', async () => {
100+
const mockItems = mockClientItems(200);
101+
const wrapper = mount(DataTable, {
102+
props: {
103+
itemsSelected: [],
104+
items: mockItems,
105+
headers: headersMocked,
106+
rowsPerPage: 5,
107+
},
108+
});
109+
const singleCheckboxArr = wrapper.findAll('.single-select__checkbox');
110+
const firstSingleCheckbox = singleCheckboxArr.at(0);
111+
await firstSingleCheckbox.trigger('click');
112+
113+
const nextPageButton = wrapper.find('.next-page__click-button');
114+
await nextPageButton.trigger('click');
115+
116+
const singleCheckboxArrInSecondPage = wrapper.findAll('.single-select__checkbox');
117+
const firstSingleCheckboxInSecondPage = singleCheckboxArrInSecondPage.at(0);
118+
await firstSingleCheckboxInSecondPage.trigger('click');
119+
120+
const updateItemsSelecedEvent = wrapper.emitted('update:itemsSelected');
121+
expect(updateItemsSelecedEvent).toHaveLength(2);
122+
expect(updateItemsSelecedEvent[1]).toEqual([[mockItems[5], mockItems[0]]]);
123+
});
124+
});
125+
126+
// Single field sorting
127+
describe('Single field sorting', () => {
128+
it('Sorting by height column', async () => {
129+
const mockItems = mockClientItems(200);
130+
const wrapper = mount(DataTable, {
131+
props: {
132+
items: mockItems,
133+
headers: headersMocked,
134+
rowsPerPage: 5,
135+
sortBy: 'height',
136+
sortType: 'desc',
137+
},
138+
});
139+
const trArr = wrapper.findAll('tbody tr');
140+
const firstTr = trArr.at(0);
141+
expect(firstTr.findAll('td').at(0).text()).toBe(mockItems[mockItems.length - 1].name);
142+
});
143+
144+
it('Sorting by height column', async () => {
145+
const mockItems = mockClientItems(200);
146+
const wrapper = mount(DataTable, {
147+
props: {
148+
items: mockItems,
149+
headers: headersMocked,
150+
rowsPerPage: 5,
151+
sortBy: 'height',
152+
sortType: 'desc',
153+
},
154+
});
155+
const sortableTh = wrapper.find('.sortable');
156+
await sortableTh.trigger('click');
157+
expect(sortableTh.classes()).include('none');
158+
159+
const trArr = wrapper.findAll('tbody tr');
160+
const firstTr = trArr.at(0);
161+
expect(firstTr.findAll('td').at(0).text()).toBe(mockItems[0].name);
162+
});
163+
});
164+
165+
// Searching
166+
describe('Searching', () => {
167+
it('Searching by specific field', async () => {
168+
const mockItems = mockClientItems(200);
169+
const wrapper = mount(DataTable, {
170+
props: {
171+
items: mockItems,
172+
headers: headersMocked,
173+
rowsPerPage: 5,
174+
searchField: 'address',
175+
searchValue: 'address-115',
176+
},
177+
});
178+
const trArr = wrapper.findAll('tbody tr');
179+
expect(trArr.length).toBe(1);
180+
expect(wrapper.findAll('tbody td').at(0).text()).toBe(mockItems[114].name);
181+
});
182+
});
183+
184+
// Server side paginate and sort
185+
describe('Server side paginate and sort', () => {
186+
it('Click next page button to load from server', async () => {
187+
const serverOptions = {
188+
page: 1,
189+
rowsPerPage: 100,
190+
sortBy: 'height',
191+
sortType: 'desc',
192+
};
193+
194+
const {
195+
serverCurrentPageItems,
196+
serverTotalItemsLength,
197+
} = await mockServerItems(serverOptions);
198+
199+
const wrapper = mount(DataTable, {
200+
props: {
201+
serverItemsLength: serverTotalItemsLength,
202+
serverOptions,
203+
items: serverCurrentPageItems,
204+
headers: headersMocked,
205+
},
206+
});
207+
expect(wrapper.findAll('tbody td').at(0).text()).toBe(serverCurrentPageItems[0].name);
208+
209+
const nextPageButton = wrapper.find('.next-page__click-button');
210+
await nextPageButton.trigger('click');
211+
212+
const updateServerOptionsEvent = wrapper.emitted('update:serverOptions');
213+
expect(updateServerOptionsEvent).toHaveLength(1);
214+
expect(updateServerOptionsEvent[0]).toEqual([{
215+
page: 2,
216+
rowsPerPage: 100,
217+
sortBy: 'height',
218+
sortType: 'desc',
219+
}]);
220+
});
221+
});

0 commit comments

Comments
 (0)