summaryrefslogtreecommitdiff
path: root/spec/frontend/sidebar/components/move/move_issue_button_spec.js
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/sidebar/components/move/move_issue_button_spec.js')
-rw-r--r--spec/frontend/sidebar/components/move/move_issue_button_spec.js157
1 files changed, 157 insertions, 0 deletions
diff --git a/spec/frontend/sidebar/components/move/move_issue_button_spec.js b/spec/frontend/sidebar/components/move/move_issue_button_spec.js
new file mode 100644
index 00000000000..acd6b23c1f5
--- /dev/null
+++ b/spec/frontend/sidebar/components/move/move_issue_button_spec.js
@@ -0,0 +1,157 @@
+import { shallowMount } from '@vue/test-utils';
+import Vue, { nextTick } from 'vue';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { visitUrl } from '~/lib/utils/url_utility';
+import { createAlert } from '~/flash';
+import ProjectSelect from '~/sidebar/components/move/issuable_move_dropdown.vue';
+import MoveIssueButton from '~/sidebar/components/move/move_issue_button.vue';
+import moveIssueMutation from '~/sidebar/queries/move_issue.mutation.graphql';
+
+Vue.use(VueApollo);
+
+jest.mock('~/flash');
+jest.mock('~/lib/utils/url_utility', () => ({
+ visitUrl: jest.fn(),
+}));
+
+const projectFullPath = 'flight/FlightJS';
+const projectsAutocompleteEndpoint = '/-/autocomplete/projects?project_id=1';
+const issueIid = '15';
+
+const mockDestinationProject = {
+ full_path: 'gitlab-org/GitLabTest',
+};
+
+const mockWebUrl = `${mockDestinationProject.full_path}/issues/${issueIid}`;
+
+const mockMutationErrorMessage = 'Example error message';
+
+const resolvedMutationWithoutErrorsMock = jest.fn().mockResolvedValue({
+ data: {
+ issueMove: {
+ issue: {
+ id: issueIid,
+ webUrl: mockWebUrl,
+ },
+ errors: [],
+ },
+ },
+});
+
+const resolvedMutationWithErrorsMock = jest.fn().mockResolvedValue({
+ data: {
+ issueMove: {
+ errors: [{ message: mockMutationErrorMessage }],
+ },
+ },
+});
+
+const rejectedMutationMock = jest.fn().mockRejectedValue({});
+
+describe('MoveIssueButton', () => {
+ let wrapper;
+ let fakeApollo;
+
+ const findProjectSelect = () => wrapper.findComponent(ProjectSelect);
+ const emitProjectSelectEvent = () => {
+ findProjectSelect().vm.$emit('move-issuable', mockDestinationProject);
+ };
+ const createComponent = (mutationResolverMock = rejectedMutationMock) => {
+ fakeApollo = createMockApollo([[moveIssueMutation, mutationResolverMock]]);
+
+ wrapper = shallowMount(MoveIssueButton, {
+ provide: {
+ projectFullPath,
+ projectsAutocompleteEndpoint,
+ issueIid,
+ },
+ apolloProvider: fakeApollo,
+ });
+ };
+
+ afterEach(() => {
+ fakeApollo = null;
+ });
+
+ it('renders the project select dropdown', () => {
+ createComponent();
+
+ expect(findProjectSelect().props()).toMatchObject({
+ projectsFetchPath: projectsAutocompleteEndpoint,
+ dropdownButtonTitle: MoveIssueButton.i18n.title,
+ dropdownHeaderTitle: MoveIssueButton.i18n.title,
+ moveInProgress: false,
+ });
+ });
+
+ describe('when the project is selected', () => {
+ it('sets loading state and dropdown button text when issue is moving', async () => {
+ createComponent();
+ expect(findProjectSelect().props()).toMatchObject({
+ dropdownButtonTitle: MoveIssueButton.i18n.title,
+ moveInProgress: false,
+ });
+
+ emitProjectSelectEvent();
+ await nextTick();
+
+ expect(findProjectSelect().props()).toMatchObject({
+ dropdownButtonTitle: MoveIssueButton.i18n.titleInProgress,
+ moveInProgress: true,
+ });
+ });
+
+ it.each`
+ condition | mutation
+ ${'a mutation returns errors'} | ${resolvedMutationWithErrorsMock}
+ ${'a mutation is rejected'} | ${rejectedMutationMock}
+ `('sets loading state to false when $condition', async ({ mutation }) => {
+ createComponent(mutation);
+ emitProjectSelectEvent();
+
+ await nextTick();
+ expect(findProjectSelect().props('moveInProgress')).toBe(true);
+
+ await waitForPromises();
+ expect(findProjectSelect().props('moveInProgress')).toBe(false);
+ });
+
+ it('creates a flash and logs errors when a mutation returns errors', async () => {
+ createComponent(resolvedMutationWithErrorsMock);
+ emitProjectSelectEvent();
+
+ await waitForPromises();
+
+ expect(createAlert).toHaveBeenCalledWith({
+ message: MoveIssueButton.i18n.moveErrorMessage,
+ captureError: true,
+ error: expect.any(Object),
+ });
+ });
+
+ it('calls a mutation for the selected issue', async () => {
+ createComponent(resolvedMutationWithoutErrorsMock);
+ emitProjectSelectEvent();
+
+ await waitForPromises();
+
+ expect(resolvedMutationWithoutErrorsMock).toHaveBeenCalledWith({
+ moveIssueInput: {
+ projectPath: projectFullPath,
+ iid: issueIid,
+ targetProjectPath: mockDestinationProject.full_path,
+ },
+ });
+ });
+
+ it('redirects to the correct page when the mutation succeeds', async () => {
+ createComponent(resolvedMutationWithoutErrorsMock);
+ emitProjectSelectEvent();
+ await waitForPromises();
+
+ expect(visitUrl).toHaveBeenCalledWith(mockWebUrl);
+ });
+ });
+});