summaryrefslogtreecommitdiff
path: root/spec/frontend/add_context_commits_modal
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/add_context_commits_modal')
-rw-r--r--spec/frontend/add_context_commits_modal/components/__snapshots__/add_context_commits_modal_spec.js.snap50
-rw-r--r--spec/frontend/add_context_commits_modal/components/add_context_commits_modal_spec.js174
-rw-r--r--spec/frontend/add_context_commits_modal/components/review_tab_container_spec.js51
-rw-r--r--spec/frontend/add_context_commits_modal/store/actions_spec.js239
-rw-r--r--spec/frontend/add_context_commits_modal/store/mutations_spec.js156
5 files changed, 670 insertions, 0 deletions
diff --git a/spec/frontend/add_context_commits_modal/components/__snapshots__/add_context_commits_modal_spec.js.snap b/spec/frontend/add_context_commits_modal/components/__snapshots__/add_context_commits_modal_spec.js.snap
new file mode 100644
index 00000000000..5fad0d07f97
--- /dev/null
+++ b/spec/frontend/add_context_commits_modal/components/__snapshots__/add_context_commits_modal_spec.js.snap
@@ -0,0 +1,50 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AddContextCommitsModal renders modal with 2 tabs 1`] = `
+<gl-modal-stub
+ body-class="add-review-item pt-0"
+ cancel-variant="light"
+ modalclass=""
+ modalid="add-review-item"
+ ok-disabled="true"
+ ok-title="Save changes"
+ scrollable="true"
+ size="md"
+ title="Add or remove previously merged commits"
+ titletag="h4"
+>
+ <gl-tabs-stub
+ contentclass="pt-0"
+ theme="indigo"
+ value="0"
+ >
+ <gl-tab-stub>
+
+ <div
+ class="mt-2"
+ >
+ <gl-search-box-by-type-stub
+ clearbuttontitle="Clear"
+ placeholder="Search by commit title or SHA"
+ value=""
+ />
+
+ <review-tab-container-stub
+ commits=""
+ emptylisttext="Your search didn't match any commits. Try a different query."
+ loadingfailedtext="Unable to load commits. Try again later."
+ />
+ </div>
+ </gl-tab-stub>
+
+ <gl-tab-stub>
+
+ <review-tab-container-stub
+ commits=""
+ emptylisttext="Commits you select appear here. Go to the first tab and select commits to add to this merge request."
+ loadingfailedtext="Unable to load commits. Try again later."
+ />
+ </gl-tab-stub>
+ </gl-tabs-stub>
+</gl-modal-stub>
+`;
diff --git a/spec/frontend/add_context_commits_modal/components/add_context_commits_modal_spec.js b/spec/frontend/add_context_commits_modal/components/add_context_commits_modal_spec.js
new file mode 100644
index 00000000000..6904e34db5d
--- /dev/null
+++ b/spec/frontend/add_context_commits_modal/components/add_context_commits_modal_spec.js
@@ -0,0 +1,174 @@
+import { shallowMount, createLocalVue } from '@vue/test-utils';
+import Vuex from 'vuex';
+import { GlModal, GlSearchBoxByType } from '@gitlab/ui';
+import AddReviewItemsModal from '~/add_context_commits_modal/components/add_context_commits_modal_wrapper.vue';
+import getDiffWithCommit from '../../diffs/mock_data/diff_with_commit';
+
+import defaultState from '~/add_context_commits_modal/store/state';
+import mutations from '~/add_context_commits_modal/store/mutations';
+import * as actions from '~/add_context_commits_modal/store/actions';
+
+const localVue = createLocalVue();
+localVue.use(Vuex);
+
+describe('AddContextCommitsModal', () => {
+ let wrapper;
+ let store;
+ const createContextCommits = jest.fn();
+ const removeContextCommits = jest.fn();
+ const resetModalState = jest.fn();
+ const searchCommits = jest.fn();
+ const { commit } = getDiffWithCommit();
+
+ const createWrapper = (props = {}) => {
+ store = new Vuex.Store({
+ mutations,
+ state: {
+ ...defaultState(),
+ },
+ actions: {
+ ...actions,
+ searchCommits,
+ createContextCommits,
+ removeContextCommits,
+ resetModalState,
+ },
+ });
+
+ wrapper = shallowMount(AddReviewItemsModal, {
+ localVue,
+ store,
+ propsData: {
+ contextCommitsPath: '',
+ targetBranch: 'master',
+ mergeRequestIid: 1,
+ projectId: 1,
+ ...props,
+ },
+ });
+ return wrapper;
+ };
+
+ const findModal = () => wrapper.find(GlModal);
+ const findSearch = () => wrapper.find(GlSearchBoxByType);
+
+ beforeEach(() => {
+ wrapper = createWrapper();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('renders modal with 2 tabs', () => {
+ expect(wrapper.element).toMatchSnapshot();
+ });
+
+ it('an ok button labeled "Save changes"', () => {
+ expect(findModal().attributes('ok-title')).toEqual('Save changes');
+ });
+
+ describe('when in first tab, renders a modal with', () => {
+ it('renders the search box component', () => {
+ expect(findSearch().exists()).toBe(true);
+ });
+
+ it('when user starts entering text in search box, it calls action "searchCommits" after waiting for 500s', () => {
+ const searchText = 'abcd';
+ findSearch().vm.$emit('input', searchText);
+ expect(searchCommits).not.toBeCalled();
+ jest.advanceTimersByTime(500);
+ expect(searchCommits).toHaveBeenCalledWith(expect.anything(), searchText, undefined);
+ });
+
+ it('disabled ok button when no row is selected', () => {
+ expect(findModal().attributes('ok-disabled')).toBe('true');
+ });
+
+ it('enabled ok button when atleast one row is selected', () => {
+ wrapper.vm.$store.state.selectedCommits = [{ ...commit, isSelected: true }];
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findModal().attributes('ok-disabled')).toBeFalsy();
+ });
+ });
+ });
+
+ describe('when in second tab, renders a modal with', () => {
+ beforeEach(() => {
+ wrapper.vm.$store.state.tabIndex = 1;
+ });
+ it('a disabled ok button when no row is selected', () => {
+ expect(findModal().attributes('ok-disabled')).toBe('true');
+ });
+
+ it('an enabled ok button when atleast one row is selected', () => {
+ wrapper.vm.$store.state.selectedCommits = [{ ...commit, isSelected: true }];
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findModal().attributes('ok-disabled')).toBeFalsy();
+ });
+ });
+
+ it('a disabled ok button in first tab, when row is selected in second tab', () => {
+ createWrapper({ selectedContextCommits: [commit] });
+ expect(wrapper.find(GlModal).attributes('ok-disabled')).toBe('true');
+ });
+ });
+
+ describe('has an ok button when clicked calls action', () => {
+ it('"createContextCommits" when only new commits to be added ', () => {
+ wrapper.vm.$store.state.selectedCommits = [{ ...commit, isSelected: true }];
+ findModal().vm.$emit('ok');
+ return wrapper.vm.$nextTick().then(() => {
+ expect(createContextCommits).toHaveBeenCalledWith(
+ expect.anything(),
+ { commits: [{ ...commit, isSelected: true }], forceReload: true },
+ undefined,
+ );
+ });
+ });
+ it('"removeContextCommits" when only added commits are to be removed ', () => {
+ wrapper.vm.$store.state.toRemoveCommits = [commit.short_id];
+ findModal().vm.$emit('ok');
+ return wrapper.vm.$nextTick().then(() => {
+ expect(removeContextCommits).toHaveBeenCalledWith(expect.anything(), true, undefined);
+ });
+ });
+ it('"createContextCommits" and "removeContextCommits" when new commits are to be added and old commits are to be removed', () => {
+ wrapper.vm.$store.state.selectedCommits = [{ ...commit, isSelected: true }];
+ wrapper.vm.$store.state.toRemoveCommits = [commit.short_id];
+ findModal().vm.$emit('ok');
+ return wrapper.vm.$nextTick().then(() => {
+ expect(createContextCommits).toHaveBeenCalledWith(
+ expect.anything(),
+ { commits: [{ ...commit, isSelected: true }] },
+ undefined,
+ );
+ expect(removeContextCommits).toHaveBeenCalledWith(expect.anything(), undefined, undefined);
+ });
+ });
+ });
+
+ describe('has a cancel button when clicked', () => {
+ it('does not call "createContextCommits" or "removeContextCommits"', () => {
+ findModal().vm.$emit('cancel');
+ expect(createContextCommits).not.toHaveBeenCalled();
+ expect(removeContextCommits).not.toHaveBeenCalled();
+ });
+ it('"resetModalState" to reset all the modal state', () => {
+ findModal().vm.$emit('cancel');
+ expect(resetModalState).toHaveBeenCalledWith(expect.anything(), undefined, undefined);
+ });
+ });
+
+ describe('when model is closed by clicking the "X" button or by pressing "ESC" key', () => {
+ it('does not call "createContextCommits" or "removeContextCommits"', () => {
+ findModal().vm.$emit('close');
+ expect(createContextCommits).not.toHaveBeenCalled();
+ expect(removeContextCommits).not.toHaveBeenCalled();
+ });
+ it('"resetModalState" to reset all the modal state', () => {
+ findModal().vm.$emit('close');
+ expect(resetModalState).toHaveBeenCalledWith(expect.anything(), undefined, undefined);
+ });
+ });
+});
diff --git a/spec/frontend/add_context_commits_modal/components/review_tab_container_spec.js b/spec/frontend/add_context_commits_modal/components/review_tab_container_spec.js
new file mode 100644
index 00000000000..4e65713a680
--- /dev/null
+++ b/spec/frontend/add_context_commits_modal/components/review_tab_container_spec.js
@@ -0,0 +1,51 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlLoadingIcon } from '@gitlab/ui';
+import ReviewTabContainer from '~/add_context_commits_modal/components/review_tab_container.vue';
+import CommitItem from '~/diffs/components/commit_item.vue';
+import getDiffWithCommit from '../../diffs/mock_data/diff_with_commit';
+
+describe('ReviewTabContainer', () => {
+ let wrapper;
+ const { commit } = getDiffWithCommit();
+
+ const createWrapper = (props = {}) => {
+ wrapper = shallowMount(ReviewTabContainer, {
+ propsData: {
+ tab: 'commits',
+ isLoading: false,
+ loadingError: false,
+ loadingFailedText: 'Failed to load commits',
+ commits: [],
+ selectedRow: [],
+ ...props,
+ },
+ });
+ };
+
+ beforeEach(() => {
+ createWrapper();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ it('shows loading icon when commits are being loaded', () => {
+ createWrapper({ isLoading: true });
+ expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
+ });
+
+ it('shows loading error text when API call fails', () => {
+ createWrapper({ loadingError: true });
+ expect(wrapper.text()).toContain('Failed to load commits');
+ });
+
+ it('shows "No commits present here" when commits are not present', () => {
+ expect(wrapper.text()).toContain('No commits present here');
+ });
+
+ it('renders all passed commits as list', () => {
+ createWrapper({ commits: [commit] });
+ expect(wrapper.findAll(CommitItem).length).toBe(1);
+ });
+});
diff --git a/spec/frontend/add_context_commits_modal/store/actions_spec.js b/spec/frontend/add_context_commits_modal/store/actions_spec.js
new file mode 100644
index 00000000000..24948dd6073
--- /dev/null
+++ b/spec/frontend/add_context_commits_modal/store/actions_spec.js
@@ -0,0 +1,239 @@
+import MockAdapter from 'axios-mock-adapter';
+import { TEST_HOST } from 'helpers/test_constants';
+import axios from '~/lib/utils/axios_utils';
+import {
+ setBaseConfig,
+ setTabIndex,
+ setCommits,
+ createContextCommits,
+ fetchContextCommits,
+ setContextCommits,
+ removeContextCommits,
+ setSelectedCommits,
+ setSearchText,
+ setToRemoveCommits,
+ resetModalState,
+} from '~/add_context_commits_modal/store/actions';
+import * as types from '~/add_context_commits_modal/store/mutation_types';
+import testAction from '../../helpers/vuex_action_helper';
+
+describe('AddContextCommitsModalStoreActions', () => {
+ const contextCommitEndpoint =
+ '/api/v4/projects/gitlab-org%2fgitlab/merge_requests/1/context_commits';
+ const mergeRequestIid = 1;
+ const projectId = 1;
+ const projectPath = 'gitlab-org/gitlab';
+ const contextCommitsPath = `${TEST_HOST}/gitlab-org/gitlab/-/merge_requests/1/context_commits.json`;
+ const dummyCommit = {
+ id: 1,
+ title: 'dummy commit',
+ short_id: 'abcdef',
+ committed_date: '2020-06-12',
+ };
+ gon.api_version = 'v4';
+ let mock;
+
+ beforeEach(() => {
+ mock = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ describe('setBaseConfig', () => {
+ it('commits SET_BASE_CONFIG', done => {
+ const options = { contextCommitsPath, mergeRequestIid, projectId };
+ testAction(
+ setBaseConfig,
+ options,
+ {
+ contextCommitsPath: '',
+ mergeRequestIid,
+ projectId,
+ },
+ [
+ {
+ type: types.SET_BASE_CONFIG,
+ payload: options,
+ },
+ ],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('setTabIndex', () => {
+ it('commits SET_TABINDEX', done => {
+ testAction(
+ setTabIndex,
+ { tabIndex: 1 },
+ { tabIndex: 0 },
+ [{ type: types.SET_TABINDEX, payload: { tabIndex: 1 } }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('setCommits', () => {
+ it('commits SET_COMMITS', done => {
+ testAction(
+ setCommits,
+ { commits: [], silentAddition: false },
+ { isLoadingCommits: false, commits: [] },
+ [{ type: types.SET_COMMITS, payload: [] }],
+ [],
+ done,
+ );
+ });
+
+ it('commits SET_COMMITS_SILENT', done => {
+ testAction(
+ setCommits,
+ { commits: [], silentAddition: true },
+ { isLoadingCommits: true, commits: [] },
+ [{ type: types.SET_COMMITS_SILENT, payload: [] }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('createContextCommits', () => {
+ it('calls API to create context commits', done => {
+ mock.onPost(contextCommitEndpoint).reply(200, {});
+
+ testAction(createContextCommits, { commits: [] }, {}, [], [], done);
+
+ createContextCommits(
+ { state: { projectId, mergeRequestIid }, commit: () => null },
+ { commits: [] },
+ )
+ .then(() => {
+ done();
+ })
+ .catch(done.fail);
+ });
+ });
+
+ describe('fetchContextCommits', () => {
+ beforeEach(() => {
+ mock
+ .onGet(
+ `/api/${gon.api_version}/projects/gitlab-org%2Fgitlab/merge_requests/1/context_commits`,
+ )
+ .reply(200, [dummyCommit]);
+ });
+ it('commits FETCH_CONTEXT_COMMITS', done => {
+ const contextCommit = { ...dummyCommit, isSelected: true };
+ testAction(
+ fetchContextCommits,
+ null,
+ {
+ mergeRequestIid,
+ projectId: projectPath,
+ isLoadingContextCommits: false,
+ contextCommitsLoadingError: false,
+ commits: [],
+ },
+ [{ type: types.FETCH_CONTEXT_COMMITS }],
+ [
+ { type: 'setContextCommits', payload: [contextCommit] },
+ { type: 'setCommits', payload: { commits: [contextCommit], silentAddition: true } },
+ { type: 'setSelectedCommits', payload: [contextCommit] },
+ ],
+ done,
+ );
+ });
+ });
+
+ describe('setContextCommits', () => {
+ it('commits SET_CONTEXT_COMMITS', done => {
+ testAction(
+ setContextCommits,
+ { data: [] },
+ { contextCommits: [], isLoadingContextCommits: false },
+ [{ type: types.SET_CONTEXT_COMMITS, payload: { data: [] } }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('removeContextCommits', () => {
+ beforeEach(() => {
+ mock
+ .onDelete('/api/v4/projects/gitlab-org%2Fgitlab/merge_requests/1/context_commits')
+ .reply(204);
+ });
+ it('calls API to remove context commits', done => {
+ testAction(
+ removeContextCommits,
+ { forceReload: false },
+ { mergeRequestIid, projectId, toRemoveCommits: [] },
+ [],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('setSelectedCommits', () => {
+ it('commits SET_SELECTED_COMMITS', done => {
+ testAction(
+ setSelectedCommits,
+ [dummyCommit],
+ { selectedCommits: [] },
+ [{ type: types.SET_SELECTED_COMMITS, payload: [dummyCommit] }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('setSearchText', () => {
+ it('commits SET_SEARCH_TEXT', done => {
+ const searchText = 'Dummy Text';
+ testAction(
+ setSearchText,
+ searchText,
+ { searchText: '' },
+ [{ type: types.SET_SEARCH_TEXT, payload: searchText }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('setToRemoveCommits', () => {
+ it('commits SET_TO_REMOVE_COMMITS', done => {
+ const commitId = 'abcde';
+
+ testAction(
+ setToRemoveCommits,
+ [commitId],
+ { toRemoveCommits: [] },
+ [{ type: types.SET_TO_REMOVE_COMMITS, payload: [commitId] }],
+ [],
+ done,
+ );
+ });
+ });
+
+ describe('resetModalState', () => {
+ it('commits RESET_MODAL_STATE', done => {
+ const commitId = 'abcde';
+
+ testAction(
+ resetModalState,
+ null,
+ { toRemoveCommits: [commitId] },
+ [{ type: types.RESET_MODAL_STATE }],
+ [],
+ done,
+ );
+ });
+ });
+});
diff --git a/spec/frontend/add_context_commits_modal/store/mutations_spec.js b/spec/frontend/add_context_commits_modal/store/mutations_spec.js
new file mode 100644
index 00000000000..22f82570ab1
--- /dev/null
+++ b/spec/frontend/add_context_commits_modal/store/mutations_spec.js
@@ -0,0 +1,156 @@
+import { TEST_HOST } from 'helpers/test_constants';
+import mutations from '~/add_context_commits_modal/store/mutations';
+import * as types from '~/add_context_commits_modal/store/mutation_types';
+import getDiffWithCommit from '../../diffs/mock_data/diff_with_commit';
+
+describe('AddContextCommitsModalStoreMutations', () => {
+ const { commit } = getDiffWithCommit();
+ describe('SET_BASE_CONFIG', () => {
+ it('should set contextCommitsPath, mergeRequestIid and projectId', () => {
+ const state = {};
+ const contextCommitsPath = `${TEST_HOST}/gitlab-org/gitlab/-/merge_requests/1/context_commits.json`;
+ const mergeRequestIid = 1;
+ const projectId = 1;
+
+ mutations[types.SET_BASE_CONFIG](state, { contextCommitsPath, mergeRequestIid, projectId });
+
+ expect(state.contextCommitsPath).toEqual(contextCommitsPath);
+ expect(state.mergeRequestIid).toEqual(mergeRequestIid);
+ expect(state.projectId).toEqual(projectId);
+ });
+ });
+
+ describe('SET_TABINDEX', () => {
+ it('sets tabIndex to specific index', () => {
+ const state = { tabIndex: 0 };
+
+ mutations[types.SET_TABINDEX](state, 1);
+
+ expect(state.tabIndex).toBe(1);
+ });
+ });
+
+ describe('FETCH_COMMITS', () => {
+ it('sets isLoadingCommits to true', () => {
+ const state = { isLoadingCommits: false };
+
+ mutations[types.FETCH_COMMITS](state);
+
+ expect(state.isLoadingCommits).toBe(true);
+ });
+ });
+
+ describe('SET_COMMITS', () => {
+ it('sets commits to passed data and stop loading', () => {
+ const state = { commits: [], isLoadingCommits: true };
+
+ mutations[types.SET_COMMITS](state, [commit]);
+
+ expect(state.commits).toStrictEqual([commit]);
+ expect(state.isLoadingCommits).toBe(false);
+ });
+ });
+
+ describe('SET_COMMITS_SILENT', () => {
+ it('sets commits to passed data and loading continues', () => {
+ const state = { commits: [], isLoadingCommits: true };
+
+ mutations[types.SET_COMMITS_SILENT](state, [commit]);
+
+ expect(state.commits).toStrictEqual([commit]);
+ expect(state.isLoadingCommits).toBe(true);
+ });
+ });
+
+ describe('FETCH_COMMITS_ERROR', () => {
+ it('sets commitsLoadingError to true', () => {
+ const state = { commitsLoadingError: false };
+
+ mutations[types.FETCH_COMMITS_ERROR](state);
+
+ expect(state.commitsLoadingError).toBe(true);
+ });
+ });
+
+ describe('FETCH_CONTEXT_COMMITS', () => {
+ it('sets isLoadingContextCommits to true', () => {
+ const state = { isLoadingContextCommits: false };
+
+ mutations[types.FETCH_CONTEXT_COMMITS](state);
+
+ expect(state.isLoadingContextCommits).toBe(true);
+ });
+ });
+
+ describe('SET_CONTEXT_COMMITS', () => {
+ it('sets contextCommit to passed data and stop loading', () => {
+ const state = { contextCommits: [], isLoadingContextCommits: true };
+
+ mutations[types.SET_CONTEXT_COMMITS](state, [commit]);
+
+ expect(state.contextCommits).toStrictEqual([commit]);
+ expect(state.isLoadingContextCommits).toBe(false);
+ });
+ });
+
+ describe('FETCH_CONTEXT_COMMITS_ERROR', () => {
+ it('sets contextCommitsLoadingError to true', () => {
+ const state = { contextCommitsLoadingError: false };
+
+ mutations[types.FETCH_CONTEXT_COMMITS_ERROR](state);
+
+ expect(state.contextCommitsLoadingError).toBe(true);
+ });
+ });
+
+ describe('SET_SELECTED_COMMITS', () => {
+ it('sets selectedCommits to specified value', () => {
+ const state = { selectedCommits: [] };
+
+ mutations[types.SET_SELECTED_COMMITS](state, [commit]);
+
+ expect(state.selectedCommits).toStrictEqual([commit]);
+ });
+ });
+
+ describe('SET_SEARCH_TEXT', () => {
+ it('sets searchText to specified value', () => {
+ const searchText = 'Test';
+ const state = { searchText: '' };
+
+ mutations[types.SET_SEARCH_TEXT](state, searchText);
+
+ expect(state.searchText).toBe(searchText);
+ });
+ });
+
+ describe('SET_TO_REMOVE_COMMITS', () => {
+ it('sets searchText to specified value', () => {
+ const state = { toRemoveCommits: [] };
+
+ mutations[types.SET_TO_REMOVE_COMMITS](state, [commit.short_id]);
+
+ expect(state.toRemoveCommits).toStrictEqual([commit.short_id]);
+ });
+ });
+
+ describe('RESET_MODAL_STATE', () => {
+ it('sets searchText to specified value', () => {
+ const state = {
+ commits: [commit],
+ contextCommits: [commit],
+ selectedCommits: [commit],
+ toRemoveCommits: [commit.short_id],
+ searchText: 'Test',
+ };
+
+ mutations[types.RESET_MODAL_STATE](state);
+
+ expect(state.commits).toStrictEqual([]);
+ expect(state.contextCommits).toStrictEqual([]);
+ expect(state.selectedCommits).toStrictEqual([]);
+ expect(state.toRemoveCommits).toStrictEqual([]);
+ expect(state.searchText).toBe('');
+ });
+ });
+});