diff options
Diffstat (limited to 'spec/frontend/issuable/related_issues/components/add_issuable_form_spec.js')
-rw-r--r-- | spec/frontend/issuable/related_issues/components/add_issuable_form_spec.js | 289 |
1 files changed, 289 insertions, 0 deletions
diff --git a/spec/frontend/issuable/related_issues/components/add_issuable_form_spec.js b/spec/frontend/issuable/related_issues/components/add_issuable_form_spec.js new file mode 100644 index 00000000000..bfbe4ec8e70 --- /dev/null +++ b/spec/frontend/issuable/related_issues/components/add_issuable_form_spec.js @@ -0,0 +1,289 @@ +import { mount, shallowMount } from '@vue/test-utils'; +import { issuableTypesMap, linkedIssueTypesMap, PathIdSeparator } from '~/related_issues/constants'; +import AddIssuableForm from '~/related_issues/components/add_issuable_form.vue'; + +const issuable1 = { + id: 200, + reference: 'foo/bar#123', + displayReference: '#123', + title: 'some title', + path: '/foo/bar/issues/123', + state: 'opened', +}; + +const issuable2 = { + id: 201, + reference: 'foo/bar#124', + displayReference: '#124', + title: 'some other thing', + path: '/foo/bar/issues/124', + state: 'opened', +}; + +const pathIdSeparator = PathIdSeparator.Issue; + +const findFormInput = wrapper => wrapper.find('.js-add-issuable-form-input').element; + +const findRadioInput = (inputs, value) => inputs.filter(input => input.element.value === value)[0]; + +const findRadioInputs = wrapper => wrapper.findAll('[name="linked-issue-type-radio"]'); + +const constructWrapper = props => { + return shallowMount(AddIssuableForm, { + propsData: { + inputValue: '', + pendingReferences: [], + pathIdSeparator, + ...props, + }, + }); +}; + +describe('AddIssuableForm', () => { + let wrapper; + + afterEach(() => { + // Jest doesn't blur an item even if it is destroyed, + // so blur the input manually after each test + const input = findFormInput(wrapper); + if (input) input.blur(); + + wrapper.destroy(); + }); + + describe('with data', () => { + describe('without references', () => { + describe('without any input text', () => { + beforeEach(() => { + wrapper = shallowMount(AddIssuableForm, { + propsData: { + inputValue: '', + pendingReferences: [], + pathIdSeparator, + }, + }); + }); + + it('should have disabled submit button', () => { + expect(wrapper.vm.$refs.addButton.disabled).toBe(true); + expect(wrapper.vm.$refs.loadingIcon).toBeUndefined(); + }); + }); + + describe('with input text', () => { + beforeEach(() => { + wrapper = shallowMount(AddIssuableForm, { + propsData: { + inputValue: 'foo', + pendingReferences: [], + pathIdSeparator, + }, + }); + }); + + it('should not have disabled submit button', () => { + expect(wrapper.vm.$refs.addButton.disabled).toBe(false); + }); + }); + }); + + describe('with references', () => { + const inputValue = 'foo #123'; + + beforeEach(() => { + wrapper = mount(AddIssuableForm, { + propsData: { + inputValue, + pendingReferences: [issuable1.reference, issuable2.reference], + pathIdSeparator, + }, + }); + }); + + it('should put input value in place', () => { + expect(findFormInput(wrapper).value).toEqual(inputValue); + }); + + it('should render pending issuables items', () => { + expect(wrapper.findAll('.js-add-issuable-form-token-list-item').length).toEqual(2); + }); + + it('should not have disabled submit button', () => { + expect(wrapper.vm.$refs.addButton.disabled).toBe(false); + }); + }); + + describe('when issuable type is "issue"', () => { + beforeEach(() => { + wrapper = mount(AddIssuableForm, { + propsData: { + inputValue: '', + issuableType: issuableTypesMap.ISSUE, + pathIdSeparator, + pendingReferences: [], + }, + }); + }); + + it('does not show radio inputs', () => { + expect(findRadioInputs(wrapper).length).toBe(0); + }); + }); + + describe('when issuable type is "epic"', () => { + beforeEach(() => { + wrapper = shallowMount(AddIssuableForm, { + propsData: { + inputValue: '', + issuableType: issuableTypesMap.EPIC, + pathIdSeparator, + pendingReferences: [], + }, + }); + }); + + it('does not show radio inputs', () => { + expect(findRadioInputs(wrapper).length).toBe(0); + }); + }); + + describe('when it is a Linked Issues form', () => { + beforeEach(() => { + wrapper = mount(AddIssuableForm, { + propsData: { + inputValue: '', + showCategorizedIssues: true, + issuableType: issuableTypesMap.ISSUE, + pathIdSeparator, + pendingReferences: [], + }, + }); + }); + + it('shows radio inputs to allow categorisation of blocking issues', () => { + expect(findRadioInputs(wrapper).length).toBeGreaterThan(0); + }); + + describe('form radio buttons', () => { + let radioInputs; + + beforeEach(() => { + radioInputs = findRadioInputs(wrapper); + }); + + it('shows "relates to" option', () => { + expect(findRadioInput(radioInputs, linkedIssueTypesMap.RELATES_TO)).not.toBeNull(); + }); + + it('shows "blocks" option', () => { + expect(findRadioInput(radioInputs, linkedIssueTypesMap.BLOCKS)).not.toBeNull(); + }); + + it('shows "is blocked by" option', () => { + expect(findRadioInput(radioInputs, linkedIssueTypesMap.IS_BLOCKED_BY)).not.toBeNull(); + }); + + it('shows 3 options in total', () => { + expect(radioInputs.length).toBe(3); + }); + }); + + describe('when the form is submitted', () => { + it('emits an event with a "relates_to" link type when the "relates to" radio input selected', done => { + jest.spyOn(wrapper.vm, '$emit').mockImplementation(() => {}); + + wrapper.vm.linkedIssueType = linkedIssueTypesMap.RELATES_TO; + wrapper.vm.onFormSubmit(); + + wrapper.vm.$nextTick(() => { + expect(wrapper.vm.$emit).toHaveBeenCalledWith('addIssuableFormSubmit', { + pendingReferences: '', + linkedIssueType: linkedIssueTypesMap.RELATES_TO, + }); + done(); + }); + }); + + it('emits an event with a "blocks" link type when the "blocks" radio input selected', done => { + jest.spyOn(wrapper.vm, '$emit').mockImplementation(() => {}); + + wrapper.vm.linkedIssueType = linkedIssueTypesMap.BLOCKS; + wrapper.vm.onFormSubmit(); + + wrapper.vm.$nextTick(() => { + expect(wrapper.vm.$emit).toHaveBeenCalledWith('addIssuableFormSubmit', { + pendingReferences: '', + linkedIssueType: linkedIssueTypesMap.BLOCKS, + }); + done(); + }); + }); + + it('emits an event with a "is_blocked_by" link type when the "is blocked by" radio input selected', done => { + jest.spyOn(wrapper.vm, '$emit').mockImplementation(() => {}); + + wrapper.vm.linkedIssueType = linkedIssueTypesMap.IS_BLOCKED_BY; + wrapper.vm.onFormSubmit(); + + wrapper.vm.$nextTick(() => { + expect(wrapper.vm.$emit).toHaveBeenCalledWith('addIssuableFormSubmit', { + pendingReferences: '', + linkedIssueType: linkedIssueTypesMap.IS_BLOCKED_BY, + }); + done(); + }); + }); + + it('shows error message when error is present', done => { + const itemAddFailureMessage = 'Something went wrong while submitting.'; + wrapper.setProps({ + hasError: true, + itemAddFailureMessage, + }); + + wrapper.vm.$nextTick(() => { + expect(wrapper.find('.gl-field-error').exists()).toBe(true); + expect(wrapper.find('.gl-field-error').text()).toContain(itemAddFailureMessage); + done(); + }); + }); + }); + }); + }); + + describe('computed', () => { + describe('transformedAutocompleteSources', () => { + const autoCompleteSources = { + issues: 'http://localhost/autocomplete/issues', + epics: 'http://localhost/autocomplete/epics', + }; + + it('returns autocomplete object', () => { + wrapper = constructWrapper({ + autoCompleteSources, + }); + + expect(wrapper.vm.transformedAutocompleteSources).toBe(autoCompleteSources); + + wrapper = constructWrapper({ + autoCompleteSources, + confidential: false, + }); + + expect(wrapper.vm.transformedAutocompleteSources).toBe(autoCompleteSources); + }); + + it('returns autocomplete sources with query `confidential_only`, when it is confidential', () => { + wrapper = constructWrapper({ + autoCompleteSources, + confidential: true, + }); + + const actualSources = wrapper.vm.transformedAutocompleteSources; + + expect(actualSources.epics).toContain('?confidential_only=true'); + expect(actualSources.issues).toContain('?confidential_only=true'); + }); + }); + }); +}); |