@gitlab/ui
Version:
GitLab UI Components
193 lines (151 loc) • 5.75 kB
JavaScript
import { nextTick } from 'vue';
import { shallowMount, mount } from '@vue/test-utils';
import { BTable } from 'bootstrap-vue';
import { logWarning } from '../../../utils/utils';
import { waitForAnimationFrame } from '../../../utils/test_utils';
import { glTableLiteWarning } from './constants';
import Table from './table.vue';
jest.mock('../../../utils/utils', () => ({
isDev: () => true,
logWarning: jest.fn(),
}));
describe('GlTable', () => {
let wrapper;
const slotsTemplate = {
empty: `
<p>Placeholder empty text</p>`,
};
const factory = ({ mountFn = shallowMount, props = {}, scopedSlots = {} } = {}) => {
wrapper = mountFn(Table, {
scopedSlots,
propsData: props,
});
};
const findBTable = () => wrapper.findComponent(BTable);
const findColHeaderAt = (index) => findBTable().find('thead').findAll('th').at(index);
const findFirstColHeader = () => findColHeaderAt(0);
const findSortIconForHeaderAt = (index) =>
findColHeaderAt(index).find('[data-testid="sort-icon"]');
afterEach(() => {
logWarning.mockClear();
});
it('should log a warning when not given any props or slots which qualifies for the usage of GlTable', async () => {
factory();
await waitForAnimationFrame();
expect(logWarning).toHaveBeenCalledWith(glTableLiteWarning, wrapper.element);
});
it('should not log a warning when given a prop which qualifies for the usage of GlTable', async () => {
factory({ props: { busy: true } });
await waitForAnimationFrame();
expect(logWarning).not.toHaveBeenCalled();
});
it('should not log a warning when given a slot which qualifies for the usage of GlTable', async () => {
factory({ scopedSlots: slotsTemplate });
await waitForAnimationFrame();
expect(logWarning).not.toHaveBeenCalled();
});
it('adds gl-table class to tableClass prop', () => {
factory({ props: { tableClass: 'test-class' } });
expect(findBTable().props().tableClass).toEqual(['gl-table', 'test-class', null]);
});
it('adds sticky header class to tableClass prop', () => {
factory({ props: { stickyHeader: true } });
expect(findBTable().props().tableClass).toEqual([
'gl-table',
undefined,
'gl-table--sticky-header',
]);
});
it('adds gl-table fields to table prop', () => {
const fields = ['name', 'age'];
factory({ props: { fields } });
expect(wrapper.props('fields')).toEqual(fields);
expect(findBTable().props('fields')).toEqual(fields);
});
describe('sortable columns', () => {
const fields = [
{
key: 'name',
label: 'Name column',
sortable: true,
},
{
key: 'age',
label: 'Age column',
sortable: true,
},
{
key: 'email',
label: 'Email column',
sortable: false,
},
];
describe('without custom slots', () => {
beforeEach(() => {
factory({ mountFn: mount, props: { fields } });
});
it('sets the correct column label', () => {
expect(findFirstColHeader().text()).toMatch(fields[0].label);
});
it('renders the ascending sort icon', async () => {
findFirstColHeader().trigger('click');
await nextTick();
const headerText = findFirstColHeader().text();
expect(headerText).toContain('↑');
});
it('renders the descending sort icon', async () => {
findFirstColHeader().trigger('click');
findFirstColHeader().trigger('click');
await nextTick();
const headerText = findFirstColHeader().text();
expect(headerText).toContain('↓');
});
it('sets initial sorting column using the sortBy property', () => {
factory({ mountFn: mount, props: { fields, sortBy: 'age' } });
expect(findSortIconForHeaderAt(0).classes()).toContain('gl-display-none');
expect(findSortIconForHeaderAt(1).classes()).not.toContain('gl-display-none');
});
it('sets initial sorting direction using the sortDesc property', () => {
factory({
mountFn: mount,
props: { fields, sortBy: 'age', sortDesc: true },
});
expect(findColHeaderAt(1).text()).toContain('↓');
});
it('does not render sort icon for non-sortable columns', () => {
expect(findSortIconForHeaderAt(2).exists()).toBe(false);
});
describe('changing the active sort column', () => {
it('hides sorting icon in previous active sort column', async () => {
await findColHeaderAt(0).trigger('click');
expect(findSortIconForHeaderAt(0).classes()).not.toContain('gl-display-none');
expect(findSortIconForHeaderAt(1).classes()).toContain('gl-display-none');
await findColHeaderAt(1).trigger('click');
expect(findSortIconForHeaderAt(0).classes()).toContain('gl-display-none');
expect(findSortIconForHeaderAt(1).classes()).not.toContain('gl-display-none');
});
});
});
describe('when headers are customized via slots', () => {
const customSlotContent = 'customSlotContent';
beforeEach(() => {
factory({
mountFn: mount,
props: {
fields,
},
scopedSlots: {
'head(name)': `<div>${customSlotContent}</div>`,
},
});
});
it('renders the ascending sort icon alongside the custom slot content', async () => {
findFirstColHeader().trigger('click');
await nextTick();
const headerText = findFirstColHeader().text();
expect(headerText).toContain('↑');
expect(headerText).toContain(customSlotContent);
});
});
});
});