Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2020-04-03 18:09:56 +0300
committerGitLab Bot <gitlab-bot@gitlab.com>2020-04-03 18:09:56 +0300
commitc08d9c22569d1c9e7c7737e183969593394133d9 (patch)
tree8ce1722f852f8921656080e04f6c9e16fa71ddb5 /spec/frontend/ide
parent546ddc3f6ac96fdf09934390a938bb391d07dc94 (diff)
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/ide')
-rw-r--r--spec/frontend/ide/components/commit_sidebar/actions_spec.js141
-rw-r--r--spec/frontend/ide/components/commit_sidebar/empty_state_spec.js29
-rw-r--r--spec/frontend/ide/components/commit_sidebar/form_spec.js196
-rw-r--r--spec/frontend/ide/components/commit_sidebar/list_collapsed_spec.js72
-rw-r--r--spec/frontend/ide/components/commit_sidebar/list_item_spec.js144
-rw-r--r--spec/frontend/ide/components/commit_sidebar/list_spec.js54
-rw-r--r--spec/frontend/ide/components/commit_sidebar/new_merge_request_option_spec.js210
-rw-r--r--spec/frontend/ide/components/commit_sidebar/success_message_spec.js35
8 files changed, 881 insertions, 0 deletions
diff --git a/spec/frontend/ide/components/commit_sidebar/actions_spec.js b/spec/frontend/ide/components/commit_sidebar/actions_spec.js
new file mode 100644
index 00000000000..b3b98a64891
--- /dev/null
+++ b/spec/frontend/ide/components/commit_sidebar/actions_spec.js
@@ -0,0 +1,141 @@
+import Vue from 'vue';
+import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
+import { projectData, branches } from 'jest/ide/mock_data';
+import { createStore } from '~/ide/stores';
+import commitActions from '~/ide/components/commit_sidebar/actions.vue';
+import consts from '~/ide/stores/modules/commit/constants';
+
+const ACTION_UPDATE_COMMIT_ACTION = 'commit/updateCommitAction';
+
+const BRANCH_DEFAULT = 'master';
+const BRANCH_PROTECTED = 'protected/access';
+const BRANCH_PROTECTED_NO_ACCESS = 'protected/no-access';
+const BRANCH_REGULAR = 'regular';
+const BRANCH_REGULAR_NO_ACCESS = 'regular/no-access';
+
+describe('IDE commit sidebar actions', () => {
+ let store;
+ let vm;
+
+ const createComponent = ({ hasMR = false, currentBranchId = 'master' } = {}) => {
+ const Component = Vue.extend(commitActions);
+
+ vm = createComponentWithStore(Component, store);
+
+ vm.$store.state.currentBranchId = currentBranchId;
+ vm.$store.state.currentProjectId = 'abcproject';
+
+ const proj = { ...projectData };
+ proj.branches[currentBranchId] = branches.find(branch => branch.name === currentBranchId);
+
+ Vue.set(vm.$store.state.projects, 'abcproject', proj);
+
+ if (hasMR) {
+ vm.$store.state.currentMergeRequestId = '1';
+ vm.$store.state.projects[store.state.currentProjectId].mergeRequests[
+ store.state.currentMergeRequestId
+ ] = { foo: 'bar' };
+ }
+
+ vm.$mount();
+
+ return vm;
+ };
+
+ beforeEach(() => {
+ store = createStore();
+ jest.spyOn(store, 'dispatch').mockImplementation(() => {});
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ vm = null;
+ });
+
+ it('renders 2 groups', () => {
+ createComponent();
+
+ expect(vm.$el.querySelectorAll('input[type="radio"]').length).toBe(2);
+ });
+
+ it('renders current branch text', () => {
+ createComponent();
+
+ expect(vm.$el.textContent).toContain('Commit to master branch');
+ });
+
+ it('hides merge request option when project merge requests are disabled', done => {
+ createComponent({ mergeRequestsEnabled: false });
+
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelectorAll('input[type="radio"]').length).toBe(2);
+ expect(vm.$el.textContent).not.toContain('Create a new branch and merge request');
+
+ done();
+ });
+ });
+
+ describe('commitToCurrentBranchText', () => {
+ it('escapes current branch', () => {
+ const injectedSrc = '<img src="x" />';
+ createComponent({ currentBranchId: injectedSrc });
+
+ expect(vm.commitToCurrentBranchText).not.toContain(injectedSrc);
+ });
+ });
+
+ describe('updateSelectedCommitAction', () => {
+ it('does not return anything if currentBranch does not exist', () => {
+ createComponent({ currentBranchId: null });
+
+ expect(vm.$store.dispatch).not.toHaveBeenCalled();
+ });
+
+ it('is not called on mount if there is already a selected commitAction', () => {
+ store.state.commitAction = '1';
+ createComponent({ currentBranchId: null });
+
+ expect(vm.$store.dispatch).not.toHaveBeenCalled();
+ });
+
+ it('calls again after staged changes', done => {
+ createComponent({ currentBranchId: null });
+
+ vm.$store.state.currentBranchId = 'master';
+ vm.$store.state.changedFiles.push({});
+ vm.$store.state.stagedFiles.push({});
+
+ vm.$nextTick()
+ .then(() => {
+ expect(vm.$store.dispatch).toHaveBeenCalledWith(
+ ACTION_UPDATE_COMMIT_ACTION,
+ expect.anything(),
+ );
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it.each`
+ input | expectedOption
+ ${{ currentBranchId: BRANCH_DEFAULT }} | ${consts.COMMIT_TO_NEW_BRANCH}
+ ${{ currentBranchId: BRANCH_PROTECTED, hasMR: true }} | ${consts.COMMIT_TO_CURRENT_BRANCH}
+ ${{ currentBranchId: BRANCH_PROTECTED, hasMR: false }} | ${consts.COMMIT_TO_CURRENT_BRANCH}
+ ${{ currentBranchId: BRANCH_PROTECTED_NO_ACCESS, hasMR: true }} | ${consts.COMMIT_TO_NEW_BRANCH}
+ ${{ currentBranchId: BRANCH_PROTECTED_NO_ACCESS, hasMR: false }} | ${consts.COMMIT_TO_NEW_BRANCH}
+ ${{ currentBranchId: BRANCH_REGULAR, hasMR: true }} | ${consts.COMMIT_TO_CURRENT_BRANCH}
+ ${{ currentBranchId: BRANCH_REGULAR, hasMR: false }} | ${consts.COMMIT_TO_CURRENT_BRANCH}
+ ${{ currentBranchId: BRANCH_REGULAR_NO_ACCESS, hasMR: true }} | ${consts.COMMIT_TO_NEW_BRANCH}
+ ${{ currentBranchId: BRANCH_REGULAR_NO_ACCESS, hasMR: false }} | ${consts.COMMIT_TO_NEW_BRANCH}
+ `(
+ 'with $input, it dispatches update commit action with $expectedOption',
+ ({ input, expectedOption }) => {
+ createComponent(input);
+
+ expect(vm.$store.dispatch.mock.calls).toEqual([
+ [ACTION_UPDATE_COMMIT_ACTION, expectedOption],
+ ]);
+ },
+ );
+ });
+});
diff --git a/spec/frontend/ide/components/commit_sidebar/empty_state_spec.js b/spec/frontend/ide/components/commit_sidebar/empty_state_spec.js
new file mode 100644
index 00000000000..16d0b354a30
--- /dev/null
+++ b/spec/frontend/ide/components/commit_sidebar/empty_state_spec.js
@@ -0,0 +1,29 @@
+import Vue from 'vue';
+import store from '~/ide/stores';
+import emptyState from '~/ide/components/commit_sidebar/empty_state.vue';
+import { createComponentWithStore } from '../../../helpers/vue_mount_component_helper';
+import { resetStore } from '../../helpers';
+
+describe('IDE commit panel empty state', () => {
+ let vm;
+
+ beforeEach(() => {
+ const Component = Vue.extend(emptyState);
+
+ Vue.set(store.state, 'noChangesStateSvgPath', 'no-changes');
+
+ vm = createComponentWithStore(Component, store);
+
+ vm.$mount();
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+
+ resetStore(vm.$store);
+ });
+
+ it('renders no changes text when last commit message is empty', () => {
+ expect(vm.$el.textContent).toContain('No changes');
+ });
+});
diff --git a/spec/frontend/ide/components/commit_sidebar/form_spec.js b/spec/frontend/ide/components/commit_sidebar/form_spec.js
new file mode 100644
index 00000000000..dfde69ab2df
--- /dev/null
+++ b/spec/frontend/ide/components/commit_sidebar/form_spec.js
@@ -0,0 +1,196 @@
+import Vue from 'vue';
+import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
+import waitForPromises from 'helpers/wait_for_promises';
+import { projectData } from 'jest/ide/mock_data';
+import store from '~/ide/stores';
+import CommitForm from '~/ide/components/commit_sidebar/form.vue';
+import { leftSidebarViews } from '~/ide/constants';
+import { resetStore } from '../../helpers';
+
+describe('IDE commit form', () => {
+ const Component = Vue.extend(CommitForm);
+ let vm;
+
+ beforeEach(() => {
+ store.state.changedFiles.push('test');
+ store.state.currentProjectId = 'abcproject';
+ store.state.currentBranchId = 'master';
+ Vue.set(store.state.projects, 'abcproject', { ...projectData });
+
+ vm = createComponentWithStore(Component, store).$mount();
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+
+ resetStore(vm.$store);
+ });
+
+ it('enables button when has changes', () => {
+ expect(vm.$el.querySelector('[disabled]')).toBe(null);
+ });
+
+ describe('compact', () => {
+ beforeEach(done => {
+ vm.isCompact = true;
+
+ vm.$nextTick(done);
+ });
+
+ it('renders commit button in compact mode', () => {
+ expect(vm.$el.querySelector('.btn-primary')).not.toBeNull();
+ expect(vm.$el.querySelector('.btn-primary').textContent).toContain('Commit');
+ });
+
+ it('does not render form', () => {
+ expect(vm.$el.querySelector('form')).toBeNull();
+ });
+
+ it('renders overview text', done => {
+ vm.$store.state.stagedFiles.push('test');
+
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelector('p').textContent).toContain('1 changed file');
+ done();
+ });
+ });
+
+ it('shows form when clicking commit button', done => {
+ vm.$el.querySelector('.btn-primary').click();
+
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelector('form')).not.toBeNull();
+
+ done();
+ });
+ });
+
+ it('toggles activity bar view when clicking commit button', done => {
+ vm.$el.querySelector('.btn-primary').click();
+
+ vm.$nextTick(() => {
+ expect(store.state.currentActivityView).toBe(leftSidebarViews.commit.name);
+
+ done();
+ });
+ });
+
+ it('collapses if lastCommitMsg is set to empty and current view is not commit view', done => {
+ store.state.lastCommitMsg = 'abc';
+ store.state.currentActivityView = leftSidebarViews.edit.name;
+
+ vm.$nextTick(() => {
+ // if commit message is set, form is uncollapsed
+ expect(vm.isCompact).toBe(false);
+
+ store.state.lastCommitMsg = '';
+
+ vm.$nextTick(() => {
+ // collapsed when set to empty
+ expect(vm.isCompact).toBe(true);
+
+ done();
+ });
+ });
+ });
+ });
+
+ describe('full', () => {
+ beforeEach(done => {
+ vm.isCompact = false;
+
+ vm.$nextTick(done);
+ });
+
+ it('updates commitMessage in store on input', done => {
+ const textarea = vm.$el.querySelector('textarea');
+
+ textarea.value = 'testing commit message';
+
+ textarea.dispatchEvent(new Event('input'));
+
+ waitForPromises()
+ .then(() => {
+ expect(vm.$store.state.commit.commitMessage).toBe('testing commit message');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('updating currentActivityView not to commit view sets compact mode', done => {
+ store.state.currentActivityView = 'a';
+
+ vm.$nextTick(() => {
+ expect(vm.isCompact).toBe(true);
+
+ done();
+ });
+ });
+
+ it('always opens itself in full view current activity view is not commit view when clicking commit button', done => {
+ vm.$el.querySelector('.btn-primary').click();
+
+ vm.$nextTick(() => {
+ expect(store.state.currentActivityView).toBe(leftSidebarViews.commit.name);
+ expect(vm.isCompact).toBe(false);
+
+ done();
+ });
+ });
+
+ describe('discard draft button', () => {
+ it('hidden when commitMessage is empty', () => {
+ expect(vm.$el.querySelector('.btn-default').textContent).toContain('Collapse');
+ });
+
+ it('resets commitMessage when clicking discard button', done => {
+ vm.$store.state.commit.commitMessage = 'testing commit message';
+
+ waitForPromises()
+ .then(() => {
+ vm.$el.querySelector('.btn-default').click();
+ })
+ .then(Vue.nextTick)
+ .then(() => {
+ expect(vm.$store.state.commit.commitMessage).not.toBe('testing commit message');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ describe('when submitting', () => {
+ beforeEach(() => {
+ jest.spyOn(vm, 'commitChanges').mockImplementation(() => {});
+ vm.$store.state.stagedFiles.push('test');
+ });
+
+ it('calls commitChanges', done => {
+ vm.$store.state.commit.commitMessage = 'testing commit message';
+
+ waitForPromises()
+ .then(() => {
+ vm.$el.querySelector('.btn-success').click();
+ })
+ .then(Vue.nextTick)
+ .then(() => {
+ expect(vm.commitChanges).toHaveBeenCalled();
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+ });
+
+ describe('commitButtonText', () => {
+ it('returns commit text when staged files exist', () => {
+ vm.$store.state.stagedFiles.push('testing');
+
+ expect(vm.commitButtonText).toBe('Commit');
+ });
+
+ it('returns stage & commit text when staged files do not exist', () => {
+ expect(vm.commitButtonText).toBe('Stage & Commit');
+ });
+ });
+});
diff --git a/spec/frontend/ide/components/commit_sidebar/list_collapsed_spec.js b/spec/frontend/ide/components/commit_sidebar/list_collapsed_spec.js
new file mode 100644
index 00000000000..45372d18965
--- /dev/null
+++ b/spec/frontend/ide/components/commit_sidebar/list_collapsed_spec.js
@@ -0,0 +1,72 @@
+import Vue from 'vue';
+import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
+import store from '~/ide/stores';
+import listCollapsed from '~/ide/components/commit_sidebar/list_collapsed.vue';
+import { file } from '../../helpers';
+import { removeWhitespace } from '../../../helpers/text_helper';
+
+describe('Multi-file editor commit sidebar list collapsed', () => {
+ let vm;
+
+ beforeEach(() => {
+ const Component = Vue.extend(listCollapsed);
+
+ vm = createComponentWithStore(Component, store, {
+ files: [
+ {
+ ...file('file1'),
+ tempFile: true,
+ },
+ file('file2'),
+ ],
+ iconName: 'staged',
+ title: 'Staged',
+ });
+
+ vm.$mount();
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ it('renders added & modified files count', () => {
+ expect(removeWhitespace(vm.$el.textContent).trim()).toBe('1 1');
+ });
+
+ describe('addedFilesLength', () => {
+ it('returns an length of temp files', () => {
+ expect(vm.addedFilesLength).toBe(1);
+ });
+ });
+
+ describe('modifiedFilesLength', () => {
+ it('returns an length of modified files', () => {
+ expect(vm.modifiedFilesLength).toBe(1);
+ });
+ });
+
+ describe('addedFilesIconClass', () => {
+ it('includes multi-file-addition when addedFiles is not empty', () => {
+ expect(vm.addedFilesIconClass).toContain('multi-file-addition');
+ });
+
+ it('excludes multi-file-addition when addedFiles is empty', () => {
+ vm.files = [];
+
+ expect(vm.addedFilesIconClass).not.toContain('multi-file-addition');
+ });
+ });
+
+ describe('modifiedFilesClass', () => {
+ it('includes multi-file-modified when addedFiles is not empty', () => {
+ expect(vm.modifiedFilesClass).toContain('multi-file-modified');
+ });
+
+ it('excludes multi-file-modified when addedFiles is empty', () => {
+ vm.files = [];
+
+ expect(vm.modifiedFilesClass).not.toContain('multi-file-modified');
+ });
+ });
+});
diff --git a/spec/frontend/ide/components/commit_sidebar/list_item_spec.js b/spec/frontend/ide/components/commit_sidebar/list_item_spec.js
new file mode 100644
index 00000000000..ebb41448905
--- /dev/null
+++ b/spec/frontend/ide/components/commit_sidebar/list_item_spec.js
@@ -0,0 +1,144 @@
+import Vue from 'vue';
+import { trimText } from 'helpers/text_helper';
+import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
+import store from '~/ide/stores';
+import listItem from '~/ide/components/commit_sidebar/list_item.vue';
+import router from '~/ide/ide_router';
+import { file, resetStore } from '../../helpers';
+
+describe('Multi-file editor commit sidebar list item', () => {
+ let vm;
+ let f;
+ let findPathEl;
+
+ beforeEach(() => {
+ const Component = Vue.extend(listItem);
+
+ f = file('test-file');
+
+ store.state.entries[f.path] = f;
+
+ vm = createComponentWithStore(Component, store, {
+ file: f,
+ activeFileKey: `staged-${f.key}`,
+ }).$mount();
+
+ findPathEl = vm.$el.querySelector('.multi-file-commit-list-path');
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+
+ resetStore(store);
+ });
+
+ const findPathText = () => trimText(findPathEl.textContent);
+
+ it('renders file path', () => {
+ expect(findPathText()).toContain(f.path);
+ });
+
+ it('correctly renders renamed entries', done => {
+ Vue.set(vm.file, 'prevName', 'Old name');
+
+ vm.$nextTick()
+ .then(() => {
+ expect(findPathText()).toEqual(`Old name → ${f.name}`);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('correctly renders entry, the name of which did not change after rename (as within a folder)', done => {
+ Vue.set(vm.file, 'prevName', f.name);
+
+ vm.$nextTick()
+ .then(() => {
+ expect(findPathText()).toEqual(f.name);
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('opens a closed file in the editor when clicking the file path', done => {
+ jest.spyOn(vm, 'openPendingTab');
+ jest.spyOn(router, 'push').mockImplementation(() => {});
+
+ findPathEl.click();
+
+ setImmediate(() => {
+ expect(vm.openPendingTab).toHaveBeenCalled();
+ expect(router.push).toHaveBeenCalled();
+
+ done();
+ });
+ });
+
+ it('calls updateViewer with diff when clicking file', done => {
+ jest.spyOn(vm, 'openFileInEditor');
+ jest.spyOn(vm, 'updateViewer');
+ jest.spyOn(router, 'push').mockImplementation(() => {});
+
+ findPathEl.click();
+
+ setImmediate(() => {
+ expect(vm.updateViewer).toHaveBeenCalledWith('diff');
+
+ done();
+ });
+ });
+
+ describe('computed', () => {
+ describe('iconName', () => {
+ it('returns modified when not a tempFile', () => {
+ expect(vm.iconName).toBe('file-modified');
+ });
+
+ it('returns addition when not a tempFile', () => {
+ f.tempFile = true;
+
+ expect(vm.iconName).toBe('file-addition');
+ });
+
+ it('returns deletion', () => {
+ f.deleted = true;
+
+ expect(vm.iconName).toBe('file-deletion');
+ });
+ });
+
+ describe('iconClass', () => {
+ it('returns modified when not a tempFile', () => {
+ expect(vm.iconClass).toContain('ide-file-modified');
+ });
+
+ it('returns addition when not a tempFile', () => {
+ f.tempFile = true;
+
+ expect(vm.iconClass).toContain('ide-file-addition');
+ });
+
+ it('returns deletion', () => {
+ f.deleted = true;
+
+ expect(vm.iconClass).toContain('ide-file-deletion');
+ });
+ });
+ });
+
+ describe('is active', () => {
+ it('does not add active class when dont keys match', () => {
+ expect(vm.$el.querySelector('.is-active')).toBe(null);
+ });
+
+ it('adds active class when keys match', done => {
+ vm.keyPrefix = 'staged';
+
+ vm.$nextTick(() => {
+ expect(vm.$el.querySelector('.is-active')).not.toBe(null);
+
+ done();
+ });
+ });
+ });
+});
diff --git a/spec/frontend/ide/components/commit_sidebar/list_spec.js b/spec/frontend/ide/components/commit_sidebar/list_spec.js
new file mode 100644
index 00000000000..ee209487665
--- /dev/null
+++ b/spec/frontend/ide/components/commit_sidebar/list_spec.js
@@ -0,0 +1,54 @@
+import Vue from 'vue';
+import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
+import store from '~/ide/stores';
+import commitSidebarList from '~/ide/components/commit_sidebar/list.vue';
+import { file, resetStore } from '../../helpers';
+
+describe('Multi-file editor commit sidebar list', () => {
+ let vm;
+
+ beforeEach(() => {
+ const Component = Vue.extend(commitSidebarList);
+
+ vm = createComponentWithStore(Component, store, {
+ title: 'Staged',
+ fileList: [],
+ iconName: 'staged',
+ action: 'stageAllChanges',
+ actionBtnText: 'stage all',
+ actionBtnIcon: 'history',
+ activeFileKey: 'staged-testing',
+ keyPrefix: 'staged',
+ });
+
+ vm.$store.state.rightPanelCollapsed = false;
+
+ vm.$mount();
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+
+ resetStore(vm.$store);
+ });
+
+ describe('with a list of files', () => {
+ beforeEach(done => {
+ const f = file('file name');
+ f.changed = true;
+ vm.fileList.push(f);
+
+ Vue.nextTick(done);
+ });
+
+ it('renders list', () => {
+ expect(vm.$el.querySelectorAll('.multi-file-commit-list > li').length).toBe(1);
+ });
+ });
+
+ describe('empty files array', () => {
+ it('renders no changes text when empty', () => {
+ expect(vm.$el.textContent).toContain('No changes');
+ });
+ });
+});
diff --git a/spec/frontend/ide/components/commit_sidebar/new_merge_request_option_spec.js b/spec/frontend/ide/components/commit_sidebar/new_merge_request_option_spec.js
new file mode 100644
index 00000000000..7cbf5ebc61a
--- /dev/null
+++ b/spec/frontend/ide/components/commit_sidebar/new_merge_request_option_spec.js
@@ -0,0 +1,210 @@
+import Vue from 'vue';
+import { createComponentWithStore } from 'helpers/vue_mount_component_helper';
+import { projectData, branches } from 'jest/ide/mock_data';
+import NewMergeRequestOption from '~/ide/components/commit_sidebar/new_merge_request_option.vue';
+import { createStore } from '~/ide/stores';
+import { PERMISSION_CREATE_MR } from '~/ide/constants';
+import consts from '~/ide/stores/modules/commit/constants';
+
+describe('create new MR checkbox', () => {
+ let store;
+ let vm;
+
+ const setMR = () => {
+ vm.$store.state.currentMergeRequestId = '1';
+ vm.$store.state.projects[store.state.currentProjectId].mergeRequests[
+ store.state.currentMergeRequestId
+ ] = { foo: 'bar' };
+ };
+
+ const setPermissions = permissions => {
+ store.state.projects[store.state.currentProjectId].userPermissions = permissions;
+ };
+
+ const createComponent = ({ currentBranchId = 'master', createNewBranch = false } = {}) => {
+ const Component = Vue.extend(NewMergeRequestOption);
+
+ vm = createComponentWithStore(Component, store);
+
+ vm.$store.state.commit.commitAction = createNewBranch
+ ? consts.COMMIT_TO_NEW_BRANCH
+ : consts.COMMIT_TO_CURRENT_BRANCH;
+
+ vm.$store.state.currentBranchId = currentBranchId;
+
+ store.state.projects.abcproject.branches[currentBranchId] = branches.find(
+ branch => branch.name === currentBranchId,
+ );
+
+ return vm.$mount();
+ };
+
+ const findInput = () => vm.$el.querySelector('input[type="checkbox"]');
+ const findLabel = () => vm.$el.querySelector('.js-ide-commit-new-mr');
+
+ beforeEach(() => {
+ store = createStore();
+
+ store.state.currentProjectId = 'abcproject';
+
+ const proj = JSON.parse(JSON.stringify(projectData));
+ proj.userPermissions[PERMISSION_CREATE_MR] = true;
+ Vue.set(store.state.projects, 'abcproject', proj);
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+ });
+
+ describe('for default branch', () => {
+ describe('is rendered when pushing to a new branch', () => {
+ beforeEach(() => {
+ createComponent({
+ currentBranchId: 'master',
+ createNewBranch: true,
+ });
+ });
+
+ it('has NO new MR', () => {
+ expect(vm.$el.textContent).not.toBe('');
+ });
+
+ it('has new MR', done => {
+ setMR();
+
+ vm.$nextTick()
+ .then(() => {
+ expect(vm.$el.textContent).not.toBe('');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ describe('is NOT rendered when pushing to the same branch', () => {
+ beforeEach(() => {
+ createComponent({
+ currentBranchId: 'master',
+ createNewBranch: false,
+ });
+ });
+
+ it('has NO new MR', () => {
+ expect(vm.$el.textContent).toBe('');
+ });
+
+ it('has new MR', done => {
+ setMR();
+
+ vm.$nextTick()
+ .then(() => {
+ expect(vm.$el.textContent).toBe('');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+ });
+
+ describe('for protected branch', () => {
+ describe('when user does not have the write access', () => {
+ beforeEach(() => {
+ createComponent({
+ currentBranchId: 'protected/no-access',
+ });
+ });
+
+ it('is rendered if MR does not exists', () => {
+ expect(vm.$el.textContent).not.toBe('');
+ });
+
+ it('is rendered if MR exists', done => {
+ setMR();
+
+ vm.$nextTick()
+ .then(() => {
+ expect(vm.$el.textContent).not.toBe('');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+
+ describe('when user has the write access', () => {
+ beforeEach(() => {
+ createComponent({
+ currentBranchId: 'protected/access',
+ });
+ });
+
+ it('is rendered if MR does not exist', () => {
+ expect(vm.$el.textContent).not.toBe('');
+ });
+
+ it('is hidden if MR exists', done => {
+ setMR();
+
+ vm.$nextTick()
+ .then(() => {
+ expect(vm.$el.textContent).toBe('');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+ });
+ });
+
+ describe('for regular branch', () => {
+ beforeEach(() => {
+ createComponent({
+ currentBranchId: 'regular',
+ });
+ });
+
+ it('is rendered if no MR exists', () => {
+ expect(vm.$el.textContent).not.toBe('');
+ });
+
+ it('is hidden if MR exists', done => {
+ setMR();
+
+ vm.$nextTick()
+ .then(() => {
+ expect(vm.$el.textContent).toBe('');
+ })
+ .then(done)
+ .catch(done.fail);
+ });
+
+ it('shows enablded checkbox', () => {
+ expect(findLabel().classList.contains('is-disabled')).toBe(false);
+ expect(findInput().disabled).toBe(false);
+ });
+ });
+
+ describe('when user cannot create MR', () => {
+ beforeEach(() => {
+ setPermissions({ [PERMISSION_CREATE_MR]: false });
+
+ createComponent({ currentBranchId: 'regular' });
+ });
+
+ it('disabled checkbox', () => {
+ expect(findLabel().classList.contains('is-disabled')).toBe(true);
+ expect(findInput().disabled).toBe(true);
+ });
+ });
+
+ it('dispatches toggleShouldCreateMR when clicking checkbox', () => {
+ createComponent({
+ currentBranchId: 'regular',
+ });
+ const el = vm.$el.querySelector('input[type="checkbox"]');
+ jest.spyOn(vm.$store, 'dispatch').mockImplementation(() => {});
+ el.dispatchEvent(new Event('change'));
+
+ expect(vm.$store.dispatch.mock.calls).toEqual(
+ expect.arrayContaining([['commit/toggleShouldCreateMR', expect.any(Object)]]),
+ );
+ });
+});
diff --git a/spec/frontend/ide/components/commit_sidebar/success_message_spec.js b/spec/frontend/ide/components/commit_sidebar/success_message_spec.js
new file mode 100644
index 00000000000..e1a432b81be
--- /dev/null
+++ b/spec/frontend/ide/components/commit_sidebar/success_message_spec.js
@@ -0,0 +1,35 @@
+import Vue from 'vue';
+import store from '~/ide/stores';
+import successMessage from '~/ide/components/commit_sidebar/success_message.vue';
+import { createComponentWithStore } from '../../../helpers/vue_mount_component_helper';
+import { resetStore } from '../../helpers';
+
+describe('IDE commit panel successful commit state', () => {
+ let vm;
+
+ beforeEach(() => {
+ const Component = Vue.extend(successMessage);
+
+ vm = createComponentWithStore(Component, store, {
+ committedStateSvgPath: 'committed-state',
+ });
+
+ vm.$mount();
+ });
+
+ afterEach(() => {
+ vm.$destroy();
+
+ resetStore(vm.$store);
+ });
+
+ it('renders last commit message when it exists', done => {
+ vm.$store.state.lastCommitMsg = 'testing commit message';
+
+ Vue.nextTick(() => {
+ expect(vm.$el.textContent).toContain('testing commit message');
+
+ done();
+ });
+ });
+});