Commit 965fd314 authored by Enrique Alcántara's avatar Enrique Alcántara

Merge branch...

Merge branch '350503-frontend-browser-popup-appears-when-updating-ci-yml-content-and-submit-a-merge-request' into 'master'

Fix unnecessary navigation modal in pipeline editor

See merge request gitlab-org/gitlab!79032
parents 53314815 df3db1df
<script> <script>
import { mergeUrlParams, redirectTo } from '~/lib/utils/url_utility';
import { __, s__, sprintf } from '~/locale'; import { __, s__, sprintf } from '~/locale';
import { import {
COMMIT_ACTION_CREATE, COMMIT_ACTION_CREATE,
COMMIT_ACTION_UPDATE, COMMIT_ACTION_UPDATE,
COMMIT_FAILURE, COMMIT_FAILURE,
COMMIT_SUCCESS, COMMIT_SUCCESS,
COMMIT_SUCCESS_WITH_REDIRECT,
} from '../../constants'; } from '../../constants';
import commitCIFile from '../../graphql/mutations/commit_ci_file.mutation.graphql'; import commitCIFile from '../../graphql/mutations/commit_ci_file.mutation.graphql';
import updateCurrentBranchMutation from '../../graphql/mutations/client/update_current_branch.mutation.graphql'; import updateCurrentBranchMutation from '../../graphql/mutations/client/update_current_branch.mutation.graphql';
...@@ -15,9 +15,6 @@ import getCurrentBranch from '../../graphql/queries/client/current_branch.query. ...@@ -15,9 +15,6 @@ import getCurrentBranch from '../../graphql/queries/client/current_branch.query.
import CommitForm from './commit_form.vue'; import CommitForm from './commit_form.vue';
const MR_SOURCE_BRANCH = 'merge_request[source_branch]';
const MR_TARGET_BRANCH = 'merge_request[target_branch]';
export default { export default {
alertTexts: { alertTexts: {
[COMMIT_FAILURE]: s__('Pipelines|The GitLab CI configuration could not be updated.'), [COMMIT_FAILURE]: s__('Pipelines|The GitLab CI configuration could not be updated.'),
...@@ -29,7 +26,7 @@ export default { ...@@ -29,7 +26,7 @@ export default {
components: { components: {
CommitForm, CommitForm,
}, },
inject: ['projectFullPath', 'ciConfigPath', 'newMergeRequestPath'], inject: ['projectFullPath', 'ciConfigPath'],
props: { props: {
ciFileContent: { ciFileContent: {
type: String, type: String,
...@@ -74,16 +71,6 @@ export default { ...@@ -74,16 +71,6 @@ export default {
}, },
}, },
methods: { methods: {
redirectToNewMergeRequest(sourceBranch) {
const url = mergeUrlParams(
{
[MR_SOURCE_BRANCH]: sourceBranch,
[MR_TARGET_BRANCH]: this.currentBranch,
},
this.newMergeRequestPath,
);
redirectTo(url);
},
async onCommitSubmit({ message, targetBranch, openMergeRequest }) { async onCommitSubmit({ message, targetBranch, openMergeRequest }) {
this.isSaving = true; this.isSaving = true;
...@@ -112,12 +99,25 @@ export default { ...@@ -112,12 +99,25 @@ export default {
if (errors?.length) { if (errors?.length) {
this.$emit('showError', { type: COMMIT_FAILURE, reasons: errors }); this.$emit('showError', { type: COMMIT_FAILURE, reasons: errors });
} else if (openMergeRequest) {
this.redirectToNewMergeRequest(targetBranch);
} else { } else {
this.$emit('commit', { type: COMMIT_SUCCESS }); const commitBranch = targetBranch;
const params = openMergeRequest
? {
type: COMMIT_SUCCESS_WITH_REDIRECT,
params: {
sourceBranch: commitBranch,
targetBranch: this.currentBranch,
},
}
: { type: COMMIT_SUCCESS };
this.$emit('commit', {
...params,
});
this.updateLastCommitBranch(targetBranch); this.updateLastCommitBranch(targetBranch);
this.updateCurrentBranch(targetBranch); this.updateCurrentBranch(targetBranch);
if (this.currentBranch === targetBranch) { if (this.currentBranch === targetBranch) {
this.$emit('updateCommitSha'); this.$emit('updateCommitSha');
} }
......
...@@ -5,6 +5,7 @@ import { __, s__ } from '~/locale'; ...@@ -5,6 +5,7 @@ import { __, s__ } from '~/locale';
import { import {
COMMIT_FAILURE, COMMIT_FAILURE,
COMMIT_SUCCESS, COMMIT_SUCCESS,
COMMIT_SUCCESS_WITH_REDIRECT,
DEFAULT_FAILURE, DEFAULT_FAILURE,
DEFAULT_SUCCESS, DEFAULT_SUCCESS,
LOAD_FAILURE_UNKNOWN, LOAD_FAILURE_UNKNOWN,
...@@ -21,14 +22,18 @@ export default { ...@@ -21,14 +22,18 @@ export default {
GlAlert, GlAlert,
CodeSnippetAlert, CodeSnippetAlert,
}, },
errorTexts: {
errors: {
[COMMIT_FAILURE]: s__('Pipelines|The GitLab CI configuration could not be updated.'), [COMMIT_FAILURE]: s__('Pipelines|The GitLab CI configuration could not be updated.'),
[DEFAULT_FAILURE]: __('Something went wrong on our end.'), [DEFAULT_FAILURE]: __('Something went wrong on our end.'),
[LOAD_FAILURE_UNKNOWN]: s__('Pipelines|The CI configuration was not loaded, please try again.'), [LOAD_FAILURE_UNKNOWN]: s__('Pipelines|The CI configuration was not loaded, please try again.'),
[PIPELINE_FAILURE]: s__('Pipelines|There was a problem with loading the pipeline data.'), [PIPELINE_FAILURE]: s__('Pipelines|There was a problem with loading the pipeline data.'),
}, },
successTexts: { success: {
[COMMIT_SUCCESS]: __('Your changes have been successfully committed.'), [COMMIT_SUCCESS]: __('Your changes have been successfully committed.'),
[COMMIT_SUCCESS_WITH_REDIRECT]: s__(
'Pipelines|Your changes have been successfully committed. Now redirecting to the new merge request page.',
),
[DEFAULT_SUCCESS]: __('Your action succeeded.'), [DEFAULT_SUCCESS]: __('Your action succeeded.'),
}, },
props: { props: {
...@@ -65,42 +70,20 @@ export default { ...@@ -65,42 +70,20 @@ export default {
}, },
computed: { computed: {
failure() { failure() {
switch (this.failureType) { const { errors } = this.$options;
case LOAD_FAILURE_UNKNOWN:
return {
text: this.$options.errorTexts[LOAD_FAILURE_UNKNOWN],
variant: 'danger',
};
case COMMIT_FAILURE:
return {
text: this.$options.errorTexts[COMMIT_FAILURE],
variant: 'danger',
};
case PIPELINE_FAILURE:
return {
text: this.$options.errorTexts[PIPELINE_FAILURE],
variant: 'danger',
};
default:
return { return {
text: this.$options.errorTexts[DEFAULT_FAILURE], text: errors[this.failureType] ?? errors[DEFAULT_FAILURE],
variant: 'danger', variant: 'danger',
}; };
}
}, },
success() { success() {
switch (this.successType) { const { success } = this.$options;
case COMMIT_SUCCESS:
return {
text: this.$options.successTexts[COMMIT_SUCCESS],
variant: 'info',
};
default:
return { return {
text: this.$options.successTexts[DEFAULT_SUCCESS], text: success[this.successType] ?? success[DEFAULT_SUCCESS],
variant: 'info', variant: 'info',
}; };
}
}, },
}, },
created() { created() {
......
...@@ -20,6 +20,7 @@ export const EDITOR_APP_VALID_STATUSES = [ ...@@ -20,6 +20,7 @@ export const EDITOR_APP_VALID_STATUSES = [
export const COMMIT_FAILURE = 'COMMIT_FAILURE'; export const COMMIT_FAILURE = 'COMMIT_FAILURE';
export const COMMIT_SUCCESS = 'COMMIT_SUCCESS'; export const COMMIT_SUCCESS = 'COMMIT_SUCCESS';
export const COMMIT_SUCCESS_WITH_REDIRECT = 'COMMIT_SUCCESS_WITH_REDIRECT';
export const DEFAULT_FAILURE = 'DEFAULT_FAILURE'; export const DEFAULT_FAILURE = 'DEFAULT_FAILURE';
export const DEFAULT_SUCCESS = 'DEFAULT_SUCCESS'; export const DEFAULT_SUCCESS = 'DEFAULT_SUCCESS';
......
<script> <script>
import { GlLoadingIcon, GlModal } from '@gitlab/ui'; import { GlLoadingIcon, GlModal } from '@gitlab/ui';
import { fetchPolicies } from '~/lib/graphql'; import { fetchPolicies } from '~/lib/graphql';
import { queryToObject } from '~/lib/utils/url_utility'; import { mergeUrlParams, queryToObject, redirectTo } from '~/lib/utils/url_utility';
import { __, s__ } from '~/locale'; import { __, s__ } from '~/locale';
import { unwrapStagesWithNeeds } from '~/pipelines/components/unwrapping_utils'; import { unwrapStagesWithNeeds } from '~/pipelines/components/unwrapping_utils';
...@@ -11,6 +11,7 @@ import PipelineEditorEmptyState from './components/ui/pipeline_editor_empty_stat ...@@ -11,6 +11,7 @@ import PipelineEditorEmptyState from './components/ui/pipeline_editor_empty_stat
import PipelineEditorMessages from './components/ui/pipeline_editor_messages.vue'; import PipelineEditorMessages from './components/ui/pipeline_editor_messages.vue';
import { import {
COMMIT_SHA_POLL_INTERVAL, COMMIT_SHA_POLL_INTERVAL,
COMMIT_SUCCESS_WITH_REDIRECT,
EDITOR_APP_STATUS_EMPTY, EDITOR_APP_STATUS_EMPTY,
EDITOR_APP_STATUS_LOADING, EDITOR_APP_STATUS_LOADING,
EDITOR_APP_STATUS_LINT_UNAVAILABLE, EDITOR_APP_STATUS_LINT_UNAVAILABLE,
...@@ -27,6 +28,9 @@ import getTemplate from './graphql/queries/get_starter_template.query.graphql'; ...@@ -27,6 +28,9 @@ import getTemplate from './graphql/queries/get_starter_template.query.graphql';
import getLatestCommitShaQuery from './graphql/queries/latest_commit_sha.query.graphql'; import getLatestCommitShaQuery from './graphql/queries/latest_commit_sha.query.graphql';
import PipelineEditorHome from './pipeline_editor_home.vue'; import PipelineEditorHome from './pipeline_editor_home.vue';
const MR_SOURCE_BRANCH = 'merge_request[source_branch]';
const MR_TARGET_BRANCH = 'merge_request[target_branch]';
export default { export default {
components: { components: {
ConfirmUnsavedChangesDialog, ConfirmUnsavedChangesDialog,
...@@ -36,14 +40,7 @@ export default { ...@@ -36,14 +40,7 @@ export default {
PipelineEditorHome, PipelineEditorHome,
PipelineEditorMessages, PipelineEditorMessages,
}, },
inject: { inject: ['ciConfigPath', 'newMergeRequestPath', 'projectFullPath'],
ciConfigPath: {
default: '',
},
projectFullPath: {
default: '',
},
},
data() { data() {
return { return {
ciConfigData: {}, ciConfigData: {},
...@@ -57,7 +54,7 @@ export default { ...@@ -57,7 +54,7 @@ export default {
lastCommittedContent: '', lastCommittedContent: '',
shouldSkipStartScreen: false, shouldSkipStartScreen: false,
showFailure: false, showFailure: false,
showResetComfirmationModal: false, showResetConfirmationModal: false,
showStartScreen: false, showStartScreen: false,
showSuccess: false, showSuccess: false,
starterTemplate: '', starterTemplate: '',
...@@ -271,17 +268,39 @@ export default { ...@@ -271,17 +268,39 @@ export default {
this.checkShouldSkipStartScreen(); this.checkShouldSkipStartScreen();
}, },
methods: { methods: {
checkShouldSkipStartScreen() {
const params = queryToObject(window.location.search);
this.shouldSkipStartScreen = Boolean(params?.add_new_config_file);
},
confirmReset() {
if (this.hasUnsavedChanges) {
this.showResetConfirmationModal = true;
}
},
hideFailure() { hideFailure() {
this.showFailure = false; this.showFailure = false;
}, },
hideSuccess() { hideSuccess() {
this.showSuccess = false; this.showSuccess = false;
}, },
confirmReset() { loadTemplateFromURL() {
if (this.hasUnsavedChanges) { const templateName = queryToObject(window.location.search)?.template;
this.showResetComfirmationModal = true;
if (templateName) {
this.starterTemplateName = templateName;
this.setNewEmptyCiConfigFile();
} }
}, },
redirectToNewMergeRequest(sourceBranch, targetBranch) {
const url = mergeUrlParams(
{
[MR_SOURCE_BRANCH]: sourceBranch,
[MR_TARGET_BRANCH]: targetBranch,
},
this.newMergeRequestPath,
);
redirectTo(url);
},
async refetchContent() { async refetchContent() {
this.$apollo.queries.initialCiFileContent.skip = false; this.$apollo.queries.initialCiFileContent.skip = false;
await this.$apollo.queries.initialCiFileContent.refetch(); await this.$apollo.queries.initialCiFileContent.refetch();
...@@ -298,7 +317,7 @@ export default { ...@@ -298,7 +317,7 @@ export default {
this.successType = type; this.successType = type;
}, },
resetContent() { resetContent() {
this.showResetComfirmationModal = false; this.showResetConfirmationModal = false;
this.currentCiFileContent = this.lastCommittedContent; this.currentCiFileContent = this.lastCommittedContent;
}, },
setAppStatus(appStatus) { setAppStatus(appStatus) {
...@@ -323,7 +342,7 @@ export default { ...@@ -323,7 +342,7 @@ export default {
this.isFetchingCommitSha = true; this.isFetchingCommitSha = true;
this.$apollo.queries.commitSha.refetch(); this.$apollo.queries.commitSha.refetch();
}, },
updateOnCommit({ type }) { async updateOnCommit({ type, params = {} }) {
this.reportSuccess(type); this.reportSuccess(type);
if (this.isNewCiConfigFile) { if (this.isNewCiConfigFile) {
...@@ -333,19 +352,17 @@ export default { ...@@ -333,19 +352,17 @@ export default {
// Keep track of the latest committed content to know // Keep track of the latest committed content to know
// if the user has made changes to the file that are unsaved. // if the user has made changes to the file that are unsaved.
this.lastCommittedContent = this.currentCiFileContent; this.lastCommittedContent = this.currentCiFileContent;
},
loadTemplateFromURL() {
const templateName = queryToObject(window.location.search)?.template;
if (templateName) { if (type === COMMIT_SUCCESS_WITH_REDIRECT) {
this.starterTemplateName = templateName; const { sourceBranch, targetBranch } = params;
this.setNewEmptyCiConfigFile(); // This force update does 2 things for us:
// 1. It make sure `hasUnsavedChanges` is updated so
// we don't show a modal when the user creates an MR
// 2. Ensure the commit success banner is visible.
await this.$forceUpdate();
this.redirectToNewMergeRequest(sourceBranch, targetBranch);
} }
}, },
checkShouldSkipStartScreen() {
const params = queryToObject(window.location.search);
this.shouldSkipStartScreen = Boolean(params?.add_new_config_file);
},
}, },
}; };
</script> </script>
...@@ -382,7 +399,7 @@ export default { ...@@ -382,7 +399,7 @@ export default {
@updateCommitSha="updateCommitSha" @updateCommitSha="updateCommitSha"
/> />
<gl-modal <gl-modal
v-model="showResetComfirmationModal" v-model="showResetConfirmationModal"
modal-id="reset-content" modal-id="reset-content"
:title="$options.i18n.resetModal.title" :title="$options.i18n.resetModal.title"
:action-cancel="$options.i18n.resetModal.actionCancel" :action-cancel="$options.i18n.resetModal.actionCancel"
......
...@@ -26486,6 +26486,9 @@ msgstr "" ...@@ -26486,6 +26486,9 @@ msgstr ""
msgid "Pipelines|Visualize" msgid "Pipelines|Visualize"
msgstr "" msgstr ""
msgid "Pipelines|Your changes have been successfully committed. Now redirecting to the new merge request page."
msgstr ""
msgid "Pipelines|detached" msgid "Pipelines|detached"
msgstr "" msgstr ""
......
...@@ -26,7 +26,7 @@ RSpec.describe 'Pipeline Editor', :js do ...@@ -26,7 +26,7 @@ RSpec.describe 'Pipeline Editor', :js do
expect(page).to have_content('Pipeline Editor') expect(page).to have_content('Pipeline Editor')
end end
context 'branch switcher' do describe 'Branch switcher' do
def switch_to_branch(branch) def switch_to_branch(branch)
find('[data-testid="branch-selector"]').click find('[data-testid="branch-selector"]').click
...@@ -64,7 +64,64 @@ RSpec.describe 'Pipeline Editor', :js do ...@@ -64,7 +64,64 @@ RSpec.describe 'Pipeline Editor', :js do
end end
end end
context 'Editor content' do describe 'Editor navigation' do
context 'when no change is made' do
it 'user can navigate away without a browser alert' do
expect(page).to have_content('Pipeline Editor')
click_link 'Pipelines'
expect(page).not_to have_content('Pipeline Editor')
end
end
context 'when a change is made' do
before do
click_button 'Collapse'
page.within('#source-editor-') do
find('textarea').send_keys '123'
# It takes some time after sending keys for the vue
# component to update
sleep 1
end
end
it 'user who tries to navigate away can cancel the action and keep their changes' do
click_link 'Pipelines'
page.driver.browser.switch_to.alert.dismiss
expect(page).to have_content('Pipeline Editor')
page.within('#source-editor-') do
expect(page).to have_content('Default Content123')
end
end
it 'user who tries to navigate away can confirm the action and discard their change' do
click_link 'Pipelines'
page.driver.browser.switch_to.alert.accept
expect(page).not_to have_content('Pipeline Editor')
end
it 'user who creates a MR is taken to the merge request page without warnings' do
expect(page).not_to have_content('New merge request')
find_field('Target Branch').set 'new_branch'
find_field('Start a new merge request with these changes').click
click_button 'Commit changes'
expect(page).not_to have_content('Pipeline Editor')
expect(page).to have_content('New merge request')
end
end
end
describe 'Editor content' do
it 'user can reset their CI configuration' do it 'user can reset their CI configuration' do
click_button 'Collapse' click_button 'Collapse'
......
...@@ -4,13 +4,13 @@ import { mount } from '@vue/test-utils'; ...@@ -4,13 +4,13 @@ import { mount } from '@vue/test-utils';
import Vue from 'vue'; import Vue from 'vue';
import createMockApollo from 'helpers/mock_apollo_helper'; import createMockApollo from 'helpers/mock_apollo_helper';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
import { objectToQuery, redirectTo } from '~/lib/utils/url_utility';
import CommitForm from '~/pipeline_editor/components/commit/commit_form.vue'; import CommitForm from '~/pipeline_editor/components/commit/commit_form.vue';
import CommitSection from '~/pipeline_editor/components/commit/commit_section.vue'; import CommitSection from '~/pipeline_editor/components/commit/commit_section.vue';
import { import {
COMMIT_ACTION_CREATE, COMMIT_ACTION_CREATE,
COMMIT_ACTION_UPDATE, COMMIT_ACTION_UPDATE,
COMMIT_SUCCESS, COMMIT_SUCCESS,
COMMIT_SUCCESS_WITH_REDIRECT,
} from '~/pipeline_editor/constants'; } from '~/pipeline_editor/constants';
import commitCreate from '~/pipeline_editor/graphql/mutations/commit_ci_file.mutation.graphql'; import commitCreate from '~/pipeline_editor/graphql/mutations/commit_ci_file.mutation.graphql';
import updatePipelineEtag from '~/pipeline_editor/graphql/mutations/client/update_pipeline_etag.mutation.graphql'; import updatePipelineEtag from '~/pipeline_editor/graphql/mutations/client/update_pipeline_etag.mutation.graphql';
...@@ -24,16 +24,8 @@ import { ...@@ -24,16 +24,8 @@ import {
mockCommitMessage, mockCommitMessage,
mockDefaultBranch, mockDefaultBranch,
mockProjectFullPath, mockProjectFullPath,
mockNewMergeRequestPath,
} from '../../mock_data'; } from '../../mock_data';
jest.mock('~/lib/utils/url_utility', () => ({
redirectTo: jest.fn(),
refreshCurrentPage: jest.fn(),
objectToQuery: jest.requireActual('~/lib/utils/url_utility').objectToQuery,
mergeUrlParams: jest.requireActual('~/lib/utils/url_utility').mergeUrlParams,
}));
const mockVariables = { const mockVariables = {
action: COMMIT_ACTION_UPDATE, action: COMMIT_ACTION_UPDATE,
projectPath: mockProjectFullPath, projectPath: mockProjectFullPath,
...@@ -47,7 +39,6 @@ const mockVariables = { ...@@ -47,7 +39,6 @@ const mockVariables = {
const mockProvide = { const mockProvide = {
ciConfigPath: mockCiConfigPath, ciConfigPath: mockCiConfigPath,
projectFullPath: mockProjectFullPath, projectFullPath: mockProjectFullPath,
newMergeRequestPath: mockNewMergeRequestPath,
}; };
describe('Pipeline Editor | Commit section', () => { describe('Pipeline Editor | Commit section', () => {
...@@ -208,19 +199,21 @@ describe('Pipeline Editor | Commit section', () => { ...@@ -208,19 +199,21 @@ describe('Pipeline Editor | Commit section', () => {
beforeEach(async () => { beforeEach(async () => {
createComponentWithApollo(); createComponentWithApollo();
mockMutateCommitData.mockResolvedValue(mockCommitCreateResponse);
await submitCommit({ await submitCommit({
branch: newBranch, branch: newBranch,
openMergeRequest: true, openMergeRequest: true,
}); });
}); });
it('redirects to the merge request page with source and target branches', () => { it('emits a commit event with the right type, sourceBranch and targetBranch', () => {
const branchesQuery = objectToQuery({ expect(wrapper.emitted('commit')).toBeTruthy();
'merge_request[source_branch]': newBranch, expect(wrapper.emitted('commit')[0]).toMatchObject([
'merge_request[target_branch]': mockDefaultBranch, {
}); type: COMMIT_SUCCESS_WITH_REDIRECT,
params: { sourceBranch: newBranch, targetBranch: mockDefaultBranch },
expect(redirectTo).toHaveBeenCalledWith(`${mockNewMergeRequestPath}?${branchesQuery}`); },
]);
}); });
}); });
......
...@@ -8,6 +8,7 @@ import PipelineEditorMessages from '~/pipeline_editor/components/ui/pipeline_edi ...@@ -8,6 +8,7 @@ import PipelineEditorMessages from '~/pipeline_editor/components/ui/pipeline_edi
import { import {
COMMIT_FAILURE, COMMIT_FAILURE,
COMMIT_SUCCESS, COMMIT_SUCCESS,
COMMIT_SUCCESS_WITH_REDIRECT,
DEFAULT_FAILURE, DEFAULT_FAILURE,
DEFAULT_SUCCESS, DEFAULT_SUCCESS,
LOAD_FAILURE_UNKNOWN, LOAD_FAILURE_UNKNOWN,
...@@ -34,7 +35,13 @@ describe('Pipeline Editor messages', () => { ...@@ -34,7 +35,13 @@ describe('Pipeline Editor messages', () => {
it('shows a message for successful commit type', () => { it('shows a message for successful commit type', () => {
createComponent({ successType: COMMIT_SUCCESS, showSuccess: true }); createComponent({ successType: COMMIT_SUCCESS, showSuccess: true });
expect(findAlert().text()).toBe(wrapper.vm.$options.successTexts[COMMIT_SUCCESS]); expect(findAlert().text()).toBe(wrapper.vm.$options.success[COMMIT_SUCCESS]);
});
it('shows a message for successful commit with redirect type', () => {
createComponent({ successType: COMMIT_SUCCESS_WITH_REDIRECT, showSuccess: true });
expect(findAlert().text()).toBe(wrapper.vm.$options.success[COMMIT_SUCCESS_WITH_REDIRECT]);
}); });
it('does not show alert when there is a successType but visibility is off', () => { it('does not show alert when there is a successType but visibility is off', () => {
...@@ -46,7 +53,7 @@ describe('Pipeline Editor messages', () => { ...@@ -46,7 +53,7 @@ describe('Pipeline Editor messages', () => {
it('shows a success alert with default copy if `showSuccess` is true and the `successType` is not valid,', () => { it('shows a success alert with default copy if `showSuccess` is true and the `successType` is not valid,', () => {
createComponent({ successType: 'random', showSuccess: true }); createComponent({ successType: 'random', showSuccess: true });
expect(findAlert().text()).toBe(wrapper.vm.$options.successTexts[DEFAULT_SUCCESS]); expect(findAlert().text()).toBe(wrapper.vm.$options.success[DEFAULT_SUCCESS]);
}); });
it('emit `hide-success` event when clicking on the dismiss button', async () => { it('emit `hide-success` event when clicking on the dismiss button', async () => {
...@@ -71,7 +78,7 @@ describe('Pipeline Editor messages', () => { ...@@ -71,7 +78,7 @@ describe('Pipeline Editor messages', () => {
`('shows a message for $message', ({ failureType, expectedFailureType }) => { `('shows a message for $message', ({ failureType, expectedFailureType }) => {
createComponent({ failureType, showFailure: true }); createComponent({ failureType, showFailure: true });
expect(findAlert().text()).toBe(wrapper.vm.$options.errorTexts[expectedFailureType]); expect(findAlert().text()).toBe(wrapper.vm.$options.errors[expectedFailureType]);
}); });
it('show failure reasons when there are some', () => { it('show failure reasons when there are some', () => {
......
...@@ -5,6 +5,7 @@ import createMockApollo from 'helpers/mock_apollo_helper'; ...@@ -5,6 +5,7 @@ import createMockApollo from 'helpers/mock_apollo_helper';
import setWindowLocation from 'helpers/set_window_location_helper'; import setWindowLocation from 'helpers/set_window_location_helper';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
import { objectToQuery, redirectTo } from '~/lib/utils/url_utility';
import { resolvers } from '~/pipeline_editor/graphql/resolvers'; import { resolvers } from '~/pipeline_editor/graphql/resolvers';
import PipelineEditorTabs from '~/pipeline_editor/components/pipeline_editor_tabs.vue'; import PipelineEditorTabs from '~/pipeline_editor/components/pipeline_editor_tabs.vue';
import PipelineEditorEmptyState from '~/pipeline_editor/components/ui/pipeline_editor_empty_state.vue'; import PipelineEditorEmptyState from '~/pipeline_editor/components/ui/pipeline_editor_empty_state.vue';
...@@ -13,7 +14,11 @@ import PipelineEditorHeader from '~/pipeline_editor/components/header/pipeline_e ...@@ -13,7 +14,11 @@ import PipelineEditorHeader from '~/pipeline_editor/components/header/pipeline_e
import ValidationSegment, { import ValidationSegment, {
i18n as validationSegmenti18n, i18n as validationSegmenti18n,
} from '~/pipeline_editor/components/header/validation_segment.vue'; } from '~/pipeline_editor/components/header/validation_segment.vue';
import { COMMIT_SUCCESS, COMMIT_FAILURE } from '~/pipeline_editor/constants'; import {
COMMIT_SUCCESS,
COMMIT_SUCCESS_WITH_REDIRECT,
COMMIT_FAILURE,
} from '~/pipeline_editor/constants';
import getBlobContent from '~/pipeline_editor/graphql/queries/blob_content.query.graphql'; import getBlobContent from '~/pipeline_editor/graphql/queries/blob_content.query.graphql';
import getCiConfigData from '~/pipeline_editor/graphql/queries/ci_config.query.graphql'; import getCiConfigData from '~/pipeline_editor/graphql/queries/ci_config.query.graphql';
import getTemplate from '~/pipeline_editor/graphql/queries/get_starter_template.query.graphql'; import getTemplate from '~/pipeline_editor/graphql/queries/get_starter_template.query.graphql';
...@@ -35,15 +40,22 @@ import { ...@@ -35,15 +40,22 @@ import {
mockDefaultBranch, mockDefaultBranch,
mockEmptyCommitShaResults, mockEmptyCommitShaResults,
mockNewCommitShaResults, mockNewCommitShaResults,
mockNewMergeRequestPath,
mockProjectFullPath, mockProjectFullPath,
} from './mock_data'; } from './mock_data';
jest.mock('~/lib/utils/url_utility', () => ({
...jest.requireActual('~/lib/utils/url_utility'),
redirectTo: jest.fn(),
}));
const localVue = createLocalVue(); const localVue = createLocalVue();
localVue.use(VueApollo); localVue.use(VueApollo);
const mockProvide = { const mockProvide = {
ciConfigPath: mockCiConfigPath, ciConfigPath: mockCiConfigPath,
defaultBranch: mockDefaultBranch, defaultBranch: mockDefaultBranch,
newMergeRequestPath: mockNewMergeRequestPath,
projectFullPath: mockProjectFullPath, projectFullPath: mockProjectFullPath,
}; };
...@@ -311,6 +323,28 @@ describe('Pipeline editor app component', () => { ...@@ -311,6 +323,28 @@ describe('Pipeline editor app component', () => {
}); });
}); });
describe('when the commit succeeds with a redirect', () => {
const newBranch = 'new-branch';
beforeEach(async () => {
await createComponentWithApollo({ stubs: { PipelineEditorMessages } });
findEditorHome().vm.$emit('commit', {
type: COMMIT_SUCCESS_WITH_REDIRECT,
params: { sourceBranch: newBranch, targetBranch: mockDefaultBranch },
});
});
it('redirects to the merge request page with source and target branches', () => {
const branchesQuery = objectToQuery({
'merge_request[source_branch]': newBranch,
'merge_request[target_branch]': mockDefaultBranch,
});
expect(redirectTo).toHaveBeenCalledWith(`${mockNewMergeRequestPath}?${branchesQuery}`);
});
});
describe('and the commit mutation fails', () => { describe('and the commit mutation fails', () => {
const commitFailedReasons = ['Commit failed']; const commitFailedReasons = ['Commit failed'];
......
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