diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2020-04-01 15:08:00 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2020-04-01 15:08:00 +0300 |
commit | 1a0d6dbdc2ac3047f4953a359ef27ba6e26074ae (patch) | |
tree | ddb78a8a0d1350dc767f049a21e0f7d37edaa82c /spec/frontend/releases/stores/modules/detail | |
parent | b11f7057d067885619ee3e513751f180b2e8ad85 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/releases/stores/modules/detail')
3 files changed, 210 insertions, 34 deletions
diff --git a/spec/frontend/releases/stores/modules/detail/actions_spec.js b/spec/frontend/releases/stores/modules/detail/actions_spec.js index 70f7432c65d..4a1790adb09 100644 --- a/spec/frontend/releases/stores/modules/detail/actions_spec.js +++ b/spec/frontend/releases/stores/modules/detail/actions_spec.js @@ -9,6 +9,7 @@ import createState from '~/releases/stores/modules/detail/state'; import createFlash from '~/flash'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { redirectTo } from '~/lib/utils/url_utility'; +import api from '~/api'; jest.mock('~/flash', () => jest.fn()); @@ -179,40 +180,92 @@ describe('Release detail actions', () => { }); describe('updateRelease', () => { - let getReleaseUrl; + let getters; + let dispatch; + let callOrder; beforeEach(() => { - state.release = release; + state.release = convertObjectPropsToCamelCase(release); state.projectId = '18'; - state.tagName = 'v1.3'; - getReleaseUrl = `/api/v4/projects/${state.projectId}/releases/${state.tagName}`; - }); + state.tagName = state.release.tagName; - it(`dispatches requestUpdateRelease and receiveUpdateReleaseSuccess`, () => { - mock.onPut(getReleaseUrl).replyOnce(200); + getters = { + releaseLinksToDelete: [{ id: '1' }, { id: '2' }], + releaseLinksToCreate: [{ id: 'new-link-1' }, { id: 'new-link-2' }], + }; - return testAction( - actions.updateRelease, - undefined, - state, - [], - [{ type: 'requestUpdateRelease' }, { type: 'receiveUpdateReleaseSuccess' }], - ); + dispatch = jest.fn(); + + callOrder = []; + jest.spyOn(api, 'updateRelease').mockImplementation(() => { + callOrder.push('updateRelease'); + return Promise.resolve(); + }); + jest.spyOn(api, 'deleteReleaseLink').mockImplementation(() => { + callOrder.push('deleteReleaseLink'); + return Promise.resolve(); + }); + jest.spyOn(api, 'createReleaseLink').mockImplementation(() => { + callOrder.push('createReleaseLink'); + return Promise.resolve(); + }); }); - it(`dispatches requestUpdateRelease and receiveUpdateReleaseError with an error object`, () => { - mock.onPut(getReleaseUrl).replyOnce(500); + it('dispatches requestUpdateRelease and receiveUpdateReleaseSuccess', () => { + return actions.updateRelease({ dispatch, state, getters }).then(() => { + expect(dispatch.mock.calls).toEqual([ + ['requestUpdateRelease'], + ['receiveUpdateReleaseSuccess'], + ]); + }); + }); - return testAction( - actions.updateRelease, - undefined, - state, - [], - [ - { type: 'requestUpdateRelease' }, - { type: 'receiveUpdateReleaseError', payload: expect.anything() }, - ], - ); + it('dispatches requestUpdateRelease and receiveUpdateReleaseError with an error object', () => { + jest.spyOn(api, 'updateRelease').mockRejectedValue(error); + + return actions.updateRelease({ dispatch, state, getters }).then(() => { + expect(dispatch.mock.calls).toEqual([ + ['requestUpdateRelease'], + ['receiveUpdateReleaseError', error], + ]); + }); + }); + + it('updates the Release, then deletes all existing links, and then recreates new links', () => { + return actions.updateRelease({ dispatch, state, getters }).then(() => { + expect(callOrder).toEqual([ + 'updateRelease', + 'deleteReleaseLink', + 'deleteReleaseLink', + 'createReleaseLink', + 'createReleaseLink', + ]); + + expect(api.updateRelease.mock.calls).toEqual([ + [ + state.projectId, + state.tagName, + { + name: state.release.name, + description: state.release.description, + }, + ], + ]); + + expect(api.deleteReleaseLink).toHaveBeenCalledTimes(getters.releaseLinksToDelete.length); + getters.releaseLinksToDelete.forEach(link => { + expect(api.deleteReleaseLink).toHaveBeenCalledWith( + state.projectId, + state.tagName, + link.id, + ); + }); + + expect(api.createReleaseLink).toHaveBeenCalledTimes(getters.releaseLinksToCreate.length); + getters.releaseLinksToCreate.forEach(link => { + expect(api.createReleaseLink).toHaveBeenCalledWith(state.projectId, state.tagName, link); + }); + }); }); }); }); diff --git a/spec/frontend/releases/stores/modules/detail/getters_spec.js b/spec/frontend/releases/stores/modules/detail/getters_spec.js new file mode 100644 index 00000000000..7dc95c24055 --- /dev/null +++ b/spec/frontend/releases/stores/modules/detail/getters_spec.js @@ -0,0 +1,59 @@ +import * as getters from '~/releases/stores/modules/detail/getters'; + +describe('Release detail getters', () => { + describe('releaseLinksToCreate', () => { + it("returns an empty array if state.release doesn't exist", () => { + const state = {}; + expect(getters.releaseLinksToCreate(state)).toEqual([]); + }); + + it("returns all release links that aren't empty", () => { + const emptyLinks = [ + { url: '', name: '' }, + { url: ' ', name: '' }, + { url: ' ', name: ' ' }, + { url: '\r\n', name: '\t' }, + ]; + + const nonEmptyLinks = [ + { url: 'https://example.com/1', name: 'Example 1' }, + { url: '', name: 'Example 2' }, + { url: 'https://example.com/3', name: '' }, + ]; + + const state = { + release: { + assets: { + links: [...emptyLinks, ...nonEmptyLinks], + }, + }, + }; + + expect(getters.releaseLinksToCreate(state)).toEqual(nonEmptyLinks); + }); + }); + + describe('releaseLinksToDelete', () => { + it("returns an empty array if state.originalRelease doesn't exist", () => { + const state = {}; + expect(getters.releaseLinksToDelete(state)).toEqual([]); + }); + + it('returns all links associated with the original release', () => { + const originalLinks = [ + { url: 'https://example.com/1', name: 'Example 1' }, + { url: 'https://example.com/2', name: 'Example 2' }, + ]; + + const state = { + originalRelease: { + assets: { + links: originalLinks, + }, + }, + }; + + expect(getters.releaseLinksToDelete(state)).toEqual(originalLinks); + }); + }); +}); diff --git a/spec/frontend/releases/stores/modules/detail/mutations_spec.js b/spec/frontend/releases/stores/modules/detail/mutations_spec.js index d49c8854ca2..cb5a1880b0c 100644 --- a/spec/frontend/releases/stores/modules/detail/mutations_spec.js +++ b/spec/frontend/releases/stores/modules/detail/mutations_spec.js @@ -8,11 +8,12 @@ import createState from '~/releases/stores/modules/detail/state'; import mutations from '~/releases/stores/modules/detail/mutations'; import * as types from '~/releases/stores/modules/detail/mutation_types'; -import { release } from '../../../mock_data'; +import { release as originalRelease } from '../../../mock_data'; +import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; describe('Release detail mutations', () => { let state; - let releaseClone; + let release; beforeEach(() => { state = createState({ @@ -23,7 +24,7 @@ describe('Release detail mutations', () => { markdownPreviewPath: 'path/to/markdown/preview', updateReleaseApiDocsPath: 'path/to/api/docs', }); - releaseClone = JSON.parse(JSON.stringify(release)); + release = convertObjectPropsToCamelCase(originalRelease); }); describe(types.REQUEST_RELEASE, () => { @@ -36,13 +37,15 @@ describe('Release detail mutations', () => { describe(types.RECEIVE_RELEASE_SUCCESS, () => { it('handles a successful response from the server', () => { - mutations[types.RECEIVE_RELEASE_SUCCESS](state, releaseClone); + mutations[types.RECEIVE_RELEASE_SUCCESS](state, release); expect(state.fetchError).toEqual(undefined); expect(state.isFetchingRelease).toEqual(false); - expect(state.release).toEqual(releaseClone); + expect(state.release).toEqual(release); + + expect(state.originalRelease).toEqual(release); }); }); @@ -61,7 +64,7 @@ describe('Release detail mutations', () => { describe(types.UPDATE_RELEASE_TITLE, () => { it("updates the release's title", () => { - state.release = releaseClone; + state.release = release; const newTitle = 'The new release title'; mutations[types.UPDATE_RELEASE_TITLE](state, newTitle); @@ -71,7 +74,7 @@ describe('Release detail mutations', () => { describe(types.UPDATE_RELEASE_NOTES, () => { it("updates the release's notes", () => { - state.release = releaseClone; + state.release = release; const newNotes = 'The new release notes'; mutations[types.UPDATE_RELEASE_NOTES](state, newNotes); @@ -89,7 +92,7 @@ describe('Release detail mutations', () => { describe(types.RECEIVE_UPDATE_RELEASE_SUCCESS, () => { it('handles a successful response from the server', () => { - mutations[types.RECEIVE_UPDATE_RELEASE_SUCCESS](state, releaseClone); + mutations[types.RECEIVE_UPDATE_RELEASE_SUCCESS](state, release); expect(state.updateError).toEqual(undefined); @@ -107,4 +110,65 @@ describe('Release detail mutations', () => { expect(state.updateError).toEqual(error); }); }); + + describe(types.ADD_EMPTY_ASSET_LINK, () => { + it('adds a new, empty link object to the release', () => { + state.release = release; + + const linksBefore = [...state.release.assets.links]; + + mutations[types.ADD_EMPTY_ASSET_LINK](state); + + expect(state.release.assets.links).toEqual([ + ...linksBefore, + { + id: expect.stringMatching(/^new-link-/), + url: '', + name: '', + }, + ]); + }); + }); + + describe(types.UPDATE_ASSET_LINK_URL, () => { + it('updates an asset link with a new URL', () => { + state.release = release; + + const newUrl = 'https://example.com/updated/url'; + + mutations[types.UPDATE_ASSET_LINK_URL](state, { + linkIdToUpdate: state.release.assets.links[0].id, + newUrl, + }); + + expect(state.release.assets.links[0].url).toEqual(newUrl); + }); + }); + + describe(types.UPDATE_ASSET_LINK_NAME, () => { + it('updates an asset link with a new name', () => { + state.release = release; + + const newName = 'Updated Link'; + + mutations[types.UPDATE_ASSET_LINK_NAME](state, { + linkIdToUpdate: state.release.assets.links[0].id, + newName, + }); + + expect(state.release.assets.links[0].name).toEqual(newName); + }); + }); + + describe(types.REMOVE_ASSET_LINK, () => { + it('removes an asset link from the release', () => { + state.release = release; + + const linkToRemove = state.release.assets.links[0]; + + mutations[types.REMOVE_ASSET_LINK](state, linkToRemove.id); + + expect(state.release.assets.links).not.toContainEqual(linkToRemove); + }); + }); }); |