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:
Diffstat (limited to 'spec/frontend/projects/commit')
-rw-r--r--spec/frontend/projects/commit/components/branches_dropdown_spec.js166
-rw-r--r--spec/frontend/projects/commit/components/form_modal_spec.js155
-rw-r--r--spec/frontend/projects/commit/components/form_trigger_spec.js44
-rw-r--r--spec/frontend/projects/commit/mock_data.js27
-rw-r--r--spec/frontend/projects/commit/store/actions_spec.js111
-rw-r--r--spec/frontend/projects/commit/store/getters_spec.js21
-rw-r--r--spec/frontend/projects/commit/store/mutations_spec.js57
7 files changed, 581 insertions, 0 deletions
diff --git a/spec/frontend/projects/commit/components/branches_dropdown_spec.js b/spec/frontend/projects/commit/components/branches_dropdown_spec.js
new file mode 100644
index 00000000000..9fa7d658405
--- /dev/null
+++ b/spec/frontend/projects/commit/components/branches_dropdown_spec.js
@@ -0,0 +1,166 @@
+import Vue from 'vue';
+import Vuex from 'vuex';
+import { shallowMount } from '@vue/test-utils';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import { GlDropdownItem, GlSearchBoxByType } from '@gitlab/ui';
+import BranchesDropdown from '~/projects/commit/components/branches_dropdown.vue';
+
+Vue.use(Vuex);
+
+describe('BranchesDropdown', () => {
+ let wrapper;
+ let store;
+ const spyFetchBranches = jest.fn();
+
+ const createComponent = (term, state = { isFetching: false }) => {
+ store = new Vuex.Store({
+ getters: {
+ joinedBranches: () => ['_master_', '_branch_1_', '_branch_2_'],
+ },
+ actions: {
+ fetchBranches: spyFetchBranches,
+ },
+ state,
+ });
+
+ wrapper = extendedWrapper(
+ shallowMount(BranchesDropdown, {
+ store,
+ propsData: {
+ value: term,
+ },
+ }),
+ );
+ };
+
+ const findAllDropdownItems = () => wrapper.findAllComponents(GlDropdownItem);
+ const findSearchBoxByType = () => wrapper.findComponent(GlSearchBoxByType);
+ const findDropdownItemByIndex = (index) => wrapper.findAllComponents(GlDropdownItem).at(index);
+ const findNoResults = () => wrapper.findByTestId('empty-result-message');
+ const findLoading = () => wrapper.findByTestId('dropdown-text-loading-icon');
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ spyFetchBranches.mockReset();
+ });
+
+ describe('On mount', () => {
+ beforeEach(() => {
+ createComponent('');
+ });
+
+ it('invokes fetchBranches', () => {
+ expect(spyFetchBranches).toHaveBeenCalled();
+ });
+ });
+
+ describe('Loading states', () => {
+ it('shows loading icon while fetching', () => {
+ createComponent('', { isFetching: true });
+
+ expect(findLoading().isVisible()).toBe(true);
+ });
+
+ it('does not show loading icon', () => {
+ createComponent('');
+
+ expect(findLoading().isVisible()).toBe(false);
+ });
+ });
+
+ describe('No branches found', () => {
+ beforeEach(() => {
+ createComponent('_non_existent_branch_');
+ });
+
+ it('renders empty results message', () => {
+ expect(findNoResults().text()).toBe('No matching results');
+ });
+
+ it('shows GlSearchBoxByType with default attributes', () => {
+ expect(findSearchBoxByType().exists()).toBe(true);
+ expect(findSearchBoxByType().vm.$attrs).toMatchObject({
+ placeholder: 'Search branches',
+ debounce: 250,
+ });
+ });
+ });
+
+ describe('Search term is empty', () => {
+ beforeEach(() => {
+ createComponent('');
+ });
+
+ it('renders all branches when search term is empty', () => {
+ expect(findAllDropdownItems()).toHaveLength(3);
+ expect(findDropdownItemByIndex(0).text()).toBe('_master_');
+ expect(findDropdownItemByIndex(1).text()).toBe('_branch_1_');
+ expect(findDropdownItemByIndex(2).text()).toBe('_branch_2_');
+ });
+
+ it('should not be selected on the inactive branch', () => {
+ expect(wrapper.vm.isSelected('_master_')).toBe(false);
+ });
+ });
+
+ describe('When searching', () => {
+ beforeEach(() => {
+ createComponent('');
+ });
+
+ it('invokes fetchBranches', async () => {
+ const spy = jest.spyOn(wrapper.vm, 'fetchBranches');
+
+ findSearchBoxByType().vm.$emit('input', '_anything_');
+
+ await wrapper.vm.$nextTick();
+
+ expect(spy).toHaveBeenCalledWith('_anything_');
+ expect(wrapper.vm.searchTerm).toBe('_anything_');
+ });
+ });
+
+ describe('Branches found', () => {
+ beforeEach(() => {
+ createComponent('_branch_1_', { branch: '_branch_1_' });
+ });
+
+ it('renders only the branch searched for', () => {
+ expect(findAllDropdownItems()).toHaveLength(1);
+ expect(findDropdownItemByIndex(0).text()).toBe('_branch_1_');
+ });
+
+ it('should not display empty results message', () => {
+ expect(findNoResults().exists()).toBe(false);
+ });
+
+ it('should signify this branch is selected', () => {
+ expect(wrapper.vm.isSelected('_branch_1_')).toBe(true);
+ });
+
+ it('should signify the branch is not selected', () => {
+ expect(wrapper.vm.isSelected('_not_selected_branch_')).toBe(false);
+ });
+
+ describe('Custom events', () => {
+ it('should emit selectBranch if an branch is clicked', () => {
+ findDropdownItemByIndex(0).vm.$emit('click');
+
+ expect(wrapper.emitted('selectBranch')).toEqual([['_branch_1_']]);
+ expect(wrapper.vm.searchTerm).toBe('_branch_1_');
+ });
+ });
+ });
+
+ describe('Case insensitive for search term', () => {
+ beforeEach(() => {
+ createComponent('_BrAnCh_1_');
+ });
+
+ it('renders only the branch searched for', () => {
+ expect(findAllDropdownItems()).toHaveLength(1);
+ expect(findDropdownItemByIndex(0).text()).toBe('_branch_1_');
+ });
+ });
+});
diff --git a/spec/frontend/projects/commit/components/form_modal_spec.js b/spec/frontend/projects/commit/components/form_modal_spec.js
new file mode 100644
index 00000000000..1c37b82fed3
--- /dev/null
+++ b/spec/frontend/projects/commit/components/form_modal_spec.js
@@ -0,0 +1,155 @@
+import MockAdapter from 'axios-mock-adapter';
+import { shallowMount, mount, createWrapper } from '@vue/test-utils';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
+import { GlModal, GlForm, GlFormCheckbox, GlSprintf } from '@gitlab/ui';
+import { within } from '@testing-library/dom';
+import axios from '~/lib/utils/axios_utils';
+import eventHub from '~/projects/commit/event_hub';
+import CommitFormModal from '~/projects/commit/components/form_modal.vue';
+import BranchesDropdown from '~/projects/commit/components/branches_dropdown.vue';
+import createStore from '~/projects/commit/store';
+import mockData from '../mock_data';
+
+describe('CommitFormModal', () => {
+ let wrapper;
+ let store;
+ let axiosMock;
+
+ const createComponent = (method, state = {}, provide = {}) => {
+ store = createStore({ ...mockData.mockModal, ...state });
+ wrapper = extendedWrapper(
+ method(CommitFormModal, {
+ provide,
+ propsData: { ...mockData.modalPropsData },
+ store,
+ attrs: {
+ static: true,
+ visible: true,
+ },
+ }),
+ );
+ };
+
+ const findModal = () => wrapper.findComponent(GlModal);
+ const findStartBranch = () => wrapper.find('#start_branch');
+ const findDropdown = () => wrapper.findComponent(BranchesDropdown);
+ const findForm = () => findModal().findComponent(GlForm);
+ const findCheckBox = () => findForm().findComponent(GlFormCheckbox);
+ const findPrependedText = () => wrapper.findByTestId('prepended-text');
+ const findAppendedText = () => wrapper.findByTestId('appended-text');
+ const getByText = (text, options) =>
+ createWrapper(within(findModal().element).getByText(text, options));
+
+ beforeEach(() => {
+ axiosMock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ axiosMock.restore();
+ });
+
+ describe('Basic interactions', () => {
+ it('Listens for opening of modal on mount', () => {
+ jest.spyOn(eventHub, '$on');
+
+ createComponent(shallowMount);
+
+ expect(eventHub.$on).toHaveBeenCalledWith(mockData.modalPropsData.openModal, wrapper.vm.show);
+ });
+
+ it('Shows modal', () => {
+ createComponent(shallowMount);
+ const rootEmit = jest.spyOn(wrapper.vm.$root, '$emit');
+
+ wrapper.vm.show();
+
+ expect(rootEmit).toHaveBeenCalledWith('bv::show::modal', mockData.modalPropsData.modalId);
+ });
+
+ it('Clears the modal state once modal is hidden', () => {
+ createComponent(shallowMount);
+ jest.spyOn(store, 'dispatch').mockImplementation();
+ wrapper.vm.checked = false;
+
+ findModal().vm.$emit('hidden');
+
+ expect(store.dispatch).toHaveBeenCalledWith('clearModal');
+ expect(store.dispatch).toHaveBeenCalledWith('setSelectedBranch', '');
+ expect(wrapper.vm.checked).toBe(true);
+ });
+
+ it('Shows the checkbox for new merge request', () => {
+ createComponent(shallowMount);
+
+ expect(findCheckBox().exists()).toBe(true);
+ });
+
+ it('Shows the prepended text', () => {
+ createComponent(shallowMount, {}, { prependedText: '_prepended_text_' });
+
+ expect(findPrependedText().exists()).toBe(true);
+ expect(findPrependedText().find(GlSprintf).attributes('message')).toBe('_prepended_text_');
+ });
+
+ it('Does not show prepended text', () => {
+ createComponent(shallowMount);
+
+ expect(findPrependedText().exists()).toBe(false);
+ });
+
+ it('Does not show extra message text', () => {
+ createComponent(shallowMount);
+
+ expect(findModal().find('[data-testid="appended-text"]').exists()).toBe(false);
+ });
+
+ it('Does not show the checkbox for new merge request', () => {
+ createComponent(shallowMount, { pushCode: false });
+
+ expect(findCheckBox().exists()).toBe(false);
+ });
+
+ it('Shows the branch in fork message', () => {
+ createComponent(shallowMount, { pushCode: false });
+
+ expect(findAppendedText().exists()).toBe(true);
+ expect(findAppendedText().find(GlSprintf).attributes('message')).toContain(
+ mockData.modalPropsData.i18n.branchInFork,
+ );
+ });
+
+ it('Shows the branch collaboration message', () => {
+ createComponent(shallowMount, { pushCode: false, branchCollaboration: true });
+
+ expect(findAppendedText().exists()).toBe(true);
+ expect(findAppendedText().find(GlSprintf).attributes('message')).toContain(
+ mockData.modalPropsData.i18n.existingBranch,
+ );
+ });
+ });
+
+ describe('Taking action on the form', () => {
+ beforeEach(() => {
+ createComponent(mount);
+ });
+
+ it('Action primary button dispatches submit action', () => {
+ const submitSpy = jest.spyOn(findForm().element, 'submit');
+
+ getByText(mockData.modalPropsData.i18n.actionPrimaryText).trigger('click');
+
+ expect(submitSpy).toHaveBeenCalled();
+
+ submitSpy.mockRestore();
+ });
+
+ it('Changes the start_branch input value', async () => {
+ findDropdown().vm.$emit('selectBranch', '_changed_branch_value_');
+
+ await wrapper.vm.$nextTick();
+
+ expect(findStartBranch().attributes('value')).toBe('_changed_branch_value_');
+ });
+ });
+});
diff --git a/spec/frontend/projects/commit/components/form_trigger_spec.js b/spec/frontend/projects/commit/components/form_trigger_spec.js
new file mode 100644
index 00000000000..ca51419d6a5
--- /dev/null
+++ b/spec/frontend/projects/commit/components/form_trigger_spec.js
@@ -0,0 +1,44 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlLink } from '@gitlab/ui';
+import FormTrigger from '~/projects/commit/components/form_trigger.vue';
+import eventHub from '~/projects/commit/event_hub';
+
+const displayText = '_display_text_';
+
+const createComponent = () => {
+ return shallowMount(FormTrigger, {
+ provide: { displayText },
+ propsData: { openModal: '_open_modal_' },
+ });
+};
+
+describe('FormTrigger', () => {
+ let wrapper;
+ let spy;
+
+ beforeEach(() => {
+ spy = jest.spyOn(eventHub, '$emit');
+ wrapper = createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ wrapper = null;
+ });
+
+ const findLink = () => wrapper.find(GlLink);
+
+ describe('displayText', () => {
+ it('includes the correct displayText for the link', () => {
+ expect(findLink().text()).toBe(displayText);
+ });
+ });
+
+ describe('clicking the link', () => {
+ it('emits openModal', () => {
+ findLink().vm.$emit('click');
+
+ expect(spy).toHaveBeenCalledWith('_open_modal_');
+ });
+ });
+});
diff --git a/spec/frontend/projects/commit/mock_data.js b/spec/frontend/projects/commit/mock_data.js
new file mode 100644
index 00000000000..2b3b5a14c98
--- /dev/null
+++ b/spec/frontend/projects/commit/mock_data.js
@@ -0,0 +1,27 @@
+import { I18N_MODAL } from '~/projects/commit/constants';
+
+export default {
+ mockModal: {
+ modalTitle: '_modal_title_',
+ endpoint: '_endpoint_',
+ branch: '_branch_',
+ pushCode: true,
+ defaultBranch: '_branch_',
+ existingBranch: '_existing_branch',
+ branchesEndpoint: '_branches_endpoint_',
+ },
+ modalPropsData: {
+ i18n: {
+ branchLabel: '_branch_label_',
+ actionPrimaryText: '_action_primary_text_',
+ startMergeRequest: '_start_merge_request_',
+ existingBranch: I18N_MODAL.existingBranch,
+ branchInFork: '_new_branch_in_fork_message_',
+ newMergeRequest: '_new merge request_',
+ actionCancelText: '_action_cancel_text_',
+ },
+ modalId: '_modal_id_',
+ openModal: '_open_modal_',
+ },
+ mockBranches: ['_branch_1', '_abc_', '_master_'],
+};
diff --git a/spec/frontend/projects/commit/store/actions_spec.js b/spec/frontend/projects/commit/store/actions_spec.js
new file mode 100644
index 00000000000..ec528d4ee88
--- /dev/null
+++ b/spec/frontend/projects/commit/store/actions_spec.js
@@ -0,0 +1,111 @@
+import MockAdapter from 'axios-mock-adapter';
+import testAction from 'helpers/vuex_action_helper';
+import axios from '~/lib/utils/axios_utils';
+import createFlash from '~/flash';
+import getInitialState from '~/projects/commit/store/state';
+import * as actions from '~/projects/commit/store/actions';
+import * as types from '~/projects/commit/store/mutation_types';
+import mockData from '../mock_data';
+import { PROJECT_BRANCHES_ERROR } from '~/projects/commit/constants';
+
+jest.mock('~/flash.js');
+
+describe('Commit form modal store actions', () => {
+ let axiosMock;
+ let state;
+
+ beforeEach(() => {
+ axiosMock = new MockAdapter(axios);
+ state = getInitialState();
+ });
+
+ afterEach(() => {
+ axiosMock.restore();
+ });
+
+ describe('clearModal', () => {
+ it('commits CLEAR_MODAL mutation', () => {
+ testAction(actions.clearModal, {}, {}, [
+ {
+ type: types.CLEAR_MODAL,
+ },
+ ]);
+ });
+ });
+
+ describe('requestBranches', () => {
+ it('commits REQUEST_BRANCHES mutation', () => {
+ testAction(actions.requestBranches, {}, {}, [
+ {
+ type: types.REQUEST_BRANCHES,
+ },
+ ]);
+ });
+ });
+
+ describe('fetchBranches', () => {
+ it('dispatch correct actions on fetchBranches', (done) => {
+ jest
+ .spyOn(axios, 'get')
+ .mockImplementation(() => Promise.resolve({ data: mockData.mockBranches }));
+
+ testAction(
+ actions.fetchBranches,
+ {},
+ state,
+ [
+ {
+ type: types.RECEIVE_BRANCHES_SUCCESS,
+ payload: mockData.mockBranches,
+ },
+ ],
+ [{ type: 'requestBranches' }],
+ () => {
+ done();
+ },
+ );
+ });
+
+ it('should show flash error and set error in state on fetchBranches failure', (done) => {
+ jest.spyOn(axios, 'get').mockRejectedValue();
+
+ testAction(actions.fetchBranches, {}, state, [], [{ type: 'requestBranches' }], () => {
+ expect(createFlash).toHaveBeenCalledWith({ message: PROJECT_BRANCHES_ERROR });
+ done();
+ });
+ });
+ });
+
+ describe('setBranch', () => {
+ it('commits SET_BRANCH mutation', () => {
+ testAction(
+ actions.setBranch,
+ {},
+ {},
+ [
+ {
+ type: types.SET_BRANCH,
+ payload: {},
+ },
+ ],
+ [
+ {
+ type: 'setSelectedBranch',
+ payload: {},
+ },
+ ],
+ );
+ });
+ });
+
+ describe('setSelectedBranch', () => {
+ it('commits SET_SELECTED_BRANCH mutation', () => {
+ testAction(actions.setSelectedBranch, {}, {}, [
+ {
+ type: types.SET_SELECTED_BRANCH,
+ payload: {},
+ },
+ ]);
+ });
+ });
+});
diff --git a/spec/frontend/projects/commit/store/getters_spec.js b/spec/frontend/projects/commit/store/getters_spec.js
new file mode 100644
index 00000000000..bd0cb356854
--- /dev/null
+++ b/spec/frontend/projects/commit/store/getters_spec.js
@@ -0,0 +1,21 @@
+import * as getters from '~/projects/commit/store/getters';
+import mockData from '../mock_data';
+
+describe('Commit form modal getters', () => {
+ describe('joinedBranches', () => {
+ it('should join fetched branches with variable branches', () => {
+ const state = {
+ branches: mockData.mockBranches,
+ };
+
+ expect(getters.joinedBranches(state)).toEqual(mockData.mockBranches.sort());
+ });
+
+ it('should provide a uniq list of branches', () => {
+ const branches = ['_branch_', '_branch_', '_different_branch'];
+ const state = { branches };
+
+ expect(getters.joinedBranches(state)).toEqual(branches.slice(1));
+ });
+ });
+});
diff --git a/spec/frontend/projects/commit/store/mutations_spec.js b/spec/frontend/projects/commit/store/mutations_spec.js
new file mode 100644
index 00000000000..59ab3d9a74a
--- /dev/null
+++ b/spec/frontend/projects/commit/store/mutations_spec.js
@@ -0,0 +1,57 @@
+import mutations from '~/projects/commit/store/mutations';
+import * as types from '~/projects/commit/store/mutation_types';
+
+describe('Commit form modal mutations', () => {
+ let stateCopy;
+
+ describe('REQUEST_BRANCHES', () => {
+ it('should set isFetching to true', () => {
+ stateCopy = { isFetching: false };
+
+ mutations[types.REQUEST_BRANCHES](stateCopy);
+
+ expect(stateCopy.isFetching).toBe(true);
+ });
+ });
+
+ describe('RECEIVE_BRANCHES_SUCCESS', () => {
+ it('should set branches', () => {
+ stateCopy = { branch: '_existing_branch_', isFetching: true };
+
+ mutations[types.RECEIVE_BRANCHES_SUCCESS](stateCopy, ['_branch_1_', '_branch_2_']);
+
+ expect(stateCopy.branches).toEqual(['_existing_branch_', '_branch_1_', '_branch_2_']);
+ expect(stateCopy.isFetching).toEqual(false);
+ });
+ });
+
+ describe('CLEAR_MODAL', () => {
+ it('should clear modal state ', () => {
+ stateCopy = { branch: '_master_', defaultBranch: '_default_branch_' };
+
+ mutations[types.CLEAR_MODAL](stateCopy);
+
+ expect(stateCopy.branch).toEqual('_default_branch_');
+ });
+ });
+
+ describe('SET_BRANCH', () => {
+ it('should set branch', () => {
+ stateCopy = { branch: '_master_' };
+
+ mutations[types.SET_BRANCH](stateCopy, '_changed_branch_');
+
+ expect(stateCopy.branch).toBe('_changed_branch_');
+ });
+ });
+
+ describe('SET_SELECTED_BRANCH', () => {
+ it('should set selectedBranch', () => {
+ stateCopy = { selectedBranch: '_master_' };
+
+ mutations[types.SET_SELECTED_BRANCH](stateCopy, '_changed_branch_');
+
+ expect(stateCopy.selectedBranch).toBe('_changed_branch_');
+ });
+ });
+});