diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-25 15:08:19 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-03-25 15:08:19 +0300 |
commit | e6baeabaa9651d90b03bb64ffce75a2c3cb89aab (patch) | |
tree | 85f3cbd6e437b17be59505cf3ac4794c1838609e /spec/frontend/registry | |
parent | 5064bf8c5647d4c4430cbb4d097cf1592416de29 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/registry')
-rw-r--r-- | spec/frontend/registry/explorer/pages/details_spec.js | 63 | ||||
-rw-r--r-- | spec/frontend/registry/explorer/pages/index_spec.js | 62 | ||||
-rw-r--r-- | spec/frontend/registry/explorer/pages/list_spec.js | 41 | ||||
-rw-r--r-- | spec/frontend/registry/explorer/stores/actions_spec.js | 67 | ||||
-rw-r--r-- | spec/frontend/registry/explorer/stores/getters_spec.js | 18 | ||||
-rw-r--r-- | spec/frontend/registry/explorer/stores/mutations_spec.js | 16 | ||||
-rw-r--r-- | spec/frontend/registry/shared/mocks.js | 4 |
7 files changed, 222 insertions, 49 deletions
diff --git a/spec/frontend/registry/explorer/pages/details_spec.js b/spec/frontend/registry/explorer/pages/details_spec.js index 660004e5eea..60e509e4a88 100644 --- a/spec/frontend/registry/explorer/pages/details_spec.js +++ b/spec/frontend/registry/explorer/pages/details_spec.js @@ -5,8 +5,15 @@ import stubChildren from 'helpers/stub_children'; import component from '~/registry/explorer/pages/details.vue'; import store from '~/registry/explorer/stores/'; import { SET_MAIN_LOADING } from '~/registry/explorer/stores/mutation_types/'; +import { + DELETE_TAG_SUCCESS_MESSAGE, + DELETE_TAG_ERROR_MESSAGE, + DELETE_TAGS_SUCCESS_MESSAGE, + DELETE_TAGS_ERROR_MESSAGE, +} from '~/registry/explorer/constants'; import { tagsListResponse } from '../mock_data'; import { GlModal } from '../stubs'; +import { $toast } from '../../shared/mocks'; describe('Details Page', () => { let wrapper; @@ -40,6 +47,7 @@ describe('Details Page', () => { id: routeId, }, }, + $toast, }, }); dispatchSpy = jest.spyOn(store, 'dispatch'); @@ -249,13 +257,11 @@ describe('Details Page', () => { }); }); - it('when only one element is selected', () => { - const deleteModal = findDeleteModal(); - - wrapper.setData({ itemsToBeDeleted: [0] }); - deleteModal.vm.$emit('ok'); + describe('when only one element is selected', () => { + it('execute the delete and remove selection', () => { + wrapper.setData({ itemsToBeDeleted: [0] }); + findDeleteModal().vm.$emit('ok'); - return wrapper.vm.$nextTick().then(() => { expect(store.dispatch).toHaveBeenCalledWith('requestDeleteTag', { tag: store.state.tags[0], params: wrapper.vm.$route.params.id, @@ -264,15 +270,33 @@ describe('Details Page', () => { expect(wrapper.vm.itemsToBeDeleted).toEqual([]); expect(findCheckedCheckboxes()).toHaveLength(0); }); + + it('show success toast on successful delete', () => { + return wrapper.vm.handleSingleDelete(0).then(() => { + expect(wrapper.vm.$toast.show).toHaveBeenCalledWith(DELETE_TAG_SUCCESS_MESSAGE, { + type: 'success', + }); + }); + }); + + it('show error toast on erred delete', () => { + dispatchSpy.mockRejectedValue(); + return wrapper.vm.handleSingleDelete(0).then(() => { + expect(wrapper.vm.$toast.show).toHaveBeenCalledWith(DELETE_TAG_ERROR_MESSAGE, { + type: 'error', + }); + }); + }); }); - it('when multiple elements are selected', () => { - const deleteModal = findDeleteModal(); + describe('when multiple elements are selected', () => { + beforeEach(() => { + wrapper.setData({ itemsToBeDeleted: [0, 1] }); + }); - wrapper.setData({ itemsToBeDeleted: [0, 1] }); - deleteModal.vm.$emit('ok'); + it('execute the delete and remove selection', () => { + findDeleteModal().vm.$emit('ok'); - return wrapper.vm.$nextTick().then(() => { expect(store.dispatch).toHaveBeenCalledWith('requestDeleteTags', { ids: store.state.tags.map(t => t.name), params: wrapper.vm.$route.params.id, @@ -281,6 +305,23 @@ describe('Details Page', () => { expect(wrapper.vm.itemsToBeDeleted).toEqual([]); expect(findCheckedCheckboxes()).toHaveLength(0); }); + + it('show success toast on successful delete', () => { + return wrapper.vm.handleMultipleDelete(0).then(() => { + expect(wrapper.vm.$toast.show).toHaveBeenCalledWith(DELETE_TAGS_SUCCESS_MESSAGE, { + type: 'success', + }); + }); + }); + + it('show error toast on erred delete', () => { + dispatchSpy.mockRejectedValue(); + return wrapper.vm.handleMultipleDelete(0).then(() => { + expect(wrapper.vm.$toast.show).toHaveBeenCalledWith(DELETE_TAGS_ERROR_MESSAGE, { + type: 'error', + }); + }); + }); }); }); diff --git a/spec/frontend/registry/explorer/pages/index_spec.js b/spec/frontend/registry/explorer/pages/index_spec.js new file mode 100644 index 00000000000..f52e7d67866 --- /dev/null +++ b/spec/frontend/registry/explorer/pages/index_spec.js @@ -0,0 +1,62 @@ +import { shallowMount } from '@vue/test-utils'; +import { GlAlert, GlSprintf, GlLink } from '@gitlab/ui'; +import component from '~/registry/explorer/pages/index.vue'; +import store from '~/registry/explorer/stores/'; + +describe('List Page', () => { + let wrapper; + let dispatchSpy; + + const findRouterView = () => wrapper.find({ ref: 'router-view' }); + const findAlert = () => wrapper.find(GlAlert); + const findLink = () => wrapper.find(GlLink); + + const mountComponent = () => { + wrapper = shallowMount(component, { + store, + stubs: { + RouterView: true, + GlSprintf, + }, + }); + }; + + beforeEach(() => { + dispatchSpy = jest.spyOn(store, 'dispatch'); + mountComponent(); + }); + + it('has a router view', () => { + expect(findRouterView().exists()).toBe(true); + }); + + describe('garbageCollectionTip alert', () => { + beforeEach(() => { + store.dispatch('setInitialState', { isAdmin: true, garbageCollectionHelpPagePath: 'foo' }); + store.dispatch('setShowGarbageCollectionTip', true); + }); + + afterEach(() => { + store.dispatch('setInitialState', {}); + store.dispatch('setShowGarbageCollectionTip', false); + }); + + it('is visible when the user is an admin and the user performed a delete action', () => { + expect(findAlert().exists()).toBe(true); + }); + + it('on dismiss disappears ', () => { + findAlert().vm.$emit('dismiss'); + expect(dispatchSpy).toHaveBeenCalledWith('setShowGarbageCollectionTip', false); + return wrapper.vm.$nextTick().then(() => { + expect(findAlert().exists()).toBe(false); + }); + }); + + it('contains a link to the docs', () => { + const link = findLink(); + expect(link.exists()).toBe(true); + expect(link.attributes('href')).toBe(store.state.config.garbageCollectionHelpPagePath); + }); + }); +}); diff --git a/spec/frontend/registry/explorer/pages/list_spec.js b/spec/frontend/registry/explorer/pages/list_spec.js index 5b713778495..3e46a29f776 100644 --- a/spec/frontend/registry/explorer/pages/list_spec.js +++ b/spec/frontend/registry/explorer/pages/list_spec.js @@ -8,8 +8,13 @@ import GroupEmptyState from '~/registry/explorer/components/group_empty_state.vu import ProjectEmptyState from '~/registry/explorer/components/project_empty_state.vue'; import store from '~/registry/explorer/stores/'; import { SET_MAIN_LOADING } from '~/registry/explorer/stores/mutation_types/'; +import { + DELETE_IMAGE_SUCCESS_MESSAGE, + DELETE_IMAGE_ERROR_MESSAGE, +} from '~/registry/explorer/constants'; import { imagesListResponse } from '../mock_data'; import { GlModal, GlEmptyState } from '../stubs'; +import { $toast } from '../../shared/mocks'; const localVue = createLocalVue(); localVue.use(VueRouter); @@ -40,6 +45,9 @@ describe('List Page', () => { GlEmptyState, GlSprintf, }, + mocks: { + $toast, + }, }); dispatchSpy = jest.spyOn(store, 'dispatch'); store.dispatch('receiveImagesListSuccess', imagesListResponse); @@ -174,11 +182,29 @@ describe('List Page', () => { const itemToDelete = wrapper.vm.images[0]; wrapper.setData({ itemToDelete }); findDeleteModal().vm.$emit('ok'); - return wrapper.vm.$nextTick().then(() => { - expect(store.dispatch).toHaveBeenCalledWith( - 'requestDeleteImage', - itemToDelete.destroy_path, - ); + expect(store.dispatch).toHaveBeenCalledWith( + 'requestDeleteImage', + itemToDelete.destroy_path, + ); + }); + + it('should show a success toast when delete request is successful', () => { + dispatchSpy.mockResolvedValue(); + return wrapper.vm.handleDeleteImage().then(() => { + expect(wrapper.vm.$toast.show).toHaveBeenCalledWith(DELETE_IMAGE_SUCCESS_MESSAGE, { + type: 'success', + }); + expect(wrapper.vm.itemToDelete).toEqual({}); + }); + }); + + it('should show a error toast when delete request fails', () => { + dispatchSpy.mockRejectedValue(); + return wrapper.vm.handleDeleteImage().then(() => { + expect(wrapper.vm.$toast.show).toHaveBeenCalledWith(DELETE_IMAGE_ERROR_MESSAGE, { + type: 'error', + }); + expect(wrapper.vm.itemToDelete).toEqual({}); }); }); }); @@ -227,7 +253,7 @@ describe('List Page', () => { beforeEach(() => { jest.spyOn(Tracking, 'event'); - dispatchSpy.mockReturnValue(); + dispatchSpy.mockResolvedValue(); }); it('send an event when delete button is clicked', () => { @@ -235,13 +261,14 @@ describe('List Page', () => { deleteBtn.vm.$emit('click'); testTrackingCall('click_button'); }); + it('send an event when cancel is pressed on modal', () => { const deleteModal = findDeleteModal(); deleteModal.vm.$emit('cancel'); testTrackingCall('cancel_delete'); }); + it('send an event when confirm is clicked on modal', () => { - dispatchSpy.mockReturnValue(); const deleteModal = findDeleteModal(); deleteModal.vm.$emit('ok'); testTrackingCall('confirm_delete'); diff --git a/spec/frontend/registry/explorer/stores/actions_spec.js b/spec/frontend/registry/explorer/stores/actions_spec.js index 3e22621058e..b39c79dd1ab 100644 --- a/spec/frontend/registry/explorer/stores/actions_spec.js +++ b/spec/frontend/registry/explorer/stores/actions_spec.js @@ -38,6 +38,17 @@ describe('Actions RegistryExplorer Store', () => { ); }); + it('setShowGarbageCollectionTip', done => { + testAction( + actions.setShowGarbageCollectionTip, + true, + null, + [{ type: types.SET_SHOW_GARBAGE_COLLECTION_TIP, payload: true }], + [], + done, + ); + }); + describe('receives api responses', () => { const response = { data: [1, 2, 3], @@ -183,18 +194,19 @@ describe('Actions RegistryExplorer Store', () => { [{ type: types.SET_MAIN_LOADING, payload: true }], [ { + type: 'setShowGarbageCollectionTip', + payload: true, + }, + { type: 'requestTagsList', payload: { pagination: {}, params }, }, ], - () => { - expect(createFlash).toHaveBeenCalled(); - done(); - }, + done, ); }); - it('should show flash message on error', done => { + it('should turn off loading on error', done => { testAction( actions.requestDeleteTag, { @@ -208,10 +220,7 @@ describe('Actions RegistryExplorer Store', () => { { type: types.SET_MAIN_LOADING, payload: false }, ], [], - () => { - expect(createFlash).toHaveBeenCalled(); - done(); - }, + done, ); }); }); @@ -235,18 +244,19 @@ describe('Actions RegistryExplorer Store', () => { [{ type: types.SET_MAIN_LOADING, payload: true }], [ { + type: 'setShowGarbageCollectionTip', + payload: true, + }, + { type: 'requestTagsList', payload: { pagination: {}, params }, }, ], - () => { - expect(createFlash).toHaveBeenCalled(); - done(); - }, + done, ); }); - it('should show flash message on error', done => { + it('should turn off loading on error', done => { mock.onDelete(url).replyOnce(500); testAction( @@ -263,17 +273,14 @@ describe('Actions RegistryExplorer Store', () => { { type: types.SET_MAIN_LOADING, payload: false }, ], [], - () => { - expect(createFlash).toHaveBeenCalled(); - done(); - }, + done, ); }); }); describe('request delete single image', () => { + const deletePath = 'delete/path'; it('successfully performs the delete request', done => { - const deletePath = 'delete/path'; mock.onDelete(deletePath).replyOnce(200); testAction( @@ -288,32 +295,32 @@ describe('Actions RegistryExplorer Store', () => { ], [ { + type: 'setShowGarbageCollectionTip', + payload: true, + }, + { type: 'requestImagesList', payload: { pagination: {} }, }, ], - () => { - expect(createFlash).toHaveBeenCalled(); - done(); - }, + done, ); }); - it('should show flash message on error', done => { + it('should turn off loading on error', done => { + mock.onDelete(deletePath).replyOnce(400); testAction( actions.requestDeleteImage, - null, + deletePath, {}, [ { type: types.SET_MAIN_LOADING, payload: true }, { type: types.SET_MAIN_LOADING, payload: false }, ], [], - () => { - expect(createFlash).toHaveBeenCalled(); - done(); - }, - ); + ).catch(() => { + done(); + }); }); }); }); diff --git a/spec/frontend/registry/explorer/stores/getters_spec.js b/spec/frontend/registry/explorer/stores/getters_spec.js index 211b8169d82..cd053ea8edc 100644 --- a/spec/frontend/registry/explorer/stores/getters_spec.js +++ b/spec/frontend/registry/explorer/stores/getters_spec.js @@ -49,4 +49,22 @@ describe('Getters RegistryExplorer store', () => { expect(getters[getter](state)).toBe(expectedPieces.join(' ')); }); }); + + describe('showGarbageCollection', () => { + it.each` + result | showGarbageCollectionTip | isAdmin + ${true} | ${true} | ${true} + ${false} | ${true} | ${false} + ${false} | ${false} | ${true} + `( + 'return $result when showGarbageCollectionTip $showGarbageCollectionTip and isAdmin is $isAdmin', + ({ result, showGarbageCollectionTip, isAdmin }) => { + state = { + config: { isAdmin }, + showGarbageCollectionTip, + }; + expect(getters.showGarbageCollection(state)).toBe(result); + }, + ); + }); }); diff --git a/spec/frontend/registry/explorer/stores/mutations_spec.js b/spec/frontend/registry/explorer/stores/mutations_spec.js index 1d5055c02d2..029fd23f7ce 100644 --- a/spec/frontend/registry/explorer/stores/mutations_spec.js +++ b/spec/frontend/registry/explorer/stores/mutations_spec.js @@ -10,7 +10,12 @@ describe('Mutations Registry Explorer Store', () => { describe('SET_INITIAL_STATE', () => { it('should set the initial state', () => { - const payload = { endpoint: 'foo', isGroupPage: true, expirationPolicy: { foo: 'bar' } }; + const payload = { + endpoint: 'foo', + isGroupPage: true, + expirationPolicy: { foo: 'bar' }, + isAdmin: true, + }; const expectedState = { ...mockState, config: payload }; mutations[types.SET_INITIAL_STATE](mockState, { ...payload, @@ -50,6 +55,15 @@ describe('Mutations Registry Explorer Store', () => { }); }); + describe('SET_SHOW_GARBAGE_COLLECTION_TIP', () => { + it('should set the showGarbageCollectionTip', () => { + const expectedState = { ...mockState, showGarbageCollectionTip: true }; + mutations[types.SET_SHOW_GARBAGE_COLLECTION_TIP](mockState, true); + + expect(mockState).toEqual(expectedState); + }); + }); + describe('SET_PAGINATION', () => { const generatePagination = () => [ { diff --git a/spec/frontend/registry/shared/mocks.js b/spec/frontend/registry/shared/mocks.js new file mode 100644 index 00000000000..e33d06e7499 --- /dev/null +++ b/spec/frontend/registry/shared/mocks.js @@ -0,0 +1,4 @@ +// eslint-disable-next-line import/prefer-default-export +export const $toast = { + show: jest.fn(), +}; |