Commit 3a20c641 authored by Payton Burdette's avatar Payton Burdette Committed by David O'Regan

Add confirmation modal for merge

Add confirmation modal when merging and
the latest pipeline is in a failed state.

Changelog: changed
parent 79a55663
<script>
import { GlModal, GlButton } from '@gitlab/ui';
import { __ } from '~/locale';
export default {
name: 'MergeFailedPipelineConfirmationDialog',
i18n: {
primary: __('Merge unverified changes'),
cancel: __('Cancel'),
info: __(
'The latest pipeline for this merge request did not succeed. The latest changes are unverified.',
),
confirmation: __('Are you sure you want to attempt to merge?'),
title: __('Merge unverified changes?'),
},
components: {
GlModal,
GlButton,
},
props: {
visible: {
type: Boolean,
required: true,
},
},
methods: {
hide() {
this.$refs.modal.hide();
},
cancel() {
this.hide();
this.$emit('cancel');
},
focusCancelButton() {
this.$refs.cancelButton.$el.focus();
},
mergeChanges() {
this.$emit('mergeWithFailedPipeline');
this.hide();
},
},
};
</script>
<template>
<gl-modal
ref="modal"
size="sm"
modal-id="merge-train-failed-pipeline-confirmation-dialog"
:title="$options.i18n.title"
:visible="visible"
data-testid="merge-failed-pipeline-confirmation-dialog"
@shown="focusCancelButton"
@hide="$emit('cancel')"
>
<p>{{ $options.i18n.info }}</p>
<p>{{ $options.i18n.confirmation }}</p>
<template #modal-footer>
<gl-button ref="cancelButton" data-testid="merge-cancel-btn" @click="cancel">{{
$options.i18n.cancel
}}</gl-button>
<gl-button variant="danger" data-testid="merge-unverified-changes" @click="mergeChanges">
{{ $options.i18n.primary }}
</gl-button>
</template>
</gl-modal>
</template>
...@@ -25,8 +25,6 @@ import { helpPagePath } from '~/helpers/help_page_helper'; ...@@ -25,8 +25,6 @@ import { helpPagePath } from '~/helpers/help_page_helper';
import MergeRequest from '../../../merge_request'; import MergeRequest from '../../../merge_request';
import { import {
AUTO_MERGE_STRATEGIES, AUTO_MERGE_STRATEGIES,
DANGER,
CONFIRM,
WARNING, WARNING,
MT_MERGE_STRATEGY, MT_MERGE_STRATEGY,
PIPELINE_FAILED_STATE, PIPELINE_FAILED_STATE,
...@@ -42,6 +40,7 @@ import CommitEdit from './commit_edit.vue'; ...@@ -42,6 +40,7 @@ import CommitEdit from './commit_edit.vue';
import CommitMessageDropdown from './commit_message_dropdown.vue'; import CommitMessageDropdown from './commit_message_dropdown.vue';
import CommitsHeader from './commits_header.vue'; import CommitsHeader from './commits_header.vue';
import SquashBeforeMerge from './squash_before_merge.vue'; import SquashBeforeMerge from './squash_before_merge.vue';
import MergeFailedPipelineConfirmationDialog from './merge_failed_pipeline_confirmation_dialog.vue';
const PIPELINE_RUNNING_STATE = 'running'; const PIPELINE_RUNNING_STATE = 'running';
const PIPELINE_PENDING_STATE = 'pending'; const PIPELINE_PENDING_STATE = 'pending';
...@@ -106,6 +105,7 @@ export default { ...@@ -106,6 +105,7 @@ export default {
GlDropdownItem, GlDropdownItem,
GlFormCheckbox, GlFormCheckbox,
GlSkeletonLoader, GlSkeletonLoader,
MergeFailedPipelineConfirmationDialog,
MergeTrainHelperIcon: () => MergeTrainHelperIcon: () =>
import('ee_component/vue_merge_request_widget/components/merge_train_helper_icon.vue'), import('ee_component/vue_merge_request_widget/components/merge_train_helper_icon.vue'),
MergeImmediatelyConfirmationDialog: () => MergeImmediatelyConfirmationDialog: () =>
...@@ -138,7 +138,8 @@ export default { ...@@ -138,7 +138,8 @@ export default {
squashBeforeMerge: this.mr.squashIsSelected, squashBeforeMerge: this.mr.squashIsSelected,
isSquashReadOnly: this.mr.squashIsReadonly, isSquashReadOnly: this.mr.squashIsReadonly,
squashCommitMessage: this.mr.squashCommitMessage, squashCommitMessage: this.mr.squashCommitMessage,
isPipelineFailedModalVisible: false, isPipelineFailedModalVisibleMergeTrain: false,
isPipelineFailedModalVisibleNormalMerge: false,
editCommitMessage: false, editCommitMessage: false,
}; };
}, },
...@@ -166,6 +167,9 @@ export default { ...@@ -166,6 +167,9 @@ export default {
return this.mr.isPipelineFailed; return this.mr.isPipelineFailed;
}, },
showMergeFailedPipelineConfirmationDialog() {
return this.status === PIPELINE_FAILED_STATE && this.isPipelineFailed;
},
isMergeAllowed() { isMergeAllowed() {
if (this.glFeatures.mergeRequestWidgetGraphql) { if (this.glFeatures.mergeRequestWidgetGraphql) {
return this.state.mergeable; return this.state.mergeable;
...@@ -248,13 +252,6 @@ export default { ...@@ -248,13 +252,6 @@ export default {
return PIPELINE_SUCCESS_STATE; return PIPELINE_SUCCESS_STATE;
}, },
mergeButtonVariant() {
if (this.status === PIPELINE_FAILED_STATE || this.isPipelineFailed) {
return DANGER;
}
return CONFIRM;
},
iconClass() { iconClass() {
if (this.shouldRenderMergeTrainHelperIcon && !this.mr.preventMerge) { if (this.shouldRenderMergeTrainHelperIcon && !this.mr.preventMerge) {
return PIPELINE_RUNNING_STATE; return PIPELINE_RUNNING_STATE;
...@@ -279,6 +276,10 @@ export default { ...@@ -279,6 +276,10 @@ export default {
return this.autoMergeText; return this.autoMergeText;
} }
if (this.status === PIPELINE_FAILED_STATE || this.isPipelineFailed) {
return __('Merge...');
}
return __('Merge'); return __('Merge');
}, },
hasPipelineMustSucceedConflict() { hasPipelineMustSucceedConflict() {
...@@ -361,8 +362,13 @@ export default { ...@@ -361,8 +362,13 @@ export default {
return this.$apollo.queries.state.refetch(); return this.$apollo.queries.state.refetch();
}, },
handleMergeButtonClick(useAutoMerge, mergeImmediately = false, confirmationClicked = false) { handleMergeButtonClick(useAutoMerge, mergeImmediately = false, confirmationClicked = false) {
if (this.showFailedPipelineModal && !confirmationClicked) { if (this.showMergeFailedPipelineConfirmationDialog && !confirmationClicked) {
this.isPipelineFailedModalVisible = true; this.isPipelineFailedModalVisibleNormalMerge = true;
return;
}
if (this.showFailedPipelineModalMergeTrain && !confirmationClicked) {
this.isPipelineFailedModalVisibleMergeTrain = true;
return; return;
} }
...@@ -434,6 +440,9 @@ export default { ...@@ -434,6 +440,9 @@ export default {
onMergeImmediatelyConfirmation() { onMergeImmediatelyConfirmation() {
this.handleMergeButtonClick(false, true, true); this.handleMergeButtonClick(false, true, true);
}, },
onMergeWithFailedPipelineConfirmation() {
this.handleMergeButtonClick(false, true, true);
},
initiateMergePolling() { initiateMergePolling() {
simplePoll( simplePoll(
(continuePolling, stopPolling) => { (continuePolling, stopPolling) => {
...@@ -559,7 +568,7 @@ export default { ...@@ -559,7 +568,7 @@ export default {
category="primary" category="primary"
class="accept-merge-request" class="accept-merge-request"
data-testid="merge-button" data-testid="merge-button"
:variant="mergeButtonVariant" variant="confirm"
:disabled="isMergeButtonDisabled" :disabled="isMergeButtonDisabled"
:loading="isMakingRequest" :loading="isMakingRequest"
data-qa-selector="merge_button" data-qa-selector="merge_button"
...@@ -570,7 +579,7 @@ export default { ...@@ -570,7 +579,7 @@ export default {
v-if="shouldShowMergeImmediatelyDropdown" v-if="shouldShowMergeImmediatelyDropdown"
v-gl-tooltip.hover.focus="__('Select merge moment')" v-gl-tooltip.hover.focus="__('Select merge moment')"
:disabled="isMergeButtonDisabled" :disabled="isMergeButtonDisabled"
:variant="mergeButtonVariant" variant="confirm"
data-qa-selector="merge_moment_dropdown" data-qa-selector="merge_moment_dropdown"
toggle-class="btn-icon js-merge-moment" toggle-class="btn-icon js-merge-moment"
> >
...@@ -593,9 +602,14 @@ export default { ...@@ -593,9 +602,14 @@ export default {
/> />
</gl-dropdown> </gl-dropdown>
<merge-train-failed-pipeline-confirmation-dialog <merge-train-failed-pipeline-confirmation-dialog
:visible="isPipelineFailedModalVisible" :visible="isPipelineFailedModalVisibleMergeTrain"
@startMergeTrain="onStartMergeTrainConfirmation" @startMergeTrain="onStartMergeTrainConfirmation"
@cancel="isPipelineFailedModalVisible = false" @cancel="isPipelineFailedModalVisibleMergeTrain = false"
/>
<merge-failed-pipeline-confirmation-dialog
:visible="isPipelineFailedModalVisibleNormalMerge"
@mergeWithFailedPipeline="onMergeWithFailedPipelineConfirmation"
@cancel="isPipelineFailedModalVisibleNormalMerge = false"
/> />
</gl-button-group> </gl-button-group>
<merge-train-helper-icon v-if="shouldRenderMergeTrainHelperIcon" class="gl-mx-3" /> <merge-train-helper-icon v-if="shouldRenderMergeTrainHelperIcon" class="gl-mx-3" />
......
...@@ -20,3 +20,8 @@ export const I18N_SHA_MISMATCH = { ...@@ -20,3 +20,8 @@ export const I18N_SHA_MISMATCH = {
warningMessage: __('Merge blocked: new changes were just added.'), warningMessage: __('Merge blocked: new changes were just added.'),
actionButtonLabel: __('Review changes'), actionButtonLabel: __('Review changes'),
}; };
export const MERGE_TRAIN_BUTTON_TEXT = {
failed: __('Start merge train...'),
passed: __('Start merge train'),
};
...@@ -48,7 +48,7 @@ export default { ...@@ -48,7 +48,7 @@ export default {
pipelineId() { pipelineId() {
return this.pipeline.id; return this.pipeline.id;
}, },
showFailedPipelineModal() { showFailedPipelineModalMergeTrain() {
return false; return false;
}, },
}, },
......
...@@ -7,6 +7,7 @@ import { ...@@ -7,6 +7,7 @@ import {
PIPELINE_FAILED_STATE, PIPELINE_FAILED_STATE,
} from '~/vue_merge_request_widget/constants'; } from '~/vue_merge_request_widget/constants';
import base from '~/vue_merge_request_widget/mixins/ready_to_merge'; import base from '~/vue_merge_request_widget/mixins/ready_to_merge';
import { MERGE_TRAIN_BUTTON_TEXT } from '~/vue_merge_request_widget/i18n';
export const MERGE_DISABLED_TEXT_UNAPPROVED = s__( export const MERGE_DISABLED_TEXT_UNAPPROVED = s__(
'mrWidget|Merge blocked: this merge request must be approved.', 'mrWidget|Merge blocked: this merge request must be approved.',
...@@ -48,7 +49,9 @@ export default { ...@@ -48,7 +49,9 @@ export default {
return __('Add to merge train when pipeline succeeds'); return __('Add to merge train when pipeline succeeds');
} else if (this.preferredAutoMergeStrategy === MT_MERGE_STRATEGY) { } else if (this.preferredAutoMergeStrategy === MT_MERGE_STRATEGY) {
if (this.stateData.mergeTrainsCount === 0) { if (this.stateData.mergeTrainsCount === 0) {
return __('Start merge train'); const pipelineFailed = this.status === PIPELINE_FAILED_STATE || this.isPipelineFailed;
return pipelineFailed ? MERGE_TRAIN_BUTTON_TEXT.failed : MERGE_TRAIN_BUTTON_TEXT.passed;
} }
return __('Add to merge train'); return __('Add to merge train');
} }
...@@ -80,7 +83,7 @@ export default { ...@@ -80,7 +83,7 @@ export default {
isMergeImmediatelyDangerous() { isMergeImmediatelyDangerous() {
return [MT_MERGE_STRATEGY, MTWPS_MERGE_STRATEGY].includes(this.preferredAutoMergeStrategy); return [MT_MERGE_STRATEGY, MTWPS_MERGE_STRATEGY].includes(this.preferredAutoMergeStrategy);
}, },
showFailedPipelineModal() { showFailedPipelineModalMergeTrain() {
const pipelineFailed = this.status === PIPELINE_FAILED_STATE || this.isPipelineFailed; const pipelineFailed = this.status === PIPELINE_FAILED_STATE || this.isPipelineFailed;
const mergeStrateyMergeTrain = this.preferredAutoMergeStrategy === MT_MERGE_STRATEGY; const mergeStrateyMergeTrain = this.preferredAutoMergeStrategy === MT_MERGE_STRATEGY;
......
...@@ -11,6 +11,7 @@ import { ...@@ -11,6 +11,7 @@ import {
MT_MERGE_STRATEGY, MT_MERGE_STRATEGY,
MTWPS_MERGE_STRATEGY, MTWPS_MERGE_STRATEGY,
} from '~/vue_merge_request_widget/constants'; } from '~/vue_merge_request_widget/constants';
import { MERGE_TRAIN_BUTTON_TEXT } from '~/vue_merge_request_widget/i18n';
import { import {
MERGE_DISABLED_TEXT, MERGE_DISABLED_TEXT,
MERGE_DISABLED_SKIPPED_PIPELINE_TEXT, MERGE_DISABLED_SKIPPED_PIPELINE_TEXT,
...@@ -405,31 +406,45 @@ describe('ReadyToMerge', () => { ...@@ -405,31 +406,45 @@ describe('ReadyToMerge', () => {
}); });
}); });
describe('Merge button variant', () => { describe('Merge train text', () => {
it('danger variant and failed text should show if pipeline failed', () => { describe('pipeline failed', () => {
factory({ beforeEach(() => {
isPipelineFailed: true, factory({
preferredAutoMergeStrategy: MT_MERGE_STRATEGY, isPipelineFailed: true,
availableAutoMergeStrategies: [MT_MERGE_STRATEGY], preferredAutoMergeStrategy: MT_MERGE_STRATEGY,
hasCI: true, availableAutoMergeStrategies: [MT_MERGE_STRATEGY],
onlyAllowMergeIfPipelineSucceeds: false, hasCI: true,
onlyAllowMergeIfPipelineSucceeds: false,
});
}); });
expect(findMergeButton().attributes('variant')).toBe('danger'); it('failed merge train text should show if pipeline failed', () => {
expect(findFailedPipelineMergeTrainText().exists()).toBe(true); expect(findFailedPipelineMergeTrainText().exists()).toBe(true);
});
it('merge button text should contain ellipsis', () => {
expect(findMergeButton().text()).toBe(MERGE_TRAIN_BUTTON_TEXT.failed);
});
}); });
it('confirm variant and failed text should not show if pipeline passed', () => { describe('pipeline passed', () => {
factory({ beforeEach(() => {
preferredAutoMergeStrategy: MT_MERGE_STRATEGY, factory({
availableAutoMergeStrategies: [MT_MERGE_STRATEGY], preferredAutoMergeStrategy: MT_MERGE_STRATEGY,
hasCI: true, availableAutoMergeStrategies: [MT_MERGE_STRATEGY],
onlyAllowMergeIfPipelineSucceeds: false, hasCI: true,
ciStatus: 'success', onlyAllowMergeIfPipelineSucceeds: false,
ciStatus: 'success',
});
}); });
expect(findMergeButton().attributes('variant')).toBe('confirm'); it('merge button text should not contain ellipsis', () => {
expect(findFailedPipelineMergeTrainText().exists()).toBe(false); expect(findMergeButton().text()).toBe(MERGE_TRAIN_BUTTON_TEXT.passed);
});
it('failed merge train text should not show if pipeline passed', () => {
expect(findFailedPipelineMergeTrainText().exists()).toBe(false);
});
}); });
}); });
}); });
...@@ -22417,9 +22417,18 @@ msgstr "" ...@@ -22417,9 +22417,18 @@ msgstr ""
msgid "Merge unavailable: merge requests are read-only in a secondary Geo node." msgid "Merge unavailable: merge requests are read-only in a secondary Geo node."
msgstr "" msgstr ""
msgid "Merge unverified changes"
msgstr ""
msgid "Merge unverified changes?"
msgstr ""
msgid "Merge when pipeline succeeds" msgid "Merge when pipeline succeeds"
msgstr "" msgstr ""
msgid "Merge..."
msgstr ""
msgid "MergeConflict|Commit to source branch" msgid "MergeConflict|Commit to source branch"
msgstr "" msgstr ""
...@@ -34033,6 +34042,9 @@ msgstr "" ...@@ -34033,6 +34042,9 @@ msgstr ""
msgid "Start merge train when pipeline succeeds" msgid "Start merge train when pipeline succeeds"
msgstr "" msgstr ""
msgid "Start merge train..."
msgstr ""
msgid "Start search" msgid "Start search"
msgstr "" msgstr ""
...@@ -35774,6 +35786,9 @@ msgstr "" ...@@ -35774,6 +35786,9 @@ msgstr ""
msgid "The latest pipeline for this merge request did not complete successfully." msgid "The latest pipeline for this merge request did not complete successfully."
msgstr "" msgstr ""
msgid "The latest pipeline for this merge request did not succeed. The latest changes are unverified."
msgstr ""
msgid "The latest pipeline for this merge request has failed." msgid "The latest pipeline for this merge request has failed."
msgstr "" msgstr ""
......
...@@ -104,10 +104,11 @@ RSpec.describe 'Merge request > User sees merge widget', :js do ...@@ -104,10 +104,11 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
visit project_merge_request_path(project, merge_request) visit project_merge_request_path(project, merge_request)
end end
it 'has danger button while waiting for external CI status' do it 'has merge button with confirm variant while waiting for external CI status' do
# Wait for the `ci_status` and `merge_check` requests # Wait for the `ci_status` and `merge_check` requests
wait_for_requests wait_for_requests
expect(page).to have_selector('.accept-merge-request.btn-danger')
expect(page).to have_selector('.accept-merge-request.btn-confirm')
end end
end end
...@@ -125,10 +126,27 @@ RSpec.describe 'Merge request > User sees merge widget', :js do ...@@ -125,10 +126,27 @@ RSpec.describe 'Merge request > User sees merge widget', :js do
visit project_merge_request_path(project, merge_request) visit project_merge_request_path(project, merge_request)
end end
it 'has danger button when not succeeded' do it 'has merge button that shows modal when pipeline does not succeeded' do
# Wait for the `ci_status` and `merge_check` requests # Wait for the `ci_status` and `merge_check` requests
wait_for_requests wait_for_requests
expect(page).to have_selector('.accept-merge-request.btn-danger')
click_button 'Merge...'
expect(page).to have_selector('[data-testid="merge-failed-pipeline-confirmation-dialog"]', visible: true)
end
it 'allows me to merge with a failed pipeline' do
modal_selector = '[data-testid="merge-failed-pipeline-confirmation-dialog"]'
wait_for_requests
click_button 'Merge...'
page.within(modal_selector) do
click_button 'Merge unverified changes'
end
expect(find('.media-body h4')).to have_content('Merging!')
end end
end end
......
import { shallowMount } from '@vue/test-utils';
import MergeFailedPipelineConfirmationDialog from '~/vue_merge_request_widget/components/states/merge_failed_pipeline_confirmation_dialog.vue';
import { trimText } from 'helpers/text_helper';
describe('MergeFailedPipelineConfirmationDialog', () => {
let wrapper;
const GlModal = {
template: `
<div>
<slot></slot>
<slot name="modal-footer"></slot>
</div>
`,
methods: {
hide: jest.fn(),
},
};
const createComponent = () => {
wrapper = shallowMount(MergeFailedPipelineConfirmationDialog, {
propsData: {
visible: true,
},
stubs: {
GlModal,
},
attachTo: document.body,
});
};
const findModal = () => wrapper.findComponent(GlModal);
const findMergeBtn = () => wrapper.find('[data-testid="merge-unverified-changes"]');
const findCancelBtn = () => wrapper.find('[data-testid="merge-cancel-btn"]');
beforeEach(() => {
createComponent();
});
afterEach(() => {
wrapper.destroy();
});
it('should render informational text explaining why merging immediately can be dangerous', () => {
expect(trimText(wrapper.text())).toContain(
'The latest pipeline for this merge request did not succeed. The latest changes are unverified. Are you sure you want to attempt to merge?',
);
});
it('should emit the mergeWithFailedPipeline event', () => {
findMergeBtn().vm.$emit('click');
expect(wrapper.emitted('mergeWithFailedPipeline')).toBeTruthy();
});
it('when the cancel button is clicked should emit cancel and call hide', () => {
jest.spyOn(findModal().vm, 'hide');
findCancelBtn().vm.$emit('click');
expect(wrapper.emitted('cancel')).toBeTruthy();
expect(findModal().vm.hide).toHaveBeenCalled();
});
it('should emit cancel when the hide event is emitted', () => {
findModal().vm.$emit('hide');
expect(wrapper.emitted('cancel')).toBeTruthy();
});
it('when modal is shown it will focus the cancel button', () => {
jest.spyOn(findCancelBtn().element, 'focus');
findModal().vm.$emit('shown');
expect(findCancelBtn().element.focus).toHaveBeenCalled();
});
});
...@@ -7,6 +7,7 @@ import CommitMessageDropdown from '~/vue_merge_request_widget/components/states/ ...@@ -7,6 +7,7 @@ import CommitMessageDropdown from '~/vue_merge_request_widget/components/states/
import CommitsHeader from '~/vue_merge_request_widget/components/states/commits_header.vue'; import CommitsHeader from '~/vue_merge_request_widget/components/states/commits_header.vue';
import ReadyToMerge from '~/vue_merge_request_widget/components/states/ready_to_merge.vue'; import ReadyToMerge from '~/vue_merge_request_widget/components/states/ready_to_merge.vue';
import SquashBeforeMerge from '~/vue_merge_request_widget/components/states/squash_before_merge.vue'; import SquashBeforeMerge from '~/vue_merge_request_widget/components/states/squash_before_merge.vue';
import MergeFailedPipelineConfirmationDialog from '~/vue_merge_request_widget/components/states/merge_failed_pipeline_confirmation_dialog.vue';
import { MWPS_MERGE_STRATEGY } from '~/vue_merge_request_widget/constants'; import { MWPS_MERGE_STRATEGY } from '~/vue_merge_request_widget/constants';
import eventHub from '~/vue_merge_request_widget/event_hub'; import eventHub from '~/vue_merge_request_widget/event_hub';
...@@ -61,6 +62,11 @@ const createTestService = () => ({ ...@@ -61,6 +62,11 @@ const createTestService = () => ({
}); });
let wrapper; let wrapper;
const findMergeButton = () => wrapper.find('[data-testid="merge-button"]');
const findPipelineFailedConfirmModal = () =>
wrapper.findComponent(MergeFailedPipelineConfirmationDialog);
const createComponent = (customConfig = {}, mergeRequestWidgetGraphql = false) => { const createComponent = (customConfig = {}, mergeRequestWidgetGraphql = false) => {
wrapper = shallowMount(ReadyToMerge, { wrapper = shallowMount(ReadyToMerge, {
propsData: { propsData: {
...@@ -132,33 +138,13 @@ describe('ReadyToMerge', () => { ...@@ -132,33 +138,13 @@ describe('ReadyToMerge', () => {
}); });
}); });
describe('mergeButtonVariant', () => { describe('Merge Button Variant', () => {
it('defaults to confirm class', () => { it('defaults to confirm class', () => {
createComponent({ createComponent({
mr: { availableAutoMergeStrategies: [] }, mr: { availableAutoMergeStrategies: [] },
}); });
expect(wrapper.vm.mergeButtonVariant).toEqual('confirm'); expect(findMergeButton().attributes('variant')).toBe('confirm');
});
it('returns confirm class for success status', () => {
createComponent({
mr: { availableAutoMergeStrategies: [], pipeline: true },
});
expect(wrapper.vm.mergeButtonVariant).toEqual('confirm');
});
it('returns confirm class for pending status', () => {
createComponent();
expect(wrapper.vm.mergeButtonVariant).toEqual('confirm');
});
it('returns danger class for failed status', () => {
createComponent({ mr: { hasCI: true } });
expect(wrapper.vm.mergeButtonVariant).toEqual('danger');
}); });
}); });
...@@ -794,4 +780,24 @@ describe('ReadyToMerge', () => { ...@@ -794,4 +780,24 @@ describe('ReadyToMerge', () => {
}); });
}); });
}); });
describe('Merge button when pipeline has failed', () => {
beforeEach(() => {
createComponent({
mr: { pipeline: {}, isPipelineFailed: true, availableAutoMergeStrategies: [] },
});
});
it('should display the correct merge text', () => {
expect(findMergeButton().text()).toBe('Merge...');
});
it('should display confirmation modal when merge button is clicked', async () => {
expect(findPipelineFailedConfirmModal().props()).toEqual({ visible: false });
await findMergeButton().vm.$emit('click');
expect(findPipelineFailedConfirmModal().props()).toEqual({ visible: true });
});
});
}); });
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment