diff options
Diffstat (limited to 'spec/frontend/integrations')
3 files changed, 359 insertions, 260 deletions
diff --git a/spec/frontend/integrations/edit/components/dynamic_field_spec.js b/spec/frontend/integrations/edit/components/dynamic_field_spec.js index da8a2f41c1b..bf044e388ea 100644 --- a/spec/frontend/integrations/edit/components/dynamic_field_spec.js +++ b/spec/frontend/integrations/edit/components/dynamic_field_spec.js @@ -35,136 +35,145 @@ describe('DynamicField', () => { const findGlFormTextarea = () => wrapper.findComponent(GlFormTextarea); describe('template', () => { - describe.each([ - [true, 'disabled', 'readonly'], - [false, undefined, undefined], - ])('dynamic field, when isInheriting = `%p`', (isInheriting, disabled, readonly) => { - describe('type is checkbox', () => { - beforeEach(() => { - createComponent( - { - type: 'checkbox', - }, - isInheriting, - ); - }); + describe.each` + isInheriting | disabled | readonly | checkboxLabel + ${true} | ${'disabled'} | ${'readonly'} | ${undefined} + ${false} | ${undefined} | ${undefined} | ${'Custom checkbox label'} + `( + 'dynamic field, when isInheriting = `%p`', + ({ isInheriting, disabled, readonly, checkboxLabel }) => { + describe('type is checkbox', () => { + beforeEach(() => { + createComponent( + { + type: 'checkbox', + checkboxLabel, + }, + isInheriting, + ); + }); - it(`renders GlFormCheckbox, which ${isInheriting ? 'is' : 'is not'} disabled`, () => { - expect(findGlFormCheckbox().exists()).toBe(true); - expect(findGlFormCheckbox().find('[type=checkbox]').attributes('disabled')).toBe( - disabled, - ); - }); + it(`renders GlFormCheckbox, which ${isInheriting ? 'is' : 'is not'} disabled`, () => { + expect(findGlFormCheckbox().exists()).toBe(true); + expect(findGlFormCheckbox().find('[type=checkbox]').attributes('disabled')).toBe( + disabled, + ); + }); - it('does not render other types of input', () => { - expect(findGlFormSelect().exists()).toBe(false); - expect(findGlFormTextarea().exists()).toBe(false); - expect(findGlFormInput().exists()).toBe(false); - }); - }); + it(`renders GlFormCheckbox with correct text content when checkboxLabel is ${checkboxLabel}`, () => { + expect(findGlFormCheckbox().text()).toBe(checkboxLabel ?? defaultProps.title); + }); - describe('type is select', () => { - beforeEach(() => { - createComponent( - { - type: 'select', - choices: [ - ['all', 'All details'], - ['standard', 'Standard'], - ], - }, - isInheriting, - ); + it('does not render other types of input', () => { + expect(findGlFormSelect().exists()).toBe(false); + expect(findGlFormTextarea().exists()).toBe(false); + expect(findGlFormInput().exists()).toBe(false); + }); }); - it(`renders GlFormSelect, which ${isInheriting ? 'is' : 'is not'} disabled`, () => { - expect(findGlFormSelect().exists()).toBe(true); - expect(findGlFormSelect().findAll('option')).toHaveLength(2); - expect(findGlFormSelect().find('select').attributes('disabled')).toBe(disabled); - }); + describe('type is select', () => { + beforeEach(() => { + createComponent( + { + type: 'select', + choices: [ + ['all', 'All details'], + ['standard', 'Standard'], + ], + }, + isInheriting, + ); + }); - it('does not render other types of input', () => { - expect(findGlFormCheckbox().exists()).toBe(false); - expect(findGlFormTextarea().exists()).toBe(false); - expect(findGlFormInput().exists()).toBe(false); - }); - }); + it(`renders GlFormSelect, which ${isInheriting ? 'is' : 'is not'} disabled`, () => { + expect(findGlFormSelect().exists()).toBe(true); + expect(findGlFormSelect().findAll('option')).toHaveLength(2); + expect(findGlFormSelect().find('select').attributes('disabled')).toBe(disabled); + }); - describe('type is textarea', () => { - beforeEach(() => { - createComponent( - { - type: 'textarea', - }, - isInheriting, - ); + it('does not render other types of input', () => { + expect(findGlFormCheckbox().exists()).toBe(false); + expect(findGlFormTextarea().exists()).toBe(false); + expect(findGlFormInput().exists()).toBe(false); + }); }); - it(`renders GlFormTextarea, which ${isInheriting ? 'is' : 'is not'} readonly`, () => { - expect(findGlFormTextarea().exists()).toBe(true); - expect(findGlFormTextarea().find('textarea').attributes('readonly')).toBe(readonly); - }); + describe('type is textarea', () => { + beforeEach(() => { + createComponent( + { + type: 'textarea', + }, + isInheriting, + ); + }); - it('does not render other types of input', () => { - expect(findGlFormCheckbox().exists()).toBe(false); - expect(findGlFormSelect().exists()).toBe(false); - expect(findGlFormInput().exists()).toBe(false); - }); - }); + it(`renders GlFormTextarea, which ${isInheriting ? 'is' : 'is not'} readonly`, () => { + expect(findGlFormTextarea().exists()).toBe(true); + expect(findGlFormTextarea().find('textarea').attributes('readonly')).toBe(readonly); + }); - describe('type is password', () => { - beforeEach(() => { - createComponent( - { - type: 'password', - }, - isInheriting, - ); + it('does not render other types of input', () => { + expect(findGlFormCheckbox().exists()).toBe(false); + expect(findGlFormSelect().exists()).toBe(false); + expect(findGlFormInput().exists()).toBe(false); + }); }); - it(`renders GlFormInput, which ${isInheriting ? 'is' : 'is not'} readonly`, () => { - expect(findGlFormInput().exists()).toBe(true); - expect(findGlFormInput().attributes('type')).toBe('password'); - expect(findGlFormInput().attributes('readonly')).toBe(readonly); - }); + describe('type is password', () => { + beforeEach(() => { + createComponent( + { + type: 'password', + }, + isInheriting, + ); + }); - it('does not render other types of input', () => { - expect(findGlFormCheckbox().exists()).toBe(false); - expect(findGlFormSelect().exists()).toBe(false); - expect(findGlFormTextarea().exists()).toBe(false); - }); - }); + it(`renders GlFormInput, which ${isInheriting ? 'is' : 'is not'} readonly`, () => { + expect(findGlFormInput().exists()).toBe(true); + expect(findGlFormInput().attributes('type')).toBe('password'); + expect(findGlFormInput().attributes('readonly')).toBe(readonly); + }); - describe('type is text', () => { - beforeEach(() => { - createComponent( - { - type: 'text', - required: true, - }, - isInheriting, - ); + it('does not render other types of input', () => { + expect(findGlFormCheckbox().exists()).toBe(false); + expect(findGlFormSelect().exists()).toBe(false); + expect(findGlFormTextarea().exists()).toBe(false); + }); }); - it(`renders GlFormInput, which ${isInheriting ? 'is' : 'is not'} readonly`, () => { - expect(findGlFormInput().exists()).toBe(true); - expect(findGlFormInput().attributes()).toMatchObject({ - type: 'text', - id: 'service_project_url', - name: 'service[project_url]', - placeholder: defaultProps.placeholder, - required: 'required', + describe('type is text', () => { + beforeEach(() => { + createComponent( + { + type: 'text', + required: true, + }, + isInheriting, + ); }); - expect(findGlFormInput().attributes('readonly')).toBe(readonly); - }); - it('does not render other types of input', () => { - expect(findGlFormCheckbox().exists()).toBe(false); - expect(findGlFormSelect().exists()).toBe(false); - expect(findGlFormTextarea().exists()).toBe(false); + it(`renders GlFormInput, which ${isInheriting ? 'is' : 'is not'} readonly`, () => { + expect(findGlFormInput().exists()).toBe(true); + expect(findGlFormInput().attributes()).toMatchObject({ + type: 'text', + id: 'service_project_url', + name: 'service[project_url]', + placeholder: defaultProps.placeholder, + required: 'required', + }); + expect(findGlFormInput().attributes('readonly')).toBe(readonly); + }); + + it('does not render other types of input', () => { + expect(findGlFormCheckbox().exists()).toBe(false); + expect(findGlFormSelect().exists()).toBe(false); + expect(findGlFormTextarea().exists()).toBe(false); + }); }); - }); - }); + }, + ); describe('help text', () => { it('renders description with help text', () => { diff --git a/spec/frontend/integrations/edit/components/jira_issues_fields_spec.js b/spec/frontend/integrations/edit/components/jira_issues_fields_spec.js index 119afbfecfe..3a664b652ac 100644 --- a/spec/frontend/integrations/edit/components/jira_issues_fields_spec.js +++ b/spec/frontend/integrations/edit/components/jira_issues_fields_spec.js @@ -1,7 +1,10 @@ import { GlFormCheckbox, GlFormInput } from '@gitlab/ui'; -import { mountExtended } from 'helpers/vue_test_utils_helper'; +import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper'; -import { GET_JIRA_ISSUE_TYPES_EVENT } from '~/integrations/constants'; +import { + GET_JIRA_ISSUE_TYPES_EVENT, + VALIDATE_INTEGRATION_FORM_EVENT, +} from '~/integrations/constants'; import JiraIssuesFields from '~/integrations/edit/components/jira_issues_fields.vue'; import eventHub from '~/integrations/edit/event_hub'; import { createStore } from '~/integrations/edit/store'; @@ -17,12 +20,17 @@ describe('JiraIssuesFields', () => { upgradePlanPath: 'https://gitlab.com', }; - const createComponent = ({ isInheriting = false, props, ...options } = {}) => { + const createComponent = ({ + isInheriting = false, + mountFn = mountExtended, + props, + ...options + } = {}) => { store = createStore({ defaultState: isInheriting ? {} : undefined, }); - wrapper = mountExtended(JiraIssuesFields, { + wrapper = mountFn(JiraIssuesFields, { propsData: { ...defaultProps, ...props }, store, stubs: ['jira-issue-creation-vulnerabilities'], @@ -38,12 +46,19 @@ describe('JiraIssuesFields', () => { const findEnableCheckboxDisabled = () => findEnableCheckbox().find('[type=checkbox]').attributes('disabled'); const findProjectKey = () => wrapper.findComponent(GlFormInput); + const findProjectKeyFormGroup = () => wrapper.findByTestId('project-key-form-group'); const findPremiumUpgradeCTA = () => wrapper.findByTestId('premium-upgrade-cta'); const findUltimateUpgradeCTA = () => wrapper.findByTestId('ultimate-upgrade-cta'); const findJiraForVulnerabilities = () => wrapper.findByTestId('jira-for-vulnerabilities'); + const findConflictWarning = () => wrapper.findByTestId('conflict-warning-text'); const setEnableCheckbox = async (isEnabled = true) => findEnableCheckbox().vm.$emit('input', isEnabled); + const assertProjectKeyState = (expectedStateValue) => { + expect(findProjectKey().attributes('state')).toBe(expectedStateValue); + expect(findProjectKeyFormGroup().attributes('state')).toBe(expectedStateValue); + }; + describe('template', () => { describe.each` showJiraIssuesIntegration | showJiraVulnerabilitiesIntegration @@ -151,19 +166,18 @@ describe('JiraIssuesFields', () => { }); describe('GitLab issues warning', () => { - const expectedText = 'Consider disabling GitLab issues'; - - it('contains warning when GitLab issues is enabled', () => { - createComponent(); - - expect(wrapper.text()).toContain(expectedText); - }); - - it('does not contain warning when GitLab issues is disabled', () => { - createComponent({ props: { gitlabIssuesEnabled: false } }); - - expect(wrapper.text()).not.toContain(expectedText); - }); + it.each` + gitlabIssuesEnabled | scenario + ${true} | ${'displays conflict warning'} + ${false} | ${'does not display conflict warning'} + `( + '$scenario when `gitlabIssuesEnabled` is `$gitlabIssuesEnabled`', + ({ gitlabIssuesEnabled }) => { + createComponent({ props: { gitlabIssuesEnabled } }); + + expect(findConflictWarning().exists()).toBe(gitlabIssuesEnabled); + }, + ); }); describe('Vulnerabilities creation', () => { @@ -211,5 +225,44 @@ describe('JiraIssuesFields', () => { expect(eventHubEmitSpy).toHaveBeenCalledWith(GET_JIRA_ISSUE_TYPES_EVENT); }); }); + + describe('Project key input field', () => { + beforeEach(() => { + createComponent({ + props: { + initialProjectKey: '', + initialEnableJiraIssues: true, + }, + mountFn: shallowMountExtended, + }); + }); + + it('sets Project Key `state` attribute to `true` by default', () => { + assertProjectKeyState('true'); + }); + + describe('when event hub recieves `VALIDATE_INTEGRATION_FORM_EVENT` event', () => { + describe('with no project key', () => { + it('sets Project Key `state` attribute to `undefined`', async () => { + eventHub.$emit(VALIDATE_INTEGRATION_FORM_EVENT); + await wrapper.vm.$nextTick(); + + assertProjectKeyState(undefined); + }); + }); + + describe('when project key is set', () => { + it('sets Project Key `state` attribute to `true`', async () => { + eventHub.$emit(VALIDATE_INTEGRATION_FORM_EVENT); + + // set the project key + await findProjectKey().vm.$emit('input', 'AB'); + await wrapper.vm.$nextTick(); + + assertProjectKeyState('true'); + }); + }); + }); + }); }); }); diff --git a/spec/frontend/integrations/integration_settings_form_spec.js b/spec/frontend/integrations/integration_settings_form_spec.js index f8f3f0fd318..c35d178e518 100644 --- a/spec/frontend/integrations/integration_settings_form_spec.js +++ b/spec/frontend/integrations/integration_settings_form_spec.js @@ -1,27 +1,38 @@ import MockAdaptor from 'axios-mock-adapter'; import IntegrationSettingsForm from '~/integrations/integration_settings_form'; +import eventHub from '~/integrations/edit/event_hub'; import axios from '~/lib/utils/axios_utils'; import toast from '~/vue_shared/plugins/global_toast'; +import { + I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE, + I18N_SUCCESSFUL_CONNECTION_MESSAGE, + I18N_DEFAULT_ERROR_MESSAGE, + GET_JIRA_ISSUE_TYPES_EVENT, + TOGGLE_INTEGRATION_EVENT, + TEST_INTEGRATION_EVENT, + SAVE_INTEGRATION_EVENT, +} from '~/integrations/constants'; +import waitForPromises from 'helpers/wait_for_promises'; jest.mock('~/vue_shared/plugins/global_toast'); +jest.mock('lodash/delay', () => (callback) => callback()); + +const FIXTURE = 'services/edit_service.html'; describe('IntegrationSettingsForm', () => { - const FIXTURE = 'services/edit_service.html'; + let integrationSettingsForm; + + const mockStoreDispatch = () => jest.spyOn(integrationSettingsForm.vue.$store, 'dispatch'); beforeEach(() => { loadFixtures(FIXTURE); + + integrationSettingsForm = new IntegrationSettingsForm('.js-integration-settings-form'); + integrationSettingsForm.init(); }); describe('constructor', () => { - let integrationSettingsForm; - - beforeEach(() => { - integrationSettingsForm = new IntegrationSettingsForm('.js-integration-settings-form'); - jest.spyOn(integrationSettingsForm, 'init').mockImplementation(() => {}); - }); - it('should initialize form element refs on class object', () => { - // Form Reference expect(integrationSettingsForm.$form).toBeDefined(); expect(integrationSettingsForm.$form.nodeName).toBe('FORM'); expect(integrationSettingsForm.formActive).toBeDefined(); @@ -32,180 +43,206 @@ describe('IntegrationSettingsForm', () => { }); }); - describe('toggleServiceState', () => { - let integrationSettingsForm; + describe('event handling', () => { + let mockAxios; beforeEach(() => { - integrationSettingsForm = new IntegrationSettingsForm('.js-integration-settings-form'); - }); - - it('should remove `novalidate` attribute to form when called with `true`', () => { - integrationSettingsForm.formActive = true; - integrationSettingsForm.toggleServiceState(); - - expect(integrationSettingsForm.$form.getAttribute('novalidate')).toBe(null); - }); - - it('should set `novalidate` attribute to form when called with `false`', () => { - integrationSettingsForm.formActive = false; - integrationSettingsForm.toggleServiceState(); - - expect(integrationSettingsForm.$form.getAttribute('novalidate')).toBeDefined(); - }); - }); - - describe('testSettings', () => { - let integrationSettingsForm; - let formData; - let mock; - - beforeEach(() => { - mock = new MockAdaptor(axios); - + mockAxios = new MockAdaptor(axios); jest.spyOn(axios, 'put'); - - integrationSettingsForm = new IntegrationSettingsForm('.js-integration-settings-form'); - integrationSettingsForm.init(); - - formData = new FormData(integrationSettingsForm.$form); }); afterEach(() => { - mock.restore(); + mockAxios.restore(); + eventHub.dispose(); // clear event hub handlers }); - it('should make an ajax request with provided `formData`', async () => { - await integrationSettingsForm.testSettings(formData); + describe('when event hub receives `TOGGLE_INTEGRATION_EVENT`', () => { + it('should remove `novalidate` attribute to form when called with `true`', () => { + eventHub.$emit(TOGGLE_INTEGRATION_EVENT, true); - expect(axios.put).toHaveBeenCalledWith(integrationSettingsForm.testEndPoint, formData); - }); + expect(integrationSettingsForm.$form.getAttribute('novalidate')).toBe(null); + }); - it('should show success message if test is successful', async () => { - jest.spyOn(integrationSettingsForm.$form, 'submit').mockImplementation(() => {}); + it('should set `novalidate` attribute to form when called with `false`', () => { + eventHub.$emit(TOGGLE_INTEGRATION_EVENT, false); - mock.onPut(integrationSettingsForm.testEndPoint).reply(200, { - error: false, + expect(integrationSettingsForm.$form.getAttribute('novalidate')).toBe('novalidate'); }); + }); - await integrationSettingsForm.testSettings(formData); + describe('when event hub receives `TEST_INTEGRATION_EVENT`', () => { + describe('when form is valid', () => { + beforeEach(() => { + jest.spyOn(integrationSettingsForm.$form, 'checkValidity').mockReturnValue(true); + }); - expect(toast).toHaveBeenCalledWith('Connection successful.'); - }); + it('should make an ajax request with provided `formData`', async () => { + eventHub.$emit(TEST_INTEGRATION_EVENT); + await waitForPromises(); - it('should show error message if ajax request responds with test error', async () => { - const errorMessage = 'Test failed.'; - const serviceResponse = 'some error'; + expect(axios.put).toHaveBeenCalledWith( + integrationSettingsForm.testEndPoint, + new FormData(integrationSettingsForm.$form), + ); + }); - mock.onPut(integrationSettingsForm.testEndPoint).reply(200, { - error: true, - message: errorMessage, - service_response: serviceResponse, - test_failed: false, - }); + it('should show success message if test is successful', async () => { + jest.spyOn(integrationSettingsForm.$form, 'submit').mockImplementation(() => {}); - await integrationSettingsForm.testSettings(formData); + mockAxios.onPut(integrationSettingsForm.testEndPoint).reply(200, { + error: false, + }); - expect(toast).toHaveBeenCalledWith(`${errorMessage} ${serviceResponse}`); - }); + eventHub.$emit(TEST_INTEGRATION_EVENT); + await waitForPromises(); - it('should show error message if ajax request failed', async () => { - const errorMessage = 'Something went wrong on our end.'; + expect(toast).toHaveBeenCalledWith(I18N_SUCCESSFUL_CONNECTION_MESSAGE); + }); - mock.onPut(integrationSettingsForm.testEndPoint).networkError(); + it('should show error message if ajax request responds with test error', async () => { + const errorMessage = 'Test failed.'; + const serviceResponse = 'some error'; - await integrationSettingsForm.testSettings(formData); + mockAxios.onPut(integrationSettingsForm.testEndPoint).reply(200, { + error: true, + message: errorMessage, + service_response: serviceResponse, + test_failed: false, + }); - expect(toast).toHaveBeenCalledWith(errorMessage); - }); + eventHub.$emit(TEST_INTEGRATION_EVENT); + await waitForPromises(); - it('should always dispatch `setIsTesting` with `false` once request is completed', async () => { - const dispatchSpy = jest.fn(); + expect(toast).toHaveBeenCalledWith(`${errorMessage} ${serviceResponse}`); + }); - mock.onPut(integrationSettingsForm.testEndPoint).networkError(); + it('should show error message if ajax request failed', async () => { + mockAxios.onPut(integrationSettingsForm.testEndPoint).networkError(); - integrationSettingsForm.vue.$store = { dispatch: dispatchSpy }; + eventHub.$emit(TEST_INTEGRATION_EVENT); + await waitForPromises(); - await integrationSettingsForm.testSettings(formData); + expect(toast).toHaveBeenCalledWith(I18N_DEFAULT_ERROR_MESSAGE); + }); - expect(dispatchSpy).toHaveBeenCalledWith('setIsTesting', false); - }); - }); + it('should always dispatch `setIsTesting` with `false` once request is completed', async () => { + const dispatchSpy = mockStoreDispatch(); + mockAxios.onPut(integrationSettingsForm.testEndPoint).networkError(); - describe('getJiraIssueTypes', () => { - let integrationSettingsForm; - let formData; - let mock; + eventHub.$emit(TEST_INTEGRATION_EVENT); + await waitForPromises(); - beforeEach(() => { - mock = new MockAdaptor(axios); + expect(dispatchSpy).toHaveBeenCalledWith('setIsTesting', false); + }); + }); - jest.spyOn(axios, 'put'); + describe('when form is invalid', () => { + beforeEach(() => { + jest.spyOn(integrationSettingsForm.$form, 'checkValidity').mockReturnValue(false); + jest.spyOn(integrationSettingsForm, 'testSettings'); + }); - integrationSettingsForm = new IntegrationSettingsForm('.js-integration-settings-form'); - integrationSettingsForm.init(); + it('should dispatch `setIsTesting` with `false` and not call `testSettings`', async () => { + const dispatchSpy = mockStoreDispatch(); - formData = new FormData(integrationSettingsForm.$form); - }); + eventHub.$emit(TEST_INTEGRATION_EVENT); + await waitForPromises(); - afterEach(() => { - mock.restore(); + expect(dispatchSpy).toHaveBeenCalledWith('setIsTesting', false); + expect(integrationSettingsForm.testSettings).not.toHaveBeenCalled(); + }); + }); }); - it('should always dispatch `requestJiraIssueTypes`', async () => { - const dispatchSpy = jest.fn(); - - mock.onPut(integrationSettingsForm.testEndPoint).networkError(); + describe('when event hub receives `GET_JIRA_ISSUE_TYPES_EVENT`', () => { + it('should always dispatch `requestJiraIssueTypes`', () => { + const dispatchSpy = mockStoreDispatch(); + mockAxios.onPut(integrationSettingsForm.testEndPoint).networkError(); - integrationSettingsForm.vue.$store = { dispatch: dispatchSpy }; + eventHub.$emit(GET_JIRA_ISSUE_TYPES_EVENT); - await integrationSettingsForm.getJiraIssueTypes(); + expect(dispatchSpy).toHaveBeenCalledWith('requestJiraIssueTypes'); + }); - expect(dispatchSpy).toHaveBeenCalledWith('requestJiraIssueTypes'); - }); + it('should make an ajax request with provided `formData`', () => { + eventHub.$emit(GET_JIRA_ISSUE_TYPES_EVENT); - it('should make an ajax request with provided `formData`', async () => { - await integrationSettingsForm.getJiraIssueTypes(formData); + expect(axios.put).toHaveBeenCalledWith( + integrationSettingsForm.testEndPoint, + new FormData(integrationSettingsForm.$form), + ); + }); - expect(axios.put).toHaveBeenCalledWith(integrationSettingsForm.testEndPoint, formData); - }); + it('should dispatch `receiveJiraIssueTypesSuccess` with the correct payload if ajax request is successful', async () => { + const dispatchSpy = mockStoreDispatch(); + const mockData = ['ISSUE', 'EPIC']; + mockAxios.onPut(integrationSettingsForm.testEndPoint).reply(200, { + error: false, + issuetypes: mockData, + }); - it('should dispatch `receiveJiraIssueTypesSuccess` with the correct payload if ajax request is successful', async () => { - const mockData = ['ISSUE', 'EPIC']; - const dispatchSpy = jest.fn(); + eventHub.$emit(GET_JIRA_ISSUE_TYPES_EVENT); + await waitForPromises(); - mock.onPut(integrationSettingsForm.testEndPoint).reply(200, { - error: false, - issuetypes: mockData, + expect(dispatchSpy).toHaveBeenCalledWith('receiveJiraIssueTypesSuccess', mockData); }); - integrationSettingsForm.vue.$store = { dispatch: dispatchSpy }; - - await integrationSettingsForm.getJiraIssueTypes(formData); + it.each(['Custom error message here', undefined])( + 'should dispatch "receiveJiraIssueTypesError" with a message if the backend responds with error', + async (responseErrorMessage) => { + const dispatchSpy = mockStoreDispatch(); + + const expectedErrorMessage = + responseErrorMessage || I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE; + mockAxios.onPut(integrationSettingsForm.testEndPoint).reply(200, { + error: true, + message: responseErrorMessage, + }); + + eventHub.$emit(GET_JIRA_ISSUE_TYPES_EVENT); + await waitForPromises(); + + expect(dispatchSpy).toHaveBeenCalledWith( + 'receiveJiraIssueTypesError', + expectedErrorMessage, + ); + }, + ); + }); + + describe('when event hub receives `SAVE_INTEGRATION_EVENT`', () => { + describe('when form is valid', () => { + beforeEach(() => { + jest.spyOn(integrationSettingsForm.$form, 'checkValidity').mockReturnValue(true); + jest.spyOn(integrationSettingsForm.$form, 'submit'); + }); - expect(dispatchSpy).toHaveBeenCalledWith('receiveJiraIssueTypesSuccess', mockData); - }); + it('should submit the form', async () => { + eventHub.$emit(SAVE_INTEGRATION_EVENT); + await waitForPromises(); - it.each(['something went wrong', undefined])( - 'should dispatch "receiveJiraIssueTypesError" with a message if the backend responds with error', - async (responseErrorMessage) => { - const defaultErrorMessage = 'Connection failed. Please check your settings.'; - const expectedErrorMessage = responseErrorMessage || defaultErrorMessage; - const dispatchSpy = jest.fn(); + expect(integrationSettingsForm.$form.submit).toHaveBeenCalled(); + expect(integrationSettingsForm.$form.submit).toHaveBeenCalledTimes(1); + }); + }); - mock.onPut(integrationSettingsForm.testEndPoint).reply(200, { - error: true, - message: responseErrorMessage, + describe('when form is invalid', () => { + beforeEach(() => { + jest.spyOn(integrationSettingsForm.$form, 'checkValidity').mockReturnValue(false); + jest.spyOn(integrationSettingsForm.$form, 'submit'); }); - integrationSettingsForm.vue.$store = { dispatch: dispatchSpy }; + it('should dispatch `setIsSaving` with `false` and not submit form', async () => { + const dispatchSpy = mockStoreDispatch(); - await integrationSettingsForm.getJiraIssueTypes(formData); + eventHub.$emit(SAVE_INTEGRATION_EVENT); - expect(dispatchSpy).toHaveBeenCalledWith( - 'receiveJiraIssueTypesError', - expectedErrorMessage, - ); - }, - ); + await waitForPromises(); + + expect(dispatchSpy).toHaveBeenCalledWith('setIsSaving', false); + expect(integrationSettingsForm.$form.submit).not.toHaveBeenCalled(); + }); + }); + }); }); }); |