summaryrefslogtreecommitdiff
path: root/spec/frontend/issuable/related_issues/components/related_issues_root_spec.js
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/issuable/related_issues/components/related_issues_root_spec.js')
-rw-r--r--spec/frontend/issuable/related_issues/components/related_issues_root_spec.js367
1 files changed, 165 insertions, 202 deletions
diff --git a/spec/frontend/issuable/related_issues/components/related_issues_root_spec.js b/spec/frontend/issuable/related_issues/components/related_issues_root_spec.js
index 1a03ea58b60..b518d2fbdec 100644
--- a/spec/frontend/issuable/related_issues/components/related_issues_root_spec.js
+++ b/spec/frontend/issuable/related_issues/components/related_issues_root_spec.js
@@ -1,4 +1,4 @@
-import { mount, shallowMount } from '@vue/test-utils';
+import { mount } from '@vue/test-utils';
import MockAdapter from 'axios-mock-adapter';
import { nextTick } from 'vue';
import waitForPromises from 'helpers/wait_for_promises';
@@ -9,8 +9,9 @@ import {
} from 'jest/issuable/components/related_issuable_mock_data';
import createFlash from '~/flash';
import axios from '~/lib/utils/axios_utils';
-import RelatedIssuesRoot from '~/related_issues/components/related_issues_root.vue';
import { linkedIssueTypesMap } from '~/related_issues/constants';
+import RelatedIssuesBlock from '~/related_issues/components/related_issues_block.vue';
+import RelatedIssuesRoot from '~/related_issues/components/related_issues_root.vue';
import relatedIssuesService from '~/related_issues/services/related_issues_service';
jest.mock('~/flash');
@@ -19,6 +20,8 @@ describe('RelatedIssuesRoot', () => {
let wrapper;
let mock;
+ const findRelatedIssuesBlock = () => wrapper.findComponent(RelatedIssuesBlock);
+
beforeEach(() => {
mock = new MockAdapter(axios);
mock.onGet(defaultProps.endpoint).reply(200, []);
@@ -26,100 +29,114 @@ describe('RelatedIssuesRoot', () => {
afterEach(() => {
mock.restore();
- if (wrapper) {
- wrapper.destroy();
- wrapper = null;
- }
+ wrapper.destroy();
});
- const createComponent = (mountFn = mount) => {
- wrapper = mountFn(RelatedIssuesRoot, {
- propsData: defaultProps,
+ const createComponent = ({ props = {}, data = {} } = {}) => {
+ wrapper = mount(RelatedIssuesRoot, {
+ propsData: {
+ ...defaultProps,
+ ...props,
+ },
+ data() {
+ return data;
+ },
});
// 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(() => {
+ describe('events', () => {
+ describe('when "relatedIssueRemoveRequest" event is emitted', () => {
+ describe('when emitted value is a numerical issue', () => {
+ beforeEach(async () => {
+ jest
+ .spyOn(relatedIssuesService.prototype, 'fetchRelatedIssues')
+ .mockReturnValue(Promise.reject());
+ await createComponent();
wrapper.vm.store.setRelatedIssues([issuable1]);
});
- });
- it('remove related issue and succeeds', () => {
- mock.onDelete(issuable1.referencePath).reply(200, { issues: [] });
+ it('removes related issue on API success', async () => {
+ mock.onDelete(issuable1.referencePath).reply(200, { issues: [] });
+
+ findRelatedIssuesBlock().vm.$emit('relatedIssueRemoveRequest', issuable1.id);
+ await axios.waitForAll();
+
+ expect(findRelatedIssuesBlock().props('relatedIssues')).toEqual([]);
+ });
+
+ it('does not remove related issue on API error', async () => {
+ mock.onDelete(issuable1.referencePath).reply(422, {});
- wrapper.vm.onRelatedIssueRemoveRequest(issuable1.id);
+ findRelatedIssuesBlock().vm.$emit('relatedIssueRemoveRequest', issuable1.id);
+ await axios.waitForAll();
- return axios.waitForAll().then(() => {
- expect(wrapper.vm.state.relatedIssues).toEqual([]);
+ expect(findRelatedIssuesBlock().props('relatedIssues')).toEqual([
+ expect.objectContaining({ id: issuable1.id }),
+ ]);
});
});
- it('remove related issue, fails, and restores to related issues', () => {
- mock.onDelete(issuable1.referencePath).reply(422, {});
+ describe('when emitted value is a work item id', () => {
+ it('removes related issue', async () => {
+ const workItem = `gid://gitlab/WorkItem/${issuable1.id}`;
+ createComponent({ data: { state: { relatedIssues: [issuable1] } } });
- wrapper.vm.onRelatedIssueRemoveRequest(issuable1.id);
+ findRelatedIssuesBlock().vm.$emit('relatedIssueRemoveRequest', workItem);
+ await nextTick();
- return axios.waitForAll().then(() => {
- expect(wrapper.vm.state.relatedIssues).toHaveLength(1);
- expect(wrapper.vm.state.relatedIssues[0].id).toEqual(issuable1.id);
+ expect(findRelatedIssuesBlock().props('relatedIssues')).toEqual([]);
});
});
});
- describe('onToggleAddRelatedIssuesForm', () => {
- beforeEach(() => createComponent(shallowMount));
+ describe('when "toggleAddRelatedIssuesForm" event is emitted', () => {
+ it('toggles related issues form to visible from hidden', async () => {
+ createComponent();
- it('toggle related issues form to visible', () => {
- wrapper.vm.onToggleAddRelatedIssuesForm();
+ findRelatedIssuesBlock().vm.$emit('toggleAddRelatedIssuesForm');
+ await nextTick();
- expect(wrapper.vm.isFormVisible).toEqual(true);
+ expect(findRelatedIssuesBlock().props('isFormVisible')).toBe(true);
});
- it('show add related issues form to hidden', () => {
- wrapper.vm.isFormVisible = true;
+ it('toggles related issues form to hidden from visible', async () => {
+ createComponent({ data: { isFormVisible: true } });
- wrapper.vm.onToggleAddRelatedIssuesForm();
+ findRelatedIssuesBlock().vm.$emit('toggleAddRelatedIssuesForm');
+ await nextTick();
- expect(wrapper.vm.isFormVisible).toEqual(false);
+ expect(findRelatedIssuesBlock().props('isFormVisible')).toBe(false);
});
});
- describe('onPendingIssueRemoveRequest', () => {
- beforeEach(() =>
- createComponent().then(() => {
- wrapper.vm.store.setPendingReferences([issuable1.reference]);
- }),
- );
+ describe('when "pendingIssuableRemoveRequest" event is emitted', () => {
+ beforeEach(() => {
+ createComponent();
+ wrapper.vm.store.setPendingReferences([issuable1.reference]);
+ });
- it('remove pending related issue', () => {
- expect(wrapper.vm.state.pendingReferences).toHaveLength(1);
+ it('removes pending related issue', async () => {
+ expect(findRelatedIssuesBlock().props('pendingReferences')).toHaveLength(1);
- wrapper.vm.onPendingIssueRemoveRequest(0);
+ findRelatedIssuesBlock().vm.$emit('pendingIssuableRemoveRequest', 0);
+ await nextTick();
- expect(wrapper.vm.state.pendingReferences).toHaveLength(0);
+ expect(findRelatedIssuesBlock().props('pendingReferences')).toHaveLength(0);
});
});
- describe('onPendingFormSubmit', () => {
- beforeEach(() => {
+ describe('when "addIssuableFormSubmit" event is emitted', () => {
+ beforeEach(async () => {
jest
.spyOn(relatedIssuesService.prototype, 'fetchRelatedIssues')
.mockReturnValue(Promise.reject());
-
- return createComponent().then(() => {
- jest.spyOn(wrapper.vm, 'processAllReferences');
- jest.spyOn(wrapper.vm.service, 'addRelatedIssues');
- createFlash.mockClear();
- });
+ await createComponent();
+ jest.spyOn(wrapper.vm, 'processAllReferences');
+ jest.spyOn(wrapper.vm.service, 'addRelatedIssues');
+ createFlash.mockClear();
});
it('processes references before submitting', () => {
@@ -130,23 +147,22 @@ describe('RelatedIssuesRoot', () => {
linkedIssueType,
};
- wrapper.vm.onPendingFormSubmit(emitObj);
+ findRelatedIssuesBlock().vm.$emit('addIssuableFormSubmit', emitObj);
expect(wrapper.vm.processAllReferences).toHaveBeenCalledWith(input);
expect(wrapper.vm.service.addRelatedIssues).toHaveBeenCalledWith([input], linkedIssueType);
});
- it('submit zero pending issue as related issue', () => {
+ it('submits zero pending issues 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);
- });
+ findRelatedIssuesBlock().vm.$emit('addIssuableFormSubmit', {});
+
+ expect(findRelatedIssuesBlock().props('pendingReferences')).toHaveLength(0);
+ expect(findRelatedIssuesBlock().props('relatedIssues')).toHaveLength(0);
});
- it('submit pending issue as related issue', () => {
+ it('submits pending issue as related issue', async () => {
mock.onPost(defaultProps.endpoint).reply(200, {
issuables: [issuable1],
result: {
@@ -154,18 +170,18 @@ describe('RelatedIssuesRoot', () => {
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);
- });
+ findRelatedIssuesBlock().vm.$emit('addIssuableFormSubmit', {});
+ await waitForPromises();
+
+ expect(findRelatedIssuesBlock().props('pendingReferences')).toHaveLength(0);
+ expect(findRelatedIssuesBlock().props('relatedIssues')).toEqual([
+ expect.objectContaining({ id: issuable1.id }),
+ ]);
});
- it('submit multiple pending issues as related issues', () => {
+ it('submits multiple pending issues as related issues', async () => {
mock.onPost(defaultProps.endpoint).reply(200, {
issuables: [issuable1, issuable2],
result: {
@@ -173,201 +189,148 @@ describe('RelatedIssuesRoot', () => {
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);
- });
+ findRelatedIssuesBlock().vm.$emit('addIssuableFormSubmit', {});
+ await waitForPromises();
+
+ expect(findRelatedIssuesBlock().props('pendingReferences')).toHaveLength(0);
+ expect(findRelatedIssuesBlock().props('relatedIssues')).toEqual([
+ expect.objectContaining({ id: issuable1.id }),
+ expect.objectContaining({ id: issuable2.id }),
+ ]);
});
- it('displays a message from the backend upon error', () => {
+ it('displays a message from the backend upon error', async () => {
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', async () => {
- wrapper.vm.onPendingFormCancel();
+ findRelatedIssuesBlock().vm.$emit('addIssuableFormSubmit', input);
+ await waitForPromises();
- await nextTick();
- expect(wrapper.vm.isFormVisible).toEqual(false);
- expect(wrapper.vm.inputValue).toEqual('');
- expect(wrapper.vm.state.pendingReferences).toHaveLength(0);
+ expect(createFlash).toHaveBeenCalledWith({ message });
});
});
- describe('fetchRelatedIssues', () => {
- beforeEach(() => createComponent());
-
- it('sets isFetching while fetching', async () => {
- wrapper.vm.fetchRelatedIssues();
+ describe('when "addIssuableFormCancel" event is emitted', () => {
+ beforeEach(() => createComponent({ data: { isFormVisible: true, inputValue: 'foo' } }));
- expect(wrapper.vm.isFetching).toEqual(true);
+ it('hides form and resets input', async () => {
+ findRelatedIssuesBlock().vm.$emit('addIssuableFormCancel');
+ await nextTick();
- await waitForPromises();
- expect(wrapper.vm.isFetching).toEqual(false);
- });
-
- it('should fetch related issues', async () => {
- mock.onGet(defaultProps.endpoint).reply(200, [issuable1, issuable2]);
-
- wrapper.vm.fetchRelatedIssues();
-
- await waitForPromises();
- 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);
+ expect(findRelatedIssuesBlock().props('isFormVisible')).toBe(false);
+ expect(findRelatedIssuesBlock().props('inputValue')).toBe('');
+ expect(findRelatedIssuesBlock().props('pendingReferences')).toHaveLength(0);
});
});
- describe('onInput', () => {
- beforeEach(() => createComponent());
-
- it('fill in issue number reference and adds to pending related issues', () => {
+ describe('when "addIssuableFormInput" event is emitted', () => {
+ it('updates pending references with issue reference', async () => {
const input = '#123 ';
- wrapper.vm.onInput({
+ createComponent();
+
+ findRelatedIssuesBlock().vm.$emit('addIssuableFormInput', {
untouchedRawReferences: [input.trim()],
touchedReference: input,
});
+ await nextTick();
- expect(wrapper.vm.state.pendingReferences).toHaveLength(1);
- expect(wrapper.vm.state.pendingReferences[0]).toEqual('#123');
+ expect(findRelatedIssuesBlock().props('pendingReferences')).toEqual([input.trim()]);
});
- it('fill in with full reference', () => {
+ it('updates pending references with full reference', async () => {
const input = 'asdf/qwer#444 ';
- wrapper.vm.onInput({ untouchedRawReferences: [input.trim()], touchedReference: input });
+ createComponent();
+
+ findRelatedIssuesBlock().vm.$emit('addIssuableFormInput', {
+ untouchedRawReferences: [input.trim()],
+ touchedReference: input,
+ });
+ await nextTick();
- expect(wrapper.vm.state.pendingReferences).toHaveLength(1);
- expect(wrapper.vm.state.pendingReferences[0]).toEqual('asdf/qwer#444');
+ expect(findRelatedIssuesBlock().props('pendingReferences')).toEqual([input.trim()]);
});
- it('fill in with issue link', () => {
+ it('updates pending references with issue link', async () => {
const link = 'http://localhost:3000/foo/bar/issues/111';
const input = `${link} `;
- wrapper.vm.onInput({ untouchedRawReferences: [input.trim()], touchedReference: input });
+ createComponent();
- expect(wrapper.vm.state.pendingReferences).toHaveLength(1);
- expect(wrapper.vm.state.pendingReferences[0]).toEqual(link);
+ findRelatedIssuesBlock().vm.$emit('addIssuableFormInput', {
+ untouchedRawReferences: [input.trim()],
+ touchedReference: input,
+ });
+ await nextTick();
+
+ expect(findRelatedIssuesBlock().props('pendingReferences')).toEqual([link]);
});
- it('fill in with multiple references', () => {
+ it('updates pending references with multiple references', async () => {
const input = 'asdf/qwer#444 #12 ';
- wrapper.vm.onInput({
+ createComponent();
+
+ findRelatedIssuesBlock().vm.$emit('addIssuableFormInput', {
untouchedRawReferences: input.trim().split(/\s/),
touchedReference: '2',
});
+ await nextTick();
- 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');
+ expect(findRelatedIssuesBlock().props('pendingReferences')).toEqual([
+ 'asdf/qwer#444',
+ '#12',
+ ]);
});
- it('fill in with some invalid things', () => {
+ it('updates pending references with invalid values', async () => {
const input = 'something random ';
- wrapper.vm.onInput({
+ createComponent();
+
+ findRelatedIssuesBlock().vm.$emit('addIssuableFormInput', {
untouchedRawReferences: input.trim().split(/\s/),
touchedReference: '2',
});
+ await nextTick();
- expect(wrapper.vm.state.pendingReferences).toHaveLength(2);
- expect(wrapper.vm.state.pendingReferences[0]).toEqual('something');
- expect(wrapper.vm.state.pendingReferences[1]).toEqual('random');
+ expect(findRelatedIssuesBlock().props('pendingReferences')).toEqual([
+ 'something',
+ 'random',
+ ]);
});
- it.each`
- pathIdSeparator
- ${'#'}
- ${'&'}
- `(
- 'prepends $pathIdSeparator when user enters a numeric value [0-9]',
- async ({ pathIdSeparator }) => {
+ it.each(['#', '&'])(
+ 'prepends %s when user enters a numeric value [0-9]',
+ async (pathIdSeparator) => {
const input = '23';
+ createComponent({ props: { pathIdSeparator } });
- await wrapper.setProps({
- pathIdSeparator,
- });
-
- wrapper.vm.onInput({
+ findRelatedIssuesBlock().vm.$emit('addIssuableFormInput', {
untouchedRawReferences: input.trim().split(/\s/),
touchedReference: input,
});
+ await nextTick();
- expect(wrapper.vm.inputValue).toBe(`${pathIdSeparator}${input}`);
+ expect(findRelatedIssuesBlock().props('inputValue')).toBe(`${pathIdSeparator}${input}`);
},
);
-
- it('prepends # when user enters a number', async () => {
- const input = 23;
-
- wrapper.vm.onInput({
- untouchedRawReferences: String(input).trim().split(/\s/),
- touchedReference: input,
- });
-
- expect(wrapper.vm.inputValue).toBe(`#${input}`);
- });
});
- 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('when "addIssuableFormBlur" event is emitted', () => {
+ beforeEach(() => {
+ createComponent();
+ jest.spyOn(wrapper.vm, 'processAllReferences').mockImplementation(() => {});
});
- });
-
- describe('processAllReferences', () => {
- beforeEach(() => createComponent());
- it('add valid reference to pending', () => {
+ it('adds any references to pending when blurring', () => {
const input = '#123';
- wrapper.vm.processAllReferences(input);
- expect(wrapper.vm.state.pendingReferences).toHaveLength(1);
- expect(wrapper.vm.state.pendingReferences[0]).toEqual('#123');
- });
+ findRelatedIssuesBlock().vm.$emit('addIssuableFormBlur', input);
- 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');
+ expect(wrapper.vm.processAllReferences).toHaveBeenCalledWith(input);
});
});
});