diff options
Diffstat (limited to 'spec/frontend/issuable')
5 files changed, 98 insertions, 30 deletions
diff --git a/spec/frontend/issuable/helpers.js b/spec/frontend/issuable/helpers.js new file mode 100644 index 00000000000..632d69c2c88 --- /dev/null +++ b/spec/frontend/issuable/helpers.js @@ -0,0 +1,18 @@ +export function getSaveableFormChildren(form, exclude = ['input.js-toggle-draft']) { + const children = Array.from(form.children); + const saveable = children.filter((e) => { + const isFiltered = exclude.reduce( + ({ isFiltered: filtered, element }, selector) => { + return { + isFiltered: filtered || element.matches(selector), + element, + }; + }, + { isFiltered: false, element: e }, + ); + + return !isFiltered.isFiltered; + }); + + return saveable; +} diff --git a/spec/frontend/issuable/issuable_form_spec.js b/spec/frontend/issuable/issuable_form_spec.js index 28ec0e22d8b..3e778e50fb8 100644 --- a/spec/frontend/issuable/issuable_form_spec.js +++ b/spec/frontend/issuable/issuable_form_spec.js @@ -4,6 +4,8 @@ import { setHTMLFixture, resetHTMLFixture } from 'helpers/fixtures'; import IssuableForm from '~/issuable/issuable_form'; import setWindowLocation from 'helpers/set_window_location_helper'; +import { getSaveableFormChildren } from './helpers'; + jest.mock('~/autosave'); const createIssuable = (form) => { @@ -18,6 +20,7 @@ describe('IssuableForm', () => { setHTMLFixture(` <form> <input name="[title]" /> + <input type="checkbox" class="js-toggle-draft" /> <textarea name="[description]"></textarea> </form> `); @@ -99,10 +102,11 @@ describe('IssuableForm', () => { ])('creates $id autosave when $id input exist', ({ id, input, selector }) => { $form.append(input); const $input = $form.find(selector); - const totalAutosaveFormFields = $form.children().length; createIssuable($form); - expect(Autosave).toHaveBeenCalledTimes(totalAutosaveFormFields); + const children = getSaveableFormChildren($form[0]); + + expect(Autosave).toHaveBeenCalledTimes(children.length); expect(Autosave).toHaveBeenLastCalledWith( $input.get(0), ['/', '', id], @@ -153,12 +157,17 @@ describe('IssuableForm', () => { }); }); - describe('wip', () => { + describe('draft', () => { + let titleField; + let toggleDraft; + beforeEach(() => { instance = createIssuable($form); + titleField = document.querySelector('input[name="[title]"]'); + toggleDraft = document.querySelector('input.js-toggle-draft'); }); - describe('removeWip', () => { + describe('removeDraft', () => { it.each` prefix ${'draFT: '} @@ -169,25 +178,25 @@ describe('IssuableForm', () => { ${' (DrafT)'} ${'draft: [draft] (draft)'} `('removes "$prefix" from the beginning of the title', ({ prefix }) => { - instance.titleField.val(`${prefix}The Issuable's Title Value`); + titleField.value = `${prefix}The Issuable's Title Value`; - instance.removeWip(); + instance.removeDraft(); - expect(instance.titleField.val()).toBe("The Issuable's Title Value"); + expect(titleField.value).toBe("The Issuable's Title Value"); }); }); - describe('addWip', () => { + describe('addDraft', () => { it("properly adds the work in progress prefix to the Issuable's title", () => { - instance.titleField.val("The Issuable's Title Value"); + titleField.value = "The Issuable's Title Value"; - instance.addWip(); + instance.addDraft(); - expect(instance.titleField.val()).toBe("Draft: The Issuable's Title Value"); + expect(titleField.value).toBe("Draft: The Issuable's Title Value"); }); }); - describe('workInProgress', () => { + describe('isMarkedDraft', () => { it.each` title | expected ${'draFT: something is happening'} | ${true} @@ -195,10 +204,45 @@ describe('IssuableForm', () => { ${'something is happening to drafts'} | ${false} ${'something is happening'} | ${false} `('returns $expected with "$title"', ({ title, expected }) => { - instance.titleField.val(title); + titleField.value = title; - expect(instance.workInProgress()).toBe(expected); + expect(instance.isMarkedDraft()).toBe(expected); }); }); + + describe('readDraftStatus', () => { + it.each` + title | checked + ${'Draft: my title'} | ${true} + ${'my title'} | ${false} + `( + 'sets the draft checkbox checked status to $checked when the title is $title', + ({ title, checked }) => { + titleField.value = title; + + instance.readDraftStatus(); + + expect(toggleDraft.checked).toBe(checked); + }, + ); + }); + + describe('writeDraftStatus', () => { + it.each` + checked | title + ${true} | ${'Draft: my title'} + ${false} | ${'my title'} + `( + 'updates the title to $title when the draft checkbox checked status is $checked', + ({ checked, title }) => { + titleField.value = 'my title'; + toggleDraft.checked = checked; + + instance.writeDraftStatus(); + + expect(titleField.value).toBe(title); + }, + ); + }); }); }); 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 index 16d4459f597..72fcab63ba7 100644 --- a/spec/frontend/issuable/related_issues/components/add_issuable_form_spec.js +++ b/spec/frontend/issuable/related_issues/components/add_issuable_form_spec.js @@ -1,9 +1,10 @@ import { GlFormGroup } from '@gitlab/ui'; import { mount, shallowMount } from '@vue/test-utils'; import { nextTick } from 'vue'; +import { TYPE_EPIC, TYPE_ISSUE } from '~/issues/constants'; import AddIssuableForm from '~/related_issues/components/add_issuable_form.vue'; import IssueToken from '~/related_issues/components/issue_token.vue'; -import { issuableTypesMap, linkedIssueTypesMap, PathIdSeparator } from '~/related_issues/constants'; +import { linkedIssueTypesMap, PathIdSeparator } from '~/related_issues/constants'; const issuable1 = { id: 200, @@ -125,7 +126,7 @@ describe('AddIssuableForm', () => { wrapper = mount(AddIssuableForm, { propsData: { inputValue: '', - issuableType: issuableTypesMap.ISSUE, + issuableType: TYPE_ISSUE, pathIdSeparator, pendingReferences: [], }, @@ -142,7 +143,7 @@ describe('AddIssuableForm', () => { wrapper = shallowMount(AddIssuableForm, { propsData: { inputValue: '', - issuableType: issuableTypesMap.EPIC, + issuableType: TYPE_EPIC, pathIdSeparator, pendingReferences: [], }, @@ -156,9 +157,9 @@ describe('AddIssuableForm', () => { describe('categorized issuables', () => { it.each` - issuableType | pathIdSeparator | contextHeader | contextFooter - ${issuableTypesMap.ISSUE} | ${PathIdSeparator.Issue} | ${'The current issue'} | ${'the following issues'} - ${issuableTypesMap.EPIC} | ${PathIdSeparator.Epic} | ${'The current epic'} | ${'the following epics'} + issuableType | pathIdSeparator | contextHeader | contextFooter + ${TYPE_ISSUE} | ${PathIdSeparator.Issue} | ${'The current issue'} | ${'the following issues'} + ${TYPE_EPIC} | ${PathIdSeparator.Epic} | ${'The current epic'} | ${'the following epics'} `( 'show header text as "$contextHeader" and footer text as "$contextFooter" issuableType is set to $issuableType', ({ issuableType, contextHeader, contextFooter }) => { @@ -184,7 +185,7 @@ describe('AddIssuableForm', () => { propsData: { inputValue: '', showCategorizedIssues: true, - issuableType: issuableTypesMap.ISSUE, + issuableType: TYPE_ISSUE, pathIdSeparator, pendingReferences: [], }, diff --git a/spec/frontend/issuable/related_issues/components/related_issues_block_spec.js b/spec/frontend/issuable/related_issues/components/related_issues_block_spec.js index 996b2406240..ff8d5073005 100644 --- a/spec/frontend/issuable/related_issues/components/related_issues_block_spec.js +++ b/spec/frontend/issuable/related_issues/components/related_issues_block_spec.js @@ -6,10 +6,10 @@ import { issuable2, issuable3, } from 'jest/issuable/components/related_issuable_mock_data'; +import { TYPE_ISSUE } from '~/issues/constants'; import RelatedIssuesBlock from '~/related_issues/components/related_issues_block.vue'; import AddIssuableForm from '~/related_issues/components/add_issuable_form.vue'; import { - issuableTypesMap, linkedIssueTypesMap, linkedIssueTypesTextMap, PathIdSeparator, @@ -34,7 +34,7 @@ describe('RelatedIssuesBlock', () => { wrapper = mountExtended(RelatedIssuesBlock, { propsData: { pathIdSeparator: PathIdSeparator.Issue, - issuableType: issuableTypesMap.ISSUE, + issuableType: TYPE_ISSUE, }, }); }); @@ -237,7 +237,7 @@ describe('RelatedIssuesBlock', () => { propsData: { pathIdSeparator: PathIdSeparator.Issue, relatedIssues: [issuable1, issuable2, issuable3], - issuableType: issuableTypesMap.ISSUE, + issuableType: TYPE_ISSUE, }, }); }); 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 bedf8bcaf34..96c0b87e2cb 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 @@ -9,6 +9,11 @@ import { } from 'jest/issuable/components/related_issuable_mock_data'; import { createAlert } from '~/flash'; import axios from '~/lib/utils/axios_utils'; +import { + HTTP_STATUS_CONFLICT, + HTTP_STATUS_OK, + HTTP_STATUS_UNPROCESSABLE_ENTITY, +} from '~/lib/utils/http_status'; 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'; @@ -24,7 +29,7 @@ describe('RelatedIssuesRoot', () => { beforeEach(() => { mock = new MockAdapter(axios); - mock.onGet(defaultProps.endpoint).reply(200, []); + mock.onGet(defaultProps.endpoint).reply(HTTP_STATUS_OK, []); }); afterEach(() => { @@ -59,7 +64,7 @@ describe('RelatedIssuesRoot', () => { }); it('removes related issue on API success', async () => { - mock.onDelete(issuable1.referencePath).reply(200, { issues: [] }); + mock.onDelete(issuable1.referencePath).reply(HTTP_STATUS_OK, { issues: [] }); findRelatedIssuesBlock().vm.$emit('relatedIssueRemoveRequest', issuable1.id); await axios.waitForAll(); @@ -68,7 +73,7 @@ describe('RelatedIssuesRoot', () => { }); it('does not remove related issue on API error', async () => { - mock.onDelete(issuable1.referencePath).reply(422, {}); + mock.onDelete(issuable1.referencePath).reply(HTTP_STATUS_UNPROCESSABLE_ENTITY, {}); findRelatedIssuesBlock().vm.$emit('relatedIssueRemoveRequest', issuable1.id); await axios.waitForAll(); @@ -163,7 +168,7 @@ describe('RelatedIssuesRoot', () => { }); it('submits pending issue as related issue', async () => { - mock.onPost(defaultProps.endpoint).reply(200, { + mock.onPost(defaultProps.endpoint).reply(HTTP_STATUS_OK, { issuables: [issuable1], result: { message: 'something was successfully related', @@ -182,7 +187,7 @@ describe('RelatedIssuesRoot', () => { }); it('submits multiple pending issues as related issues', async () => { - mock.onPost(defaultProps.endpoint).reply(200, { + mock.onPost(defaultProps.endpoint).reply(HTTP_STATUS_OK, { issuables: [issuable1, issuable2], result: { message: 'something was successfully related', @@ -204,7 +209,7 @@ describe('RelatedIssuesRoot', () => { it('passes an error message from the backend upon error', async () => { const input = '#123'; const message = 'error'; - mock.onPost(defaultProps.endpoint).reply(409, { message }); + mock.onPost(defaultProps.endpoint).reply(HTTP_STATUS_CONFLICT, { message }); wrapper.vm.store.setPendingReferences([issuable1.reference, issuable2.reference]); expect(findRelatedIssuesBlock().props('hasError')).toBe(false); |