Commit b00b9dbc authored by Himanshu Kapoor's avatar Himanshu Kapoor Committed by Kushal Pandya

Improve WebIDE error messages on committing

parent 3e51944e
...@@ -7,7 +7,6 @@ import CommitMessageField from './message_field.vue'; ...@@ -7,7 +7,6 @@ import CommitMessageField from './message_field.vue';
import Actions from './actions.vue'; import Actions from './actions.vue';
import SuccessMessage from './success_message.vue'; import SuccessMessage from './success_message.vue';
import { leftSidebarViews, MAX_WINDOW_HEIGHT_COMPACT } from '../../constants'; import { leftSidebarViews, MAX_WINDOW_HEIGHT_COMPACT } from '../../constants';
import consts from '../../stores/modules/commit/constants';
import { createUnexpectedCommitError } from '../../lib/errors'; import { createUnexpectedCommitError } from '../../lib/errors';
export default { export default {
...@@ -45,12 +44,11 @@ export default { ...@@ -45,12 +44,11 @@ export default {
return this.currentActivityView === leftSidebarViews.commit.name; return this.currentActivityView === leftSidebarViews.commit.name;
}, },
commitErrorPrimaryAction() { commitErrorPrimaryAction() {
if (!this.lastCommitError?.canCreateBranch) { const { primaryAction } = this.lastCommitError || {};
return undefined;
}
return { return {
text: __('Create new branch'), button: primaryAction ? { text: primaryAction.text } : undefined,
callback: primaryAction?.callback?.bind(this, this.$store) || (() => {}),
}; };
}, },
}, },
...@@ -78,9 +76,6 @@ export default { ...@@ -78,9 +76,6 @@ export default {
commit() { commit() {
return this.commitChanges(); return this.commitChanges();
}, },
forceCreateNewBranch() {
return this.updateCommitAction(consts.COMMIT_TO_NEW_BRANCH).then(() => this.commit());
},
handleCompactState() { handleCompactState() {
if (this.lastCommitMsg) { if (this.lastCommitMsg) {
this.isCompact = false; this.isCompact = false;
...@@ -188,9 +183,9 @@ export default { ...@@ -188,9 +183,9 @@ export default {
ref="commitErrorModal" ref="commitErrorModal"
modal-id="ide-commit-error-modal" modal-id="ide-commit-error-modal"
:title="lastCommitError.title" :title="lastCommitError.title"
:action-primary="commitErrorPrimaryAction" :action-primary="commitErrorPrimaryAction.button"
:action-cancel="{ text: __('Cancel') }" :action-cancel="{ text: __('Cancel') }"
@ok="forceCreateNewBranch" @ok="commitErrorPrimaryAction.callback"
> >
<div v-safe-html="lastCommitError.messageHTML"></div> <div v-safe-html="lastCommitError.messageHTML"></div>
</gl-modal> </gl-modal>
......
import { escape } from 'lodash'; import { escape } from 'lodash';
import { __ } from '~/locale'; import { __ } from '~/locale';
import consts from '../stores/modules/commit/constants';
const CODEOWNERS_REGEX = /Push.*protected branches.*CODEOWNERS/; const CODEOWNERS_REGEX = /Push.*protected branches.*CODEOWNERS/;
const BRANCH_CHANGED_REGEX = /changed.*since.*start.*edit/; const BRANCH_CHANGED_REGEX = /changed.*since.*start.*edit/;
const BRANCH_ALREADY_EXISTS = /branch.*already.*exists/;
export const createUnexpectedCommitError = () => ({ const createNewBranchAndCommit = store =>
store
.dispatch('commit/updateCommitAction', consts.COMMIT_TO_NEW_BRANCH)
.then(() => store.dispatch('commit/commitChanges'));
export const createUnexpectedCommitError = message => ({
title: __('Unexpected error'), title: __('Unexpected error'),
messageHTML: __('Could not commit. An unexpected error occurred.'), messageHTML: escape(message) || __('Could not commit. An unexpected error occurred.'),
canCreateBranch: false,
}); });
export const createCodeownersCommitError = message => ({ export const createCodeownersCommitError = message => ({
title: __('CODEOWNERS rule violation'), title: __('CODEOWNERS rule violation'),
messageHTML: escape(message), messageHTML: escape(message),
canCreateBranch: true, primaryAction: {
text: __('Create new branch'),
callback: createNewBranchAndCommit,
},
}); });
export const createBranchChangedCommitError = message => ({ export const createBranchChangedCommitError = message => ({
title: __('Branch changed'), title: __('Branch changed'),
messageHTML: `${escape(message)}<br/><br/>${__('Would you like to create a new branch?')}`, messageHTML: `${escape(message)}<br/><br/>${__('Would you like to create a new branch?')}`,
canCreateBranch: true, primaryAction: {
text: __('Create new branch'),
callback: createNewBranchAndCommit,
},
});
export const branchAlreadyExistsCommitError = message => ({
title: __('Branch already exists'),
messageHTML: `${escape(message)}<br/><br/>${__(
'Would you like to try auto-generating a branch name?',
)}`,
primaryAction: {
text: __('Create new branch'),
callback: store =>
store.dispatch('commit/addSuffixToBranchName').then(() => createNewBranchAndCommit(store)),
},
}); });
export const parseCommitError = e => { export const parseCommitError = e => {
...@@ -33,7 +57,9 @@ export const parseCommitError = e => { ...@@ -33,7 +57,9 @@ export const parseCommitError = e => {
return createCodeownersCommitError(message); return createCodeownersCommitError(message);
} else if (BRANCH_CHANGED_REGEX.test(message)) { } else if (BRANCH_CHANGED_REGEX.test(message)) {
return createBranchChangedCommitError(message); return createBranchChangedCommitError(message);
} else if (BRANCH_ALREADY_EXISTS.test(message)) {
return branchAlreadyExistsCommitError(message);
} }
return createUnexpectedCommitError(); return createUnexpectedCommitError(message);
}; };
...@@ -6,6 +6,7 @@ import { ...@@ -6,6 +6,7 @@ import {
PERMISSION_CREATE_MR, PERMISSION_CREATE_MR,
PERMISSION_PUSH_CODE, PERMISSION_PUSH_CODE,
} from '../constants'; } from '../constants';
import { addNumericSuffix } from '~/ide/utils';
import Api from '~/api'; import Api from '~/api';
export const activeFile = state => state.openFiles.find(file => file.active) || null; export const activeFile = state => state.openFiles.find(file => file.active) || null;
...@@ -167,10 +168,7 @@ export const getAvailableFileName = (state, getters) => path => { ...@@ -167,10 +168,7 @@ export const getAvailableFileName = (state, getters) => path => {
let newPath = path; let newPath = path;
while (getters.entryExists(newPath)) { while (getters.entryExists(newPath)) {
newPath = newPath.replace( newPath = addNumericSuffix(newPath);
/([ _-]?)(\d*)(\..+?$|$)/,
(_, before, number, after) => `${before || '_'}${Number(number) + 1}${after}`,
);
} }
return newPath; return newPath;
......
...@@ -8,6 +8,7 @@ import consts from './constants'; ...@@ -8,6 +8,7 @@ import consts from './constants';
import { leftSidebarViews } from '../../../constants'; import { leftSidebarViews } from '../../../constants';
import eventHub from '../../../eventhub'; import eventHub from '../../../eventhub';
import { parseCommitError } from '../../../lib/errors'; import { parseCommitError } from '../../../lib/errors';
import { addNumericSuffix } from '~/ide/utils';
export const updateCommitMessage = ({ commit }, message) => { export const updateCommitMessage = ({ commit }, message) => {
commit(types.UPDATE_COMMIT_MESSAGE, message); commit(types.UPDATE_COMMIT_MESSAGE, message);
...@@ -17,11 +18,8 @@ export const discardDraft = ({ commit }) => { ...@@ -17,11 +18,8 @@ export const discardDraft = ({ commit }) => {
commit(types.UPDATE_COMMIT_MESSAGE, ''); commit(types.UPDATE_COMMIT_MESSAGE, '');
}; };
export const updateCommitAction = ({ commit, getters }, commitAction) => { export const updateCommitAction = ({ commit }, commitAction) => {
commit(types.UPDATE_COMMIT_ACTION, { commit(types.UPDATE_COMMIT_ACTION, { commitAction });
commitAction,
});
commit(types.TOGGLE_SHOULD_CREATE_MR, !getters.shouldHideNewMrOption);
}; };
export const toggleShouldCreateMR = ({ commit }) => { export const toggleShouldCreateMR = ({ commit }) => {
...@@ -32,6 +30,12 @@ export const updateBranchName = ({ commit }, branchName) => { ...@@ -32,6 +30,12 @@ export const updateBranchName = ({ commit }, branchName) => {
commit(types.UPDATE_NEW_BRANCH_NAME, branchName); commit(types.UPDATE_NEW_BRANCH_NAME, branchName);
}; };
export const addSuffixToBranchName = ({ commit, state }) => {
const newBranchName = addNumericSuffix(state.newBranchName, true);
commit(types.UPDATE_NEW_BRANCH_NAME, newBranchName);
};
export const setLastCommitMessage = ({ commit, rootGetters }, data) => { export const setLastCommitMessage = ({ commit, rootGetters }, data) => {
const { currentProject } = rootGetters; const { currentProject } = rootGetters;
const commitStats = data.stats const commitStats = data.stats
...@@ -107,7 +111,7 @@ export const updateFilesAfterCommit = ({ commit, dispatch, rootState, rootGetter ...@@ -107,7 +111,7 @@ export const updateFilesAfterCommit = ({ commit, dispatch, rootState, rootGetter
export const commitChanges = ({ commit, state, getters, dispatch, rootState, rootGetters }) => { export const commitChanges = ({ commit, state, getters, dispatch, rootState, rootGetters }) => {
// Pull commit options out because they could change // Pull commit options out because they could change
// During some of the pre and post commit processing // During some of the pre and post commit processing
const { shouldCreateMR, isCreatingNewBranch, branchName } = getters; const { shouldCreateMR, shouldHideNewMrOption, isCreatingNewBranch, branchName } = getters;
const newBranch = state.commitAction !== consts.COMMIT_TO_CURRENT_BRANCH; const newBranch = state.commitAction !== consts.COMMIT_TO_CURRENT_BRANCH;
const stageFilesPromise = rootState.stagedFiles.length const stageFilesPromise = rootState.stagedFiles.length
? Promise.resolve() ? Promise.resolve()
...@@ -167,7 +171,7 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo ...@@ -167,7 +171,7 @@ export const commitChanges = ({ commit, state, getters, dispatch, rootState, roo
commit(rootTypes.SET_LAST_COMMIT_MSG, '', { root: true }); commit(rootTypes.SET_LAST_COMMIT_MSG, '', { root: true });
}, 5000); }, 5000);
if (shouldCreateMR) { if (shouldCreateMR && !shouldHideNewMrOption) {
const { currentProject } = rootGetters; const { currentProject } = rootGetters;
const targetBranch = isCreatingNewBranch const targetBranch = isCreatingNewBranch
? rootState.currentBranchId ? rootState.currentBranchId
......
...@@ -10,9 +10,7 @@ export default { ...@@ -10,9 +10,7 @@ export default {
Object.assign(state, { commitAction }); Object.assign(state, { commitAction });
}, },
[types.UPDATE_NEW_BRANCH_NAME](state, newBranchName) { [types.UPDATE_NEW_BRANCH_NAME](state, newBranchName) {
Object.assign(state, { Object.assign(state, { newBranchName });
newBranchName,
});
}, },
[types.UPDATE_LOADING](state, submitCommitLoading) { [types.UPDATE_LOADING](state, submitCommitLoading) {
Object.assign(state, { Object.assign(state, {
......
...@@ -139,6 +139,34 @@ export function getFileEOL(content = '') { ...@@ -139,6 +139,34 @@ export function getFileEOL(content = '') {
return content.includes('\r\n') ? 'CRLF' : 'LF'; return content.includes('\r\n') ? 'CRLF' : 'LF';
} }
/**
* Adds or increments the numeric suffix to a filename/branch name.
* Retains underscore or dash before the numeric suffix if it already exists.
*
* Examples:
* hello -> hello-1
* hello-2425 -> hello-2425
* hello.md -> hello-1.md
* hello_2.md -> hello_3.md
* hello_ -> hello_1
* master-patch-22432 -> master-patch-22433
* patch_332 -> patch_333
*
* @param {string} filename File name or branch name
* @param {number} [randomize] Should randomize the numeric suffix instead of auto-incrementing?
*/
export function addNumericSuffix(filename, randomize = false) {
return filename.replace(/([ _-]?)(\d*)(\..+?$|$)/, (_, before, number, after) => {
const n = randomize
? Math.random()
.toString()
.substring(2, 7)
.slice(-5)
: Number(number) + 1;
return `${before || '-'}${n}${after}`;
});
}
export const measurePerformance = ( export const measurePerformance = (
mark, mark,
measureName, measureName,
......
---
title: Improve WebIDE error messages on committing
merge_request: 43408
author:
type: changed
...@@ -4215,6 +4215,9 @@ msgstr "" ...@@ -4215,6 +4215,9 @@ msgstr ""
msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}" msgid "Branch %{branch_name} was created. To set up auto deploy, choose a GitLab CI Yaml template and commit your changes. %{link_to_autodeploy_doc}"
msgstr "" msgstr ""
msgid "Branch already exists"
msgstr ""
msgid "Branch changed" msgid "Branch changed"
msgstr "" msgstr ""
...@@ -29467,6 +29470,9 @@ msgstr "" ...@@ -29467,6 +29470,9 @@ msgstr ""
msgid "Would you like to create a new branch?" msgid "Would you like to create a new branch?"
msgstr "" msgstr ""
msgid "Would you like to try auto-generating a branch name?"
msgstr ""
msgid "Write" msgid "Write"
msgstr "" msgstr ""
......
...@@ -7,7 +7,12 @@ import { createStore } from '~/ide/stores'; ...@@ -7,7 +7,12 @@ import { createStore } from '~/ide/stores';
import consts from '~/ide/stores/modules/commit/constants'; import consts from '~/ide/stores/modules/commit/constants';
import CommitForm from '~/ide/components/commit_sidebar/form.vue'; import CommitForm from '~/ide/components/commit_sidebar/form.vue';
import { leftSidebarViews } from '~/ide/constants'; import { leftSidebarViews } from '~/ide/constants';
import { createCodeownersCommitError, createUnexpectedCommitError } from '~/ide/lib/errors'; import {
createCodeownersCommitError,
createUnexpectedCommitError,
createBranchChangedCommitError,
branchAlreadyExistsCommitError,
} from '~/ide/lib/errors';
describe('IDE commit form', () => { describe('IDE commit form', () => {
const Component = Vue.extend(CommitForm); const Component = Vue.extend(CommitForm);
...@@ -290,20 +295,30 @@ describe('IDE commit form', () => { ...@@ -290,20 +295,30 @@ describe('IDE commit form', () => {
jest.spyOn(vm.$store, 'dispatch').mockReturnValue(Promise.resolve()); jest.spyOn(vm.$store, 'dispatch').mockReturnValue(Promise.resolve());
}); });
it('updates commit action and commits', async () => { const commitActions = [
store.state.commit.commitError = createCodeownersCommitError('test message'); ['commit/updateCommitAction', consts.COMMIT_TO_NEW_BRANCH],
['commit/commitChanges'],
];
await vm.$nextTick(); it.each`
commitError | expectedActions
${createCodeownersCommitError} | ${commitActions}
${createBranchChangedCommitError} | ${commitActions}
${branchAlreadyExistsCommitError} | ${[['commit/addSuffixToBranchName'], ...commitActions]}
`(
'updates commit action and commits for error: $commitError',
async ({ commitError, expectedActions }) => {
store.state.commit.commitError = commitError('test message');
getByText(document.body, 'Create new branch').click(); await vm.$nextTick();
await waitForPromises(); getByText(document.body, 'Create new branch').click();
expect(vm.$store.dispatch.mock.calls).toEqual([ await waitForPromises();
['commit/updateCommitAction', consts.COMMIT_TO_NEW_BRANCH],
['commit/commitChanges', undefined], expect(vm.$store.dispatch.mock.calls).toEqual(expectedActions);
]); },
}); );
}); });
}); });
......
...@@ -2,6 +2,7 @@ import { ...@@ -2,6 +2,7 @@ import {
createUnexpectedCommitError, createUnexpectedCommitError,
createCodeownersCommitError, createCodeownersCommitError,
createBranchChangedCommitError, createBranchChangedCommitError,
branchAlreadyExistsCommitError,
parseCommitError, parseCommitError,
} from '~/ide/lib/errors'; } from '~/ide/lib/errors';
...@@ -21,35 +22,22 @@ describe('~/ide/lib/errors', () => { ...@@ -21,35 +22,22 @@ describe('~/ide/lib/errors', () => {
}, },
}); });
describe('createCodeownersCommitError', () => { const NEW_BRANCH_SUFFIX = `<br/><br/>Would you like to create a new branch?`;
it('uses given message', () => { const AUTOGENERATE_SUFFIX = `<br/><br/>Would you like to try auto-generating a branch name?`;
expect(createCodeownersCommitError(TEST_MESSAGE)).toEqual({
title: 'CODEOWNERS rule violation',
messageHTML: TEST_MESSAGE,
canCreateBranch: true,
});
});
it('escapes special chars', () => { it.each`
expect(createCodeownersCommitError(TEST_SPECIAL)).toEqual({ fn | title | message | messageHTML
title: 'CODEOWNERS rule violation', ${createCodeownersCommitError} | ${'CODEOWNERS rule violation'} | ${TEST_MESSAGE} | ${TEST_MESSAGE}
messageHTML: TEST_SPECIAL_ESCAPED, ${createCodeownersCommitError} | ${'CODEOWNERS rule violation'} | ${TEST_SPECIAL} | ${TEST_SPECIAL_ESCAPED}
canCreateBranch: true, ${branchAlreadyExistsCommitError} | ${'Branch already exists'} | ${TEST_MESSAGE} | ${`${TEST_MESSAGE}${AUTOGENERATE_SUFFIX}`}
}); ${branchAlreadyExistsCommitError} | ${'Branch already exists'} | ${TEST_SPECIAL} | ${`${TEST_SPECIAL_ESCAPED}${AUTOGENERATE_SUFFIX}`}
}); ${createBranchChangedCommitError} | ${'Branch changed'} | ${TEST_MESSAGE} | ${`${TEST_MESSAGE}${NEW_BRANCH_SUFFIX}`}
}); ${createBranchChangedCommitError} | ${'Branch changed'} | ${TEST_SPECIAL} | ${`${TEST_SPECIAL_ESCAPED}${NEW_BRANCH_SUFFIX}`}
`('$fn escapes and uses given message="$message"', ({ fn, title, message, messageHTML }) => {
describe('createBranchChangedCommitError', () => { expect(fn(message)).toEqual({
it.each` title,
message | expectedMessage messageHTML,
${TEST_MESSAGE} | ${`${TEST_MESSAGE}<br/><br/>Would you like to create a new branch?`} primaryAction: { text: 'Create new branch', callback: expect.any(Function) },
${TEST_SPECIAL} | ${`${TEST_SPECIAL_ESCAPED}<br/><br/>Would you like to create a new branch?`}
`('uses given message="$message"', ({ message, expectedMessage }) => {
expect(createBranchChangedCommitError(message)).toEqual({
title: 'Branch changed',
messageHTML: expectedMessage,
canCreateBranch: true,
});
}); });
}); });
...@@ -60,7 +48,7 @@ describe('~/ide/lib/errors', () => { ...@@ -60,7 +48,7 @@ describe('~/ide/lib/errors', () => {
${{}} | ${createUnexpectedCommitError()} ${{}} | ${createUnexpectedCommitError()}
${{ response: {} }} | ${createUnexpectedCommitError()} ${{ response: {} }} | ${createUnexpectedCommitError()}
${{ response: { data: {} } }} | ${createUnexpectedCommitError()} ${{ response: { data: {} } }} | ${createUnexpectedCommitError()}
${createResponseError('test')} | ${createUnexpectedCommitError()} ${createResponseError(TEST_MESSAGE)} | ${createUnexpectedCommitError(TEST_MESSAGE)}
${createResponseError(CODEOWNERS_MESSAGE)} | ${createCodeownersCommitError(CODEOWNERS_MESSAGE)} ${createResponseError(CODEOWNERS_MESSAGE)} | ${createCodeownersCommitError(CODEOWNERS_MESSAGE)}
${createResponseError(CHANGED_MESSAGE)} | ${createBranchChangedCommitError(CHANGED_MESSAGE)} ${createResponseError(CHANGED_MESSAGE)} | ${createBranchChangedCommitError(CHANGED_MESSAGE)}
`('parses message into error object with "$message"', ({ message, expectation }) => { `('parses message into error object with "$message"', ({ message, expectation }) => {
......
...@@ -449,16 +449,16 @@ describe('IDE store getters', () => { ...@@ -449,16 +449,16 @@ describe('IDE store getters', () => {
describe('getAvailableFileName', () => { describe('getAvailableFileName', () => {
it.each` it.each`
path | newPath path | newPath
${'foo'} | ${'foo_1'} ${'foo'} | ${'foo-1'}
${'foo__93.png'} | ${'foo__94.png'} ${'foo__93.png'} | ${'foo__94.png'}
${'foo/bar.png'} | ${'foo/bar_1.png'} ${'foo/bar.png'} | ${'foo/bar-1.png'}
${'foo/bar--34.png'} | ${'foo/bar--35.png'} ${'foo/bar--34.png'} | ${'foo/bar--35.png'}
${'foo/bar 2.png'} | ${'foo/bar 3.png'} ${'foo/bar 2.png'} | ${'foo/bar 3.png'}
${'foo/bar-621.png'} | ${'foo/bar-622.png'} ${'foo/bar-621.png'} | ${'foo/bar-622.png'}
${'jquery.min.js'} | ${'jquery_1.min.js'} ${'jquery.min.js'} | ${'jquery-1.min.js'}
${'my_spec_22.js.snap'} | ${'my_spec_23.js.snap'} ${'my_spec_22.js.snap'} | ${'my_spec_23.js.snap'}
${'subtitles5.mp4.srt'} | ${'subtitles_6.mp4.srt'} ${'subtitles5.mp4.srt'} | ${'subtitles-6.mp4.srt'}
${'sample_file.mp3'} | ${'sample_file_1.mp3'} ${'sample-file.mp3'} | ${'sample-file-1.mp3'}
${'Screenshot 2020-05-26 at 10.53.08 PM.png'} | ${'Screenshot 2020-05-26 at 11.53.08 PM.png'} ${'Screenshot 2020-05-26 at 10.53.08 PM.png'} | ${'Screenshot 2020-05-26 at 11.53.08 PM.png'}
`('suffixes the path with a number if the path already exists', ({ path, newPath }) => { `('suffixes the path with a number if the path already exists', ({ path, newPath }) => {
localState.entries[path] = file(); localState.entries[path] = file();
......
...@@ -76,59 +76,38 @@ describe('IDE commit module actions', () => { ...@@ -76,59 +76,38 @@ describe('IDE commit module actions', () => {
.then(done) .then(done)
.catch(done.fail); .catch(done.fail);
}); });
});
it('sets shouldCreateMR to true if "Create new MR" option is visible', done => { describe('updateBranchName', () => {
Object.assign(store.state, { let originalGon;
shouldHideNewMrOption: false,
});
testAction( beforeEach(() => {
actions.updateCommitAction, originalGon = window.gon;
{}, window.gon = { current_username: 'johndoe' };
store.state,
[ store.state.currentBranchId = 'master';
{
type: mutationTypes.UPDATE_COMMIT_ACTION,
payload: { commitAction: expect.anything() },
},
{ type: mutationTypes.TOGGLE_SHOULD_CREATE_MR, payload: true },
],
[],
done,
);
}); });
it('sets shouldCreateMR to false if "Create new MR" option is hidden', done => { afterEach(() => {
Object.assign(store.state, { window.gon = originalGon;
shouldHideNewMrOption: true, });
});
testAction( it('updates store with new branch name', async () => {
actions.updateCommitAction, await store.dispatch('commit/updateBranchName', 'branch-name');
{},
store.state, expect(store.state.commit.newBranchName).toBe('branch-name');
[
{
type: mutationTypes.UPDATE_COMMIT_ACTION,
payload: { commitAction: expect.anything() },
},
{ type: mutationTypes.TOGGLE_SHOULD_CREATE_MR, payload: false },
],
[],
done,
);
}); });
}); });
describe('updateBranchName', () => { describe('addSuffixToBranchName', () => {
it('updates store with new branch name', done => { it('adds suffix to branchName', async () => {
store jest.spyOn(Math, 'random').mockReturnValue(0.391352525);
.dispatch('commit/updateBranchName', 'branch-name')
.then(() => { store.state.commit.newBranchName = 'branch-name';
expect(store.state.commit.newBranchName).toBe('branch-name');
}) await store.dispatch('commit/addSuffixToBranchName');
.then(done)
.catch(done.fail); expect(store.state.commit.newBranchName).toBe('branch-name-39135');
}); });
}); });
...@@ -318,13 +297,16 @@ describe('IDE commit module actions', () => { ...@@ -318,13 +297,16 @@ describe('IDE commit module actions', () => {
currentBranchId: 'master', currentBranchId: 'master',
projects: { projects: {
abcproject: { abcproject: {
default_branch: 'master',
web_url: 'webUrl', web_url: 'webUrl',
branches: { branches: {
master: { master: {
name: 'master',
workingReference: '1', workingReference: '1',
commit: { commit: {
id: TEST_COMMIT_SHA, id: TEST_COMMIT_SHA,
}, },
can_push: true,
}, },
}, },
userPermissions: { userPermissions: {
...@@ -499,6 +481,16 @@ describe('IDE commit module actions', () => { ...@@ -499,6 +481,16 @@ describe('IDE commit module actions', () => {
.catch(done.fail); .catch(done.fail);
}); });
it('does not redirect to merge request page if shouldCreateMR is checked, but branch is the default branch', async () => {
jest.spyOn(eventHub, '$on').mockImplementation();
store.state.commit.commitAction = consts.COMMIT_TO_CURRENT_BRANCH;
store.state.commit.shouldCreateMR = true;
await store.dispatch('commit/commitChanges');
expect(visitUrl).not.toHaveBeenCalled();
});
it('resets changed files before redirecting', () => { it('resets changed files before redirecting', () => {
jest.spyOn(eventHub, '$on').mockImplementation(); jest.spyOn(eventHub, '$on').mockImplementation();
......
...@@ -9,6 +9,7 @@ import { ...@@ -9,6 +9,7 @@ import {
getPathParents, getPathParents,
getPathParent, getPathParent,
readFileAsDataURL, readFileAsDataURL,
addNumericSuffix,
} from '~/ide/utils'; } from '~/ide/utils';
describe('WebIDE utils', () => { describe('WebIDE utils', () => {
...@@ -291,4 +292,43 @@ describe('WebIDE utils', () => { ...@@ -291,4 +292,43 @@ describe('WebIDE utils', () => {
}); });
}); });
}); });
/*
* hello-2425 -> hello-2425
* hello.md -> hello-1.md
* hello_2.md -> hello_3.md
* hello_ -> hello_1
* master-patch-22432 -> master-patch-22433
* patch_332 -> patch_333
*/
describe('addNumericSuffix', () => {
it.each`
input | output
${'hello'} | ${'hello-1'}
${'hello2'} | ${'hello-3'}
${'hello.md'} | ${'hello-1.md'}
${'hello_2.md'} | ${'hello_3.md'}
${'hello_'} | ${'hello_1'}
${'master-patch-22432'} | ${'master-patch-22433'}
${'patch_332'} | ${'patch_333'}
`('adds a numeric suffix to a given filename/branch name: $input', ({ input, output }) => {
expect(addNumericSuffix(input)).toBe(output);
});
it.each`
input | output
${'hello'} | ${'hello-39135'}
${'hello2'} | ${'hello-39135'}
${'hello.md'} | ${'hello-39135.md'}
${'hello_2.md'} | ${'hello_39135.md'}
${'hello_'} | ${'hello_39135'}
${'master-patch-22432'} | ${'master-patch-39135'}
${'patch_332'} | ${'patch_39135'}
`('adds a random suffix if randomize=true is passed for name: $input', ({ input, output }) => {
jest.spyOn(Math, 'random').mockReturnValue(0.391352525);
expect(addNumericSuffix(input, true)).toBe(output);
});
});
}); });
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