Commit 57f0c635 authored by Simon Knox's avatar Simon Knox

Merge branch '342121-move-getIssueTypes-to-vue-component' into 'master'

Move `getJiraIssueTypes` to Vuex action

See merge request gitlab-org/gitlab!75484
parents b2b6cb55 7878cee8
...@@ -2,7 +2,6 @@ import { s__, __ } from '~/locale'; ...@@ -2,7 +2,6 @@ import { s__, __ } from '~/locale';
export const TEST_INTEGRATION_EVENT = 'testIntegration'; export const TEST_INTEGRATION_EVENT = 'testIntegration';
export const SAVE_INTEGRATION_EVENT = 'saveIntegration'; export const SAVE_INTEGRATION_EVENT = 'saveIntegration';
export const GET_JIRA_ISSUE_TYPES_EVENT = 'getJiraIssueTypes';
export const TOGGLE_INTEGRATION_EVENT = 'toggleIntegration'; export const TOGGLE_INTEGRATION_EVENT = 'toggleIntegration';
export const VALIDATE_INTEGRATION_FORM_EVENT = 'validateIntegrationForm'; export const VALIDATE_INTEGRATION_FORM_EVENT = 'validateIntegrationForm';
......
import axios from '~/lib/utils/axios_utils';
/**
* Test the validity of [integrationFormData].
* @return Promise<{ issuetypes: []String }> - issuetypes contains valid Jira issue types.
*/
export const testIntegrationSettings = (testPath, integrationFormData) => {
return axios.put(testPath, integrationFormData);
};
...@@ -69,6 +69,10 @@ export default { ...@@ -69,6 +69,10 @@ export default {
return this.isInstanceOrGroupLevel && this.propsSource.resetPath; return this.isInstanceOrGroupLevel && this.propsSource.resetPath;
}, },
}, },
mounted() {
// this form element is defined in Haml
this.form = document.querySelector('.js-integration-settings-form');
},
methods: { methods: {
...mapActions([ ...mapActions([
'setOverride', 'setOverride',
...@@ -76,6 +80,7 @@ export default { ...@@ -76,6 +80,7 @@ export default {
'setIsTesting', 'setIsTesting',
'setIsResetting', 'setIsResetting',
'fetchResetIntegration', 'fetchResetIntegration',
'requestJiraIssueTypes',
]), ]),
onSaveClick() { onSaveClick() {
this.setIsSaving(true); this.setIsSaving(true);
...@@ -88,6 +93,10 @@ export default { ...@@ -88,6 +93,10 @@ export default {
onResetClick() { onResetClick() {
this.fetchResetIntegration(); this.fetchResetIntegration();
}, },
onRequestJiraIssueTypes() {
const formData = new FormData(this.form);
this.requestJiraIssueTypes(formData);
},
}, },
helpHtmlConfig: { helpHtmlConfig: {
ADD_ATTR: ['target'], // allow external links, can be removed after https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1427 is implemented ADD_ATTR: ['target'], // allow external links, can be removed after https://gitlab.com/gitlab-org/gitlab-ui/-/issues/1427 is implemented
...@@ -135,6 +144,7 @@ export default { ...@@ -135,6 +144,7 @@ export default {
v-if="isJira && !isInstanceOrGroupLevel" v-if="isJira && !isInstanceOrGroupLevel"
:key="`${currentKey}-jira-issues-fields`" :key="`${currentKey}-jira-issues-fields`"
v-bind="propsSource.jiraIssuesProps" v-bind="propsSource.jiraIssuesProps"
@request-jira-issue-types="onRequestJiraIssueTypes"
/> />
<div v-if="isEditable" class="footer-block row-content-block"> <div v-if="isEditable" class="footer-block row-content-block">
<template v-if="isInstanceOrGroupLevel"> <template v-if="isInstanceOrGroupLevel">
......
<script> <script>
import { GlFormGroup, GlFormCheckbox, GlFormInput, GlSprintf, GlLink } from '@gitlab/ui'; import { GlFormGroup, GlFormCheckbox, GlFormInput, GlSprintf, GlLink } from '@gitlab/ui';
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex';
import { import { VALIDATE_INTEGRATION_FORM_EVENT } from '~/integrations/constants';
VALIDATE_INTEGRATION_FORM_EVENT,
GET_JIRA_ISSUE_TYPES_EVENT,
} from '~/integrations/constants';
import { s__, __ } from '~/locale'; import { s__, __ } from '~/locale';
import eventHub from '../event_hub'; import eventHub from '../event_hub';
import JiraUpgradeCta from './jira_upgrade_cta.vue'; import JiraUpgradeCta from './jira_upgrade_cta.vue';
...@@ -91,9 +88,6 @@ export default { ...@@ -91,9 +88,6 @@ export default {
validateForm() { validateForm() {
this.validated = true; this.validated = true;
}, },
getJiraIssueTypes() {
eventHub.$emit(GET_JIRA_ISSUE_TYPES_EVENT);
},
}, },
i18n: { i18n: {
sectionTitle: s__('JiraService|View Jira issues in GitLab'), sectionTitle: s__('JiraService|View Jira issues in GitLab'),
...@@ -136,7 +130,7 @@ export default { ...@@ -136,7 +130,7 @@ export default {
:initial-issue-type-id="initialVulnerabilitiesIssuetype" :initial-issue-type-id="initialVulnerabilitiesIssuetype"
:show-full-feature="showJiraVulnerabilitiesIntegration" :show-full-feature="showJiraVulnerabilitiesIntegration"
data-testid="jira-for-vulnerabilities" data-testid="jira-for-vulnerabilities"
@request-get-issue-types="getJiraIssueTypes" @request-jira-issue-types="$emit('request-jira-issue-types')"
/> />
<jira-upgrade-cta <jira-upgrade-cta
v-if="!showJiraVulnerabilitiesIntegration" v-if="!showJiraVulnerabilitiesIntegration"
......
import axios from 'axios'; import axios from 'axios';
import { refreshCurrentPage } from '~/lib/utils/url_utility'; import { refreshCurrentPage } from '~/lib/utils/url_utility';
import {
VALIDATE_INTEGRATION_FORM_EVENT,
I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE,
I18N_DEFAULT_ERROR_MESSAGE,
} from '~/integrations/constants';
import { testIntegrationSettings } from '../api';
import eventHub from '../event_hub';
import * as types from './mutation_types'; 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);
...@@ -27,10 +34,28 @@ export const fetchResetIntegration = ({ dispatch, getters }) => { ...@@ -27,10 +34,28 @@ export const fetchResetIntegration = ({ dispatch, getters }) => {
.catch(() => dispatch('receiveResetIntegrationError')); .catch(() => dispatch('receiveResetIntegrationError'));
}; };
export const requestJiraIssueTypes = ({ commit }) => { export const requestJiraIssueTypes = ({ commit, dispatch, getters }, formData) => {
commit(types.SET_JIRA_ISSUE_TYPES_ERROR_MESSAGE, ''); commit(types.SET_JIRA_ISSUE_TYPES_ERROR_MESSAGE, '');
commit(types.SET_IS_LOADING_JIRA_ISSUE_TYPES, true); commit(types.SET_IS_LOADING_JIRA_ISSUE_TYPES, true);
return testIntegrationSettings(getters.propsSource.testPath, formData)
.then(
({
data: { issuetypes, error, message = I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE },
}) => {
if (error || !issuetypes?.length) {
eventHub.$emit(VALIDATE_INTEGRATION_FORM_EVENT);
throw new Error(message);
}
dispatch('receiveJiraIssueTypesSuccess', issuetypes);
},
)
.catch(({ message = I18N_DEFAULT_ERROR_MESSAGE }) => {
dispatch('receiveJiraIssueTypesError', message);
});
}; };
export const receiveJiraIssueTypesSuccess = ({ commit }, issueTypes = []) => { export const receiveJiraIssueTypesSuccess = ({ commit }, issueTypes = []) => {
commit(types.SET_IS_LOADING_JIRA_ISSUE_TYPES, false); commit(types.SET_IS_LOADING_JIRA_ISSUE_TYPES, false);
commit(types.SET_JIRA_ISSUE_TYPES, issueTypes); commit(types.SET_JIRA_ISSUE_TYPES, issueTypes);
......
import { delay } from 'lodash'; import { delay } from 'lodash';
import toast from '~/vue_shared/plugins/global_toast'; import toast from '~/vue_shared/plugins/global_toast';
import axios from '../lib/utils/axios_utils';
import initForm from './edit'; import initForm from './edit';
import eventHub from './edit/event_hub'; import eventHub from './edit/event_hub';
import { import {
TEST_INTEGRATION_EVENT, TEST_INTEGRATION_EVENT,
SAVE_INTEGRATION_EVENT, SAVE_INTEGRATION_EVENT,
GET_JIRA_ISSUE_TYPES_EVENT,
TOGGLE_INTEGRATION_EVENT, TOGGLE_INTEGRATION_EVENT,
VALIDATE_INTEGRATION_FORM_EVENT, VALIDATE_INTEGRATION_FORM_EVENT,
I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE,
I18N_DEFAULT_ERROR_MESSAGE, I18N_DEFAULT_ERROR_MESSAGE,
I18N_SUCCESSFUL_CONNECTION_MESSAGE, I18N_SUCCESSFUL_CONNECTION_MESSAGE,
} from './constants'; } from './constants';
import { testIntegrationSettings } from './edit/api';
export default class IntegrationSettingsForm { export default class IntegrationSettingsForm {
constructor(formSelector) { constructor(formSelector) {
...@@ -41,9 +39,6 @@ export default class IntegrationSettingsForm { ...@@ -41,9 +39,6 @@ export default class IntegrationSettingsForm {
eventHub.$on(SAVE_INTEGRATION_EVENT, () => { eventHub.$on(SAVE_INTEGRATION_EVENT, () => {
this.saveIntegration(); this.saveIntegration();
}); });
eventHub.$on(GET_JIRA_ISSUE_TYPES_EVENT, () => {
this.getJiraIssueTypes(new FormData(this.$form));
});
} }
saveIntegration() { saveIntegration() {
...@@ -96,43 +91,12 @@ export default class IntegrationSettingsForm { ...@@ -96,43 +91,12 @@ export default class IntegrationSettingsForm {
* *
* @return {Promise} * @return {Promise}
*/ */
getJiraIssueTypes(formData) {
const {
$store: { dispatch },
} = this.vue;
dispatch('requestJiraIssueTypes');
return this.fetchTestSettings(formData)
.then(
({
data: { issuetypes, error, message = I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE },
}) => {
if (error || !issuetypes?.length) {
eventHub.$emit(VALIDATE_INTEGRATION_FORM_EVENT);
throw new Error(message);
}
dispatch('receiveJiraIssueTypesSuccess', issuetypes);
},
)
.catch(({ message = I18N_DEFAULT_ERROR_MESSAGE }) => {
dispatch('receiveJiraIssueTypesError', message);
});
}
/**
* Send request to the test endpoint which checks if the current config is valid
*/
fetchTestSettings(formData) {
return axios.put(this.testEndPoint, formData);
}
/** /**
* Test Integration config * Test Integration config
*/ */
testSettings(formData) { testSettings(formData) {
return this.fetchTestSettings(formData) return testIntegrationSettings(this.testEndPoint, formData)
.then(({ data }) => { .then(({ data }) => {
if (data.error) { if (data.error) {
toast(`${data.message} ${data.service_response}`); toast(`${data.message} ${data.service_response}`);
......
...@@ -120,12 +120,15 @@ export default { ...@@ -120,12 +120,15 @@ export default {
}, },
created() { created() {
if (this.initialIsEnabled) { if (this.initialIsEnabled) {
this.$emit('request-get-issue-types'); this.requestJiraIssueTypes();
} }
}, },
methods: { methods: {
requestJiraIssueTypes() {
this.$emit('request-jira-issue-types');
},
handleLoadJiraIssueTypesClick() { handleLoadJiraIssueTypesClick() {
this.$emit('request-get-issue-types'); this.requestJiraIssueTypes();
this.projectKeyForCurrentIssues = this.projectKey; this.projectKeyForCurrentIssues = this.projectKey;
this.isLoadingErrorAlertDimissed = false; this.isLoadingErrorAlertDimissed = false;
}, },
......
...@@ -205,9 +205,9 @@ describe('JiraIssuesFields', () => { ...@@ -205,9 +205,9 @@ describe('JiraIssuesFields', () => {
}); });
it('emits "fetch-issues-clicked" when clicked', async () => { it('emits "fetch-issues-clicked" when clicked', async () => {
expect(wrapper.emitted('request-get-issue-types')).toBe(undefined); expect(wrapper.emitted('request-jira-issue-types')).toBe(undefined);
await findFetchIssueTypeButton().vm.$emit('click'); await findFetchIssueTypeButton().vm.$emit('click');
expect(wrapper.emitted('request-get-issue-types')).toHaveLength(1); expect(wrapper.emitted('request-jira-issue-types')).toHaveLength(1);
}); });
}); });
......
...@@ -16,6 +16,7 @@ import { createStore } from '~/integrations/edit/store'; ...@@ -16,6 +16,7 @@ import { createStore } from '~/integrations/edit/store';
describe('IntegrationForm', () => { describe('IntegrationForm', () => {
let wrapper; let wrapper;
let dispatch;
const createComponent = ({ const createComponent = ({
customStateProps = {}, customStateProps = {},
...@@ -23,12 +24,15 @@ describe('IntegrationForm', () => { ...@@ -23,12 +24,15 @@ describe('IntegrationForm', () => {
initialState = {}, initialState = {},
props = {}, props = {},
} = {}) => { } = {}) => {
wrapper = shallowMountExtended(IntegrationForm, { const store = createStore({
propsData: { ...props },
store: createStore({
customState: { ...mockIntegrationProps, ...customStateProps }, customState: { ...mockIntegrationProps, ...customStateProps },
...initialState, ...initialState,
}), });
dispatch = jest.spyOn(store, 'dispatch').mockImplementation();
wrapper = shallowMountExtended(IntegrationForm, {
propsData: { ...props },
store,
stubs: { stubs: {
OverrideDropdown, OverrideDropdown,
ActiveCheckbox, ActiveCheckbox,
...@@ -195,13 +199,29 @@ describe('IntegrationForm', () => { ...@@ -195,13 +199,29 @@ describe('IntegrationForm', () => {
}); });
describe('type is "jira"', () => { describe('type is "jira"', () => {
it('renders JiraTriggerFields', () => { beforeEach(() => {
jest.spyOn(document, 'querySelector').mockReturnValue(document.createElement('form'));
createComponent({ createComponent({
customStateProps: { type: 'jira' }, customStateProps: { type: 'jira', testPath: '/test' },
});
}); });
it('renders JiraTriggerFields', () => {
expect(findJiraTriggerFields().exists()).toBe(true); expect(findJiraTriggerFields().exists()).toBe(true);
}); });
it('renders JiraIssuesFields', () => {
expect(findJiraIssuesFields().exists()).toBe(true);
});
describe('when JiraIssueFields emits `request-jira-issue-types` event', () => {
it('dispatches `requestJiraIssueTypes` action', () => {
findJiraIssuesFields().vm.$emit('request-jira-issue-types');
expect(dispatch).toHaveBeenCalledWith('requestJiraIssueTypes', expect.any(FormData));
});
});
}); });
describe('triggerEvents is present', () => { describe('triggerEvents is present', () => {
......
import { GlFormCheckbox, GlFormInput } from '@gitlab/ui'; import { GlFormCheckbox, GlFormInput } from '@gitlab/ui';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper'; import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
import { import { VALIDATE_INTEGRATION_FORM_EVENT } from '~/integrations/constants';
GET_JIRA_ISSUE_TYPES_EVENT,
VALIDATE_INTEGRATION_FORM_EVENT,
} from '~/integrations/constants';
import JiraIssuesFields from '~/integrations/edit/components/jira_issues_fields.vue'; import JiraIssuesFields from '~/integrations/edit/components/jira_issues_fields.vue';
import eventHub from '~/integrations/edit/event_hub'; import eventHub from '~/integrations/edit/event_hub';
import { createStore } from '~/integrations/edit/store'; import { createStore } from '~/integrations/edit/store';
...@@ -216,13 +213,11 @@ describe('JiraIssuesFields', () => { ...@@ -216,13 +213,11 @@ describe('JiraIssuesFields', () => {
); );
}); });
it('emits "getJiraIssueTypes" to the eventHub when the jira-vulnerabilities component requests to fetch issue types', async () => { it('emits "request-jira-issue-types` when the jira-vulnerabilities component requests to fetch issue types', async () => {
const eventHubEmitSpy = jest.spyOn(eventHub, '$emit');
await setEnableCheckbox(true); await setEnableCheckbox(true);
await findJiraForVulnerabilities().vm.$emit('request-get-issue-types'); await findJiraForVulnerabilities().vm.$emit('request-jira-issue-types');
expect(eventHubEmitSpy).toHaveBeenCalledWith(GET_JIRA_ISSUE_TYPES_EVENT); expect(wrapper.emitted('request-jira-issue-types')).toHaveLength(1);
}); });
}); });
......
...@@ -14,3 +14,9 @@ export const mockIntegrationProps = { ...@@ -14,3 +14,9 @@ export const mockIntegrationProps = {
type: '', type: '',
inheritFromId: 25, inheritFromId: 25,
}; };
export const mockJiraIssueTypes = [
{ id: '1', name: 'issue', description: 'issue' },
{ id: '2', name: 'bug', description: 'bug' },
{ id: '3', name: 'epic', description: 'epic' },
];
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper'; import testAction from 'helpers/vuex_action_helper';
import { I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE } from '~/integrations/constants';
import { import {
setOverride, setOverride,
setIsSaving, setIsSaving,
...@@ -14,14 +17,21 @@ import { ...@@ -14,14 +17,21 @@ import {
import * as types from '~/integrations/edit/store/mutation_types'; import * as types from '~/integrations/edit/store/mutation_types';
import createState from '~/integrations/edit/store/state'; import createState from '~/integrations/edit/store/state';
import { refreshCurrentPage } from '~/lib/utils/url_utility'; import { refreshCurrentPage } from '~/lib/utils/url_utility';
import { mockJiraIssueTypes } from '../mock_data';
jest.mock('~/lib/utils/url_utility'); jest.mock('~/lib/utils/url_utility');
describe('Integration form store actions', () => { describe('Integration form store actions', () => {
let state; let state;
let mockAxios;
beforeEach(() => { beforeEach(() => {
state = createState(); state = createState();
mockAxios = new MockAdapter(axios);
});
afterEach(() => {
mockAxios.restore();
}); });
describe('setOverride', () => { describe('setOverride', () => {
...@@ -75,11 +85,28 @@ describe('Integration form store actions', () => { ...@@ -75,11 +85,28 @@ describe('Integration form store actions', () => {
}); });
describe('requestJiraIssueTypes', () => { describe('requestJiraIssueTypes', () => {
it('should commit SET_JIRA_ISSUE_TYPES_ERROR_MESSAGE and SET_IS_LOADING_JIRA_ISSUE_TYPES mutations', () => { describe.each`
return testAction(requestJiraIssueTypes, null, state, [ scenario | responseCode | response | action
${'when successful'} | ${200} | ${{ issuetypes: mockJiraIssueTypes }} | ${{ type: 'receiveJiraIssueTypesSuccess', payload: mockJiraIssueTypes }}
${'when response has no issue types'} | ${200} | ${{ issuetypes: [] }} | ${{ type: 'receiveJiraIssueTypesError', payload: I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE }}
${'when response includes error'} | ${200} | ${{ error: new Error() }} | ${{ type: 'receiveJiraIssueTypesError', payload: I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE }}
${'when error occurs'} | ${500} | ${{}} | ${{ type: 'receiveJiraIssueTypesError', payload: expect.any(String) }}
`('$scenario', ({ responseCode, response, action }) => {
it(`should commit SET_JIRA_ISSUE_TYPES_ERROR_MESSAGE and SET_IS_LOADING_JIRA_ISSUE_TYPES mutations, and dispatch ${action.type}`, () => {
mockAxios.onPut('/test').replyOnce(responseCode, response);
return testAction(
requestJiraIssueTypes,
new FormData(),
{ propsSource: { testPath: '/test' } },
[
// should clear the error messages and set the loading state
{ type: types.SET_JIRA_ISSUE_TYPES_ERROR_MESSAGE, payload: '' }, { type: types.SET_JIRA_ISSUE_TYPES_ERROR_MESSAGE, payload: '' },
{ type: types.SET_IS_LOADING_JIRA_ISSUE_TYPES, payload: true }, { type: types.SET_IS_LOADING_JIRA_ISSUE_TYPES, payload: true },
]); ],
[action],
);
});
}); });
}); });
......
...@@ -4,10 +4,8 @@ import eventHub from '~/integrations/edit/event_hub'; ...@@ -4,10 +4,8 @@ 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 toast from '~/vue_shared/plugins/global_toast';
import { import {
I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE,
I18N_SUCCESSFUL_CONNECTION_MESSAGE, I18N_SUCCESSFUL_CONNECTION_MESSAGE,
I18N_DEFAULT_ERROR_MESSAGE, I18N_DEFAULT_ERROR_MESSAGE,
GET_JIRA_ISSUE_TYPES_EVENT,
TOGGLE_INTEGRATION_EVENT, TOGGLE_INTEGRATION_EVENT,
TEST_INTEGRATION_EVENT, TEST_INTEGRATION_EVENT,
SAVE_INTEGRATION_EVENT, SAVE_INTEGRATION_EVENT,
...@@ -154,62 +152,6 @@ describe('IntegrationSettingsForm', () => { ...@@ -154,62 +152,6 @@ describe('IntegrationSettingsForm', () => {
}); });
}); });
describe('when event hub receives `GET_JIRA_ISSUE_TYPES_EVENT`', () => {
it('should always dispatch `requestJiraIssueTypes`', () => {
const dispatchSpy = mockStoreDispatch();
mockAxios.onPut(integrationSettingsForm.testEndPoint).networkError();
eventHub.$emit(GET_JIRA_ISSUE_TYPES_EVENT);
expect(dispatchSpy).toHaveBeenCalledWith('requestJiraIssueTypes');
});
it('should make an ajax request with provided `formData`', () => {
eventHub.$emit(GET_JIRA_ISSUE_TYPES_EVENT);
expect(axios.put).toHaveBeenCalledWith(
integrationSettingsForm.testEndPoint,
new FormData(integrationSettingsForm.$form),
);
});
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,
});
eventHub.$emit(GET_JIRA_ISSUE_TYPES_EVENT);
await waitForPromises();
expect(dispatchSpy).toHaveBeenCalledWith('receiveJiraIssueTypesSuccess', mockData);
});
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 event hub receives `SAVE_INTEGRATION_EVENT`', () => {
describe('when form is valid', () => { describe('when form is valid', () => {
beforeEach(() => { beforeEach(() => {
......
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