Commit 5a925f1e authored by Natalia Tepluhina's avatar Natalia Tepluhina

Merge branch 'nmezzopera-merge-conflict-vuex-store-tests' into 'master'

Add unit test for merge_conflicts new vuex store

See merge request gitlab-org/gitlab!56494
parents f0b10634 1cee41d9
...@@ -67,7 +67,7 @@ export const isReadyToCommit = (state) => { ...@@ -67,7 +67,7 @@ export const isReadyToCommit = (state) => {
} }
} }
return !state.isSubmitting && hasCommitMessage && !unresolved; return Boolean(!state.isSubmitting && hasCommitMessage && !unresolved);
}; };
export const getCommitButtonText = (state) => { export const getCommitButtonText = (state) => {
......
import axios from 'axios'; import axios from 'axios';
import MockAdapter from 'axios-mock-adapter'; import MockAdapter from 'axios-mock-adapter';
import Cookies from 'js-cookie';
import { useMockLocationHelper } from 'helpers/mock_window_location_helper'; import { useMockLocationHelper } from 'helpers/mock_window_location_helper';
import testAction from 'helpers/vuex_action_helper'; import testAction from 'helpers/vuex_action_helper';
import createFlash from '~/flash'; import createFlash from '~/flash';
...@@ -10,6 +11,7 @@ import { restoreFileLinesState, markLine, decorateFiles } from '~/merge_conflict ...@@ -10,6 +11,7 @@ import { restoreFileLinesState, markLine, decorateFiles } from '~/merge_conflict
jest.mock('~/flash.js'); jest.mock('~/flash.js');
jest.mock('~/merge_conflicts/utils'); jest.mock('~/merge_conflicts/utils');
jest.mock('js-cookie');
describe('merge conflicts actions', () => { describe('merge conflicts actions', () => {
let mock; let mock;
...@@ -80,6 +82,25 @@ describe('merge conflicts actions', () => { ...@@ -80,6 +82,25 @@ describe('merge conflicts actions', () => {
}); });
}); });
describe('setConflictsData', () => {
it('INTERACTIVE_RESOLVE_MODE updates the correct file ', (done) => {
decorateFiles.mockReturnValue([{ bar: 'baz' }]);
testAction(
actions.setConflictsData,
{ files, foo: 'bar' },
{},
[
{
type: types.SET_CONFLICTS_DATA,
payload: { foo: 'bar', files: [{ bar: 'baz' }] },
},
],
[],
done,
);
});
});
describe('submitResolvedConflicts', () => { describe('submitResolvedConflicts', () => {
useMockLocationHelper(); useMockLocationHelper();
const resolveConflictsPath = 'resolve/conflicts/path/mock'; const resolveConflictsPath = 'resolve/conflicts/path/mock';
...@@ -120,21 +141,109 @@ describe('merge conflicts actions', () => { ...@@ -120,21 +141,109 @@ describe('merge conflicts actions', () => {
}); });
}); });
describe('setConflictsData', () => { describe('setLoadingState', () => {
it('INTERACTIVE_RESOLVE_MODE updates the correct file ', (done) => { it('commits the right mutation', () => {
decorateFiles.mockReturnValue([{ bar: 'baz' }]);
testAction( testAction(
actions.setConflictsData, actions.setLoadingState,
{ files, foo: 'bar' }, true,
{}, {},
[ [
{ {
type: types.SET_CONFLICTS_DATA, type: types.SET_LOADING_STATE,
payload: { foo: 'bar', files: [{ bar: 'baz' }] }, payload: true,
},
],
[],
);
});
});
describe('setErrorState', () => {
it('commits the right mutation', () => {
testAction(
actions.setErrorState,
true,
{},
[
{
type: types.SET_ERROR_STATE,
payload: true,
},
],
[],
);
});
});
describe('setFailedRequest', () => {
it('commits the right mutation', () => {
testAction(
actions.setFailedRequest,
'errors in the request',
{},
[
{
type: types.SET_FAILED_REQUEST,
payload: 'errors in the request',
},
],
[],
);
});
});
describe('setViewType', () => {
it('commits the right mutation', (done) => {
const payload = 'viewType';
testAction(
actions.setViewType,
payload,
{},
[
{
type: types.SET_VIEW_TYPE,
payload,
},
],
[],
() => {
expect(Cookies.set).toHaveBeenCalledWith('diff_view', payload);
done();
},
);
});
});
describe('setSubmitState', () => {
it('commits the right mutation', () => {
testAction(
actions.setSubmitState,
true,
{},
[
{
type: types.SET_SUBMIT_STATE,
payload: true,
},
],
[],
);
});
});
describe('updateCommitMessage', () => {
it('commits the right mutation', () => {
testAction(
actions.updateCommitMessage,
'some message',
{},
[
{
type: types.UPDATE_CONFLICTS_DATA,
payload: { commitMessage: 'some message' },
}, },
], ],
[], [],
done,
); );
}); });
}); });
......
import {
CONFLICT_TYPES,
EDIT_RESOLVE_MODE,
INTERACTIVE_RESOLVE_MODE,
} from '~/merge_conflicts/constants';
import * as getters from '~/merge_conflicts/store/getters';
import realState from '~/merge_conflicts/store/state';
describe('Merge Conflicts getters', () => {
let state;
beforeEach(() => {
state = realState();
});
describe('getConflictsCount', () => {
it('returns zero when there are no files', () => {
state.conflictsData.files = [];
expect(getters.getConflictsCount(state)).toBe(0);
});
it(`counts the number of sections in files of type ${CONFLICT_TYPES.TEXT}`, () => {
state.conflictsData.files = [
{ sections: [{ conflict: true }], type: CONFLICT_TYPES.TEXT },
{ sections: [{ conflict: true }, { conflict: true }], type: CONFLICT_TYPES.TEXT },
];
expect(getters.getConflictsCount(state)).toBe(3);
});
it(`counts the number of file in files not of type ${CONFLICT_TYPES.TEXT}`, () => {
state.conflictsData.files = [
{ sections: [{ conflict: true }], type: '' },
{ sections: [{ conflict: true }, { conflict: true }], type: '' },
];
expect(getters.getConflictsCount(state)).toBe(2);
});
});
describe('getConflictsCountText', () => {
it('with one conflicts', () => {
const getConflictsCount = 1;
expect(getters.getConflictsCountText(state, { getConflictsCount })).toBe('1 conflict');
});
it('with more than one conflicts', () => {
const getConflictsCount = 3;
expect(getters.getConflictsCountText(state, { getConflictsCount })).toBe('3 conflicts');
});
});
describe('isReadyToCommit', () => {
it('return false when isSubmitting is true', () => {
state.conflictsData.files = [];
state.isSubmitting = true;
state.conflictsData.commitMessage = 'foo';
expect(getters.isReadyToCommit(state)).toBe(false);
});
it('returns false when has no commit message', () => {
state.conflictsData.files = [];
state.isSubmitting = false;
state.conflictsData.commitMessage = '';
expect(getters.isReadyToCommit(state)).toBe(false);
});
it('returns true when all conflicts are resolved and is not submitting and we have a commitMessage', () => {
state.conflictsData.files = [
{
resolveMode: INTERACTIVE_RESOLVE_MODE,
type: CONFLICT_TYPES.TEXT,
sections: [{ conflict: true }],
resolutionData: { foo: 'bar' },
},
];
state.isSubmitting = false;
state.conflictsData.commitMessage = 'foo';
expect(getters.isReadyToCommit(state)).toBe(true);
});
describe('unresolved', () => {
it(`files with resolvedMode set to ${EDIT_RESOLVE_MODE} and empty count as unresolved`, () => {
state.conflictsData.files = [
{ content: '', resolveMode: EDIT_RESOLVE_MODE },
{ content: 'foo' },
];
state.isSubmitting = false;
state.conflictsData.commitMessage = 'foo';
expect(getters.isReadyToCommit(state)).toBe(false);
});
it(`in files with resolvedMode = ${INTERACTIVE_RESOLVE_MODE} we count resolvedConflicts vs unresolved ones`, () => {
state.conflictsData.files = [
{
resolveMode: INTERACTIVE_RESOLVE_MODE,
type: CONFLICT_TYPES.TEXT,
sections: [{ conflict: true }],
resolutionData: {},
},
];
state.isSubmitting = false;
state.conflictsData.commitMessage = 'foo';
expect(getters.isReadyToCommit(state)).toBe(false);
});
});
});
describe('getCommitButtonText', () => {
it('when is submitting', () => {
state.isSubmitting = true;
expect(getters.getCommitButtonText(state)).toBe('Committing...');
});
it('when is not submitting', () => {
expect(getters.getCommitButtonText(state)).toBe('Commit to source branch');
});
});
describe('getCommitData', () => {
it('returns commit data', () => {
const baseFile = {
new_path: 'new_path',
old_path: 'new_path',
};
state.conflictsData.commitMessage = 'foo';
state.conflictsData.files = [
{
...baseFile,
resolveMode: INTERACTIVE_RESOLVE_MODE,
type: CONFLICT_TYPES.TEXT,
sections: [{ conflict: true }],
resolutionData: { bar: 'baz' },
},
{
...baseFile,
resolveMode: EDIT_RESOLVE_MODE,
type: CONFLICT_TYPES.TEXT,
content: 'resolve_mode_content',
},
{
...baseFile,
type: CONFLICT_TYPES.TEXT_EDITOR,
content: 'text_editor_content',
},
];
expect(getters.getCommitData(state)).toStrictEqual({
commit_message: 'foo',
files: [
{ ...baseFile, sections: { bar: 'baz' } },
{ ...baseFile, content: 'resolve_mode_content' },
{ ...baseFile, content: 'text_editor_content' },
],
});
});
});
describe('fileTextTypePresent', () => {
it(`returns true if there is a file with type ${CONFLICT_TYPES.TEXT}`, () => {
state.conflictsData.files = [{ type: CONFLICT_TYPES.TEXT }];
expect(getters.fileTextTypePresent(state)).toBe(true);
});
it(`returns false if there is no file with type ${CONFLICT_TYPES.TEXT}`, () => {
state.conflictsData.files = [{ type: CONFLICT_TYPES.TEXT_EDITOR }];
expect(getters.fileTextTypePresent(state)).toBe(false);
});
});
describe('getFileIndex', () => {
it(`returns the index of a file from it's blob path`, () => {
const blobPath = 'blobPath/foo';
state.conflictsData.files = [{ foo: 'bar' }, { baz: 'foo', blobPath }];
expect(getters.getFileIndex(state)({ blobPath })).toBe(1);
});
});
});
import { VIEW_TYPES } from '~/merge_conflicts/constants';
import * as types from '~/merge_conflicts/store/mutation_types';
import mutations from '~/merge_conflicts/store/mutations';
import realState from '~/merge_conflicts/store/state';
describe('Mutations merge conflicts store', () => {
let mockState;
beforeEach(() => {
mockState = realState();
});
describe('SET_LOADING_STATE', () => {
it('should set loading', () => {
mutations[types.SET_LOADING_STATE](mockState, true);
expect(mockState.isLoading).toBe(true);
});
});
describe('SET_ERROR_STATE', () => {
it('should set hasError', () => {
mutations[types.SET_ERROR_STATE](mockState, true);
expect(mockState.hasError).toBe(true);
});
});
describe('SET_FAILED_REQUEST', () => {
it('should set hasError and errorMessage', () => {
const payload = 'message';
mutations[types.SET_FAILED_REQUEST](mockState, payload);
expect(mockState.hasError).toBe(true);
expect(mockState.conflictsData.errorMessage).toBe(payload);
});
});
describe('SET_VIEW_TYPE', () => {
it('should set diffView', () => {
mutations[types.SET_VIEW_TYPE](mockState, VIEW_TYPES.INLINE);
expect(mockState.diffView).toBe(VIEW_TYPES.INLINE);
});
it(`if payload is ${VIEW_TYPES.PARALLEL} sets isParallel`, () => {
mutations[types.SET_VIEW_TYPE](mockState, VIEW_TYPES.PARALLEL);
expect(mockState.isParallel).toBe(true);
});
});
describe('SET_SUBMIT_STATE', () => {
it('should set isSubmitting', () => {
mutations[types.SET_SUBMIT_STATE](mockState, true);
expect(mockState.isSubmitting).toBe(true);
});
});
describe('SET_CONFLICTS_DATA', () => {
it('should set conflictsData', () => {
mutations[types.SET_CONFLICTS_DATA](mockState, {
files: [],
commit_message: 'foo',
source_branch: 'bar',
target_branch: 'baz',
commit_sha: '123456789',
});
expect(mockState.conflictsData).toStrictEqual({
files: [],
commitMessage: 'foo',
sourceBranch: 'bar',
targetBranch: 'baz',
shortCommitSha: '1234567',
});
});
});
describe('UPDATE_CONFLICTS_DATA', () => {
it('should update existing conflicts data', () => {
const payload = { foo: 'bar' };
mutations[types.UPDATE_CONFLICTS_DATA](mockState, payload);
expect(mockState.conflictsData).toStrictEqual(payload);
});
});
describe('UPDATE_FILE', () => {
it('should update a file based on its index', () => {
mockState.conflictsData.files = [{ foo: 'bar' }, { baz: 'bar' }];
mutations[types.UPDATE_FILE](mockState, { file: { new: 'one' }, index: 1 });
expect(mockState.conflictsData.files).toStrictEqual([{ foo: 'bar' }, { new: 'one' }]);
});
});
});
import * as utils from '~/merge_conflicts/utils';
describe('merge conflicts utils', () => {
describe('getFilePath', () => {
it('returns new path if they are the same', () => {
expect(utils.getFilePath({ new_path: 'a', old_path: 'a' })).toBe('a');
});
it('returns concatenated paths if they are different', () => {
expect(utils.getFilePath({ new_path: 'b', old_path: 'a' })).toBe('a → b');
});
});
describe('checkLineLengths', () => {
it('add empty lines to the left when right has more lines', () => {
const result = utils.checkLineLengths({ left: [1], right: [1, 2] });
expect(result.left).toHaveLength(result.right.length);
expect(result.left).toStrictEqual([1, { lineType: 'emptyLine', richText: '' }]);
});
it('add empty lines to the right when left has more lines', () => {
const result = utils.checkLineLengths({ left: [1, 2], right: [1] });
expect(result.right).toHaveLength(result.left.length);
expect(result.right).toStrictEqual([1, { lineType: 'emptyLine', richText: '' }]);
});
});
describe('getHeadHeaderLine', () => {
it('decorates the id', () => {
expect(utils.getHeadHeaderLine(1)).toStrictEqual({
buttonTitle: 'Use ours',
id: 1,
isHead: true,
isHeader: true,
isSelected: false,
isUnselected: false,
richText: 'HEAD//our changes',
section: 'head',
type: 'new',
});
});
});
describe('decorateLineForInlineView', () => {
it.each`
type | truthyProp
${'new'} | ${'isHead'}
${'old'} | ${'isOrigin'}
${'match'} | ${'hasMatch'}
`(
'when the type is $type decorates the line with $truthyProp set as true',
({ type, truthyProp }) => {
expect(utils.decorateLineForInlineView({ type, rich_text: 'rich' }, 1, true)).toStrictEqual(
{
id: 1,
hasConflict: true,
isHead: false,
isOrigin: false,
hasMatch: false,
richText: 'rich',
isSelected: false,
isUnselected: false,
[truthyProp]: true,
},
);
},
);
});
describe('getLineForParallelView', () => {
it.todo('should return a proper value');
});
describe('getOriginHeaderLine', () => {
it('decorates the id', () => {
expect(utils.getOriginHeaderLine(1)).toStrictEqual({
buttonTitle: 'Use theirs',
id: 1,
isHeader: true,
isOrigin: true,
isSelected: false,
isUnselected: false,
richText: 'origin//their changes',
section: 'origin',
type: 'old',
});
});
});
describe('setInlineLine', () => {
it.todo('should return a proper value');
});
describe('setParallelLine', () => {
it.todo('should return a proper value');
});
describe('decorateFiles', () => {
it.todo('should return a proper value');
});
describe('restoreFileLinesState', () => {
it.todo('should return a proper value');
});
describe('markLine', () => {
it.todo('should return a proper value');
});
});
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