diff options
Diffstat (limited to 'spec/frontend/frequent_items/components')
3 files changed, 110 insertions, 36 deletions
diff --git a/spec/frontend/frequent_items/components/app_spec.js b/spec/frontend/frequent_items/components/app_spec.js index c201bbf4af2..b1e87aca63d 100644 --- a/spec/frontend/frequent_items/components/app_spec.js +++ b/spec/frontend/frequent_items/components/app_spec.js @@ -1,3 +1,4 @@ +import { GlButton, GlIcon } from '@gitlab/ui'; import MockAdapter from 'axios-mock-adapter'; import Vue, { nextTick } from 'vue'; import Vuex from 'vuex'; @@ -103,6 +104,7 @@ describe('Frequent Items App Component', () => { expect(loading.exists()).toBe(true); expect(loading.find('[aria-label="Loading projects"]').exists()).toBe(true); + expect(findSectionHeader().exists()).toBe(false); }); it('should render frequent projects list header', () => { @@ -112,25 +114,6 @@ describe('Frequent Items App Component', () => { expect(sectionHeader.text()).toBe('Frequently visited'); }); - it('should render frequent projects list', async () => { - const expectedResult = getTopFrequentItems(mockFrequentProjects); - localStorage.setItem(TEST_STORAGE_KEY, JSON.stringify(mockFrequentProjects)); - - expect(findFrequentItems().length).toBe(1); - - triggerDropdownOpen(); - await nextTick(); - - expect(findFrequentItems().length).toBe(expectedResult.length); - expect(findFrequentItemsList().props()).toEqual({ - items: expectedResult, - namespace: TEST_NAMESPACE, - hasSearchQuery: false, - isFetchFailed: false, - matcher: '', - }); - }); - it('should render searched projects list', async () => { mock.onGet(/\/api\/v4\/projects.json(.*)$/).replyOnce(200, mockSearchedProjects.data); @@ -164,6 +147,47 @@ describe('Frequent Items App Component', () => { }), ); }); + + describe('with frequent items list', () => { + const expectedResult = getTopFrequentItems(mockFrequentProjects); + + beforeEach(async () => { + localStorage.setItem(TEST_STORAGE_KEY, JSON.stringify(mockFrequentProjects)); + triggerDropdownOpen(); + await nextTick(); + }); + + it('should render edit button within header', () => { + const itemEditButton = findSectionHeader().findComponent(GlButton); + + expect(itemEditButton.exists()).toBe(true); + expect(itemEditButton.attributes('title')).toBe('Toggle edit mode'); + expect(itemEditButton.findComponent(GlIcon).props('name')).toBe('pencil'); + }); + + it('should render frequent projects list', () => { + expect(findFrequentItems().length).toBe(expectedResult.length); + expect(findFrequentItemsList().props()).toEqual({ + items: expectedResult, + namespace: TEST_NAMESPACE, + hasSearchQuery: false, + isFetchFailed: false, + isItemRemovalFailed: false, + matcher: '', + }); + }); + + it('dispatches action `toggleItemsListEditablity` when edit button is clicked', async () => { + const itemEditButton = findSectionHeader().findComponent(GlButton); + itemEditButton.vm.$emit('click'); + + await nextTick(); + + expect(store.dispatch).toHaveBeenCalledWith( + `${TEST_VUEX_MODULE}/toggleItemsListEditablity`, + ); + }); + }); }); describe('with searchClass', () => { diff --git a/spec/frontend/frequent_items/components/frequent_items_list_item_spec.js b/spec/frontend/frequent_items/components/frequent_items_list_item_spec.js index e6673fa78ec..4f2badf869d 100644 --- a/spec/frontend/frequent_items/components/frequent_items_list_item_spec.js +++ b/spec/frontend/frequent_items/components/frequent_items_list_item_spec.js @@ -1,5 +1,5 @@ -import { GlButton } from '@gitlab/ui'; -import Vue from 'vue'; +import { GlIcon } from '@gitlab/ui'; +import Vue, { nextTick } from 'vue'; import Vuex from 'vuex'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import { trimText } from 'helpers/text_helper'; @@ -12,6 +12,7 @@ import { mockProject } from '../mock_data'; Vue.use(Vuex); describe('FrequentItemsListItemComponent', () => { + const TEST_VUEX_MODULE = 'frequentProjects'; let wrapper; let trackingSpy; let store; @@ -20,11 +21,18 @@ describe('FrequentItemsListItemComponent', () => { const findAvatar = () => wrapper.findComponent(ProjectAvatar); const findAllTitles = () => wrapper.findAllByTestId('frequent-items-item-title'); const findNamespace = () => wrapper.findByTestId('frequent-items-item-namespace'); - const findAllButtons = () => wrapper.findAllComponents(GlButton); + const findAllFrequentItems = () => wrapper.findAllByTestId('frequent-item-link'); const findAllNamespace = () => wrapper.findAllByTestId('frequent-items-item-namespace'); const findAllAvatars = () => wrapper.findAllComponents(ProjectAvatar); const findAllMetadataContainers = () => wrapper.findAllByTestId('frequent-items-item-metadata-container'); + const findRemoveButton = () => wrapper.findByTestId('item-remove'); + + const toggleItemsListEditablity = async () => { + store.dispatch(`${TEST_VUEX_MODULE}/toggleItemsListEditablity`); + + await nextTick(); + }; const createComponent = (props = {}) => { wrapper = shallowMountExtended(frequentItemsListItemComponent, { @@ -38,7 +46,7 @@ describe('FrequentItemsListItemComponent', () => { ...props, }, provide: { - vuexModule: 'frequentProjects', + vuexModule: TEST_VUEX_MODULE, }, }); }; @@ -102,7 +110,7 @@ describe('FrequentItemsListItemComponent', () => { it.each` name | selector | expected - ${'button'} | ${findAllButtons} | ${1} + ${'list item'} | ${findAllFrequentItems} | ${1} ${'avatar container'} | ${findAllAvatars} | ${1} ${'metadata container'} | ${findAllMetadataContainers} | ${1} ${'title'} | ${findAllTitles} | ${1} @@ -111,8 +119,37 @@ describe('FrequentItemsListItemComponent', () => { expect(selector()).toHaveLength(expected); }); + it('renders remove button within item when `isItemsListEditable` is true', async () => { + await toggleItemsListEditablity(); + + const removeButton = findRemoveButton(); + expect(removeButton.exists()).toBe(true); + expect(removeButton.attributes('title')).toBe('Remove'); + expect(removeButton.findComponent(GlIcon).props('name')).toBe('close'); + }); + + it('dispatches action `removeFrequentItem` when remove button is clicked', async () => { + await toggleItemsListEditablity(); + + jest.spyOn(store, 'dispatch'); + + const removeButton = findRemoveButton(); + removeButton.vm.$emit( + 'click', + { stopPropagation: jest.fn(), preventDefault: jest.fn() }, + mockProject.id, + ); + + await nextTick(); + + expect(store.dispatch).toHaveBeenCalledWith( + `${TEST_VUEX_MODULE}/removeFrequentItem`, + mockProject.id, + ); + }); + it('tracks when item link is clicked', () => { - const link = wrapper.findComponent(GlButton); + const link = wrapper.findByTestId('frequent-item-link'); link.vm.$emit('click'); diff --git a/spec/frontend/frequent_items/components/frequent_items_list_spec.js b/spec/frontend/frequent_items/components/frequent_items_list_spec.js index 9f08a432a3d..d024925f62b 100644 --- a/spec/frontend/frequent_items/components/frequent_items_list_spec.js +++ b/spec/frontend/frequent_items/components/frequent_items_list_spec.js @@ -18,6 +18,7 @@ describe('FrequentItemsListComponent', () => { namespace: 'projects', items: mockFrequentProjects, isFetchFailed: false, + isItemRemovalFailed: false, hasSearchQuery: false, matcher: 'lab', ...props, @@ -51,22 +52,34 @@ describe('FrequentItemsListComponent', () => { }); describe('fetched item messages', () => { - it('should return appropriate empty list message based on value of `localStorageFailed` prop with projects', async () => { + it('should show default empty list message', async () => { createComponent({ - isFetchFailed: true, + items: [], }); - expect(wrapper.vm.listEmptyMessage).toBe( - 'This feature requires browser localStorage support', + expect(wrapper.findByTestId('frequent-items-list-empty').text()).toContain( + 'Projects you visit often will appear here', ); - - wrapper.setProps({ - isFetchFailed: false, - }); - await nextTick(); - - expect(wrapper.vm.listEmptyMessage).toBe('Projects you visit often will appear here'); }); + + it.each` + isFetchFailed | isItemRemovalFailed + ${true} | ${false} + ${false} | ${true} + `( + 'should show failure message when `isFetchFailed` is $isFetchFailed or `isItemRemovalFailed` is $isItemRemovalFailed', + ({ isFetchFailed, isItemRemovalFailed }) => { + createComponent({ + items: [], + isFetchFailed, + isItemRemovalFailed, + }); + + expect(wrapper.findByTestId('frequent-items-list-empty').text()).toContain( + 'This feature requires browser localStorage support', + ); + }, + ); }); describe('searched item messages', () => { |