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:
authorGitLab Bot <gitlab-bot@gitlab.com>2022-07-18 15:08:41 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2022-07-18 15:08:41 +0300
commit5c5d24f032b67d98452f391192386e330a0f880c (patch)
tree9e58d94388f63cb825e426fea2c4929740604768 /spec/frontend/releases
parent5ccb67600c63549774a28811d177dd673e6dd4d0 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/releases')
-rw-r--r--spec/frontend/releases/__snapshots__/util_spec.js.snap1
-rw-r--r--spec/frontend/releases/components/app_edit_new_spec.js29
-rw-r--r--spec/frontend/releases/components/app_index_spec.js31
-rw-r--r--spec/frontend/releases/components/confirm_delete_modal_spec.js89
-rw-r--r--spec/frontend/releases/stores/modules/detail/actions_spec.js134
-rw-r--r--spec/frontend/releases/stores/modules/detail/getters_spec.js20
6 files changed, 303 insertions, 1 deletions
diff --git a/spec/frontend/releases/__snapshots__/util_spec.js.snap b/spec/frontend/releases/__snapshots__/util_spec.js.snap
index 0bf0ef1ded4..90a33152877 100644
--- a/spec/frontend/releases/__snapshots__/util_spec.js.snap
+++ b/spec/frontend/releases/__snapshots__/util_spec.js.snap
@@ -269,6 +269,7 @@ Object {
"name": "The first release",
"releasedAt": 2018-12-10T00:00:00.000Z,
"tagName": "v1.1",
+ "tagPath": "/releases-namespace/releases-project/-/tags/v1.1",
},
}
`;
diff --git a/spec/frontend/releases/components/app_edit_new_spec.js b/spec/frontend/releases/components/app_edit_new_spec.js
index bccb0849800..cb044b9e891 100644
--- a/spec/frontend/releases/components/app_edit_new_spec.js
+++ b/spec/frontend/releases/components/app_edit_new_spec.js
@@ -11,6 +11,7 @@ import setWindowLocation from 'helpers/set_window_location_helper';
import { TEST_HOST } from 'helpers/test_constants';
import ReleaseEditNewApp from '~/releases/components/app_edit_new.vue';
import AssetLinksForm from '~/releases/components/asset_links_form.vue';
+import ConfirmDeleteModal from '~/releases/components/confirm_delete_modal.vue';
import { BACK_URL_PARAM } from '~/releases/constants';
import MarkdownField from '~/vue_shared/components/markdown/field.vue';
@@ -43,6 +44,7 @@ describe('Release edit/new component', () => {
initializeRelease: jest.fn(),
saveRelease: jest.fn(),
addEmptyAssetLink: jest.fn(),
+ deleteRelease: jest.fn(),
};
getters = {
@@ -287,4 +289,31 @@ describe('Release edit/new component', () => {
});
});
});
+
+ describe('delete', () => {
+ const findConfirmDeleteModal = () => wrapper.findComponent(ConfirmDeleteModal);
+
+ it('calls the deleteRelease action on confirmation', async () => {
+ await factory();
+ findConfirmDeleteModal().vm.$emit('delete');
+
+ expect(actions.deleteRelease).toHaveBeenCalled();
+ });
+
+ it('is hidden if this is a new release', async () => {
+ await factory({
+ store: {
+ modules: {
+ editNew: {
+ state: {
+ isExistingRelease: false,
+ },
+ },
+ },
+ },
+ });
+
+ expect(findConfirmDeleteModal().exists()).toBe(false);
+ });
+ });
});
diff --git a/spec/frontend/releases/components/app_index_spec.js b/spec/frontend/releases/components/app_index_spec.js
index 63ce4c8bb17..f64f07de90e 100644
--- a/spec/frontend/releases/components/app_index_spec.js
+++ b/spec/frontend/releases/components/app_index_spec.js
@@ -8,6 +8,7 @@ import waitForPromises from 'helpers/wait_for_promises';
import allReleasesQuery from '~/releases/graphql/queries/all_releases.query.graphql';
import createFlash from '~/flash';
import { historyPushState } from '~/lib/utils/common_utils';
+import { sprintf, __ } from '~/locale';
import ReleasesIndexApp from '~/releases/components/app_index.vue';
import ReleaseBlock from '~/releases/components/release_block.vue';
import ReleaseSkeletonLoader from '~/releases/components/release_skeleton_loader.vue';
@@ -15,6 +16,7 @@ import ReleasesEmptyState from '~/releases/components/releases_empty_state.vue';
import ReleasesPagination from '~/releases/components/releases_pagination.vue';
import ReleasesSort from '~/releases/components/releases_sort.vue';
import { PAGE_SIZE, CREATED_ASC, DEFAULT_SORT } from '~/releases/constants';
+import { deleteReleaseSessionKey } from '~/releases/util';
Vue.use(VueApollo);
@@ -44,6 +46,7 @@ describe('app_index.vue', () => {
let singleRelease;
let noReleases;
let queryMock;
+ let toast;
const createComponent = ({
singleResponse = Promise.resolve(singleRelease),
@@ -58,12 +61,17 @@ describe('app_index.vue', () => {
],
]);
+ toast = jest.fn();
+
wrapper = shallowMountExtended(ReleasesIndexApp, {
apolloProvider,
provide: {
newReleasePath,
projectPath,
},
+ mocks: {
+ $toast: { show: toast },
+ },
});
};
@@ -395,4 +403,27 @@ describe('app_index.vue', () => {
},
);
});
+
+ describe('after deleting', () => {
+ const release = 'fake release';
+ const key = deleteReleaseSessionKey(projectPath);
+
+ beforeEach(async () => {
+ window.sessionStorage.setItem(key, release);
+
+ await createComponent();
+ });
+
+ it('shows a toast', async () => {
+ expect(toast).toHaveBeenCalledWith(
+ sprintf(__('Release %{release} has been successfully deleted.'), {
+ release,
+ }),
+ );
+ });
+
+ it('clears session storage', async () => {
+ expect(window.sessionStorage.getItem(key)).toBe(null);
+ });
+ });
});
diff --git a/spec/frontend/releases/components/confirm_delete_modal_spec.js b/spec/frontend/releases/components/confirm_delete_modal_spec.js
new file mode 100644
index 00000000000..f7c526c1ced
--- /dev/null
+++ b/spec/frontend/releases/components/confirm_delete_modal_spec.js
@@ -0,0 +1,89 @@
+import Vue, { nextTick } from 'vue';
+import Vuex from 'vuex';
+import { GlModal } from '@gitlab/ui';
+import originalOneReleaseForEditingQueryResponse from 'test_fixtures/graphql/releases/graphql/queries/one_release_for_editing.query.graphql.json';
+import { convertOneReleaseGraphQLResponse } from '~/releases/util';
+import ConfirmDeleteModal from '~/releases/components/confirm_delete_modal.vue';
+import { mountExtended } from 'helpers/vue_test_utils_helper';
+import { __, sprintf } from '~/locale';
+
+Vue.use(Vuex);
+
+const release = convertOneReleaseGraphQLResponse(originalOneReleaseForEditingQueryResponse).data;
+const deleteReleaseDocsPath = 'path/to/delete/release/docs';
+
+describe('~/releases/components/confirm_delete_modal.vue', () => {
+ let wrapper;
+ let state;
+
+ const factory = async () => {
+ state = {
+ release,
+ deleteReleaseDocsPath,
+ };
+
+ const store = new Vuex.Store({
+ modules: {
+ editNew: {
+ namespaced: true,
+ state,
+ },
+ },
+ });
+
+ wrapper = mountExtended(ConfirmDeleteModal, {
+ store,
+ });
+
+ await nextTick();
+ };
+
+ beforeEach(() => {
+ factory();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('button', () => {
+ it('should open the modal on click', async () => {
+ await wrapper.findByRole('button', { name: 'Delete' }).trigger('click');
+
+ const title = wrapper.findByText(
+ sprintf(__('Delete release %{release}?'), { release: release.name }),
+ );
+
+ expect(title.exists()).toBe(true);
+ });
+ });
+
+ describe('modal', () => {
+ beforeEach(async () => {
+ await wrapper.findByRole('button', { name: 'Delete' }).trigger('click');
+ });
+
+ it('confirms the user wants to delete the release', () => {
+ const text = wrapper.findByText(__('Are you sure you want to delete this release?'));
+
+ expect(text.exists()).toBe(true);
+ });
+
+ it('links to the tag', () => {
+ const tagPath = wrapper.findByRole('link', { name: release.tagName });
+ expect(tagPath.attributes('href')).toBe(release.tagPath);
+ });
+
+ it('links to the docs on deleting releases', () => {
+ const docsPath = wrapper.findByRole('link', { name: 'Deleting a release' });
+
+ expect(docsPath.attributes('href')).toBe(deleteReleaseDocsPath);
+ });
+
+ it('emits a delete event on action primary', () => {
+ wrapper.findComponent(GlModal).vm.$emit('primary');
+
+ expect(wrapper.emitted('delete')).toEqual([[]]);
+ });
+ });
+});
diff --git a/spec/frontend/releases/stores/modules/detail/actions_spec.js b/spec/frontend/releases/stores/modules/detail/actions_spec.js
index c7ee214013f..ce3b690213c 100644
--- a/spec/frontend/releases/stores/modules/detail/actions_spec.js
+++ b/spec/frontend/releases/stores/modules/detail/actions_spec.js
@@ -9,10 +9,15 @@ import { ASSET_LINK_TYPE } from '~/releases/constants';
import createReleaseAssetLinkMutation from '~/releases/graphql/mutations/create_release_link.mutation.graphql';
import deleteReleaseAssetLinkMutation from '~/releases/graphql/mutations/delete_release_link.mutation.graphql';
import updateReleaseMutation from '~/releases/graphql/mutations/update_release.mutation.graphql';
+import deleteReleaseMutation from '~/releases/graphql/mutations/delete_release.mutation.graphql';
import * as actions from '~/releases/stores/modules/edit_new/actions';
import * as types from '~/releases/stores/modules/edit_new/mutation_types';
import createState from '~/releases/stores/modules/edit_new/state';
-import { gqClient, convertOneReleaseGraphQLResponse } from '~/releases/util';
+import {
+ gqClient,
+ convertOneReleaseGraphQLResponse,
+ deleteReleaseSessionKey,
+} from '~/releases/util';
jest.mock('~/api/tags_api');
@@ -586,6 +591,133 @@ describe('Release edit/new actions', () => {
});
});
+ describe('deleteRelease', () => {
+ let getters;
+ let dispatch;
+ let commit;
+ let release;
+
+ beforeEach(() => {
+ getters = {
+ releaseDeleteMutationVariables: {
+ input: {
+ projectPath: 'test-org/test',
+ tagName: 'v1.0',
+ },
+ },
+ };
+
+ release = convertOneReleaseGraphQLResponse(releaseResponse).data;
+
+ setupState({
+ release,
+ originalRelease: release,
+ ...getters,
+ });
+
+ dispatch = jest.fn();
+ commit = jest.fn();
+
+ gqClient.mutate.mockResolvedValue({
+ data: {
+ releaseDelete: {
+ errors: [],
+ },
+ releaseAssetLinkDelete: {
+ errors: [],
+ },
+ },
+ });
+ });
+
+ describe('when the delete is successful', () => {
+ beforeEach(() => {
+ window.sessionStorage.clear();
+ });
+
+ it('dispatches receiveSaveReleaseSuccess', async () => {
+ await actions.deleteRelease({ commit, dispatch, state, getters });
+ expect(dispatch.mock.calls).toEqual([
+ ['receiveSaveReleaseSuccess', state.releasesPagePath],
+ ]);
+ });
+
+ it('deletes the release', async () => {
+ await actions.deleteRelease({ commit, dispatch, state, getters });
+ expect(gqClient.mutate.mock.calls[0]).toEqual([
+ {
+ mutation: deleteReleaseMutation,
+ variables: getters.releaseDeleteMutationVariables,
+ },
+ ]);
+ });
+
+ it('stores the name for toasting', async () => {
+ await actions.deleteRelease({ commit, dispatch, state, getters });
+ expect(window.sessionStorage.getItem(deleteReleaseSessionKey(state.projectPath))).toBe(
+ state.release.name,
+ );
+ });
+ });
+
+ describe('when the delete request fails', () => {
+ beforeEach(() => {
+ gqClient.mutate.mockRejectedValue(error);
+ });
+
+ it('dispatches requestDeleteRelease and receiveSaveReleaseError with an error object', async () => {
+ await actions.deleteRelease({ commit, dispatch, state, getters });
+
+ expect(commit.mock.calls).toContainEqual([types.RECEIVE_SAVE_RELEASE_ERROR, error]);
+ });
+
+ it('shows a flash message', async () => {
+ await actions.deleteRelease({ commit, dispatch, state, getters });
+
+ expect(createFlash).toHaveBeenCalledTimes(1);
+ expect(createFlash).toHaveBeenCalledWith({
+ message: 'Something went wrong while deleting the release.',
+ });
+ });
+ });
+
+ describe('when the delete returns errors', () => {
+ beforeEach(() => {
+ gqClient.mutate.mockResolvedValue({
+ data: {
+ releaseUpdate: {
+ errors: ['Something went wrong!'],
+ },
+ releaseAssetLinkDelete: {
+ errors: [],
+ },
+ releaseAssetLinkCreate: {
+ errors: [],
+ },
+ },
+ });
+ });
+
+ it('dispatches requestDeleteRelease and receiveSaveReleaseError with an error object', async () => {
+ await actions.deleteRelease({ commit, dispatch, state, getters });
+
+ expect(commit.mock.calls).toContainEqual([
+ types.RECEIVE_SAVE_RELEASE_ERROR,
+ expect.any(Error),
+ ]);
+ });
+
+ it('shows a flash message', async () => {
+ await actions.deleteRelease({ commit, dispatch, state, getters });
+
+ expect(createFlash).toHaveBeenCalledTimes(1);
+ expect(createFlash).toHaveBeenCalledWith({
+ message: 'Something went wrong while deleting the release.',
+ });
+ });
+ });
+ });
+
describe('fetchTagNotes', () => {
const tagName = 'v8.0.0';
diff --git a/spec/frontend/releases/stores/modules/detail/getters_spec.js b/spec/frontend/releases/stores/modules/detail/getters_spec.js
index 2fb38e6ec1a..4ac6eaebaa2 100644
--- a/spec/frontend/releases/stores/modules/detail/getters_spec.js
+++ b/spec/frontend/releases/stores/modules/detail/getters_spec.js
@@ -369,6 +369,26 @@ describe('Release edit/new getters', () => {
});
});
+ describe('releaseDeleteMutationVariables', () => {
+ it('returns all the data needed for the releaseDelete GraphQL mutation', () => {
+ const state = {
+ projectPath: 'test-org/test',
+ release: { tagName: 'v1.0' },
+ };
+
+ const expectedVariables = {
+ input: {
+ projectPath: 'test-org/test',
+ tagName: 'v1.0',
+ },
+ };
+
+ const actualVariables = getters.releaseDeleteMutationVariables(state);
+
+ expect(actualVariables).toEqual(expectedVariables);
+ });
+ });
+
describe('formattedReleaseNotes', () => {
it.each`
description | includeTagNotes | tagNotes | included