342 lines
11 KiB
JavaScript
342 lines
11 KiB
JavaScript
|
import { mount, shallowMount } from '@vue/test-utils';
|
||
|
import MockAdapter from 'axios-mock-adapter';
|
||
|
import waitForPromises from 'helpers/wait_for_promises';
|
||
|
import {
|
||
|
defaultProps,
|
||
|
issuable1,
|
||
|
issuable2,
|
||
|
} from 'jest/vue_shared/components/issue/related_issuable_mock_data';
|
||
|
import RelatedIssuesRoot from '~/related_issues/components/related_issues_root.vue';
|
||
|
import relatedIssuesService from '~/related_issues/services/related_issues_service';
|
||
|
import { linkedIssueTypesMap } from '~/related_issues/constants';
|
||
|
import axios from '~/lib/utils/axios_utils';
|
||
|
import { deprecatedCreateFlash as createFlash } from '~/flash';
|
||
|
|
||
|
jest.mock('~/flash');
|
||
|
|
||
|
describe('RelatedIssuesRoot', () => {
|
||
|
let wrapper;
|
||
|
let mock;
|
||
|
|
||
|
beforeEach(() => {
|
||
|
mock = new MockAdapter(axios);
|
||
|
mock.onGet(defaultProps.endpoint).reply(200, []);
|
||
|
});
|
||
|
|
||
|
afterEach(() => {
|
||
|
mock.restore();
|
||
|
if (wrapper) {
|
||
|
wrapper.destroy();
|
||
|
wrapper = null;
|
||
|
}
|
||
|
});
|
||
|
|
||
|
const createComponent = (mountFn = mount) => {
|
||
|
wrapper = mountFn(RelatedIssuesRoot, {
|
||
|
propsData: defaultProps,
|
||
|
});
|
||
|
|
||
|
// Wait for fetch request `fetchRelatedIssues` to complete before starting to test
|
||
|
return waitForPromises();
|
||
|
};
|
||
|
|
||
|
describe('methods', () => {
|
||
|
describe('onRelatedIssueRemoveRequest', () => {
|
||
|
beforeEach(() => {
|
||
|
jest
|
||
|
.spyOn(relatedIssuesService.prototype, 'fetchRelatedIssues')
|
||
|
.mockReturnValue(Promise.reject());
|
||
|
|
||
|
return createComponent().then(() => {
|
||
|
wrapper.vm.store.setRelatedIssues([issuable1]);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it('remove related issue and succeeds', () => {
|
||
|
mock.onDelete(issuable1.referencePath).reply(200, { issues: [] });
|
||
|
|
||
|
wrapper.vm.onRelatedIssueRemoveRequest(issuable1.id);
|
||
|
|
||
|
return axios.waitForAll().then(() => {
|
||
|
expect(wrapper.vm.state.relatedIssues).toEqual([]);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it('remove related issue, fails, and restores to related issues', () => {
|
||
|
mock.onDelete(issuable1.referencePath).reply(422, {});
|
||
|
|
||
|
wrapper.vm.onRelatedIssueRemoveRequest(issuable1.id);
|
||
|
|
||
|
return axios.waitForAll().then(() => {
|
||
|
expect(wrapper.vm.state.relatedIssues).toHaveLength(1);
|
||
|
expect(wrapper.vm.state.relatedIssues[0].id).toEqual(issuable1.id);
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('onToggleAddRelatedIssuesForm', () => {
|
||
|
beforeEach(() => createComponent(shallowMount));
|
||
|
|
||
|
it('toggle related issues form to visible', () => {
|
||
|
wrapper.vm.onToggleAddRelatedIssuesForm();
|
||
|
|
||
|
expect(wrapper.vm.isFormVisible).toEqual(true);
|
||
|
});
|
||
|
|
||
|
it('show add related issues form to hidden', () => {
|
||
|
wrapper.vm.isFormVisible = true;
|
||
|
|
||
|
wrapper.vm.onToggleAddRelatedIssuesForm();
|
||
|
|
||
|
expect(wrapper.vm.isFormVisible).toEqual(false);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('onPendingIssueRemoveRequest', () => {
|
||
|
beforeEach(() =>
|
||
|
createComponent().then(() => {
|
||
|
wrapper.vm.store.setPendingReferences([issuable1.reference]);
|
||
|
}),
|
||
|
);
|
||
|
|
||
|
it('remove pending related issue', () => {
|
||
|
expect(wrapper.vm.state.pendingReferences).toHaveLength(1);
|
||
|
|
||
|
wrapper.vm.onPendingIssueRemoveRequest(0);
|
||
|
|
||
|
expect(wrapper.vm.state.pendingReferences).toHaveLength(0);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('onPendingFormSubmit', () => {
|
||
|
beforeEach(() => {
|
||
|
jest
|
||
|
.spyOn(relatedIssuesService.prototype, 'fetchRelatedIssues')
|
||
|
.mockReturnValue(Promise.reject());
|
||
|
|
||
|
return createComponent().then(() => {
|
||
|
jest.spyOn(wrapper.vm, 'processAllReferences');
|
||
|
jest.spyOn(wrapper.vm.service, 'addRelatedIssues');
|
||
|
createFlash.mockClear();
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it('processes references before submitting', () => {
|
||
|
const input = '#123';
|
||
|
const linkedIssueType = linkedIssueTypesMap.RELATES_TO;
|
||
|
const emitObj = {
|
||
|
pendingReferences: input,
|
||
|
linkedIssueType,
|
||
|
};
|
||
|
|
||
|
wrapper.vm.onPendingFormSubmit(emitObj);
|
||
|
|
||
|
expect(wrapper.vm.processAllReferences).toHaveBeenCalledWith(input);
|
||
|
expect(wrapper.vm.service.addRelatedIssues).toHaveBeenCalledWith([input], linkedIssueType);
|
||
|
});
|
||
|
|
||
|
it('submit zero pending issue as related issue', () => {
|
||
|
wrapper.vm.store.setPendingReferences([]);
|
||
|
wrapper.vm.onPendingFormSubmit({});
|
||
|
|
||
|
return waitForPromises().then(() => {
|
||
|
expect(wrapper.vm.state.pendingReferences).toHaveLength(0);
|
||
|
expect(wrapper.vm.state.relatedIssues).toHaveLength(0);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it('submit pending issue as related issue', () => {
|
||
|
mock.onPost(defaultProps.endpoint).reply(200, {
|
||
|
issuables: [issuable1],
|
||
|
result: {
|
||
|
message: 'something was successfully related',
|
||
|
status: 'success',
|
||
|
},
|
||
|
});
|
||
|
|
||
|
wrapper.vm.store.setPendingReferences([issuable1.reference]);
|
||
|
wrapper.vm.onPendingFormSubmit({});
|
||
|
|
||
|
return waitForPromises().then(() => {
|
||
|
expect(wrapper.vm.state.pendingReferences).toHaveLength(0);
|
||
|
expect(wrapper.vm.state.relatedIssues).toHaveLength(1);
|
||
|
expect(wrapper.vm.state.relatedIssues[0].id).toEqual(issuable1.id);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it('submit multiple pending issues as related issues', () => {
|
||
|
mock.onPost(defaultProps.endpoint).reply(200, {
|
||
|
issuables: [issuable1, issuable2],
|
||
|
result: {
|
||
|
message: 'something was successfully related',
|
||
|
status: 'success',
|
||
|
},
|
||
|
});
|
||
|
|
||
|
wrapper.vm.store.setPendingReferences([issuable1.reference, issuable2.reference]);
|
||
|
wrapper.vm.onPendingFormSubmit({});
|
||
|
|
||
|
return waitForPromises().then(() => {
|
||
|
expect(wrapper.vm.state.pendingReferences).toHaveLength(0);
|
||
|
expect(wrapper.vm.state.relatedIssues).toHaveLength(2);
|
||
|
expect(wrapper.vm.state.relatedIssues[0].id).toEqual(issuable1.id);
|
||
|
expect(wrapper.vm.state.relatedIssues[1].id).toEqual(issuable2.id);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it('displays a message from the backend upon error', () => {
|
||
|
const input = '#123';
|
||
|
const message = 'error';
|
||
|
|
||
|
mock.onPost(defaultProps.endpoint).reply(409, { message });
|
||
|
wrapper.vm.store.setPendingReferences([issuable1.reference, issuable2.reference]);
|
||
|
|
||
|
expect(createFlash).not.toHaveBeenCalled();
|
||
|
wrapper.vm.onPendingFormSubmit(input);
|
||
|
|
||
|
return waitForPromises().then(() => {
|
||
|
expect(createFlash).toHaveBeenCalledWith(message);
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('onPendingFormCancel', () => {
|
||
|
beforeEach(() =>
|
||
|
createComponent().then(() => {
|
||
|
wrapper.vm.isFormVisible = true;
|
||
|
wrapper.vm.inputValue = 'foo';
|
||
|
}),
|
||
|
);
|
||
|
|
||
|
it('when canceling and hiding add issuable form', () => {
|
||
|
wrapper.vm.onPendingFormCancel();
|
||
|
|
||
|
return wrapper.vm.$nextTick().then(() => {
|
||
|
expect(wrapper.vm.isFormVisible).toEqual(false);
|
||
|
expect(wrapper.vm.inputValue).toEqual('');
|
||
|
expect(wrapper.vm.state.pendingReferences).toHaveLength(0);
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('fetchRelatedIssues', () => {
|
||
|
beforeEach(() => createComponent());
|
||
|
|
||
|
it('sets isFetching while fetching', () => {
|
||
|
wrapper.vm.fetchRelatedIssues();
|
||
|
|
||
|
expect(wrapper.vm.isFetching).toEqual(true);
|
||
|
|
||
|
return waitForPromises().then(() => {
|
||
|
expect(wrapper.vm.isFetching).toEqual(false);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
it('should fetch related issues', () => {
|
||
|
mock.onGet(defaultProps.endpoint).reply(200, [issuable1, issuable2]);
|
||
|
|
||
|
wrapper.vm.fetchRelatedIssues();
|
||
|
|
||
|
return waitForPromises().then(() => {
|
||
|
expect(wrapper.vm.state.relatedIssues).toHaveLength(2);
|
||
|
expect(wrapper.vm.state.relatedIssues[0].id).toEqual(issuable1.id);
|
||
|
expect(wrapper.vm.state.relatedIssues[1].id).toEqual(issuable2.id);
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('onInput', () => {
|
||
|
beforeEach(() => createComponent());
|
||
|
|
||
|
it('fill in issue number reference and adds to pending related issues', () => {
|
||
|
const input = '#123 ';
|
||
|
wrapper.vm.onInput({
|
||
|
untouchedRawReferences: [input.trim()],
|
||
|
touchedReference: input,
|
||
|
});
|
||
|
|
||
|
expect(wrapper.vm.state.pendingReferences).toHaveLength(1);
|
||
|
expect(wrapper.vm.state.pendingReferences[0]).toEqual('#123');
|
||
|
});
|
||
|
|
||
|
it('fill in with full reference', () => {
|
||
|
const input = 'asdf/qwer#444 ';
|
||
|
wrapper.vm.onInput({ untouchedRawReferences: [input.trim()], touchedReference: input });
|
||
|
|
||
|
expect(wrapper.vm.state.pendingReferences).toHaveLength(1);
|
||
|
expect(wrapper.vm.state.pendingReferences[0]).toEqual('asdf/qwer#444');
|
||
|
});
|
||
|
|
||
|
it('fill in with issue link', () => {
|
||
|
const link = 'http://localhost:3000/foo/bar/issues/111';
|
||
|
const input = `${link} `;
|
||
|
wrapper.vm.onInput({ untouchedRawReferences: [input.trim()], touchedReference: input });
|
||
|
|
||
|
expect(wrapper.vm.state.pendingReferences).toHaveLength(1);
|
||
|
expect(wrapper.vm.state.pendingReferences[0]).toEqual(link);
|
||
|
});
|
||
|
|
||
|
it('fill in with multiple references', () => {
|
||
|
const input = 'asdf/qwer#444 #12 ';
|
||
|
wrapper.vm.onInput({
|
||
|
untouchedRawReferences: input.trim().split(/\s/),
|
||
|
touchedReference: 2,
|
||
|
});
|
||
|
|
||
|
expect(wrapper.vm.state.pendingReferences).toHaveLength(2);
|
||
|
expect(wrapper.vm.state.pendingReferences[0]).toEqual('asdf/qwer#444');
|
||
|
expect(wrapper.vm.state.pendingReferences[1]).toEqual('#12');
|
||
|
});
|
||
|
|
||
|
it('fill in with some invalid things', () => {
|
||
|
const input = 'something random ';
|
||
|
wrapper.vm.onInput({
|
||
|
untouchedRawReferences: input.trim().split(/\s/),
|
||
|
touchedReference: 2,
|
||
|
});
|
||
|
|
||
|
expect(wrapper.vm.state.pendingReferences).toHaveLength(2);
|
||
|
expect(wrapper.vm.state.pendingReferences[0]).toEqual('something');
|
||
|
expect(wrapper.vm.state.pendingReferences[1]).toEqual('random');
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('onBlur', () => {
|
||
|
beforeEach(() =>
|
||
|
createComponent().then(() => {
|
||
|
jest.spyOn(wrapper.vm, 'processAllReferences').mockImplementation(() => {});
|
||
|
}),
|
||
|
);
|
||
|
|
||
|
it('add any references to pending when blurring', () => {
|
||
|
const input = '#123';
|
||
|
|
||
|
wrapper.vm.onBlur(input);
|
||
|
|
||
|
expect(wrapper.vm.processAllReferences).toHaveBeenCalledWith(input);
|
||
|
});
|
||
|
});
|
||
|
|
||
|
describe('processAllReferences', () => {
|
||
|
beforeEach(() => createComponent());
|
||
|
|
||
|
it('add valid reference to pending', () => {
|
||
|
const input = '#123';
|
||
|
wrapper.vm.processAllReferences(input);
|
||
|
|
||
|
expect(wrapper.vm.state.pendingReferences).toHaveLength(1);
|
||
|
expect(wrapper.vm.state.pendingReferences[0]).toEqual('#123');
|
||
|
});
|
||
|
|
||
|
it('add any valid references to pending', () => {
|
||
|
const input = 'asdf #123';
|
||
|
wrapper.vm.processAllReferences(input);
|
||
|
|
||
|
expect(wrapper.vm.state.pendingReferences).toHaveLength(2);
|
||
|
expect(wrapper.vm.state.pendingReferences[0]).toEqual('asdf');
|
||
|
expect(wrapper.vm.state.pendingReferences[1]).toEqual('#123');
|
||
|
});
|
||
|
});
|
||
|
});
|
||
|
});
|