diff --git a/app/assets/javascripts/integrations/edit/components/jira_issues_fields.vue b/app/assets/javascripts/integrations/edit/components/jira_issues_fields.vue
index 1baa2b440b0..f8a44f0c2a2 100644
--- a/app/assets/javascripts/integrations/edit/components/jira_issues_fields.vue
+++ b/app/assets/javascripts/integrations/edit/components/jira_issues_fields.vue
@@ -8,6 +8,7 @@ import {
GlButton,
GlCard,
} from '@gitlab/ui';
+import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import eventHub from '../event_hub';
export default {
@@ -20,18 +21,36 @@ export default {
GlLink,
GlButton,
GlCard,
+ JiraIssueCreationVulnerabilities: () =>
+ import('ee_component/integrations/edit/components/jira_issue_creation_vulnerabilities.vue'),
},
+ mixins: [glFeatureFlagsMixin()],
props: {
showJiraIssuesIntegration: {
type: Boolean,
required: false,
default: false,
},
+ showJiraVulnerabilitiesIntegration: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
initialEnableJiraIssues: {
type: Boolean,
required: false,
default: null,
},
+ initialEnableJiraVulnerabilities: {
+ type: Boolean,
+ required: false,
+ default: false,
+ },
+ initialVulnerabilitiesIssuetype: {
+ type: String,
+ required: false,
+ default: '',
+ },
initialProjectKey: {
type: String,
required: false,
@@ -45,12 +64,12 @@ export default {
upgradePlanPath: {
type: String,
required: false,
- default: null,
+ default: '',
},
editProjectPath: {
type: String,
required: false,
- default: null,
+ default: '',
},
},
data() {
@@ -64,6 +83,13 @@ export default {
validProjectKey() {
return !this.enableJiraIssues || Boolean(this.projectKey) || !this.validated;
},
+ showJiraVulnerabilitiesOptions() {
+ return (
+ this.enableJiraIssues &&
+ this.showJiraVulnerabilitiesIntegration &&
+ this.glFeatures.jiraForVulnerabilities
+ );
+ },
},
created() {
eventHub.$on('validateForm', this.validateForm);
@@ -75,6 +101,9 @@ export default {
validateForm() {
this.validated = true;
},
+ getJiraIssueTypes() {
+ eventHub.$emit('getJiraIssueTypes');
+ },
},
};
@@ -105,6 +134,14 @@ export default {
}}
+
{{ __('This is a Premium feature') }}
diff --git a/app/assets/javascripts/integrations/edit/index.js b/app/assets/javascripts/integrations/edit/index.js
index 4d63bd5ed3a..7a4e8b11bb0 100644
--- a/app/assets/javascripts/integrations/edit/index.js
+++ b/app/assets/javascripts/integrations/edit/index.js
@@ -27,6 +27,7 @@ function parseDatasetToProps(data) {
cancelPath,
testPath,
resetPath,
+ vulnerabilitiesIssuetype,
...booleanAttributes
} = data;
const {
@@ -38,7 +39,9 @@ function parseDatasetToProps(data) {
mergeRequestEvents,
enableComments,
showJiraIssuesIntegration,
+ showJiraVulnerabilitiesIntegration,
enableJiraIssues,
+ enableJiraVulnerabilities,
gitlabIssuesEnabled,
} = parseBooleanInData(booleanAttributes);
@@ -59,7 +62,10 @@ function parseDatasetToProps(data) {
},
jiraIssuesProps: {
showJiraIssuesIntegration,
+ showJiraVulnerabilitiesIntegration,
initialEnableJiraIssues: enableJiraIssues,
+ initialEnableJiraVulnerabilities: enableJiraVulnerabilities,
+ initialVulnerabilitiesIssuetype: vulnerabilitiesIssuetype,
initialProjectKey: projectKey,
gitlabIssuesEnabled,
upgradePlanPath,
diff --git a/app/assets/javascripts/integrations/edit/store/actions.js b/app/assets/javascripts/integrations/edit/store/actions.js
index 421917b720a..400397c050c 100644
--- a/app/assets/javascripts/integrations/edit/store/actions.js
+++ b/app/assets/javascripts/integrations/edit/store/actions.js
@@ -26,3 +26,18 @@ export const fetchResetIntegration = ({ dispatch, getters }) => {
.then(() => dispatch('receiveResetIntegrationSuccess'))
.catch(() => dispatch('receiveResetIntegrationError'));
};
+
+export const requestJiraIssueTypes = ({ commit }) => {
+ commit(types.SET_JIRA_ISSUE_TYPES_ERROR_MESSAGE, '');
+ commit(types.SET_IS_LOADING_JIRA_ISSUE_TYPES, true);
+};
+export const receiveJiraIssueTypesSuccess = ({ commit }, issueTypes = []) => {
+ commit(types.SET_IS_LOADING_JIRA_ISSUE_TYPES, false);
+ commit(types.SET_JIRA_ISSUE_TYPES, issueTypes);
+};
+
+export const receiveJiraIssueTypesError = ({ commit }, errorMessage) => {
+ commit(types.SET_IS_LOADING_JIRA_ISSUE_TYPES, false);
+ commit(types.SET_JIRA_ISSUE_TYPES, []);
+ commit(types.SET_JIRA_ISSUE_TYPES_ERROR_MESSAGE, errorMessage);
+};
diff --git a/app/assets/javascripts/integrations/edit/store/mutation_types.js b/app/assets/javascripts/integrations/edit/store/mutation_types.js
index 54928148b22..c681056a515 100644
--- a/app/assets/javascripts/integrations/edit/store/mutation_types.js
+++ b/app/assets/javascripts/integrations/edit/store/mutation_types.js
@@ -3,5 +3,9 @@ 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_LOADING_JIRA_ISSUE_TYPES = 'SET_IS_LOADING_JIRA_ISSUE_TYPES';
+export const SET_JIRA_ISSUE_TYPES_ERROR_MESSAGE = 'SET_JIRA_ISSUE_TYPES_ERROR_MESSAGE';
+export const SET_JIRA_ISSUE_TYPES = 'SET_JIRA_ISSUE_TYPES';
+
export const REQUEST_RESET_INTEGRATION = 'REQUEST_RESET_INTEGRATION';
export const RECEIVE_RESET_INTEGRATION_ERROR = 'RECEIVE_RESET_INTEGRATION_ERROR';
diff --git a/app/assets/javascripts/integrations/edit/store/mutations.js b/app/assets/javascripts/integrations/edit/store/mutations.js
index 826757e665b..279df1b9266 100644
--- a/app/assets/javascripts/integrations/edit/store/mutations.js
+++ b/app/assets/javascripts/integrations/edit/store/mutations.js
@@ -19,4 +19,13 @@ export default {
[types.RECEIVE_RESET_INTEGRATION_ERROR](state) {
state.isResetting = false;
},
+ [types.SET_JIRA_ISSUE_TYPES](state, jiraIssueTypes) {
+ state.jiraIssueTypes = jiraIssueTypes;
+ },
+ [types.SET_IS_LOADING_JIRA_ISSUE_TYPES](state, isLoadingJiraIssueTypes) {
+ state.isLoadingJiraIssueTypes = isLoadingJiraIssueTypes;
+ },
+ [types.SET_JIRA_ISSUE_TYPES_ERROR_MESSAGE](state, errorMessage) {
+ state.loadingJiraIssueTypesErrorMessage = errorMessage;
+ },
};
diff --git a/app/assets/javascripts/integrations/edit/store/state.js b/app/assets/javascripts/integrations/edit/store/state.js
index aae3db1583f..1c0b274e4ef 100644
--- a/app/assets/javascripts/integrations/edit/store/state.js
+++ b/app/assets/javascripts/integrations/edit/store/state.js
@@ -8,5 +8,8 @@ export default ({ defaultState = null, customState = {} } = {}) => {
isSaving: false,
isTesting: false,
isResetting: false,
+ isLoadingJiraIssueTypes: false,
+ loadingJiraIssueTypesErrorMessage: '',
+ jiraIssueTypes: [],
};
};
diff --git a/app/assets/javascripts/integrations/integration_settings_form.js b/app/assets/javascripts/integrations/integration_settings_form.js
index 861655a6a64..486dc50d873 100644
--- a/app/assets/javascripts/integrations/integration_settings_form.js
+++ b/app/assets/javascripts/integrations/integration_settings_form.js
@@ -33,6 +33,12 @@ export default class IntegrationSettingsForm {
eventHub.$on('saveIntegration', () => {
this.saveIntegration();
});
+ eventHub.$on('getJiraIssueTypes', () => {
+ // eslint-disable-next-line no-jquery/no-serialize
+ this.getJiraIssueTypes(this.$form.serialize());
+ });
+
+ eventHub.$emit('formInitialized');
}
saveIntegration() {
@@ -79,16 +85,59 @@ export default class IntegrationSettingsForm {
}
}
+ /**
+ * Get a list of Jira issue types for the currently configured project
+ *
+ * @param {string} formData - URL encoded string containing the form data
+ *
+ * @return {Promise}
+ */
+ getJiraIssueTypes(formData) {
+ const {
+ $store: { dispatch },
+ } = this.vue;
+
+ dispatch('requestJiraIssueTypes');
+
+ return this.fetchTestSettings(formData)
+ .then(
+ ({
+ data: {
+ issuetypes,
+ error,
+ message = s__('Integrations|Connection failed. Please check your settings.'),
+ },
+ }) => {
+ if (error || !issuetypes?.length) {
+ eventHub.$emit('validateForm');
+ throw new Error(message);
+ }
+
+ dispatch('receiveJiraIssueTypesSuccess', issuetypes);
+ },
+ )
+ .catch(({ message = __('Something went wrong on our end.') }) => {
+ 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
*/
testSettings(formData) {
- return axios
- .put(this.testEndPoint, formData)
+ return this.fetchTestSettings(formData)
.then(({ data }) => {
if (data.error) {
toast(`${data.message} ${data.service_response}`);
} else {
+ this.vue.$store.dispatch('receiveJiraIssueTypesSuccess', data.issuetypes);
toast(s__('Integrations|Connection successful.'));
}
})
diff --git a/locale/gitlab.pot b/locale/gitlab.pot
index 264272aadb9..40accd34767 100644
--- a/locale/gitlab.pot
+++ b/locale/gitlab.pot
@@ -16091,15 +16091,27 @@ msgstr ""
msgid "JiraService|%{user_link} mentioned this issue in %{entity_link} of %{project_link}%{branch}:{quote}%{entity_message}{quote}"
msgstr ""
+msgid "JiraService|An error occured while fetching issue list"
+msgstr ""
+
+msgid "JiraService|Define the type of Jira issue to create from a vulnerability."
+msgstr ""
+
msgid "JiraService|Displaying Jira issues while leaving the GitLab issue functionality enabled might be confusing. Consider %{linkStart}disabling GitLab issues%{linkEnd} if they won’t otherwise be used."
msgstr ""
msgid "JiraService|Enable Jira issues"
msgstr ""
+msgid "JiraService|Enable Jira issues creation from vulnerabilities"
+msgstr ""
+
msgid "JiraService|Events for %{noteable_model_name} are disabled."
msgstr ""
+msgid "JiraService|Fetch issue types for this Jira project"
+msgstr ""
+
msgid "JiraService|For example, 12, 24"
msgstr ""
@@ -16109,6 +16121,9 @@ msgstr ""
msgid "JiraService|Issue List"
msgstr ""
+msgid "JiraService|Issues created from vulnerabilities in this project will be Jira issues, even if GitLab issues are enabled."
+msgstr ""
+
msgid "JiraService|Jira API URL"
msgstr ""
@@ -16124,6 +16139,9 @@ msgstr ""
msgid "JiraService|Jira issue tracker"
msgstr ""
+msgid "JiraService|Jira issue type"
+msgstr ""
+
msgid "JiraService|Jira project key"
msgstr ""
@@ -16136,6 +16154,15 @@ msgstr ""
msgid "JiraService|Password or API token"
msgstr ""
+msgid "JiraService|Project key changed, refresh list"
+msgstr ""
+
+msgid "JiraService|Project key is required to generate issue types"
+msgstr ""
+
+msgid "JiraService|Select issue type"
+msgstr ""
+
msgid "JiraService|Set transition IDs for Jira workflow transitions. %{link_start}Learn more%{link_end}"
msgstr ""
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 eaeed2703d1..b866cf8bc03 100644
--- a/spec/frontend/integrations/edit/components/jira_issues_fields_spec.js
+++ b/spec/frontend/integrations/edit/components/jira_issues_fields_spec.js
@@ -3,18 +3,22 @@ import { mount } from '@vue/test-utils';
import { GlFormCheckbox, GlFormInput } from '@gitlab/ui';
import JiraIssuesFields from '~/integrations/edit/components/jira_issues_fields.vue';
+import eventHub from '~/integrations/edit/event_hub';
describe('JiraIssuesFields', () => {
let wrapper;
const defaultProps = {
- showJiraIssuesIntegration: true,
editProjectPath: '/edit',
+ showJiraIssuesIntegration: true,
+ showJiraVulnerabilitiesIntegration: true,
};
- const createComponent = (props) => {
+ const createComponent = ({ props, ...options } = {}) => {
wrapper = mount(JiraIssuesFields, {
propsData: { ...defaultProps, ...props },
+ stubs: ['jira-issue-creation-vulnerabilities'],
+ ...options,
});
};
@@ -28,11 +32,14 @@ describe('JiraIssuesFields', () => {
const findEnableCheckbox = () => wrapper.find(GlFormCheckbox);
const findProjectKey = () => wrapper.find(GlFormInput);
const expectedBannerText = 'This is a Premium feature';
+ const findJiraForVulnerabilities = () => wrapper.find('[data-testid="jira-for-vulnerabilities"]');
+ const setEnableCheckbox = async (isEnabled = true) =>
+ findEnableCheckbox().vm.$emit('input', isEnabled);
describe('template', () => {
describe('upgrade banner for non-Premium user', () => {
beforeEach(() => {
- createComponent({ initialProjectKey: '', showJiraIssuesIntegration: false });
+ createComponent({ props: { initialProjectKey: '', showJiraIssuesIntegration: false } });
});
it('shows upgrade banner', () => {
@@ -47,7 +54,7 @@ describe('JiraIssuesFields', () => {
describe('Enable Jira issues checkbox', () => {
beforeEach(() => {
- createComponent({ initialProjectKey: '' });
+ createComponent({ props: { initialProjectKey: '' } });
});
it('does not show upgrade banner', () => {
@@ -69,20 +76,16 @@ describe('JiraIssuesFields', () => {
});
describe('on enable issues', () => {
- it('enables project_key input', () => {
- findEnableCheckbox().vm.$emit('input', true);
+ it('enables project_key input', async () => {
+ await setEnableCheckbox(true);
- return wrapper.vm.$nextTick().then(() => {
- expect(findProjectKey().attributes('disabled')).toBeUndefined();
- });
+ expect(findProjectKey().attributes('disabled')).toBeUndefined();
});
- it('requires project_key input', () => {
- findEnableCheckbox().vm.$emit('input', true);
+ it('requires project_key input', async () => {
+ await setEnableCheckbox(true);
- return wrapper.vm.$nextTick().then(() => {
- expect(findProjectKey().attributes('required')).toBe('required');
- });
+ expect(findProjectKey().attributes('required')).toBe('required');
});
});
});
@@ -103,10 +106,46 @@ describe('JiraIssuesFields', () => {
});
it('does not contain warning when GitLab issues is disabled', () => {
- createComponent({ gitlabIssuesEnabled: false });
+ createComponent({ props: { gitlabIssuesEnabled: false } });
expect(wrapper.text()).not.toContain(expectedText);
});
});
+
+ describe('Vulnerabilities creation', () => {
+ beforeEach(() => {
+ createComponent({ provide: { glFeatures: { jiraForVulnerabilities: true } } });
+ });
+
+ it.each([true, false])(
+ 'shows the jira-vulnerabilities component correctly when jira issues enables is set to "%s"',
+ async (hasJiraIssuesEnabled) => {
+ await setEnableCheckbox(hasJiraIssuesEnabled);
+
+ expect(findJiraForVulnerabilities().exists()).toBe(hasJiraIssuesEnabled);
+ },
+ );
+
+ it('emits "getJiraIssueTypes" to the eventHub when the jira-vulnerabilities component requests to fetch issue types', async () => {
+ const eventHubEmitSpy = jest.spyOn(eventHub, '$emit');
+
+ await setEnableCheckbox(true);
+ await findJiraForVulnerabilities().vm.$emit('request-get-issue-types');
+
+ expect(eventHubEmitSpy).toHaveBeenCalledWith('getJiraIssueTypes');
+ });
+
+ describe('with "jiraForVulnerabilities" feature flag disabled', () => {
+ beforeEach(async () => {
+ createComponent({
+ provide: { glFeatures: { jiraForVulnerabilities: false } },
+ });
+ });
+
+ it('does not show section', () => {
+ expect(findJiraForVulnerabilities().exists()).toBe(false);
+ });
+ });
+ });
});
});
diff --git a/spec/frontend/integrations/edit/store/actions_spec.js b/spec/frontend/integrations/edit/store/actions_spec.js
index 1ff881c265d..4b7060fae55 100644
--- a/spec/frontend/integrations/edit/store/actions_spec.js
+++ b/spec/frontend/integrations/edit/store/actions_spec.js
@@ -9,6 +9,9 @@ import {
requestResetIntegration,
receiveResetIntegrationSuccess,
receiveResetIntegrationError,
+ requestJiraIssueTypes,
+ receiveJiraIssueTypesSuccess,
+ receiveJiraIssueTypesError,
} from '~/integrations/edit/store/actions';
import * as types from '~/integrations/edit/store/mutation_types';
@@ -70,4 +73,34 @@ describe('Integration form store actions', () => {
]);
});
});
+
+ describe('requestJiraIssueTypes', () => {
+ it('should commit SET_JIRA_ISSUE_TYPES_ERROR_MESSAGE and SET_IS_LOADING_JIRA_ISSUE_TYPES mutations', () => {
+ return testAction(requestJiraIssueTypes, null, state, [
+ { type: types.SET_JIRA_ISSUE_TYPES_ERROR_MESSAGE, payload: '' },
+ { type: types.SET_IS_LOADING_JIRA_ISSUE_TYPES, payload: true },
+ ]);
+ });
+ });
+
+ describe('receiveJiraIssueTypesSuccess', () => {
+ it('should commit SET_IS_LOADING_JIRA_ISSUE_TYPES and SET_JIRA_ISSUE_TYPES mutations', () => {
+ const issueTypes = ['issue', 'epic'];
+ return testAction(receiveJiraIssueTypesSuccess, issueTypes, state, [
+ { type: types.SET_IS_LOADING_JIRA_ISSUE_TYPES, payload: false },
+ { type: types.SET_JIRA_ISSUE_TYPES, payload: issueTypes },
+ ]);
+ });
+ });
+
+ describe('receiveJiraIssueTypesError', () => {
+ it('should commit SET_IS_LOADING_JIRA_ISSUE_TYPES, SET_JIRA_ISSUE_TYPES and SET_JIRA_ISSUE_TYPES_ERROR_MESSAGE mutations', () => {
+ const errorMessage = 'something went wrong';
+ return testAction(receiveJiraIssueTypesError, errorMessage, state, [
+ { type: types.SET_IS_LOADING_JIRA_ISSUE_TYPES, payload: false },
+ { type: types.SET_JIRA_ISSUE_TYPES, payload: [] },
+ { type: types.SET_JIRA_ISSUE_TYPES_ERROR_MESSAGE, payload: errorMessage },
+ ]);
+ });
+ });
});
diff --git a/spec/frontend/integrations/edit/store/mutations_spec.js b/spec/frontend/integrations/edit/store/mutations_spec.js
index 81f39adb87f..bf2a51d4dad 100644
--- a/spec/frontend/integrations/edit/store/mutations_spec.js
+++ b/spec/frontend/integrations/edit/store/mutations_spec.js
@@ -56,4 +56,30 @@ describe('Integration form store mutations', () => {
expect(state.isResetting).toBe(false);
});
});
+
+ describe(`${types.SET_JIRA_ISSUE_TYPES}`, () => {
+ it('sets jiraIssueTypes', () => {
+ const jiraIssueTypes = ['issue', 'epic'];
+ mutations[types.SET_JIRA_ISSUE_TYPES](state, jiraIssueTypes);
+
+ expect(state.jiraIssueTypes).toBe(jiraIssueTypes);
+ });
+ });
+
+ describe(`${types.SET_IS_LOADING_JIRA_ISSUE_TYPES}`, () => {
+ it.each([true, false])('sets isLoadingJiraIssueTypes to "%s"', (isLoading) => {
+ mutations[types.SET_IS_LOADING_JIRA_ISSUE_TYPES](state, isLoading);
+
+ expect(state.isLoadingJiraIssueTypes).toBe(isLoading);
+ });
+ });
+
+ describe(`${types.SET_JIRA_ISSUE_TYPES_ERROR_MESSAGE}`, () => {
+ it('sets loadingJiraIssueTypesErrorMessage', () => {
+ const errorMessage = 'something went wrong';
+ mutations[types.SET_JIRA_ISSUE_TYPES_ERROR_MESSAGE](state, errorMessage);
+
+ expect(state.loadingJiraIssueTypesErrorMessage).toBe(errorMessage);
+ });
+ });
});
diff --git a/spec/frontend/integrations/edit/store/state_spec.js b/spec/frontend/integrations/edit/store/state_spec.js
index 4d0f4a1da71..6cd84836395 100644
--- a/spec/frontend/integrations/edit/store/state_spec.js
+++ b/spec/frontend/integrations/edit/store/state_spec.js
@@ -9,6 +9,9 @@ describe('Integration form state factory', () => {
isTesting: false,
isResetting: false,
override: false,
+ isLoadingJiraIssueTypes: false,
+ jiraIssueTypes: [],
+ loadingJiraIssueTypesErrorMessage: '',
});
});
diff --git a/spec/frontend/integrations/integration_settings_form_spec.js b/spec/frontend/integrations/integration_settings_form_spec.js
index bba851ad796..373f8f196f9 100644
--- a/spec/frontend/integrations/integration_settings_form_spec.js
+++ b/spec/frontend/integrations/integration_settings_form_spec.js
@@ -132,4 +132,83 @@ describe('IntegrationSettingsForm', () => {
expect(dispatchSpy).toHaveBeenCalledWith('setIsTesting', false);
});
});
+
+ describe('getJiraIssueTypes', () => {
+ let integrationSettingsForm;
+ let formData;
+ let mock;
+
+ beforeEach(() => {
+ mock = new MockAdaptor(axios);
+
+ jest.spyOn(axios, 'put');
+
+ integrationSettingsForm = new IntegrationSettingsForm('.js-integration-settings-form');
+ integrationSettingsForm.init();
+
+ // eslint-disable-next-line no-jquery/no-serialize
+ formData = integrationSettingsForm.$form.serialize();
+ });
+
+ afterEach(() => {
+ mock.restore();
+ });
+
+ it('should always dispatch `requestJiraIssueTypes`', async () => {
+ const dispatchSpy = jest.fn();
+
+ mock.onPut(integrationSettingsForm.testEndPoint).networkError();
+
+ integrationSettingsForm.vue.$store = { dispatch: dispatchSpy };
+
+ await integrationSettingsForm.getJiraIssueTypes();
+
+ expect(dispatchSpy).toHaveBeenCalledWith('requestJiraIssueTypes');
+ });
+
+ it('should make an ajax request with provided `formData`', async () => {
+ await integrationSettingsForm.getJiraIssueTypes(formData);
+
+ expect(axios.put).toHaveBeenCalledWith(integrationSettingsForm.testEndPoint, formData);
+ });
+
+ it('should dispatch `receiveJiraIssueTypesSuccess` with the correct payload if ajax request is successful', async () => {
+ const mockData = ['ISSUE', 'EPIC'];
+ const dispatchSpy = jest.fn();
+
+ mock.onPut(integrationSettingsForm.testEndPoint).reply(200, {
+ error: false,
+ issuetypes: mockData,
+ });
+
+ integrationSettingsForm.vue.$store = { dispatch: dispatchSpy };
+
+ await integrationSettingsForm.getJiraIssueTypes(formData);
+
+ expect(dispatchSpy).toHaveBeenCalledWith('receiveJiraIssueTypesSuccess', mockData);
+ });
+
+ 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();
+
+ mock.onPut(integrationSettingsForm.testEndPoint).reply(200, {
+ error: true,
+ message: responseErrorMessage,
+ });
+
+ integrationSettingsForm.vue.$store = { dispatch: dispatchSpy };
+
+ await integrationSettingsForm.getJiraIssueTypes(formData);
+
+ expect(dispatchSpy).toHaveBeenCalledWith(
+ 'receiveJiraIssueTypesError',
+ expectedErrorMessage,
+ );
+ },
+ );
+ });
});