summaryrefslogtreecommitdiff
path: root/spec/frontend/integrations
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/integrations')
-rw-r--r--spec/frontend/integrations/edit/components/active_checkbox_spec.js23
-rw-r--r--spec/frontend/integrations/edit/components/integration_form_spec.js308
-rw-r--r--spec/frontend/integrations/edit/components/jira_issues_fields_spec.js13
-rw-r--r--spec/frontend/integrations/edit/mock_data.js6
-rw-r--r--spec/frontend/integrations/edit/store/actions_spec.js51
-rw-r--r--spec/frontend/integrations/edit/store/getters_spec.js32
-rw-r--r--spec/frontend/integrations/edit/store/mutations_spec.js16
-rw-r--r--spec/frontend/integrations/edit/store/state_spec.js1
-rw-r--r--spec/frontend/integrations/integration_settings_form_spec.js248
-rw-r--r--spec/frontend/integrations/overrides/components/integration_overrides_spec.js63
10 files changed, 386 insertions, 375 deletions
diff --git a/spec/frontend/integrations/edit/components/active_checkbox_spec.js b/spec/frontend/integrations/edit/components/active_checkbox_spec.js
index df7ffd19747..0dc31616166 100644
--- a/spec/frontend/integrations/edit/components/active_checkbox_spec.js
+++ b/spec/frontend/integrations/edit/components/active_checkbox_spec.js
@@ -34,16 +34,22 @@ describe('ActiveCheckbox', () => {
});
});
- describe('initialActivated is false', () => {
- it('renders GlFormCheckbox as unchecked', () => {
+ describe('initialActivated is `false`', () => {
+ beforeEach(() => {
createComponent({
initialActivated: false,
});
+ });
+ it('renders GlFormCheckbox as unchecked', () => {
expect(findGlFormCheckbox().exists()).toBe(true);
expect(findGlFormCheckbox().vm.$attrs.checked).toBe(false);
expect(findInputInCheckbox().attributes('disabled')).toBeUndefined();
});
+
+ it('emits `toggle-integration-active` event with `false` on mount', () => {
+ expect(wrapper.emitted('toggle-integration-active')[0]).toEqual([false]);
+ });
});
describe('initialActivated is true', () => {
@@ -63,10 +69,21 @@ describe('ActiveCheckbox', () => {
findInputInCheckbox().trigger('click');
await wrapper.vm.$nextTick();
-
expect(findGlFormCheckbox().vm.$attrs.checked).toBe(false);
});
});
+
+ it('emits `toggle-integration-active` event with `true` on mount', () => {
+ expect(wrapper.emitted('toggle-integration-active')[0]).toEqual([true]);
+ });
+
+ describe('on checkbox `change` event', () => {
+ it('emits `toggle-integration-active` event', () => {
+ findGlFormCheckbox().vm.$emit('change', false);
+
+ expect(wrapper.emitted('toggle-integration-active')[1]).toEqual([false]);
+ });
+ });
});
});
});
diff --git a/spec/frontend/integrations/edit/components/integration_form_spec.js b/spec/frontend/integrations/edit/components/integration_form_spec.js
index 0a9cbadb249..4c1394f3a87 100644
--- a/spec/frontend/integrations/edit/components/integration_form_spec.js
+++ b/spec/frontend/integrations/edit/components/integration_form_spec.js
@@ -1,6 +1,8 @@
+import axios from 'axios';
+import MockAdapter from 'axios-mock-adapter';
+import * as Sentry from '@sentry/browser';
import { setHTMLFixture } from 'helpers/fixtures';
import { shallowMountExtended } from 'helpers/vue_test_utils_helper';
-
import { mockIntegrationProps } from 'jest/integrations/edit/mock_data';
import ActiveCheckbox from '~/integrations/edit/components/active_checkbox.vue';
import ConfirmationModal from '~/integrations/edit/components/confirmation_modal.vue';
@@ -11,11 +13,27 @@ import JiraTriggerFields from '~/integrations/edit/components/jira_trigger_field
import OverrideDropdown from '~/integrations/edit/components/override_dropdown.vue';
import ResetConfirmationModal from '~/integrations/edit/components/reset_confirmation_modal.vue';
import TriggerFields from '~/integrations/edit/components/trigger_fields.vue';
-import { integrationLevels } from '~/integrations/constants';
+import waitForPromises from 'helpers/wait_for_promises';
+import {
+ integrationLevels,
+ I18N_SUCCESSFUL_CONNECTION_MESSAGE,
+ VALIDATE_INTEGRATION_FORM_EVENT,
+ I18N_DEFAULT_ERROR_MESSAGE,
+} from '~/integrations/constants';
import { createStore } from '~/integrations/edit/store';
+import eventHub from '~/integrations/edit/event_hub';
+import httpStatus from '~/lib/utils/http_status';
+
+jest.mock('~/integrations/edit/event_hub');
+jest.mock('@sentry/browser');
describe('IntegrationForm', () => {
+ const mockToastShow = jest.fn();
+
let wrapper;
+ let dispatch;
+ let mockAxios;
+ let mockForm;
const createComponent = ({
customStateProps = {},
@@ -23,12 +41,18 @@ describe('IntegrationForm', () => {
initialState = {},
props = {},
} = {}) => {
+ const store = createStore({
+ customState: { ...mockIntegrationProps, ...customStateProps },
+ ...initialState,
+ });
+ dispatch = jest.spyOn(store, 'dispatch').mockImplementation();
+
wrapper = shallowMountExtended(IntegrationForm, {
- propsData: { ...props },
- store: createStore({
- customState: { ...mockIntegrationProps, ...customStateProps },
- ...initialState,
- }),
+ propsData: { ...props, formSelector: '.test' },
+ provide: {
+ glFeatures: featureFlags,
+ },
+ store,
stubs: {
OverrideDropdown,
ActiveCheckbox,
@@ -36,46 +60,42 @@ describe('IntegrationForm', () => {
JiraTriggerFields,
TriggerFields,
},
- provide: {
- glFeatures: featureFlags,
+ mocks: {
+ $toast: {
+ show: mockToastShow,
+ },
},
});
};
- afterEach(() => {
- wrapper.destroy();
- });
+ const createForm = ({ isValid = true } = {}) => {
+ mockForm = document.createElement('form');
+ jest.spyOn(document, 'querySelector').mockReturnValue(mockForm);
+ jest.spyOn(mockForm, 'checkValidity').mockReturnValue(isValid);
+ jest.spyOn(mockForm, 'submit');
+ };
const findOverrideDropdown = () => wrapper.findComponent(OverrideDropdown);
const findActiveCheckbox = () => wrapper.findComponent(ActiveCheckbox);
const findConfirmationModal = () => wrapper.findComponent(ConfirmationModal);
const findResetConfirmationModal = () => wrapper.findComponent(ResetConfirmationModal);
const findResetButton = () => wrapper.findByTestId('reset-button');
+ const findSaveButton = () => wrapper.findByTestId('save-button');
+ const findTestButton = () => wrapper.findByTestId('test-button');
const findJiraTriggerFields = () => wrapper.findComponent(JiraTriggerFields);
const findJiraIssuesFields = () => wrapper.findComponent(JiraIssuesFields);
const findTriggerFields = () => wrapper.findComponent(TriggerFields);
- describe('template', () => {
- describe('showActive is true', () => {
- it('renders ActiveCheckbox', () => {
- createComponent();
-
- expect(findActiveCheckbox().exists()).toBe(true);
- });
- });
-
- describe('showActive is false', () => {
- it('does not render ActiveCheckbox', () => {
- createComponent({
- customStateProps: {
- showActive: false,
- },
- });
+ beforeEach(() => {
+ mockAxios = new MockAdapter(axios);
+ });
- expect(findActiveCheckbox().exists()).toBe(false);
- });
- });
+ afterEach(() => {
+ wrapper.destroy();
+ mockAxios.restore();
+ });
+ describe('template', () => {
describe('integrationLevel is instance', () => {
it('renders ConfirmationModal', () => {
createComponent({
@@ -195,13 +215,29 @@ describe('IntegrationForm', () => {
});
describe('type is "jira"', () => {
- it('renders JiraTriggerFields', () => {
+ beforeEach(() => {
+ jest.spyOn(document, 'querySelector').mockReturnValue(document.createElement('form'));
+
createComponent({
- customStateProps: { type: 'jira' },
+ customStateProps: { type: 'jira', testPath: '/test' },
});
+ });
+ it('renders JiraTriggerFields', () => {
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', () => {
@@ -303,4 +339,210 @@ describe('IntegrationForm', () => {
});
});
});
+
+ describe('ActiveCheckbox', () => {
+ describe.each`
+ showActive
+ ${true}
+ ${false}
+ `('when `showActive` is $showActive', ({ showActive }) => {
+ it(`${showActive ? 'renders' : 'does not render'} ActiveCheckbox`, () => {
+ createComponent({
+ customStateProps: {
+ showActive,
+ },
+ });
+
+ expect(findActiveCheckbox().exists()).toBe(showActive);
+ });
+ });
+
+ describe.each`
+ formActive | novalidate
+ ${true} | ${null}
+ ${false} | ${'true'}
+ `(
+ 'when `toggle-integration-active` is emitted with $formActive',
+ ({ formActive, novalidate }) => {
+ beforeEach(async () => {
+ createForm();
+ createComponent({
+ customStateProps: {
+ showActive: true,
+ initialActivated: false,
+ },
+ });
+
+ await findActiveCheckbox().vm.$emit('toggle-integration-active', formActive);
+ });
+
+ it(`sets noValidate to ${novalidate}`, () => {
+ expect(mockForm.getAttribute('novalidate')).toBe(novalidate);
+ });
+ },
+ );
+ });
+
+ describe('when `save` button is clicked', () => {
+ describe('buttons', () => {
+ beforeEach(async () => {
+ createForm();
+ createComponent({
+ customStateProps: {
+ showActive: true,
+ canTest: true,
+ initialActivated: true,
+ },
+ });
+
+ await findSaveButton().vm.$emit('click', new Event('click'));
+ });
+
+ it('sets save button `loading` prop to `true`', () => {
+ expect(findSaveButton().props('loading')).toBe(true);
+ });
+
+ it('sets test button `disabled` prop to `true`', () => {
+ expect(findTestButton().props('disabled')).toBe(true);
+ });
+ });
+
+ describe.each`
+ checkValidityReturn | integrationActive
+ ${true} | ${false}
+ ${true} | ${true}
+ ${false} | ${false}
+ `(
+ 'when form is valid (checkValidity returns $checkValidityReturn and integrationActive is $integrationActive)',
+ ({ integrationActive, checkValidityReturn }) => {
+ beforeEach(async () => {
+ createForm({ isValid: checkValidityReturn });
+ createComponent({
+ customStateProps: {
+ showActive: true,
+ canTest: true,
+ initialActivated: integrationActive,
+ },
+ });
+
+ await findSaveButton().vm.$emit('click', new Event('click'));
+ });
+
+ it('submit form', () => {
+ expect(mockForm.submit).toHaveBeenCalledTimes(1);
+ });
+ },
+ );
+
+ describe('when form is invalid (checkValidity returns false and integrationActive is true)', () => {
+ beforeEach(async () => {
+ createForm({ isValid: false });
+ createComponent({
+ customStateProps: {
+ showActive: true,
+ canTest: true,
+ initialActivated: true,
+ },
+ });
+
+ await findSaveButton().vm.$emit('click', new Event('click'));
+ });
+
+ it('does not submit form', () => {
+ expect(mockForm.submit).not.toHaveBeenCalled();
+ });
+
+ it('sets save button `loading` prop to `false`', () => {
+ expect(findSaveButton().props('loading')).toBe(false);
+ });
+
+ it('sets test button `disabled` prop to `false`', () => {
+ expect(findTestButton().props('disabled')).toBe(false);
+ });
+
+ it('emits `VALIDATE_INTEGRATION_FORM_EVENT`', () => {
+ expect(eventHub.$emit).toHaveBeenCalledWith(VALIDATE_INTEGRATION_FORM_EVENT);
+ });
+ });
+ });
+
+ describe('when `test` button is clicked', () => {
+ describe('when form is invalid', () => {
+ it('emits `VALIDATE_INTEGRATION_FORM_EVENT` event to the event hub', () => {
+ createForm({ isValid: false });
+ createComponent({
+ customStateProps: {
+ showActive: true,
+ canTest: true,
+ },
+ });
+
+ findTestButton().vm.$emit('click', new Event('click'));
+
+ expect(eventHub.$emit).toHaveBeenCalledWith(VALIDATE_INTEGRATION_FORM_EVENT);
+ });
+ });
+
+ describe('when form is valid', () => {
+ const mockTestPath = '/test';
+
+ beforeEach(() => {
+ createForm({ isValid: true });
+ createComponent({
+ customStateProps: {
+ showActive: true,
+ canTest: true,
+ testPath: mockTestPath,
+ },
+ });
+ });
+
+ describe('buttons', () => {
+ 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);
+ });
+ });
+ });
+ });
});
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 3a664b652ac..b5a8eed3598 100644
--- a/spec/frontend/integrations/edit/components/jira_issues_fields_spec.js
+++ b/spec/frontend/integrations/edit/components/jira_issues_fields_spec.js
@@ -1,10 +1,7 @@
import { GlFormCheckbox, GlFormInput } from '@gitlab/ui';
import { mountExtended, shallowMountExtended } from 'helpers/vue_test_utils_helper';
-import {
- GET_JIRA_ISSUE_TYPES_EVENT,
- VALIDATE_INTEGRATION_FORM_EVENT,
-} from '~/integrations/constants';
+import { 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';
@@ -216,13 +213,11 @@ describe('JiraIssuesFields', () => {
);
});
- it('emits "getJiraIssueTypes" to the eventHub when the jira-vulnerabilities component requests to fetch issue types', async () => {
- const eventHubEmitSpy = jest.spyOn(eventHub, '$emit');
-
+ it('emits "request-jira-issue-types` when the jira-vulnerabilities component requests to fetch issue types', async () => {
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);
});
});
diff --git a/spec/frontend/integrations/edit/mock_data.js b/spec/frontend/integrations/edit/mock_data.js
index 27ba0768331..3c45ed0fb1b 100644
--- a/spec/frontend/integrations/edit/mock_data.js
+++ b/spec/frontend/integrations/edit/mock_data.js
@@ -14,3 +14,9 @@ export const mockIntegrationProps = {
type: '',
inheritFromId: 25,
};
+
+export const mockJiraIssueTypes = [
+ { id: '1', name: 'issue', description: 'issue' },
+ { id: '2', name: 'bug', description: 'bug' },
+ { id: '3', name: 'epic', description: 'epic' },
+];
diff --git a/spec/frontend/integrations/edit/store/actions_spec.js b/spec/frontend/integrations/edit/store/actions_spec.js
index e2f4c138ece..b413de2b286 100644
--- a/spec/frontend/integrations/edit/store/actions_spec.js
+++ b/spec/frontend/integrations/edit/store/actions_spec.js
@@ -1,8 +1,9 @@
+import axios from 'axios';
+import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
+import { I18N_FETCH_TEST_SETTINGS_DEFAULT_ERROR_MESSAGE } from '~/integrations/constants';
import {
setOverride,
- setIsSaving,
- setIsTesting,
setIsResetting,
requestResetIntegration,
receiveResetIntegrationSuccess,
@@ -14,14 +15,21 @@ import {
import * as types from '~/integrations/edit/store/mutation_types';
import createState from '~/integrations/edit/store/state';
import { refreshCurrentPage } from '~/lib/utils/url_utility';
+import { mockJiraIssueTypes } from '../mock_data';
jest.mock('~/lib/utils/url_utility');
describe('Integration form store actions', () => {
let state;
+ let mockAxios;
beforeEach(() => {
state = createState();
+ mockAxios = new MockAdapter(axios);
+ });
+
+ afterEach(() => {
+ mockAxios.restore();
});
describe('setOverride', () => {
@@ -30,18 +38,6 @@ describe('Integration form store actions', () => {
});
});
- describe('setIsSaving', () => {
- it('should commit isSaving mutation', () => {
- return testAction(setIsSaving, true, state, [{ type: types.SET_IS_SAVING, payload: true }]);
- });
- });
-
- describe('setIsTesting', () => {
- it('should commit isTesting mutation', () => {
- return testAction(setIsTesting, true, state, [{ type: types.SET_IS_TESTING, payload: true }]);
- });
- });
-
describe('setIsResetting', () => {
it('should commit isResetting mutation', () => {
return testAction(setIsResetting, true, state, [
@@ -75,11 +71,28 @@ 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.each`
+ 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_IS_LOADING_JIRA_ISSUE_TYPES, payload: true },
+ ],
+ [action],
+ );
+ });
});
});
diff --git a/spec/frontend/integrations/edit/store/getters_spec.js b/spec/frontend/integrations/edit/store/getters_spec.js
index ad7a887dff2..3353e0c84cc 100644
--- a/spec/frontend/integrations/edit/store/getters_spec.js
+++ b/spec/frontend/integrations/edit/store/getters_spec.js
@@ -1,11 +1,4 @@
-import {
- currentKey,
- isInheriting,
- isDisabled,
- propsSource,
-} from '~/integrations/edit/store/getters';
-import * as types from '~/integrations/edit/store/mutation_types';
-import mutations from '~/integrations/edit/store/mutations';
+import { currentKey, isInheriting, propsSource } from '~/integrations/edit/store/getters';
import createState from '~/integrations/edit/store/state';
import { mockIntegrationProps } from '../mock_data';
@@ -52,29 +45,6 @@ describe('Integration form store getters', () => {
});
});
- describe('isDisabled', () => {
- it.each`
- isSaving | isTesting | isResetting | expected
- ${false} | ${false} | ${false} | ${false}
- ${true} | ${false} | ${false} | ${true}
- ${false} | ${true} | ${false} | ${true}
- ${false} | ${false} | ${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',
- ({ isSaving, isTesting, isResetting, expected }) => {
- mutations[types.SET_IS_SAVING](state, isSaving);
- mutations[types.SET_IS_TESTING](state, isTesting);
- mutations[types.SET_IS_RESETTING](state, isResetting);
-
- expect(isDisabled(state)).toBe(expected);
- },
- );
- });
-
describe('propsSource', () => {
beforeEach(() => {
state.defaultState = defaultState;
diff --git a/spec/frontend/integrations/edit/store/mutations_spec.js b/spec/frontend/integrations/edit/store/mutations_spec.js
index 18faa2f6bba..641547550d1 100644
--- a/spec/frontend/integrations/edit/store/mutations_spec.js
+++ b/spec/frontend/integrations/edit/store/mutations_spec.js
@@ -17,22 +17,6 @@ describe('Integration form store mutations', () => {
});
});
- describe(`${types.SET_IS_SAVING}`, () => {
- it('sets isSaving', () => {
- mutations[types.SET_IS_SAVING](state, true);
-
- expect(state.isSaving).toBe(true);
- });
- });
-
- 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}`, () => {
it('sets isResetting', () => {
mutations[types.SET_IS_RESETTING](state, true);
diff --git a/spec/frontend/integrations/edit/store/state_spec.js b/spec/frontend/integrations/edit/store/state_spec.js
index 6cd84836395..5582be7fd3c 100644
--- a/spec/frontend/integrations/edit/store/state_spec.js
+++ b/spec/frontend/integrations/edit/store/state_spec.js
@@ -6,7 +6,6 @@ describe('Integration form state factory', () => {
defaultState: null,
customState: {},
isSaving: false,
- isTesting: false,
isResetting: false,
override: false,
isLoadingJiraIssueTypes: false,
diff --git a/spec/frontend/integrations/integration_settings_form_spec.js b/spec/frontend/integrations/integration_settings_form_spec.js
deleted file mode 100644
index c35d178e518..00000000000
--- a/spec/frontend/integrations/integration_settings_form_spec.js
+++ /dev/null
@@ -1,248 +0,0 @@
-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', () => {
- let integrationSettingsForm;
-
- const mockStoreDispatch = () => jest.spyOn(integrationSettingsForm.vue.$store, 'dispatch');
-
- beforeEach(() => {
- loadFixtures(FIXTURE);
-
- integrationSettingsForm = new IntegrationSettingsForm('.js-integration-settings-form');
- integrationSettingsForm.init();
- });
-
- describe('constructor', () => {
- it('should initialize form element refs on class object', () => {
- expect(integrationSettingsForm.$form).toBeDefined();
- expect(integrationSettingsForm.$form.nodeName).toBe('FORM');
- expect(integrationSettingsForm.formActive).toBeDefined();
- });
-
- it('should initialize form metadata on class object', () => {
- expect(integrationSettingsForm.testEndPoint).toBeDefined();
- });
- });
-
- describe('event handling', () => {
- let mockAxios;
-
- beforeEach(() => {
- mockAxios = new MockAdaptor(axios);
- jest.spyOn(axios, 'put');
- });
-
- afterEach(() => {
- mockAxios.restore();
- eventHub.dispose(); // clear event hub handlers
- });
-
- 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(integrationSettingsForm.$form.getAttribute('novalidate')).toBe(null);
- });
-
- it('should set `novalidate` attribute to form when called with `false`', () => {
- eventHub.$emit(TOGGLE_INTEGRATION_EVENT, false);
-
- expect(integrationSettingsForm.$form.getAttribute('novalidate')).toBe('novalidate');
- });
- });
-
- describe('when event hub receives `TEST_INTEGRATION_EVENT`', () => {
- describe('when form is valid', () => {
- beforeEach(() => {
- jest.spyOn(integrationSettingsForm.$form, 'checkValidity').mockReturnValue(true);
- });
-
- it('should make an ajax request with provided `formData`', async () => {
- eventHub.$emit(TEST_INTEGRATION_EVENT);
- 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);
- 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);
- 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);
- 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);
- await waitForPromises();
-
- expect(dispatchSpy).toHaveBeenCalledWith('setIsTesting', false);
- });
- });
-
- describe('when form is invalid', () => {
- beforeEach(() => {
- jest.spyOn(integrationSettingsForm.$form, 'checkValidity').mockReturnValue(false);
- jest.spyOn(integrationSettingsForm, 'testSettings');
- });
-
- it('should dispatch `setIsTesting` with `false` and not call `testSettings`', async () => {
- const dispatchSpy = mockStoreDispatch();
-
- eventHub.$emit(TEST_INTEGRATION_EVENT);
- await waitForPromises();
-
- expect(dispatchSpy).toHaveBeenCalledWith('setIsTesting', false);
- expect(integrationSettingsForm.testSettings).not.toHaveBeenCalled();
- });
- });
- });
-
- 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 form is valid', () => {
- beforeEach(() => {
- jest.spyOn(integrationSettingsForm.$form, 'checkValidity').mockReturnValue(true);
- jest.spyOn(integrationSettingsForm.$form, 'submit');
- });
-
- it('should submit the form', async () => {
- eventHub.$emit(SAVE_INTEGRATION_EVENT);
- await waitForPromises();
-
- expect(integrationSettingsForm.$form.submit).toHaveBeenCalled();
- expect(integrationSettingsForm.$form.submit).toHaveBeenCalledTimes(1);
- });
- });
-
- describe('when form is invalid', () => {
- beforeEach(() => {
- jest.spyOn(integrationSettingsForm.$form, 'checkValidity').mockReturnValue(false);
- jest.spyOn(integrationSettingsForm.$form, 'submit');
- });
-
- it('should dispatch `setIsSaving` with `false` and not submit form', async () => {
- const dispatchSpy = mockStoreDispatch();
-
- eventHub.$emit(SAVE_INTEGRATION_EVENT);
-
- await waitForPromises();
-
- expect(dispatchSpy).toHaveBeenCalledWith('setIsSaving', false);
- expect(integrationSettingsForm.$form.submit).not.toHaveBeenCalled();
- });
- });
- });
- });
-});
diff --git a/spec/frontend/integrations/overrides/components/integration_overrides_spec.js b/spec/frontend/integrations/overrides/components/integration_overrides_spec.js
index ae89d05cead..8abd83887f7 100644
--- a/spec/frontend/integrations/overrides/components/integration_overrides_spec.js
+++ b/spec/frontend/integrations/overrides/components/integration_overrides_spec.js
@@ -8,6 +8,7 @@ import IntegrationOverrides from '~/integrations/overrides/components/integratio
import axios from '~/lib/utils/axios_utils';
import httpStatus from '~/lib/utils/http_status';
import ProjectAvatar from '~/vue_shared/components/project_avatar.vue';
+import UrlSync from '~/vue_shared/components/url_sync.vue';
const mockOverrides = Array(DEFAULT_PER_PAGE * 3)
.fill(1)
@@ -26,9 +27,10 @@ describe('IntegrationOverrides', () => {
overridesPath: 'mock/overrides',
};
- const createComponent = ({ mountFn = shallowMount } = {}) => {
+ const createComponent = ({ mountFn = shallowMount, stubs } = {}) => {
wrapper = mountFn(IntegrationOverrides, {
propsData: defaultProps,
+ stubs,
});
};
@@ -127,27 +129,58 @@ describe('IntegrationOverrides', () => {
});
describe('pagination', () => {
- it('triggers fetch when `input` event is emitted', async () => {
- createComponent();
- jest.spyOn(axios, 'get');
- await waitForPromises();
+ describe('when total items does not exceed the page limit', () => {
+ it('does not render', async () => {
+ mockAxios.onGet(defaultProps.overridesPath).reply(httpStatus.OK, [mockOverrides[0]], {
+ 'X-TOTAL': DEFAULT_PER_PAGE - 1,
+ 'X-PAGE': 1,
+ });
+
+ createComponent();
+
+ // wait for initial load
+ await waitForPromises();
- await findPagination().vm.$emit('input', 2);
- expect(axios.get).toHaveBeenCalledWith(defaultProps.overridesPath, {
- params: { page: 2, per_page: DEFAULT_PER_PAGE },
+ expect(findPagination().exists()).toBe(false);
});
});
- it('does not render with <=1 page', async () => {
- mockAxios.onGet(defaultProps.overridesPath).reply(httpStatus.OK, [mockOverrides[0]], {
- 'X-TOTAL': 1,
- 'X-PAGE': 1,
+ describe('when total items exceeds the page limit', () => {
+ const mockPage = 2;
+
+ beforeEach(async () => {
+ createComponent({ stubs: { UrlSync } });
+ mockAxios.onGet(defaultProps.overridesPath).reply(httpStatus.OK, [mockOverrides[0]], {
+ 'X-TOTAL': DEFAULT_PER_PAGE * 2,
+ 'X-PAGE': mockPage,
+ });
+
+ // wait for initial load
+ await waitForPromises();
});
- createComponent();
- await waitForPromises();
+ it('renders', () => {
+ expect(findPagination().exists()).toBe(true);
+ });
- expect(findPagination().exists()).toBe(false);
+ describe('when navigating to a page', () => {
+ beforeEach(async () => {
+ jest.spyOn(axios, 'get');
+
+ // trigger a page change
+ await findPagination().vm.$emit('input', mockPage);
+ });
+
+ it('performs GET request with correct params', () => {
+ expect(axios.get).toHaveBeenCalledWith(defaultProps.overridesPath, {
+ params: { page: mockPage, per_page: DEFAULT_PER_PAGE },
+ });
+ });
+
+ it('updates `page` URL parameter', () => {
+ expect(window.location.search).toBe(`?page=${mockPage}`);
+ });
+ });
});
});
});