From 48c0bb84393057706323105ffebee94b6ee8ca98 Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Tue, 14 Nov 2023 01:31:11 -0700 Subject: [PATCH 01/15] Add draft merge check --- .../components/checks/draft.stories.js | 52 ++++++++++++ .../components/checks/draft.vue | 79 +++++++++++++++++++ .../components/merge_checks.stories.js | 4 + 3 files changed, 135 insertions(+) create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/checks/draft.vue diff --git a/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js b/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js new file mode 100644 index 00000000000000..bec327cb39a5b6 --- /dev/null +++ b/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js @@ -0,0 +1,52 @@ +import createMockApollo from 'helpers/mock_apollo_helper'; +import draftStateQuery from '../../queries/states/draft.query.graphql'; +import Draft from './draft.vue'; + +const defaultRender = ({ apolloProvider, check, mr }) => ({ + components: { Draft }, + apolloProvider, + data() { + return { mr, check }; + }, + template: '', +}); + +const Template = ({ failed, userPermissionUpdateMergeRequest }) => { + const requestHandlers = [ + [ + draftStateQuery, + () => Promise.resolve({ + data: { + project: { + id: '1', + mergeRequest: { + id: '2', + userPermissions: { + updateMergeRequest: userPermissionUpdateMergeRequest, + } + } + } + } + }), + ], + ]; + const apolloProvider = createMockApollo(requestHandlers); + + return defaultRender({ + apolloProvider, + check: { + identifier: 'draft_status', + status: 'failed', + }, + }); +}; + +export const Default = Template.bind({}); +Default.args = { + userPermissionUpdateMergeRequest: true, +}; + +export default { + title: 'vue_merge_request_widget/merge_checks/draft', + component: Draft, +}; diff --git a/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.vue b/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.vue new file mode 100644 index 00000000000000..e374a3a771c82f --- /dev/null +++ b/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.vue @@ -0,0 +1,79 @@ + + + diff --git a/app/assets/javascripts/vue_merge_request_widget/components/merge_checks.stories.js b/app/assets/javascripts/vue_merge_request_widget/components/merge_checks.stories.js index 77dc5b1d0daaa5..a1171fe5d256e3 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/merge_checks.stories.js +++ b/app/assets/javascripts/vue_merge_request_widget/components/merge_checks.stories.js @@ -41,6 +41,10 @@ const Template = ({ canMerge, failed, pushToSourceBranch }) => { identifier: 'CONFLICT', status: failed ? 'FAILED' : 'SUCCESS', }, + { + identifier: 'DRAFT_STATUS', + status: failed ? 'FAILED' : 'SUCCESS', + }, ], }, }, -- GitLab From 756cc9e41e8b9fa2b2644f2df9d039d92c65e82c Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Wed, 15 Nov 2023 11:51:52 -0700 Subject: [PATCH 02/15] Override component name to use non-generic implementation --- .../vue_merge_request_widget/components/checks/constants.js | 1 + 1 file changed, 1 insertion(+) diff --git a/app/assets/javascripts/vue_merge_request_widget/components/checks/constants.js b/app/assets/javascripts/vue_merge_request_widget/components/checks/constants.js index a8d2736531a515..24bc7017e060b9 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/checks/constants.js +++ b/app/assets/javascripts/vue_merge_request_widget/components/checks/constants.js @@ -1,6 +1,7 @@ export const COMPONENTS = { conflict: () => import('./conflicts.vue'), discussions_not_resolved: () => import('./unresolved_discussions.vue'), + draft_status: () => import('./draft.vue'), need_rebase: () => import('./rebase.vue'), default: () => import('./message.vue'), }; -- GitLab From d27e22d2cebc6afc466b158f8933e5c4592db70b Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Wed, 15 Nov 2023 11:52:12 -0700 Subject: [PATCH 03/15] Use API-matching casing for FAILED status --- .../vue_merge_request_widget/components/checks/draft.stories.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js b/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js index bec327cb39a5b6..2e0585ee1afa98 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js +++ b/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js @@ -36,7 +36,7 @@ const Template = ({ failed, userPermissionUpdateMergeRequest }) => { apolloProvider, check: { identifier: 'draft_status', - status: 'failed', + status: 'FAILED', }, }); }; -- GitLab From 63deee5fa174dd48d23e6859387dae6e9cbeb0aa Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Wed, 15 Nov 2023 11:52:33 -0700 Subject: [PATCH 04/15] Remove failed toggleable value since "false" doesn't work anyway --- .../vue_merge_request_widget/components/checks/draft.stories.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js b/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js index 2e0585ee1afa98..f5ae11abedb2c5 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js +++ b/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js @@ -11,7 +11,7 @@ const defaultRender = ({ apolloProvider, check, mr }) => ({ template: '', }); -const Template = ({ failed, userPermissionUpdateMergeRequest }) => { +const Template = ({ userPermissionUpdateMergeRequest }) => { const requestHandlers = [ [ draftStateQuery, -- GitLab From bcb01bc30a794fa38d1aa0c9cc1f7dcc0a4e7f6f Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Wed, 15 Nov 2023 11:53:00 -0700 Subject: [PATCH 05/15] Remove use of service in preparation for using a GQL mutation --- .../vue_merge_request_widget/components/checks/draft.vue | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.vue b/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.vue index e374a3a771c82f..b06c862cb69c47 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.vue @@ -22,11 +22,6 @@ export default { }, }, props: { - service: { - type: Object, - required: false, - default: () => ({}), - }, mr: { type: Object, required: false, @@ -64,7 +59,7 @@ export default { }, methods: { removeDraft(){ - this.service.removeWIP(); + } } }; -- GitLab From 8261157b0ff7ae60a73961e20507a49f1e720b5b Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Wed, 15 Nov 2023 11:53:17 -0700 Subject: [PATCH 06/15] Computed values aren't called --- .../vue_merge_request_widget/components/checks/draft.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.vue b/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.vue index b06c862cb69c47..a7f8b95d43ff0b 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.vue @@ -45,7 +45,7 @@ export default { return this.state.userPermissions.updateMergeRequest; }, showTertiaryButton(){ - return !this.isLoading && this.userCanUpdateMergeRequest(); + return !this.isLoading && this.userCanUpdateMergeRequest; }, tertiaryActionsButtons() { return [ -- GitLab From 95d42f5f273a1c35d307c6d8b783bacf073e4dff Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Tue, 28 Nov 2023 12:11:54 -0700 Subject: [PATCH 07/15] Run prettier on the Storybook file --- .../components/checks/draft.stories.js | 27 ++++++++++--------- 1 file changed, 14 insertions(+), 13 deletions(-) diff --git a/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js b/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js index f5ae11abedb2c5..bbd292f4d7827e 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js +++ b/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js @@ -15,19 +15,20 @@ const Template = ({ userPermissionUpdateMergeRequest }) => { const requestHandlers = [ [ draftStateQuery, - () => Promise.resolve({ - data: { - project: { - id: '1', - mergeRequest: { - id: '2', - userPermissions: { - updateMergeRequest: userPermissionUpdateMergeRequest, - } - } - } - } - }), + () => + Promise.resolve({ + data: { + project: { + id: '1', + mergeRequest: { + id: '2', + userPermissions: { + updateMergeRequest: userPermissionUpdateMergeRequest, + }, + }, + }, + }, + }), ], ]; const apolloProvider = createMockApollo(requestHandlers); -- GitLab From 19fccd4ef7b0099fb4f1e82f87bf80a842a50b78 Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Tue, 28 Nov 2023 12:12:49 -0700 Subject: [PATCH 08/15] Move text to an i18n file --- .../vue_merge_request_widget/components/checks/draft.vue | 4 +++- .../vue_merge_request_widget/components/checks/i18n.js | 4 ++++ 2 files changed, 7 insertions(+), 1 deletion(-) create mode 100644 app/assets/javascripts/vue_merge_request_widget/components/checks/i18n.js diff --git a/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.vue b/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.vue index a7f8b95d43ff0b..b081525163b11e 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.vue @@ -5,6 +5,8 @@ import draftStateQuery from '../../queries/states/draft.query.graphql'; import ActionButtons from '../action_buttons.vue'; import MergeChecksMessage from './message.vue'; +import { DRAFT_CHECK_READY, DRAFT_CHECK_ERROR } from './i18n'; + export default { name: 'MergeChecksDraft', components: { @@ -50,7 +52,7 @@ export default { tertiaryActionsButtons() { return [ { - text: s__('mrWidget|Mark as ready'), + text: DRAFT_CHECK_READY, category: 'default', onClick: () => this.removeDraft(), }, diff --git a/app/assets/javascripts/vue_merge_request_widget/components/checks/i18n.js b/app/assets/javascripts/vue_merge_request_widget/components/checks/i18n.js new file mode 100644 index 00000000000000..de504af5fccdf3 --- /dev/null +++ b/app/assets/javascripts/vue_merge_request_widget/components/checks/i18n.js @@ -0,0 +1,4 @@ +import { __, s__ } from '~/locale'; + +export const DRAFT_CHECK_ERROR = __('Something went wrong. Please try again.'); +export const DRAFT_CHECK_READY = s__('mrWidgetDraftCheck|Mark as ready'); -- GitLab From d5fb0228cdb1db2229354cd85a2010270199fc16 Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Tue, 28 Nov 2023 12:13:11 -0700 Subject: [PATCH 09/15] Use GQL mutations to modify the MR's draft status --- .../components/checks/draft.vue | 104 +++++++++++++++++- .../queries/states/draft.query.graphql | 3 + 2 files changed, 101 insertions(+), 6 deletions(-) diff --git a/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.vue b/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.vue index b081525163b11e..7af97448965d18 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.vue @@ -1,7 +1,14 @@ diff --git a/app/assets/javascripts/vue_merge_request_widget/queries/states/draft.query.graphql b/app/assets/javascripts/vue_merge_request_widget/queries/states/draft.query.graphql index 54f2233439f55f..c1190a07ef84a3 100644 --- a/app/assets/javascripts/vue_merge_request_widget/queries/states/draft.query.graphql +++ b/app/assets/javascripts/vue_merge_request_widget/queries/states/draft.query.graphql @@ -2,7 +2,10 @@ query mrUserPermission($projectPath: ID!, $iid: String!) { project(fullPath: $projectPath) { id mergeRequest(iid: $iid) { + draft id + mergeableDiscussionsState + title userPermissions { updateMergeRequest } -- GitLab From a60d3cb40338ed14185427de3b087858f12a885b Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Tue, 28 Nov 2023 12:15:48 -0700 Subject: [PATCH 10/15] Add mock data to the storybook story apollo mock client --- .../vue_merge_request_widget/components/checks/draft.stories.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js b/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js index bbd292f4d7827e..c444588df9e7d4 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js +++ b/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js @@ -19,7 +19,9 @@ const Template = ({ userPermissionUpdateMergeRequest }) => { Promise.resolve({ data: { project: { + draft: true, id: '1', + title: 'Draft: MR title', mergeRequest: { id: '2', userPermissions: { -- GitLab From a45e8f8a37ad9ca428337a848855ce2b57b066fc Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Tue, 28 Nov 2023 12:37:06 -0700 Subject: [PATCH 11/15] Use the non-draft mock data to respond to the draft status query Since storybook doesn't initially make a GraphQL query, this response will be used after the mutation happens, so we should send back the "it's not a draft any more" response. --- .../components/checks/draft.stories.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js b/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js index c444588df9e7d4..ec2eda4f82959e 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js +++ b/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js @@ -19,11 +19,12 @@ const Template = ({ userPermissionUpdateMergeRequest }) => { Promise.resolve({ data: { project: { - draft: true, id: '1', - title: 'Draft: MR title', mergeRequest: { + draft: false, id: '2', + title: 'MR title', + mergeableDiscussionsState: true, userPermissions: { updateMergeRequest: userPermissionUpdateMergeRequest, }, -- GitLab From 29de60f15dbdaacbcc4c2d1e47a4fb02cbeb94df Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Tue, 28 Nov 2023 12:37:23 -0700 Subject: [PATCH 12/15] Mock the mark as ready draft mutation --- .../components/checks/draft.stories.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js b/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js index ec2eda4f82959e..537c975652f7cc 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js +++ b/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.stories.js @@ -1,5 +1,6 @@ import createMockApollo from 'helpers/mock_apollo_helper'; import draftStateQuery from '../../queries/states/draft.query.graphql'; +import removeDraftMutation from '../../queries/toggle_draft.mutation.graphql'; import Draft from './draft.vue'; const defaultRender = ({ apolloProvider, check, mr }) => ({ @@ -33,6 +34,23 @@ const Template = ({ userPermissionUpdateMergeRequest }) => { }, }), ], + [ + removeDraftMutation, + () => + Promise.resolve({ + data: { + mergeRequestSetDraft: { + mergeRequest: { + draft: false, + id: '2', + title: 'MR title', + mergeableDiscussionsState: true, + }, + errors: [], + }, + }, + }), + ], ]; const apolloProvider = createMockApollo(requestHandlers); -- GitLab From 32ebb1bc8b1badc00d7e2476d65415fcf3ccfed2 Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Tue, 28 Nov 2023 17:30:57 -0700 Subject: [PATCH 13/15] Update with extracted localization strings --- locale/gitlab.pot | 3 +++ 1 file changed, 3 insertions(+) diff --git a/locale/gitlab.pot b/locale/gitlab.pot index 6872275f38490b..a364af32443d07 100644 --- a/locale/gitlab.pot +++ b/locale/gitlab.pot @@ -57666,6 +57666,9 @@ msgstr "" msgid "mrWidgetCommitsAdded|The changes were not merged into %{targetBranch}." msgstr "" +msgid "mrWidgetDraftCheck|Mark as ready" +msgstr "" + msgid "mrWidgetNothingToMerge|Merge request contains no changes" msgstr "" -- GitLab From bbb31adeacf2b7e2466a252bfedc1f1afd735644 Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Tue, 28 Nov 2023 17:54:47 -0700 Subject: [PATCH 14/15] Fix other tests that use the same gql queries --- .../components/states/work_in_progress_spec.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/spec/frontend/vue_merge_request_widget/components/states/work_in_progress_spec.js b/spec/frontend/vue_merge_request_widget/components/states/work_in_progress_spec.js index f46829539a8f77..509b5adb3b2305 100644 --- a/spec/frontend/vue_merge_request_widget/components/states/work_in_progress_spec.js +++ b/spec/frontend/vue_merge_request_widget/components/states/work_in_progress_spec.js @@ -42,6 +42,9 @@ describe('~/vue_merge_request_widget/components/states/work_in_progress.vue', () mergeRequest: { __typename: 'MergeRequest', id: TEST_MR_ID, + draft: true, + title: TEST_MR_TITLE, + mergeableDiscussionsState: false, userPermissions: { updateMergeRequest: canUpdateMergeRequest, }, -- GitLab From 5fd005d2c35a2cd960ca15f1300dd6f631b41027 Mon Sep 17 00:00:00 2001 From: Thomas Randolph Date: Wed, 29 Nov 2023 19:47:47 -0700 Subject: [PATCH 15/15] Add tests for the draft check component --- .../components/checks/draft.vue | 1 + .../components/checks/message.vue | 2 +- .../components/checks/draft_spec.js | 196 ++++++++++++++++++ 3 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 spec/frontend/vue_merge_request_widget/components/checks/draft_spec.js diff --git a/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.vue b/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.vue index 7af97448965d18..dbe0d2ac243b52 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/checks/draft.vue @@ -65,6 +65,7 @@ export default { { text: DRAFT_CHECK_READY, category: 'default', + testId: 'mark-as-ready-button', onClick: () => this.removeDraft(), }, ]; diff --git a/app/assets/javascripts/vue_merge_request_widget/components/checks/message.vue b/app/assets/javascripts/vue_merge_request_widget/components/checks/message.vue index e91c76e7ff07a7..7f21445559a0ee 100644 --- a/app/assets/javascripts/vue_merge_request_widget/components/checks/message.vue +++ b/app/assets/javascripts/vue_merge_request_widget/components/checks/message.vue @@ -8,7 +8,7 @@ const ICON_NAMES = { success: 'success', }; -const FAILURE_REASONS = { +export const FAILURE_REASONS = { broken_status: __('Cannot merge the source into the target branch, due to a conflict.'), ci_must_pass: __('Pipeline must succeed.'), conflict: __('Merge conflicts must be resolved.'), diff --git a/spec/frontend/vue_merge_request_widget/components/checks/draft_spec.js b/spec/frontend/vue_merge_request_widget/components/checks/draft_spec.js new file mode 100644 index 00000000000000..cc605c8c83deec --- /dev/null +++ b/spec/frontend/vue_merge_request_widget/components/checks/draft_spec.js @@ -0,0 +1,196 @@ +import Vue from 'vue'; +import VueApollo from 'vue-apollo'; + +import getStateQueryResponse from 'test_fixtures/graphql/merge_requests/get_state.query.graphql.json'; + +import { createAlert } from '~/alert'; + +import { mountExtended } from 'helpers/vue_test_utils_helper'; +import createMockApollo from 'helpers/mock_apollo_helper'; +import waitForPromises from 'helpers/wait_for_promises'; + +import MergeRequest from '~/merge_request'; + +import DraftCheck from '~/vue_merge_request_widget/components/checks/draft.vue'; +import { + DRAFT_CHECK_READY, + DRAFT_CHECK_ERROR, +} from '~/vue_merge_request_widget/components/checks/i18n'; +import { FAILURE_REASONS } from '~/vue_merge_request_widget/components/checks/message.vue'; + +import draftQuery from '~/vue_merge_request_widget/queries/states/draft.query.graphql'; +import getStateQuery from '~/vue_merge_request_widget/queries/get_state.query.graphql'; +import removeDraftMutation from '~/vue_merge_request_widget/queries/toggle_draft.mutation.graphql'; + +Vue.use(VueApollo); + +const TEST_PROJECT_ID = getStateQueryResponse.data.project.id; +const TEST_MR_ID = getStateQueryResponse.data.project.mergeRequest.id; +const TEST_MR_IID = '23'; +const TEST_MR_TITLE = 'Test MR Title'; +const TEST_PROJECT_PATH = 'lorem/ipsum'; + +jest.mock('~/alert'); +jest.mock('~/merge_request', () => ({ toggleDraftStatus: jest.fn() })); + +describe('~/vue_merge_request_widget/components/checks/draft.vue', () => { + let wrapper; + let apolloProvider; + + let draftQuerySpy; + let removeDraftMutationSpy; + + const findMarkReadyButton = () => wrapper.findByTestId('mark-as-ready-button'); + + const createDraftQueryResponse = (canUpdateMergeRequest) => ({ + data: { + project: { + __typename: 'Project', + id: TEST_PROJECT_ID, + mergeRequest: { + __typename: 'MergeRequest', + id: TEST_MR_ID, + draft: true, + title: TEST_MR_TITLE, + mergeableDiscussionsState: false, + userPermissions: { + updateMergeRequest: canUpdateMergeRequest, + }, + }, + }, + }, + }); + const createRemoveDraftMutationResponse = () => ({ + data: { + mergeRequestSetDraft: { + __typename: 'MergeRequestSetWipPayload', + errors: [], + mergeRequest: { + __typename: 'MergeRequest', + id: TEST_MR_ID, + title: TEST_MR_TITLE, + draft: false, + mergeableDiscussionsState: true, + }, + }, + }, + }); + + const createComponent = async () => { + wrapper = mountExtended(DraftCheck, { + apolloProvider, + propsData: { + mr: { + issuableId: TEST_MR_ID, + title: TEST_MR_TITLE, + iid: TEST_MR_IID, + targetProjectFullPath: TEST_PROJECT_PATH, + }, + check: { + identifier: 'draft_status', + status: 'FAILED', + }, + }, + }); + + await waitForPromises(); + + // why: draft.vue has some coupling that this query has been read before + // for some reason this has to happen **after** the component has mounted + // or apollo throws errors. + apolloProvider.defaultClient.cache.writeQuery({ + query: getStateQuery, + variables: { + projectPath: TEST_PROJECT_PATH, + iid: TEST_MR_IID, + }, + data: getStateQueryResponse.data, + }); + }; + + beforeEach(() => { + draftQuerySpy = jest.fn().mockResolvedValue(createDraftQueryResponse(true)); + removeDraftMutationSpy = jest.fn().mockResolvedValue(createRemoveDraftMutationResponse()); + + apolloProvider = createMockApollo([ + [draftQuery, draftQuerySpy], + [removeDraftMutation, removeDraftMutationSpy], + ]); + }); + + describe('when user can update MR', () => { + beforeEach(async () => { + await createComponent(); + }); + + it('renders text', () => { + const message = wrapper.text(); + expect(message).toContain(FAILURE_REASONS.draft_status); + }); + + it('renders mark ready button', () => { + expect(findMarkReadyButton().text()).toBe(DRAFT_CHECK_READY); + }); + + it('does not call remove draft mutation', () => { + expect(removeDraftMutationSpy).not.toHaveBeenCalled(); + }); + + describe('when mark ready button is clicked', () => { + beforeEach(async () => { + findMarkReadyButton().vm.$emit('click'); + + await waitForPromises(); + }); + + it('calls mutation spy', () => { + expect(removeDraftMutationSpy).toHaveBeenCalledWith({ + draft: false, + iid: TEST_MR_IID, + projectPath: TEST_PROJECT_PATH, + }); + }); + + it('does not create alert', () => { + expect(createAlert).not.toHaveBeenCalled(); + }); + + it('calls toggleDraftStatus', () => { + expect(MergeRequest.toggleDraftStatus).toHaveBeenCalledWith(TEST_MR_TITLE, true); + }); + }); + + describe('when mutation fails and ready button is clicked', () => { + beforeEach(async () => { + removeDraftMutationSpy.mockRejectedValue(new Error('TEST FAIL')); + findMarkReadyButton().vm.$emit('click'); + + await waitForPromises(); + }); + + it('creates alert', () => { + expect(createAlert).toHaveBeenCalledWith({ + message: DRAFT_CHECK_ERROR, + }); + }); + + it('does not call toggleDraftStatus', () => { + expect(MergeRequest.toggleDraftStatus).not.toHaveBeenCalled(); + }); + }); + }); + + describe('when user cannot update MR', () => { + beforeEach(async () => { + draftQuerySpy.mockResolvedValue(createDraftQueryResponse(false)); + + createComponent(); + + await waitForPromises(); + }); + + it('does not render mark ready button', () => { + expect(findMarkReadyButton().exists()).toBe(false); + }); + }); +}); -- GitLab