Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/releases/stores/modules/detail/actions_spec.js')
-rw-r--r--spec/frontend/releases/stores/modules/detail/actions_spec.js442
1 files changed, 328 insertions, 114 deletions
diff --git a/spec/frontend/releases/stores/modules/detail/actions_spec.js b/spec/frontend/releases/stores/modules/detail/actions_spec.js
index 1d164b9f5c1..d18437ccec3 100644
--- a/spec/frontend/releases/stores/modules/detail/actions_spec.js
+++ b/spec/frontend/releases/stores/modules/detail/actions_spec.js
@@ -1,9 +1,11 @@
import { cloneDeep } from 'lodash';
import originalOneReleaseForEditingQueryResponse from 'test_fixtures/graphql/releases/graphql/queries/one_release_for_editing.query.graphql.json';
import testAction from 'helpers/vuex_action_helper';
+import { useLocalStorageSpy } from 'helpers/local_storage_helper';
import { getTag } from '~/api/tags_api';
import { createAlert } from '~/alert';
import { redirectTo } from '~/lib/utils/url_utility'; // eslint-disable-line import/no-deprecated
+import AccessorUtilities from '~/lib/utils/accessor';
import { s__ } from '~/locale';
import { ASSET_LINK_TYPE } from '~/releases/constants';
import createReleaseAssetLinkMutation from '~/releases/graphql/mutations/create_release_link.mutation.graphql';
@@ -20,6 +22,7 @@ jest.mock('~/api/tags_api');
jest.mock('~/alert');
+jest.mock('~/lib/utils/accessor');
jest.mock('~/lib/utils/url_utility', () => ({
redirectTo: jest.fn(),
joinPaths: jest.requireActual('~/lib/utils/url_utility').joinPaths,
@@ -34,78 +37,203 @@ jest.mock('~/releases/util', () => ({
}));
describe('Release edit/new actions', () => {
+ useLocalStorageSpy();
+
let state;
let releaseResponse;
let error;
const projectPath = 'test/project-path';
+ const draftActions = [{ type: 'saveDraftRelease' }, { type: 'saveDraftCreateFrom' }];
const setupState = (updates = {}) => {
state = {
...createState({
projectPath,
projectId: '18',
- isExistingRelease: true,
+ isExistingRelease: false,
tagName: releaseResponse.tag_name,
releasesPagePath: 'path/to/releases/page',
markdownDocsPath: 'path/to/markdown/docs',
markdownPreviewPath: 'path/to/markdown/preview',
}),
+ localStorageKey: `${projectPath}/release/new`,
+ localStorageCreateFromKey: `${projectPath}/release/new/createFrom`,
...updates,
};
};
beforeEach(() => {
+ AccessorUtilities.canUseLocalStorage.mockReturnValue(true);
releaseResponse = cloneDeep(originalOneReleaseForEditingQueryResponse);
gon.api_version = 'v4';
error = new Error('Yikes!');
createAlert.mockClear();
});
+ afterEach(() => {
+ jest.clearAllMocks();
+ });
+
describe('when creating a new release', () => {
beforeEach(() => {
setupState({ isExistingRelease: false });
});
describe('initializeRelease', () => {
- it(`commits ${types.INITIALIZE_EMPTY_RELEASE}`, () => {
- testAction(actions.initializeRelease, undefined, state, [
- { type: types.INITIALIZE_EMPTY_RELEASE },
- ]);
+ it('dispatches loadDraftRelease', () => {
+ return testAction({
+ action: actions.initializeRelease,
+ state,
+ expectedMutations: [],
+ expectedActions: [{ type: 'loadDraftRelease' }],
+ });
+ });
+ });
+
+ describe('loadDraftRelease', () => {
+ it(`with no saved release, it commits ${types.INITIALIZE_EMPTY_RELEASE}`, () => {
+ testAction({
+ action: actions.loadDraftRelease,
+ state,
+ expectedMutations: [{ type: types.INITIALIZE_EMPTY_RELEASE }],
+ });
+ });
+
+ it('with saved release, loads the release from local storage', () => {
+ const release = {
+ tagName: 'v1.3',
+ tagMessage: 'hello',
+ name: '',
+ description: '',
+ milestones: [],
+ groupMilestones: [],
+ releasedAt: new Date(),
+ assets: {
+ links: [],
+ },
+ };
+ const createFrom = 'main';
+
+ window.localStorage.setItem(`${state.projectPath}/release/new`, JSON.stringify(release));
+ window.localStorage.setItem(
+ `${state.projectPath}/release/new/createFrom`,
+ JSON.stringify(createFrom),
+ );
+
+ return testAction({
+ action: actions.loadDraftRelease,
+ state,
+ expectedMutations: [
+ { type: types.INITIALIZE_RELEASE, payload: release },
+ { type: types.UPDATE_CREATE_FROM, payload: createFrom },
+ ],
+ });
+ });
+ });
+
+ describe('clearDraftRelease', () => {
+ it('calls window.localStorage.clear', () => {
+ return testAction({ action: actions.clearDraftRelease, state }).then(() => {
+ expect(window.localStorage.removeItem).toHaveBeenCalledTimes(2);
+ expect(window.localStorage.removeItem).toHaveBeenCalledWith(state.localStorageKey);
+ expect(window.localStorage.removeItem).toHaveBeenCalledWith(
+ state.localStorageCreateFromKey,
+ );
+ });
+ });
+ });
+
+ describe('saveDraftCreateFrom', () => {
+ it('saves the create from to local storage', () => {
+ const createFrom = 'main';
+ setupState({ createFrom });
+ return testAction({ action: actions.saveDraftCreateFrom, state }).then(() => {
+ expect(window.localStorage.setItem).toHaveBeenCalledTimes(1);
+ expect(window.localStorage.setItem).toHaveBeenCalledWith(
+ state.localStorageCreateFromKey,
+ JSON.stringify(createFrom),
+ );
+ });
+ });
+ });
+
+ describe('saveDraftRelease', () => {
+ let release;
+
+ beforeEach(() => {
+ release = {
+ tagName: 'v1.3',
+ tagMessage: 'hello',
+ name: '',
+ description: '',
+ milestones: [],
+ groupMilestones: [],
+ releasedAt: new Date(),
+ assets: {
+ links: [],
+ },
+ };
+ });
+
+ it('saves the draft release to local storage', () => {
+ setupState({ release, releasedAtChanged: true });
+
+ return testAction({ action: actions.saveDraftRelease, state }).then(() => {
+ expect(window.localStorage.setItem).toHaveBeenCalledTimes(1);
+ expect(window.localStorage.setItem).toHaveBeenCalledWith(
+ state.localStorageKey,
+ JSON.stringify(state.release),
+ );
+ });
+ });
+
+ it('ignores the released at date if it has not been changed', () => {
+ setupState({ release, releasedAtChanged: false });
+
+ return testAction({ action: actions.saveDraftRelease, state }).then(() => {
+ expect(window.localStorage.setItem).toHaveBeenCalledTimes(1);
+ expect(window.localStorage.setItem).toHaveBeenCalledWith(
+ state.localStorageKey,
+ JSON.stringify({ ...state.release, releasedAt: undefined }),
+ );
+ });
});
});
describe('saveRelease', () => {
it(`commits ${types.REQUEST_SAVE_RELEASE} and then dispatched "createRelease"`, () => {
- testAction(
- actions.saveRelease,
- undefined,
+ testAction({
+ action: actions.saveRelease,
state,
- [{ type: types.REQUEST_SAVE_RELEASE }],
- [{ type: 'createRelease' }],
- );
+ expectedMutations: [{ type: types.REQUEST_SAVE_RELEASE }],
+ expectedActions: [{ type: 'createRelease' }],
+ });
});
});
});
describe('when editing an existing release', () => {
- beforeEach(setupState);
+ beforeEach(() => setupState({ isExistingRelease: true }));
describe('initializeRelease', () => {
it('dispatches "fetchRelease"', () => {
- testAction(actions.initializeRelease, undefined, state, [], [{ type: 'fetchRelease' }]);
+ testAction({
+ action: actions.initializeRelease,
+ state,
+ expectedActions: [{ type: 'fetchRelease' }],
+ });
});
});
describe('saveRelease', () => {
it(`commits ${types.REQUEST_SAVE_RELEASE} and then dispatched "updateRelease"`, () => {
- testAction(
- actions.saveRelease,
- undefined,
+ testAction({
+ action: actions.saveRelease,
state,
- [{ type: types.REQUEST_SAVE_RELEASE }],
- [{ type: 'updateRelease' }],
- );
+ expectedMutations: [{ type: types.REQUEST_SAVE_RELEASE }],
+ expectedActions: [{ type: 'updateRelease' }],
+ });
});
});
});
@@ -120,15 +248,19 @@ describe('Release edit/new actions', () => {
});
it(`commits ${types.REQUEST_RELEASE} and then commits ${types.RECEIVE_RELEASE_SUCCESS} with the converted release object`, () => {
- return testAction(actions.fetchRelease, undefined, state, [
- {
- type: types.REQUEST_RELEASE,
- },
- {
- type: types.RECEIVE_RELEASE_SUCCESS,
- payload: convertOneReleaseGraphQLResponse(releaseResponse).data,
- },
- ]);
+ return testAction({
+ action: actions.fetchRelease,
+ state,
+ expectedMutations: [
+ {
+ type: types.REQUEST_RELEASE,
+ },
+ {
+ type: types.RECEIVE_RELEASE_SUCCESS,
+ payload: convertOneReleaseGraphQLResponse(releaseResponse).data,
+ },
+ ],
+ });
});
});
@@ -138,15 +270,19 @@ describe('Release edit/new actions', () => {
});
it(`commits ${types.REQUEST_RELEASE} and then commits ${types.RECEIVE_RELEASE_ERROR} with an error object`, () => {
- return testAction(actions.fetchRelease, undefined, state, [
- {
- type: types.REQUEST_RELEASE,
- },
- {
- type: types.RECEIVE_RELEASE_ERROR,
- payload: expect.any(Error),
- },
- ]);
+ return testAction({
+ action: actions.fetchRelease,
+ state,
+ expectedMutations: [
+ {
+ type: types.REQUEST_RELEASE,
+ },
+ {
+ type: types.RECEIVE_RELEASE_ERROR,
+ payload: expect.any(Error),
+ },
+ ],
+ });
});
it(`shows an alert message`, () => {
@@ -163,89 +299,140 @@ describe('Release edit/new actions', () => {
describe('updateReleaseTagName', () => {
it(`commits ${types.UPDATE_RELEASE_TAG_NAME} with the updated tag name`, () => {
const newTag = 'updated-tag-name';
- return testAction(actions.updateReleaseTagName, newTag, state, [
- { type: types.UPDATE_RELEASE_TAG_NAME, payload: newTag },
- ]);
+ return testAction({
+ action: actions.updateReleaseTagName,
+ payload: newTag,
+ state,
+ expectedMutations: [{ type: types.UPDATE_RELEASE_TAG_NAME, payload: newTag }],
+ expectedActions: draftActions,
+ });
+ });
+ it('does not save drafts when editing', () => {
+ const newTag = 'updated-tag-name';
+ return testAction({
+ action: actions.updateReleaseTagName,
+ payload: newTag,
+ state: { ...state, isExistingRelease: true },
+ expectedMutations: [{ type: types.UPDATE_RELEASE_TAG_NAME, payload: newTag }],
+ });
});
});
describe('updateReleaseTagMessage', () => {
it(`commits ${types.UPDATE_RELEASE_TAG_MESSAGE} with the updated tag name`, () => {
const newMessage = 'updated-tag-message';
- return testAction(actions.updateReleaseTagMessage, newMessage, state, [
- { type: types.UPDATE_RELEASE_TAG_MESSAGE, payload: newMessage },
- ]);
+ return testAction({
+ action: actions.updateReleaseTagMessage,
+ payload: newMessage,
+ state,
+ expectedMutations: [{ type: types.UPDATE_RELEASE_TAG_MESSAGE, payload: newMessage }],
+ expectedActions: draftActions,
+ });
});
});
describe('updateReleasedAt', () => {
it(`commits ${types.UPDATE_RELEASED_AT} with the updated date`, () => {
const newDate = new Date();
- return testAction(actions.updateReleasedAt, newDate, state, [
- { type: types.UPDATE_RELEASED_AT, payload: newDate },
- ]);
+ return testAction({
+ action: actions.updateReleasedAt,
+ payload: newDate,
+ state,
+ expectedMutations: [{ type: types.UPDATE_RELEASED_AT, payload: newDate }],
+ expectedActions: draftActions,
+ });
});
});
describe('updateCreateFrom', () => {
it(`commits ${types.UPDATE_CREATE_FROM} with the updated ref`, () => {
const newRef = 'my-feature-branch';
- return testAction(actions.updateCreateFrom, newRef, state, [
- { type: types.UPDATE_CREATE_FROM, payload: newRef },
- ]);
+ return testAction({
+ action: actions.updateCreateFrom,
+ payload: newRef,
+ state,
+ expectedMutations: [{ type: types.UPDATE_CREATE_FROM, payload: newRef }],
+ expectedActions: draftActions,
+ });
});
});
describe('updateShowCreateFrom', () => {
it(`commits ${types.UPDATE_SHOW_CREATE_FROM} with the updated ref`, () => {
const newRef = 'my-feature-branch';
- return testAction(actions.updateShowCreateFrom, newRef, state, [
- { type: types.UPDATE_SHOW_CREATE_FROM, payload: newRef },
- ]);
+ return testAction({
+ action: actions.updateShowCreateFrom,
+ payload: newRef,
+ state,
+ expectedMutations: [{ type: types.UPDATE_SHOW_CREATE_FROM, payload: newRef }],
+ });
});
});
describe('updateReleaseTitle', () => {
it(`commits ${types.UPDATE_RELEASE_TITLE} with the updated release title`, () => {
const newTitle = 'The new release title';
- return testAction(actions.updateReleaseTitle, newTitle, state, [
- { type: types.UPDATE_RELEASE_TITLE, payload: newTitle },
- ]);
+ return testAction({
+ action: actions.updateReleaseTitle,
+ payload: newTitle,
+ state,
+ expectedMutations: [{ type: types.UPDATE_RELEASE_TITLE, payload: newTitle }],
+ expectedActions: draftActions,
+ });
});
});
describe('updateReleaseNotes', () => {
it(`commits ${types.UPDATE_RELEASE_NOTES} with the updated release notes`, () => {
const newReleaseNotes = 'The new release notes';
- return testAction(actions.updateReleaseNotes, newReleaseNotes, state, [
- { type: types.UPDATE_RELEASE_NOTES, payload: newReleaseNotes },
- ]);
+ return testAction({
+ action: actions.updateReleaseNotes,
+ payload: newReleaseNotes,
+ state,
+ expectedMutations: [{ type: types.UPDATE_RELEASE_NOTES, payload: newReleaseNotes }],
+ expectedActions: draftActions,
+ });
});
});
describe('updateReleaseMilestones', () => {
it(`commits ${types.UPDATE_RELEASE_MILESTONES} with the updated release milestones`, () => {
const newReleaseMilestones = ['v0.0', 'v0.1'];
- return testAction(actions.updateReleaseMilestones, newReleaseMilestones, state, [
- { type: types.UPDATE_RELEASE_MILESTONES, payload: newReleaseMilestones },
- ]);
+ return testAction({
+ action: actions.updateReleaseMilestones,
+ payload: newReleaseMilestones,
+ state,
+ expectedMutations: [
+ { type: types.UPDATE_RELEASE_MILESTONES, payload: newReleaseMilestones },
+ ],
+ expectedActions: draftActions,
+ });
});
});
describe('updateReleaseGroupMilestones', () => {
it(`commits ${types.UPDATE_RELEASE_GROUP_MILESTONES} with the updated release group milestones`, () => {
const newReleaseGroupMilestones = ['v0.0', 'v0.1'];
- return testAction(actions.updateReleaseGroupMilestones, newReleaseGroupMilestones, state, [
- { type: types.UPDATE_RELEASE_GROUP_MILESTONES, payload: newReleaseGroupMilestones },
- ]);
+ return testAction({
+ action: actions.updateReleaseGroupMilestones,
+ payload: newReleaseGroupMilestones,
+ state,
+ expectedMutations: [
+ { type: types.UPDATE_RELEASE_GROUP_MILESTONES, payload: newReleaseGroupMilestones },
+ ],
+ expectedActions: draftActions,
+ });
});
});
describe('addEmptyAssetLink', () => {
it(`commits ${types.ADD_EMPTY_ASSET_LINK}`, () => {
- return testAction(actions.addEmptyAssetLink, undefined, state, [
- { type: types.ADD_EMPTY_ASSET_LINK },
- ]);
+ return testAction({
+ action: actions.addEmptyAssetLink,
+ state,
+ expectedMutations: [{ type: types.ADD_EMPTY_ASSET_LINK }],
+ expectedActions: draftActions,
+ });
});
});
@@ -256,9 +443,13 @@ describe('Release edit/new actions', () => {
newUrl: 'https://example.com/updated',
};
- return testAction(actions.updateAssetLinkUrl, params, state, [
- { type: types.UPDATE_ASSET_LINK_URL, payload: params },
- ]);
+ return testAction({
+ action: actions.updateAssetLinkUrl,
+ payload: params,
+ state,
+ expectedMutations: [{ type: types.UPDATE_ASSET_LINK_URL, payload: params }],
+ expectedActions: draftActions,
+ });
});
});
@@ -269,9 +460,13 @@ describe('Release edit/new actions', () => {
newName: 'Updated link name',
};
- return testAction(actions.updateAssetLinkName, params, state, [
- { type: types.UPDATE_ASSET_LINK_NAME, payload: params },
- ]);
+ return testAction({
+ action: actions.updateAssetLinkName,
+ payload: params,
+ state,
+ expectedMutations: [{ type: types.UPDATE_ASSET_LINK_NAME, payload: params }],
+ expectedActions: draftActions,
+ });
});
});
@@ -282,30 +477,45 @@ describe('Release edit/new actions', () => {
newType: ASSET_LINK_TYPE.RUNBOOK,
};
- return testAction(actions.updateAssetLinkType, params, state, [
- { type: types.UPDATE_ASSET_LINK_TYPE, payload: params },
- ]);
+ return testAction({
+ action: actions.updateAssetLinkType,
+ payload: params,
+ state,
+ expectedMutations: [{ type: types.UPDATE_ASSET_LINK_TYPE, payload: params }],
+ expectedActions: draftActions,
+ });
});
});
describe('removeAssetLink', () => {
it(`commits ${types.REMOVE_ASSET_LINK} with the ID of the asset link to remove`, () => {
const idToRemove = 2;
- return testAction(actions.removeAssetLink, idToRemove, state, [
- { type: types.REMOVE_ASSET_LINK, payload: idToRemove },
- ]);
+ return testAction({
+ action: actions.removeAssetLink,
+ payload: idToRemove,
+ state,
+ expectedMutations: [{ type: types.REMOVE_ASSET_LINK, payload: idToRemove }],
+ expectedActions: draftActions,
+ });
});
});
describe('receiveSaveReleaseSuccess', () => {
- it(`commits ${types.RECEIVE_SAVE_RELEASE_SUCCESS}`, () =>
- testAction(actions.receiveSaveReleaseSuccess, releaseResponse, state, [
- { type: types.RECEIVE_SAVE_RELEASE_SUCCESS },
- ]));
+ it(`commits ${types.RECEIVE_SAVE_RELEASE_SUCCESS} and dispatches clearDraftRelease`, () =>
+ testAction({
+ action: actions.receiveSaveReleaseSuccess,
+ payload: releaseResponse,
+ state,
+ expectedMutations: [{ type: types.RECEIVE_SAVE_RELEASE_SUCCESS }],
+ expectedActions: [{ type: 'clearDraftRelease' }],
+ }));
it("redirects to the release's dedicated page", () => {
const { selfUrl } = releaseResponse.data.project.release.links;
- actions.receiveSaveReleaseSuccess({ commit: jest.fn(), state }, selfUrl);
+ actions.receiveSaveReleaseSuccess(
+ { commit: jest.fn(), state, dispatch: jest.fn() },
+ selfUrl,
+ );
expect(redirectTo).toHaveBeenCalledTimes(1); // eslint-disable-line import/no-deprecated
expect(redirectTo).toHaveBeenCalledWith(selfUrl); // eslint-disable-line import/no-deprecated
});
@@ -346,18 +556,16 @@ describe('Release edit/new actions', () => {
});
it(`dispatches "receiveSaveReleaseSuccess" with the converted release object`, () => {
- return testAction(
- actions.createRelease,
- undefined,
+ return testAction({
+ action: actions.createRelease,
state,
- [],
- [
+ expectedActions: [
{
type: 'receiveSaveReleaseSuccess',
payload: selfUrl,
},
],
- );
+ });
});
});
@@ -367,12 +575,16 @@ describe('Release edit/new actions', () => {
});
it(`commits ${types.RECEIVE_SAVE_RELEASE_ERROR} with an error object`, () => {
- return testAction(actions.createRelease, undefined, state, [
- {
- type: types.RECEIVE_SAVE_RELEASE_ERROR,
- payload: expect.any(Error),
- },
- ]);
+ return testAction({
+ action: actions.createRelease,
+ state,
+ expectedMutations: [
+ {
+ type: types.RECEIVE_SAVE_RELEASE_ERROR,
+ payload: expect.any(Error),
+ },
+ ],
+ });
});
it(`shows an alert message`, () => {
@@ -393,12 +605,16 @@ describe('Release edit/new actions', () => {
});
it(`commits ${types.RECEIVE_SAVE_RELEASE_ERROR} with an error object`, () => {
- return testAction(actions.createRelease, undefined, state, [
- {
- type: types.RECEIVE_SAVE_RELEASE_ERROR,
- payload: expect.any(Error),
- },
- ]);
+ return testAction({
+ action: actions.createRelease,
+ state,
+ expectedMutations: [
+ {
+ type: types.RECEIVE_SAVE_RELEASE_ERROR,
+ payload: expect.any(Error),
+ },
+ ],
+ });
});
it(`shows an alert message`, () => {
@@ -760,16 +976,15 @@ describe('Release edit/new actions', () => {
const tag = { message: 'this is a tag' };
getTag.mockResolvedValue({ data: tag });
- await testAction(
- actions.fetchTagNotes,
- tagName,
+ await testAction({
+ action: actions.fetchTagNotes,
+ payload: tagName,
state,
- [
+ expectedMutations: [
{ type: types.REQUEST_TAG_NOTES },
{ type: types.RECEIVE_TAG_NOTES_SUCCESS, payload: tag },
],
- [],
- );
+ });
expect(getTag).toHaveBeenCalledWith(state.projectId, tagName);
});
@@ -777,16 +992,15 @@ describe('Release edit/new actions', () => {
error = new Error();
getTag.mockRejectedValue(error);
- await testAction(
- actions.fetchTagNotes,
- tagName,
+ await testAction({
+ action: actions.fetchTagNotes,
+ payload: tagName,
state,
- [
+ expectedMutations: [
{ type: types.REQUEST_TAG_NOTES },
{ type: types.RECEIVE_TAG_NOTES_ERROR, payload: error },
],
- [],
- );
+ });
expect(createAlert).toHaveBeenCalledWith({
message: s__('Release|Unable to fetch the tag notes.'),