Commit 9c59b0e2 authored by Ezekiel Kigbo's avatar Ezekiel Kigbo

Merge branch '342121-move-remaining-events-to-vue-components' into 'master'

Move "test settings" code from integration_settings_form.js to Vue component

See merge request gitlab-org/gitlab!76291
parents 9709e437 aaa16315
import { s__, __ } from '~/locale'; import { s__, __ } from '~/locale';
export const TEST_INTEGRATION_EVENT = 'testIntegration';
export const SAVE_INTEGRATION_EVENT = 'saveIntegration'; export const SAVE_INTEGRATION_EVENT = 'saveIntegration';
export const VALIDATE_INTEGRATION_FORM_EVENT = 'validateIntegrationForm'; export const VALIDATE_INTEGRATION_FORM_EVENT = 'validateIntegrationForm';
......
<script> <script>
import { GlButton, GlModalDirective, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui'; import { GlButton, GlModalDirective, GlSafeHtmlDirective as SafeHtml } from '@gitlab/ui';
import * as Sentry from '@sentry/browser';
import { mapState, mapActions, mapGetters } from 'vuex'; import { mapState, mapActions, mapGetters } from 'vuex';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin'; import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import { import {
TEST_INTEGRATION_EVENT,
SAVE_INTEGRATION_EVENT, SAVE_INTEGRATION_EVENT,
VALIDATE_INTEGRATION_FORM_EVENT,
I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE,
I18N_DEFAULT_ERROR_MESSAGE,
I18N_SUCCESSFUL_CONNECTION_MESSAGE,
integrationLevels, integrationLevels,
} from '~/integrations/constants'; } from '~/integrations/constants';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import { testIntegrationSettings } from '../api';
import ActiveCheckbox from './active_checkbox.vue'; import ActiveCheckbox from './active_checkbox.vue';
import ConfirmationModal from './confirmation_modal.vue'; import ConfirmationModal from './confirmation_modal.vue';
import DynamicField from './dynamic_field.vue'; import DynamicField from './dynamic_field.vue';
...@@ -50,18 +54,12 @@ export default { ...@@ -50,18 +54,12 @@ export default {
data() { data() {
return { return {
integrationActive: false, integrationActive: false,
testingLoading: false,
}; };
}, },
computed: { computed: {
...mapGetters(['currentKey', 'propsSource', 'isDisabled']), ...mapGetters(['currentKey', 'propsSource', 'isDisabled']),
...mapState([ ...mapState(['defaultState', 'customState', 'override', 'isSaving', 'isResetting']),
'defaultState',
'customState',
'override',
'isSaving',
'isTesting',
'isResetting',
]),
isEditable() { isEditable() {
return this.propsSource.editable; return this.propsSource.editable;
}, },
...@@ -74,9 +72,18 @@ export default { ...@@ -74,9 +72,18 @@ export default {
this.customState.integrationLevel === integrationLevels.GROUP this.customState.integrationLevel === integrationLevels.GROUP
); );
}, },
showReset() { showResetButton() {
return this.isInstanceOrGroupLevel && this.propsSource.resetPath; return this.isInstanceOrGroupLevel && this.propsSource.resetPath;
}, },
showTestButton() {
return this.propsSource.canTest;
},
disableSaveButton() {
return Boolean(this.isResetting || this.testingLoading);
},
disableResetButton() {
return Boolean(this.isSaving || this.testingLoading);
},
}, },
mounted() { mounted() {
// this form element is defined in Haml // this form element is defined in Haml
...@@ -86,7 +93,6 @@ export default { ...@@ -86,7 +93,6 @@ export default {
...mapActions([ ...mapActions([
'setOverride', 'setOverride',
'setIsSaving', 'setIsSaving',
'setIsTesting',
'setIsResetting', 'setIsResetting',
'fetchResetIntegration', 'fetchResetIntegration',
'requestJiraIssueTypes', 'requestJiraIssueTypes',
...@@ -98,17 +104,39 @@ export default { ...@@ -98,17 +104,39 @@ export default {
eventHub.$emit(SAVE_INTEGRATION_EVENT, formValid); eventHub.$emit(SAVE_INTEGRATION_EVENT, formValid);
}, },
onTestClick() { onTestClick() {
this.setIsTesting(true); this.testingLoading = true;
const formValid = this.form.checkValidity(); if (!this.form.checkValidity()) {
eventHub.$emit(TEST_INTEGRATION_EVENT, formValid); eventHub.$emit(VALIDATE_INTEGRATION_FORM_EVENT);
return;
}
testIntegrationSettings(this.propsSource.testPath, this.getFormData())
.then(({ data: { error, message = I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE } }) => {
if (error) {
eventHub.$emit(VALIDATE_INTEGRATION_FORM_EVENT);
this.$toast.show(message);
return;
}
this.$toast.show(I18N_SUCCESSFUL_CONNECTION_MESSAGE);
})
.catch((error) => {
this.$toast.show(I18N_DEFAULT_ERROR_MESSAGE);
Sentry.captureException(error);
})
.finally(() => {
this.testingLoading = false;
});
}, },
onResetClick() { onResetClick() {
this.fetchResetIntegration(); this.fetchResetIntegration();
}, },
onRequestJiraIssueTypes() { onRequestJiraIssueTypes() {
const formData = new FormData(this.form); this.requestJiraIssueTypes(this.getFormData());
this.requestJiraIssueTypes(formData); },
getFormData() {
return new FormData(this.form);
}, },
onToggleIntegrationState(integrationActive) { onToggleIntegrationState(integrationActive) {
this.integrationActive = integrationActive; this.integrationActive = integrationActive;
...@@ -183,7 +211,7 @@ export default { ...@@ -183,7 +211,7 @@ export default {
category="primary" category="primary"
variant="confirm" variant="confirm"
:loading="isSaving" :loading="isSaving"
:disabled="isDisabled" :disabled="disableSaveButton"
data-qa-selector="save_changes_button" data-qa-selector="save_changes_button"
> >
{{ __('Save changes') }} {{ __('Save changes') }}
...@@ -196,7 +224,7 @@ export default { ...@@ -196,7 +224,7 @@ export default {
variant="confirm" variant="confirm"
type="submit" type="submit"
:loading="isSaving" :loading="isSaving"
:disabled="isDisabled" :disabled="disableSaveButton"
data-testid="save-button" data-testid="save-button"
data-qa-selector="save_changes_button" data-qa-selector="save_changes_button"
@click.prevent="onSaveClick" @click.prevent="onSaveClick"
...@@ -205,25 +233,24 @@ export default { ...@@ -205,25 +233,24 @@ export default {
</gl-button> </gl-button>
<gl-button <gl-button
v-if="propsSource.canTest" v-if="showTestButton"
category="secondary" category="secondary"
variant="confirm" variant="confirm"
:loading="isTesting" :loading="testingLoading"
:disabled="isDisabled" :disabled="isDisabled"
:href="propsSource.testPath"
data-testid="test-button" data-testid="test-button"
@click.prevent="onTestClick" @click.prevent="onTestClick"
> >
{{ __('Test settings') }} {{ __('Test settings') }}
</gl-button> </gl-button>
<template v-if="showReset"> <template v-if="showResetButton">
<gl-button <gl-button
v-gl-modal.confirmResetIntegration v-gl-modal.confirmResetIntegration
category="secondary" category="secondary"
variant="confirm" variant="confirm"
:loading="isResetting" :loading="isResetting"
:disabled="isDisabled" :disabled="disableResetButton"
data-testid="reset-button" data-testid="reset-button"
> >
{{ __('Reset') }} {{ __('Reset') }}
......
...@@ -11,7 +11,6 @@ import * as types from './mutation_types'; ...@@ -11,7 +11,6 @@ import * as types from './mutation_types';
export const setOverride = ({ commit }, override) => commit(types.SET_OVERRIDE, override); export const setOverride = ({ commit }, override) => commit(types.SET_OVERRIDE, override);
export const setIsSaving = ({ commit }, isSaving) => commit(types.SET_IS_SAVING, isSaving); export const setIsSaving = ({ commit }, isSaving) => commit(types.SET_IS_SAVING, isSaving);
export const setIsTesting = ({ commit }, isTesting) => commit(types.SET_IS_TESTING, isTesting);
export const setIsResetting = ({ commit }, isResetting) => export const setIsResetting = ({ commit }, isResetting) =>
commit(types.SET_IS_RESETTING, isResetting); commit(types.SET_IS_RESETTING, isResetting);
......
export const isInheriting = (state) => (state.defaultState === null ? false : !state.override); export const isInheriting = (state) => (state.defaultState === null ? false : !state.override);
export const isDisabled = (state) => state.isSaving || state.isTesting || state.isResetting; export const isDisabled = (state) => state.isSaving || state.isResetting;
export const propsSource = (state, getters) => export const propsSource = (state, getters) =>
getters.isInheriting ? state.defaultState : state.customState; getters.isInheriting ? state.defaultState : state.customState;
......
export const SET_OVERRIDE = 'SET_OVERRIDE'; export const SET_OVERRIDE = 'SET_OVERRIDE';
export const SET_IS_SAVING = 'SET_IS_SAVING'; export const SET_IS_SAVING = 'SET_IS_SAVING';
export const SET_IS_TESTING = 'SET_IS_TESTING';
export const SET_IS_RESETTING = 'SET_IS_RESETTING'; export const SET_IS_RESETTING = 'SET_IS_RESETTING';
export const SET_IS_LOADING_JIRA_ISSUE_TYPES = 'SET_IS_LOADING_JIRA_ISSUE_TYPES'; export const SET_IS_LOADING_JIRA_ISSUE_TYPES = 'SET_IS_LOADING_JIRA_ISSUE_TYPES';
......
...@@ -7,9 +7,6 @@ export default { ...@@ -7,9 +7,6 @@ export default {
[types.SET_IS_SAVING](state, isSaving) { [types.SET_IS_SAVING](state, isSaving) {
state.isSaving = isSaving; state.isSaving = isSaving;
}, },
[types.SET_IS_TESTING](state, isTesting) {
state.isTesting = isTesting;
},
[types.SET_IS_RESETTING](state, isResetting) { [types.SET_IS_RESETTING](state, isResetting) {
state.isResetting = isResetting; state.isResetting = isResetting;
}, },
......
...@@ -6,7 +6,6 @@ export default ({ defaultState = null, customState = {} } = {}) => { ...@@ -6,7 +6,6 @@ export default ({ defaultState = null, customState = {} } = {}) => {
defaultState, defaultState,
customState, customState,
isSaving: false, isSaving: false,
isTesting: false,
isResetting: false, isResetting: false,
isLoadingJiraIssueTypes: false, isLoadingJiraIssueTypes: false,
loadingJiraIssueTypesErrorMessage: '', loadingJiraIssueTypesErrorMessage: '',
......
import { delay } from 'lodash'; import { delay } from 'lodash';
import toast from '~/vue_shared/plugins/global_toast';
import initForm from './edit'; import initForm from './edit';
import eventHub from './edit/event_hub'; import eventHub from './edit/event_hub';
import { import { SAVE_INTEGRATION_EVENT, VALIDATE_INTEGRATION_FORM_EVENT } from './constants';
TEST_INTEGRATION_EVENT,
SAVE_INTEGRATION_EVENT,
VALIDATE_INTEGRATION_FORM_EVENT,
I18N_DEFAULT_ERROR_MESSAGE,
I18N_SUCCESSFUL_CONNECTION_MESSAGE,
} from './constants';
import { testIntegrationSettings } from './edit/api';
export default class IntegrationSettingsForm { export default class IntegrationSettingsForm {
constructor(formSelector) { constructor(formSelector) {
...@@ -29,9 +21,6 @@ export default class IntegrationSettingsForm { ...@@ -29,9 +21,6 @@ export default class IntegrationSettingsForm {
document.querySelector('.js-vue-default-integration-settings'), document.querySelector('.js-vue-default-integration-settings'),
this.formSelector, this.formSelector,
); );
eventHub.$on(TEST_INTEGRATION_EVENT, (formValid) => {
this.testIntegration(formValid);
});
eventHub.$on(SAVE_INTEGRATION_EVENT, (formValid) => { eventHub.$on(SAVE_INTEGRATION_EVENT, (formValid) => {
this.saveIntegration(formValid); this.saveIntegration(formValid);
}); });
...@@ -53,47 +42,4 @@ export default class IntegrationSettingsForm { ...@@ -53,47 +42,4 @@ export default class IntegrationSettingsForm {
this.vue.$store.dispatch('setIsSaving', false); this.vue.$store.dispatch('setIsSaving', false);
} }
} }
testIntegration(formValid) {
// Service was marked active so now we check;
// 1) If form contents are valid
// 2) If this service can be tested
// If both conditions are true, we override form submission
// and test the service using provided configuration.
if (formValid) {
this.testSettings(new FormData(this.$form));
} else {
eventHub.$emit(VALIDATE_INTEGRATION_FORM_EVENT);
this.vue.$store.dispatch('setIsTesting', false);
}
}
/**
* Get a list of Jira issue types for the currently configured project
*
* @param {string} formData - URL encoded string containing the form data
*
* @return {Promise}
*/
/**
* Test Integration config
*/
testSettings(formData) {
return testIntegrationSettings(this.testEndPoint, formData)
.then(({ data }) => {
if (data.error) {
toast(`${data.message} ${data.service_response}`);
} else {
this.vue.$store.dispatch('receiveJiraIssueTypesSuccess', data.issuetypes);
toast(I18N_SUCCESSFUL_CONNECTION_MESSAGE);
}
})
.catch(() => {
toast(I18N_DEFAULT_ERROR_MESSAGE);
})
.finally(() => {
this.vue.$store.dispatch('setIsTesting', false);
});
}
} }
...@@ -81,12 +81,7 @@ export default { ...@@ -81,12 +81,7 @@ export default {
}, },
computed: { computed: {
...mapGetters(['isInheriting']), ...mapGetters(['isInheriting']),
...mapState([ ...mapState(['jiraIssueTypes', 'isLoadingJiraIssueTypes', 'loadingJiraIssueTypesErrorMessage']),
'isTesting',
'jiraIssueTypes',
'isLoadingJiraIssueTypes',
'loadingJiraIssueTypesErrorMessage',
]),
checkboxDisabled() { checkboxDisabled() {
return !this.showFullFeature || this.isInheriting; return !this.showFullFeature || this.isInheriting;
}, },
...@@ -180,7 +175,7 @@ export default { ...@@ -180,7 +175,7 @@ export default {
<gl-dropdown <gl-dropdown
class="gl-w-full" class="gl-w-full"
:disabled="!jiraIssueTypes.length" :disabled="!jiraIssueTypes.length"
:loading="isLoadingJiraIssueTypes || isTesting" :loading="isLoadingJiraIssueTypes"
:text="checkedIssueType.name || $options.i18n.issueTypeSelect.defaultText" :text="checkedIssueType.name || $options.i18n.issueTypeSelect.defaultText"
> >
<gl-dropdown-item <gl-dropdown-item
......
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import * as Sentry from '@sentry/browser';
import { setHTMLFixture } from 'helpers/fixtures'; import { setHTMLFixture } from 'helpers/fixtures';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { mockIntegrationProps } from 'jest/integrations/edit/mock_data'; import { mockIntegrationProps } from 'jest/integrations/edit/mock_data';
import ActiveCheckbox from '~/integrations/edit/components/active_checkbox.vue'; import ActiveCheckbox from '~/integrations/edit/components/active_checkbox.vue';
import ConfirmationModal from '~/integrations/edit/components/confirmation_modal.vue'; import ConfirmationModal from '~/integrations/edit/components/confirmation_modal.vue';
...@@ -11,19 +13,27 @@ import JiraTriggerFields from '~/integrations/edit/components/jira_trigger_field ...@@ -11,19 +13,27 @@ import JiraTriggerFields from '~/integrations/edit/components/jira_trigger_field
import OverrideDropdown from '~/integrations/edit/components/override_dropdown.vue'; import OverrideDropdown from '~/integrations/edit/components/override_dropdown.vue';
import ResetConfirmationModal from '~/integrations/edit/components/reset_confirmation_modal.vue'; import ResetConfirmationModal from '~/integrations/edit/components/reset_confirmation_modal.vue';
import TriggerFields from '~/integrations/edit/components/trigger_fields.vue'; import TriggerFields from '~/integrations/edit/components/trigger_fields.vue';
import waitForPromises from 'helpers/wait_for_promises';
import { import {
integrationLevels, integrationLevels,
TEST_INTEGRATION_EVENT, I18N_SUCCESSFUL_CONNECTION_MESSAGE,
VALIDATE_INTEGRATION_FORM_EVENT,
SAVE_INTEGRATION_EVENT, SAVE_INTEGRATION_EVENT,
I18N_DEFAULT_ERROR_MESSAGE,
} from '~/integrations/constants'; } from '~/integrations/constants';
import { createStore } from '~/integrations/edit/store'; import { createStore } from '~/integrations/edit/store';
import eventHub from '~/integrations/edit/event_hub'; import eventHub from '~/integrations/edit/event_hub';
import httpStatus from '~/lib/utils/http_status';
jest.mock('~/integrations/edit/event_hub'); jest.mock('~/integrations/edit/event_hub');
jest.mock('@sentry/browser');
describe('IntegrationForm', () => { describe('IntegrationForm', () => {
const mockToastShow = jest.fn();
let wrapper; let wrapper;
let dispatch; let dispatch;
let mockAxios;
const createComponent = ({ const createComponent = ({
customStateProps = {}, customStateProps = {},
...@@ -39,6 +49,9 @@ describe('IntegrationForm', () => { ...@@ -39,6 +49,9 @@ describe('IntegrationForm', () => {
wrapper = shallowMountExtended(IntegrationForm, { wrapper = shallowMountExtended(IntegrationForm, {
propsData: { ...props, formSelector: '.test' }, propsData: { ...props, formSelector: '.test' },
provide: {
glFeatures: featureFlags,
},
store, store,
stubs: { stubs: {
OverrideDropdown, OverrideDropdown,
...@@ -47,15 +60,21 @@ describe('IntegrationForm', () => { ...@@ -47,15 +60,21 @@ describe('IntegrationForm', () => {
JiraTriggerFields, JiraTriggerFields,
TriggerFields, TriggerFields,
}, },
provide: { mocks: {
glFeatures: featureFlags, $toast: {
show: mockToastShow,
},
}, },
}); });
}; };
afterEach(() => { const createForm = ({ isValid = true } = {}) => {
wrapper.destroy(); const mockForm = document.createElement('form');
}); jest.spyOn(document, 'querySelector').mockReturnValue(mockForm);
jest.spyOn(mockForm, 'checkValidity').mockReturnValue(isValid);
return mockForm;
};
const findOverrideDropdown = () => wrapper.findComponent(OverrideDropdown); const findOverrideDropdown = () => wrapper.findComponent(OverrideDropdown);
const findActiveCheckbox = () => wrapper.findComponent(ActiveCheckbox); const findActiveCheckbox = () => wrapper.findComponent(ActiveCheckbox);
...@@ -68,6 +87,15 @@ describe('IntegrationForm', () => { ...@@ -68,6 +87,15 @@ describe('IntegrationForm', () => {
const findJiraIssuesFields = () => wrapper.findComponent(JiraIssuesFields); const findJiraIssuesFields = () => wrapper.findComponent(JiraIssuesFields);
const findTriggerFields = () => wrapper.findComponent(TriggerFields); const findTriggerFields = () => wrapper.findComponent(TriggerFields);
beforeEach(() => {
mockAxios = new MockAdapter(axios);
});
afterEach(() => {
wrapper.destroy();
mockAxios.restore();
});
describe('template', () => { describe('template', () => {
describe('integrationLevel is instance', () => { describe('integrationLevel is instance', () => {
it('renders ConfirmationModal', () => { it('renders ConfirmationModal', () => {
...@@ -399,18 +427,9 @@ describe('IntegrationForm', () => { ...@@ -399,18 +427,9 @@ describe('IntegrationForm', () => {
}); });
describe('when `test` button is clicked', () => { describe('when `test` button is clicked', () => {
let mockForm; describe('when form is invalid', () => {
it('emits `VALIDATE_INTEGRATION_FORM_EVENT` event to the event hub', () => {
describe.each` createForm({ isValid: false });
formValid
${true}
${false}
`('when form checkValidity returns $formValid', ({ formValid }) => {
beforeEach(() => {
mockForm = document.createElement('form');
jest.spyOn(document, 'querySelector').mockReturnValue(mockForm);
jest.spyOn(mockForm, 'checkValidity').mockReturnValue(formValid);
createComponent({ createComponent({
customStateProps: { customStateProps: {
showActive: true, showActive: true,
...@@ -419,14 +438,70 @@ describe('IntegrationForm', () => { ...@@ -419,14 +438,70 @@ describe('IntegrationForm', () => {
}); });
findTestButton().vm.$emit('click', new Event('click')); findTestButton().vm.$emit('click', new Event('click'));
expect(eventHub.$emit).toHaveBeenCalledWith(VALIDATE_INTEGRATION_FORM_EVENT);
}); });
});
describe('when form is valid', () => {
const mockTestPath = '/test';
it('dispatches setIsTesting action', () => { beforeEach(() => {
expect(dispatch).toHaveBeenCalledWith('setIsTesting', true); createForm({ isValid: true });
createComponent({
customStateProps: {
showActive: true,
canTest: true,
testPath: mockTestPath,
},
});
}); });
it(`emits \`TEST_INTEGRATION_EVENT\` event with payload \`${formValid}\``, () => { describe('buttons', () => {
expect(eventHub.$emit).toHaveBeenCalledWith(TEST_INTEGRATION_EVENT, formValid); beforeEach(async () => {
await findTestButton().vm.$emit('click', new Event('click'));
});
it('sets test button `loading` prop to `true`', () => {
expect(findTestButton().props('loading')).toBe(true);
});
it('sets save button `disabled` prop to `true`', () => {
expect(findSaveButton().props('disabled')).toBe(true);
});
});
describe.each`
scenario | replyStatus | errorMessage | expectToast | expectSentry
${'when "test settings" request fails'} | ${httpStatus.INTERNAL_SERVER_ERROR} | ${undefined} | ${I18N_DEFAULT_ERROR_MESSAGE} | ${true}
${'when "test settings" returns an error'} | ${httpStatus.OK} | ${'an error'} | ${'an error'} | ${false}
${'when "test settings" succeeds'} | ${httpStatus.OK} | ${undefined} | ${I18N_SUCCESSFUL_CONNECTION_MESSAGE} | ${false}
`('$scenario', ({ replyStatus, errorMessage, expectToast, expectSentry }) => {
beforeEach(async () => {
mockAxios.onPut(mockTestPath).replyOnce(replyStatus, {
error: Boolean(errorMessage),
message: errorMessage,
});
await findTestButton().vm.$emit('click', new Event('click'));
await waitForPromises();
});
it(`calls toast with '${expectToast}'`, () => {
expect(mockToastShow).toHaveBeenCalledWith(expectToast);
});
it('sets `loading` prop of test button to `false`', () => {
expect(findTestButton().props('loading')).toBe(false);
});
it('sets save button `disabled` prop to `false`', () => {
expect(findSaveButton().props('disabled')).toBe(false);
});
it(`${expectSentry ? 'does' : 'does not'} capture exception in Sentry`, () => {
expect(Sentry.captureException).toHaveBeenCalledTimes(expectSentry ? 1 : 0);
});
}); });
}); });
}); });
......
...@@ -5,7 +5,6 @@ import { I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE } from '~/integrations/c ...@@ -5,7 +5,6 @@ import { I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE } from '~/integrations/c
import { import {
setOverride, setOverride,
setIsSaving, setIsSaving,
setIsTesting,
setIsResetting, setIsResetting,
requestResetIntegration, requestResetIntegration,
receiveResetIntegrationSuccess, receiveResetIntegrationSuccess,
...@@ -46,12 +45,6 @@ describe('Integration form store actions', () => { ...@@ -46,12 +45,6 @@ describe('Integration form store actions', () => {
}); });
}); });
describe('setIsTesting', () => {
it('should commit isTesting mutation', () => {
return testAction(setIsTesting, true, state, [{ type: types.SET_IS_TESTING, payload: true }]);
});
});
describe('setIsResetting', () => { describe('setIsResetting', () => {
it('should commit isResetting mutation', () => { it('should commit isResetting mutation', () => {
return testAction(setIsResetting, true, state, [ return testAction(setIsResetting, true, state, [
......
...@@ -54,20 +54,15 @@ describe('Integration form store getters', () => { ...@@ -54,20 +54,15 @@ describe('Integration form store getters', () => {
describe('isDisabled', () => { describe('isDisabled', () => {
it.each` it.each`
isSaving | isTesting | isResetting | expected isSaving | isResetting | expected
${false} | ${false} | ${false} | ${false} ${false} | ${false} | ${false}
${true} | ${false} | ${false} | ${true} ${true} | ${false} | ${true}
${false} | ${true} | ${false} | ${true} ${false} | ${true} | ${true}
${false} | ${false} | ${true} | ${true} ${true} | ${true} | ${true}
${false} | ${true} | ${true} | ${true}
${true} | ${false} | ${true} | ${true}
${true} | ${true} | ${false} | ${true}
${true} | ${true} | ${true} | ${true}
`( `(
'when isSaving = $isSaving, isTesting = $isTesting, isResetting = $isResetting then isDisabled = $expected', 'when isSaving = $isSaving, isResetting = $isResetting then isDisabled = $expected',
({ isSaving, isTesting, isResetting, expected }) => { ({ isSaving, isResetting, expected }) => {
mutations[types.SET_IS_SAVING](state, isSaving); mutations[types.SET_IS_SAVING](state, isSaving);
mutations[types.SET_IS_TESTING](state, isTesting);
mutations[types.SET_IS_RESETTING](state, isResetting); mutations[types.SET_IS_RESETTING](state, isResetting);
expect(isDisabled(state)).toBe(expected); expect(isDisabled(state)).toBe(expected);
......
...@@ -25,14 +25,6 @@ describe('Integration form store mutations', () => { ...@@ -25,14 +25,6 @@ describe('Integration form store mutations', () => {
}); });
}); });
describe(`${types.SET_IS_TESTING}`, () => {
it('sets isTesting', () => {
mutations[types.SET_IS_TESTING](state, true);
expect(state.isTesting).toBe(true);
});
});
describe(`${types.SET_IS_RESETTING}`, () => { describe(`${types.SET_IS_RESETTING}`, () => {
it('sets isResetting', () => { it('sets isResetting', () => {
mutations[types.SET_IS_RESETTING](state, true); mutations[types.SET_IS_RESETTING](state, true);
......
...@@ -6,7 +6,6 @@ describe('Integration form state factory', () => { ...@@ -6,7 +6,6 @@ describe('Integration form state factory', () => {
defaultState: null, defaultState: null,
customState: {}, customState: {},
isSaving: false, isSaving: false,
isTesting: false,
isResetting: false, isResetting: false,
override: false, override: false,
isLoadingJiraIssueTypes: false, isLoadingJiraIssueTypes: false,
......
...@@ -2,13 +2,7 @@ import MockAdaptor from 'axios-mock-adapter'; ...@@ -2,13 +2,7 @@ import MockAdaptor from 'axios-mock-adapter';
import IntegrationSettingsForm from '~/integrations/integration_settings_form'; import IntegrationSettingsForm from '~/integrations/integration_settings_form';
import eventHub from '~/integrations/edit/event_hub'; import eventHub from '~/integrations/edit/event_hub';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import toast from '~/vue_shared/plugins/global_toast'; import { SAVE_INTEGRATION_EVENT } from '~/integrations/constants';
import {
I18N_SUCCESSFUL_CONNECTION_MESSAGE,
I18N_DEFAULT_ERROR_MESSAGE,
TEST_INTEGRATION_EVENT,
SAVE_INTEGRATION_EVENT,
} from '~/integrations/constants';
import waitForPromises from 'helpers/wait_for_promises'; import waitForPromises from 'helpers/wait_for_promises';
jest.mock('~/vue_shared/plugins/global_toast'); jest.mock('~/vue_shared/plugins/global_toast');
...@@ -29,6 +23,10 @@ describe('IntegrationSettingsForm', () => { ...@@ -29,6 +23,10 @@ describe('IntegrationSettingsForm', () => {
integrationSettingsForm.init(); integrationSettingsForm.init();
}); });
afterEach(() => {
eventHub.dispose(); // clear event hub handlers
});
describe('constructor', () => { describe('constructor', () => {
it('should initialize form element refs on class object', () => { it('should initialize form element refs on class object', () => {
expect(integrationSettingsForm.$form).toBeDefined(); expect(integrationSettingsForm.$form).toBeDefined();
...@@ -47,88 +45,11 @@ describe('IntegrationSettingsForm', () => { ...@@ -47,88 +45,11 @@ describe('IntegrationSettingsForm', () => {
beforeEach(() => { beforeEach(() => {
mockAxios = new MockAdaptor(axios); mockAxios = new MockAdaptor(axios);
jest.spyOn(axios, 'put'); jest.spyOn(axios, 'put');
jest.spyOn(integrationSettingsForm, 'testSettings');
jest.spyOn(integrationSettingsForm.$form, 'submit'); jest.spyOn(integrationSettingsForm.$form, 'submit');
}); });
afterEach(() => { afterEach(() => {
mockAxios.restore(); mockAxios.restore();
eventHub.dispose(); // clear event hub handlers
});
describe('when event hub receives `TEST_INTEGRATION_EVENT`', () => {
describe('when form is valid', () => {
it('should make an ajax request with provided `formData`', async () => {
eventHub.$emit(TEST_INTEGRATION_EVENT, true);
await waitForPromises();
expect(axios.put).toHaveBeenCalledWith(
integrationSettingsForm.testEndPoint,
new FormData(integrationSettingsForm.$form),
);
});
it('should show success message if test is successful', async () => {
jest.spyOn(integrationSettingsForm.$form, 'submit').mockImplementation(() => {});
mockAxios.onPut(integrationSettingsForm.testEndPoint).reply(200, {
error: false,
});
eventHub.$emit(TEST_INTEGRATION_EVENT, true);
await waitForPromises();
expect(toast).toHaveBeenCalledWith(I18N_SUCCESSFUL_CONNECTION_MESSAGE);
});
it('should show error message if ajax request responds with test error', async () => {
const errorMessage = 'Test failed.';
const serviceResponse = 'some error';
mockAxios.onPut(integrationSettingsForm.testEndPoint).reply(200, {
error: true,
message: errorMessage,
service_response: serviceResponse,
test_failed: false,
});
eventHub.$emit(TEST_INTEGRATION_EVENT, true);
await waitForPromises();
expect(toast).toHaveBeenCalledWith(`${errorMessage} ${serviceResponse}`);
});
it('should show error message if ajax request failed', async () => {
mockAxios.onPut(integrationSettingsForm.testEndPoint).networkError();
eventHub.$emit(TEST_INTEGRATION_EVENT, true);
await waitForPromises();
expect(toast).toHaveBeenCalledWith(I18N_DEFAULT_ERROR_MESSAGE);
});
it('should always dispatch `setIsTesting` with `false` once request is completed', async () => {
const dispatchSpy = mockStoreDispatch();
mockAxios.onPut(integrationSettingsForm.testEndPoint).networkError();
eventHub.$emit(TEST_INTEGRATION_EVENT, true);
await waitForPromises();
expect(dispatchSpy).toHaveBeenCalledWith('setIsTesting', false);
});
});
describe('when form is invalid', () => {
it('should dispatch `setIsTesting` with `false` and not call `testSettings`', async () => {
const dispatchSpy = mockStoreDispatch();
eventHub.$emit(TEST_INTEGRATION_EVENT, false);
await waitForPromises();
expect(dispatchSpy).toHaveBeenCalledWith('setIsTesting', false);
expect(integrationSettingsForm.testSettings).not.toHaveBeenCalled();
});
});
}); });
describe('when event hub receives `SAVE_INTEGRATION_EVENT`', () => { describe('when event hub receives `SAVE_INTEGRATION_EVENT`', () => {
...@@ -137,7 +58,6 @@ describe('IntegrationSettingsForm', () => { ...@@ -137,7 +58,6 @@ describe('IntegrationSettingsForm', () => {
eventHub.$emit(SAVE_INTEGRATION_EVENT, true); eventHub.$emit(SAVE_INTEGRATION_EVENT, true);
await waitForPromises(); await waitForPromises();
expect(integrationSettingsForm.$form.submit).toHaveBeenCalled();
expect(integrationSettingsForm.$form.submit).toHaveBeenCalledTimes(1); expect(integrationSettingsForm.$form.submit).toHaveBeenCalledTimes(1);
}); });
}); });
......
...@@ -28,7 +28,7 @@ RSpec.shared_context 'project service activation' do ...@@ -28,7 +28,7 @@ RSpec.shared_context 'project service activation' do
end end
def click_test_integration def click_test_integration
click_link('Test settings') click_button('Test settings')
end end
def click_test_then_save_integration(expect_test_to_fail: true) def click_test_then_save_integration(expect_test_to_fail: true)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment