import { GlButton, GlFormCheckbox, GlKeysetPagination } from '@gitlab/ui'; import { nextTick } from 'vue'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import component from '~/packages_and_registries/shared/components/registry_list.vue'; describe('Registry List', () => { let wrapper; const items = [{ id: 'a' }, { id: 'b' }]; const defaultPropsData = { title: 'test_title', items, }; const rowScopedSlot = `
{{props.first}}

{{props.isSelected(props.item)}}

`; const mountComponent = ({ propsData = defaultPropsData } = {}) => { wrapper = shallowMountExtended(component, { propsData, scopedSlots: { default: rowScopedSlot, }, }); }; const findSelectAll = () => wrapper.findComponent(GlFormCheckbox); const findDeleteSelected = () => wrapper.findComponent(GlButton); const findPagination = () => wrapper.findComponent(GlKeysetPagination); const findScopedSlots = () => wrapper.findAllByTestId('scoped-slot'); const findScopedSlotSelectButton = (index) => findScopedSlots().at(index).find('button'); const findScopedSlotFirstValue = (index) => findScopedSlots().at(index).find('span'); const findScopedSlotIsSelectedValue = (index) => findScopedSlots().at(index).find('p'); afterEach(() => { wrapper.destroy(); }); describe('header', () => { it('renders the title passed in the prop', () => { mountComponent(); expect(wrapper.text()).toContain(defaultPropsData.title); }); describe('select all checkbox', () => { beforeEach(() => { mountComponent(); }); it('exists', () => { expect(findSelectAll().exists()).toBe(true); expect(findSelectAll().attributes('aria-label')).toBe('Select all'); expect(findSelectAll().attributes('disabled')).toBeUndefined(); expect(findSelectAll().attributes('indeterminate')).toBeUndefined(); }); it('sets disabled prop to true when items length is 0', () => { mountComponent({ propsData: { ...defaultPropsData, items: [] } }); expect(findSelectAll().attributes('disabled')).toBe('true'); }); it('when few are selected, sets indeterminate prop to true', async () => { await findScopedSlotSelectButton(0).trigger('click'); expect(findSelectAll().attributes('indeterminate')).toBe('true'); }); it('when all are selected, sets the right checkbox label', async () => { findSelectAll().vm.$emit('change', true); await nextTick(); expect(findSelectAll().attributes('aria-label')).toBe('Unselect all'); }); it('select and unselect all', async () => { // no row is not selected items.forEach((item, index) => { expect(findScopedSlotIsSelectedValue(index).text()).toBe(''); }); // simulate selection findSelectAll().vm.$emit('change', true); await nextTick(); // all rows selected items.forEach((item, index) => { expect(findScopedSlotIsSelectedValue(index).text()).toBe('true'); }); // simulate de-selection findSelectAll().vm.$emit('change', false); await nextTick(); // no row is not selected items.forEach((item, index) => { expect(findScopedSlotIsSelectedValue(index).text()).toBe('false'); }); }); }); describe('delete button', () => { it('has the correct text', () => { mountComponent(); expect(findDeleteSelected().text()).toBe(component.i18n.deleteSelected); }); it('is hidden when hiddenDelete is true', () => { mountComponent({ propsData: { ...defaultPropsData, hiddenDelete: true } }); expect(findDeleteSelected().exists()).toBe(false); }); it('is disabled when isLoading is true', () => { mountComponent({ propsData: { ...defaultPropsData, isLoading: true } }); expect(findDeleteSelected().props('disabled')).toBe(true); }); it('is disabled when no row is selected', async () => { mountComponent(); expect(findDeleteSelected().props('disabled')).toBe(true); await findScopedSlotSelectButton(0).trigger('click'); expect(findDeleteSelected().props('disabled')).toBe(false); }); it('on click emits the delete event with the selected rows', async () => { mountComponent(); await findScopedSlotSelectButton(0).trigger('click'); findDeleteSelected().vm.$emit('click'); expect(wrapper.emitted('delete')).toEqual([[[items[0]]]]); }); }); }); describe('main area', () => { beforeEach(() => { mountComponent(); }); it('renders scopedSlots based on the items props', () => { expect(findScopedSlots()).toHaveLength(items.length); }); it('populates the scope of the slot correctly', async () => { expect(findScopedSlots().at(0).exists()).toBe(true); // it's the first slot expect(findScopedSlotFirstValue(0).text()).toBe('true'); // item is not selected, falsy is translated to empty string expect(findScopedSlotIsSelectedValue(0).text()).toBe(''); // find the button with the bound function await findScopedSlotSelectButton(0).trigger('click'); // the item is selected expect(findScopedSlotIsSelectedValue(0).text()).toBe('true'); }); }); describe('footer', () => { let pagination; beforeEach(() => { pagination = { hasPreviousPage: false, hasNextPage: true }; }); it('has a pagination', () => { mountComponent({ propsData: { ...defaultPropsData, pagination }, }); expect(findPagination().props()).toMatchObject(pagination); }); it.each` hasPreviousPage | hasNextPage | visible ${true} | ${true} | ${true} ${true} | ${false} | ${true} ${false} | ${true} | ${true} ${false} | ${false} | ${false} `( 'when hasPreviousPage is $hasPreviousPage and hasNextPage is $hasNextPage is $visible that the pagination is shown', ({ hasPreviousPage, hasNextPage, visible }) => { pagination = { hasPreviousPage, hasNextPage }; mountComponent({ propsData: { ...defaultPropsData, pagination }, }); expect(findPagination().exists()).toBe(visible); }, ); it('pagination emits the correct events', () => { mountComponent({ propsData: { ...defaultPropsData, pagination }, }); findPagination().vm.$emit('prev'); expect(wrapper.emitted('prev-page')).toEqual([[]]); findPagination().vm.$emit('next'); expect(wrapper.emitted('next-page')).toEqual([[]]); }); }); });