diff options
Diffstat (limited to 'spec/frontend/issuable_list/components/issuable_list_root_spec.js')
-rw-r--r-- | spec/frontend/issuable_list/components/issuable_list_root_spec.js | 198 |
1 files changed, 193 insertions, 5 deletions
diff --git a/spec/frontend/issuable_list/components/issuable_list_root_spec.js b/spec/frontend/issuable_list/components/issuable_list_root_spec.js index 34184522b55..add5d9e8e2d 100644 --- a/spec/frontend/issuable_list/components/issuable_list_root_spec.js +++ b/spec/frontend/issuable_list/components/issuable_list_root_spec.js @@ -1,16 +1,21 @@ import { mount } from '@vue/test-utils'; -import { GlLoadingIcon, GlPagination } from '@gitlab/ui'; +import { GlSkeletonLoading, GlPagination } from '@gitlab/ui'; + +import { TEST_HOST } from 'helpers/test_constants'; import IssuableListRoot from '~/issuable_list/components/issuable_list_root.vue'; import IssuableTabs from '~/issuable_list/components/issuable_tabs.vue'; import IssuableItem from '~/issuable_list/components/issuable_item.vue'; import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue'; -import { mockIssuableListProps } from '../mock_data'; +import { mockIssuableListProps, mockIssuables } from '../mock_data'; -const createComponent = (propsData = mockIssuableListProps) => +const createComponent = ({ props = mockIssuableListProps, data = {} } = {}) => mount(IssuableListRoot, { - propsData, + propsData: props, + data() { + return data; + }, slots: { 'nav-actions': ` <button class="js-new-issuable">New issuable</button> @@ -32,6 +37,139 @@ describe('IssuableListRoot', () => { wrapper.destroy(); }); + describe('computed', () => { + const mockCheckedIssuables = { + [mockIssuables[0].iid]: { checked: true, issuable: mockIssuables[0] }, + [mockIssuables[1].iid]: { checked: true, issuable: mockIssuables[1] }, + [mockIssuables[2].iid]: { checked: true, issuable: mockIssuables[2] }, + }; + + const mIssuables = [mockIssuables[0], mockIssuables[1], mockIssuables[2]]; + + describe('skeletonItemCount', () => { + it.each` + totalItems | defaultPageSize | currentPage | returnValue + ${100} | ${20} | ${1} | ${20} + ${105} | ${20} | ${6} | ${5} + ${7} | ${20} | ${1} | ${7} + ${0} | ${20} | ${1} | ${5} + `( + 'returns $returnValue when totalItems is $totalItems, defaultPageSize is $defaultPageSize and currentPage is $currentPage', + async ({ totalItems, defaultPageSize, currentPage, returnValue }) => { + wrapper.setProps({ + totalItems, + defaultPageSize, + currentPage, + }); + + await wrapper.vm.$nextTick(); + + expect(wrapper.vm.skeletonItemCount).toBe(returnValue); + }, + ); + }); + + describe('allIssuablesChecked', () => { + it.each` + checkedIssuables | issuables | specTitle | returnValue + ${mockCheckedIssuables} | ${mIssuables} | ${'same as'} | ${true} + ${{}} | ${mIssuables} | ${'not same as'} | ${false} + `( + 'returns $returnValue when bulkEditIssuables count is $specTitle issuables count', + async ({ checkedIssuables, issuables, returnValue }) => { + wrapper.setProps({ + issuables, + }); + + await wrapper.vm.$nextTick(); + + wrapper.setData({ + checkedIssuables, + }); + + await wrapper.vm.$nextTick(); + + expect(wrapper.vm.allIssuablesChecked).toBe(returnValue); + }, + ); + }); + + describe('bulkEditIssuables', () => { + it('returns array of issuables which have `checked` set to true within checkedIssuables map', async () => { + wrapper.setData({ + checkedIssuables: mockCheckedIssuables, + }); + + await wrapper.vm.$nextTick(); + + expect(wrapper.vm.bulkEditIssuables).toHaveLength(mIssuables.length); + }); + }); + }); + + describe('watch', () => { + describe('issuables', () => { + it('populates `checkedIssuables` prop with all issuables', async () => { + wrapper.setProps({ + issuables: [mockIssuables[0]], + }); + + await wrapper.vm.$nextTick(); + + expect(Object.keys(wrapper.vm.checkedIssuables)).toHaveLength(1); + expect(wrapper.vm.checkedIssuables[mockIssuables[0].iid]).toEqual({ + checked: false, + issuable: mockIssuables[0], + }); + }); + }); + + describe('urlParams', () => { + it('updates window URL reflecting props within `urlParams`', async () => { + const urlParams = { + state: 'closed', + sort: 'updated_asc', + page: 1, + search: 'foo', + }; + + wrapper.setProps({ + urlParams, + }); + + await wrapper.vm.$nextTick(); + + expect(global.window.location.href).toBe( + `${TEST_HOST}/?state=${urlParams.state}&sort=${urlParams.sort}&page=${urlParams.page}&search=${urlParams.search}`, + ); + }); + }); + }); + + describe('methods', () => { + describe('issuableId', () => { + it('returns id value from provided issuable object', () => { + expect(wrapper.vm.issuableId({ id: 1 })).toBe(1); + expect(wrapper.vm.issuableId({ iid: 1 })).toBe(1); + expect(wrapper.vm.issuableId({})).toBeDefined(); + }); + }); + + describe('issuableChecked', () => { + it('returns boolean value representing checked status of issuable item', async () => { + wrapper.setData({ + checkedIssuables: { + [mockIssuables[0].iid]: { checked: true, issuable: mockIssuables[0] }, + }, + }); + + await wrapper.vm.$nextTick(); + + expect(wrapper.vm.issuableChecked(mockIssuables[0])).toBe(true); + }); + }); + }); + describe('template', () => { it('renders component container element with class "issuable-list-container"', () => { expect(wrapper.classes()).toContain('issuable-list-container'); @@ -86,7 +224,7 @@ describe('IssuableListRoot', () => { await wrapper.vm.$nextTick(); - expect(wrapper.find(GlLoadingIcon).exists()).toBe(true); + expect(wrapper.findAll(GlSkeletonLoading)).toHaveLength(wrapper.vm.skeletonItemCount); }); it('renders issuable-item component for each item within `issuables` array', () => { @@ -114,6 +252,7 @@ describe('IssuableListRoot', () => { it('renders gl-pagination when `showPaginationControls` prop is true', async () => { wrapper.setProps({ showPaginationControls: true, + totalItems: 10, }); await wrapper.vm.$nextTick(); @@ -125,18 +264,51 @@ describe('IssuableListRoot', () => { value: 1, prevPage: 0, nextPage: 2, + totalItems: 10, align: 'center', }); }); }); describe('events', () => { + let wrapperChecked; + + beforeEach(() => { + wrapperChecked = createComponent({ + data: { + checkedIssuables: { + [mockIssuables[0].iid]: { checked: true, issuable: mockIssuables[0] }, + }, + }, + }); + }); + + afterEach(() => { + wrapperChecked.destroy(); + }); + it('issuable-tabs component emits `click-tab` event on `click-tab` event', () => { wrapper.find(IssuableTabs).vm.$emit('click'); expect(wrapper.emitted('click-tab')).toBeTruthy(); }); + it('sets all issuables as checked when filtered-search-bar component emits `checked-input` event', async () => { + const searchEl = wrapperChecked.find(FilteredSearchBar); + + searchEl.vm.$emit('checked-input', true); + + await wrapperChecked.vm.$nextTick(); + + expect(searchEl.emitted('checked-input')).toBeTruthy(); + expect(searchEl.emitted('checked-input').length).toBe(1); + + expect(wrapperChecked.vm.checkedIssuables[mockIssuables[0].iid]).toEqual({ + checked: true, + issuable: mockIssuables[0], + }); + }); + it('filtered-search-bar component emits `filter` event on `onFilter` & `sort` event on `onSort` events', () => { const searchEl = wrapper.find(FilteredSearchBar); @@ -146,6 +318,22 @@ describe('IssuableListRoot', () => { expect(wrapper.emitted('sort')).toBeTruthy(); }); + it('sets an issuable as checked when issuable-item component emits `checked-input` event', async () => { + const issuableItem = wrapperChecked.findAll(IssuableItem).at(0); + + issuableItem.vm.$emit('checked-input', true); + + await wrapperChecked.vm.$nextTick(); + + expect(issuableItem.emitted('checked-input')).toBeTruthy(); + expect(issuableItem.emitted('checked-input').length).toBe(1); + + expect(wrapperChecked.vm.checkedIssuables[mockIssuables[0].iid]).toEqual({ + checked: true, + issuable: mockIssuables[0], + }); + }); + it('gl-pagination component emits `page-change` event on `input` event', async () => { wrapper.setProps({ showPaginationControls: true, |