Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/alerts_settings/components/alerts_settings_form_spec.js')
-rw-r--r--spec/frontend/alerts_settings/components/alerts_settings_form_spec.js258
1 files changed, 161 insertions, 97 deletions
diff --git a/spec/frontend/alerts_settings/components/alerts_settings_form_spec.js b/spec/frontend/alerts_settings/components/alerts_settings_form_spec.js
index d2dcff14432..9912ac433a5 100644
--- a/spec/frontend/alerts_settings/components/alerts_settings_form_spec.js
+++ b/spec/frontend/alerts_settings/components/alerts_settings_form_spec.js
@@ -1,5 +1,7 @@
import { GlForm, GlFormSelect, GlFormInput, GlToggle, GlFormTextarea, GlTab } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
+import { nextTick } from 'vue';
+import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import waitForPromises from 'helpers/wait_for_promises';
import MappingBuilder from '~/alerts_settings/components/alert_mapping_builder.vue';
import AlertsSettingsForm from '~/alerts_settings/components/alerts_settings_form.vue';
@@ -8,48 +10,52 @@ import alertFields from '../mocks/alert_fields.json';
import parsedMapping from '../mocks/parsed_mapping.json';
import { defaultAlertSettingsConfig } from './util';
+const scrollIntoViewMock = jest.fn();
+HTMLElement.prototype.scrollIntoView = scrollIntoViewMock;
+
describe('AlertsSettingsForm', () => {
let wrapper;
const mockToastShow = jest.fn();
const createComponent = ({ data = {}, props = {}, multiIntegrations = true } = {}) => {
- wrapper = mount(AlertsSettingsForm, {
- data() {
- return { ...data };
- },
- propsData: {
- loading: false,
- canAddIntegration: true,
- ...props,
- },
- provide: {
- ...defaultAlertSettingsConfig,
- multiIntegrations,
- },
- mocks: {
- $apollo: {
- query: jest.fn(),
+ wrapper = extendedWrapper(
+ mount(AlertsSettingsForm, {
+ data() {
+ return { ...data };
},
- $toast: {
- show: mockToastShow,
+ propsData: {
+ loading: false,
+ canAddIntegration: true,
+ ...props,
},
- },
- });
+ provide: {
+ ...defaultAlertSettingsConfig,
+ multiIntegrations,
+ },
+ mocks: {
+ $apollo: {
+ query: jest.fn(),
+ },
+ $toast: {
+ show: mockToastShow,
+ },
+ },
+ }),
+ );
};
const findForm = () => wrapper.findComponent(GlForm);
const findSelect = () => wrapper.findComponent(GlFormSelect);
const findFormFields = () => wrapper.findAllComponents(GlFormInput);
const findFormToggle = () => wrapper.findComponent(GlToggle);
- const findSamplePayloadSection = () => wrapper.find('[data-testid="sample-payload-section"]');
- const findMappingBuilderSection = () => wrapper.find(`[id = "mapping-builder"]`);
+ const findSamplePayloadSection = () => wrapper.findByTestId('sample-payload-section');
const findMappingBuilder = () => wrapper.findComponent(MappingBuilder);
- const findSubmitButton = () => wrapper.find(`[type = "submit"]`);
- const findMultiSupportText = () =>
- wrapper.find(`[data-testid="multi-integrations-not-supported"]`);
- const findJsonTestSubmit = () => wrapper.find(`[data-testid="send-test-alert"]`);
+
+ const findSubmitButton = () => wrapper.findByTestId('integration-form-submit');
+ const findMultiSupportText = () => wrapper.findByTestId('multi-integrations-not-supported');
+ const findJsonTestSubmit = () => wrapper.findByTestId('send-test-alert');
const findJsonTextArea = () => wrapper.find(`[id = "test-payload"]`);
- const findActionBtn = () => wrapper.find(`[data-testid="payload-action-btn"]`);
+ const findActionBtn = () => wrapper.findByTestId('payload-action-btn');
const findTabs = () => wrapper.findAllComponents(GlTab);
afterEach(() => {
@@ -74,10 +80,6 @@ describe('AlertsSettingsForm', () => {
createComponent();
});
- it('renders the initial template', () => {
- expect(wrapper.element).toMatchSnapshot();
- });
-
it('render the initial form with only an integration type dropdown', () => {
expect(findForm().exists()).toBe(true);
expect(findSelect().exists()).toBe(true);
@@ -151,29 +153,28 @@ describe('AlertsSettingsForm', () => {
findMappingBuilder().vm.$emit('onMappingUpdate', sampleMapping);
findForm().trigger('submit');
- expect(wrapper.emitted('create-new-integration')[0]).toEqual([
- {
- type: typeSet.http,
- variables: {
- name: integrationName,
- active: true,
- payloadAttributeMappings: sampleMapping,
- payloadExample: '{}',
- },
+ expect(wrapper.emitted('create-new-integration')[0][0]).toMatchObject({
+ type: typeSet.http,
+ variables: {
+ name: integrationName,
+ active: true,
+ payloadAttributeMappings: sampleMapping,
+ payloadExample: '{}',
},
- ]);
+ });
});
it('update', () => {
createComponent({
data: {
- selectedIntegration: typeSet.http,
- currentIntegration: { id: '1', name: 'Test integration pre' },
+ integrationForm: { id: '1', name: 'Test integration pre', type: typeSet.http },
+ currentIntegration: { id: '1' },
},
props: {
loading: false,
},
});
+
const updatedIntegrationName = 'Test integration post';
enableIntegration(0, updatedIntegrationName);
@@ -181,21 +182,16 @@ describe('AlertsSettingsForm', () => {
expect(submitBtn.exists()).toBe(true);
expect(submitBtn.text()).toBe('Save integration');
- findForm().trigger('submit');
-
- expect(wrapper.emitted('update-integration')[0]).toEqual(
- expect.arrayContaining([
- {
- type: typeSet.http,
- variables: {
- name: updatedIntegrationName,
- active: true,
- payloadAttributeMappings: [],
- payloadExample: '{}',
- },
- },
- ]),
- );
+ submitBtn.trigger('click');
+ expect(wrapper.emitted('update-integration')[0][0]).toMatchObject({
+ type: typeSet.http,
+ variables: {
+ name: updatedIntegrationName,
+ active: true,
+ payloadAttributeMappings: [],
+ payloadExample: '{}',
+ },
+ });
});
});
@@ -211,16 +207,17 @@ describe('AlertsSettingsForm', () => {
findForm().trigger('submit');
- expect(wrapper.emitted('create-new-integration')[0]).toEqual([
- { type: typeSet.prometheus, variables: { apiUrl, active: true } },
- ]);
+ expect(wrapper.emitted('create-new-integration')[0][0]).toMatchObject({
+ type: typeSet.prometheus,
+ variables: { apiUrl, active: true },
+ });
});
it('update', () => {
createComponent({
data: {
- selectedIntegration: typeSet.prometheus,
- currentIntegration: { id: '1', apiUrl: 'https://test-pre.com' },
+ integrationForm: { id: '1', apiUrl: 'https://test-pre.com', type: typeSet.prometheus },
+ currentIntegration: { id: '1' },
},
props: {
loading: false,
@@ -236,9 +233,10 @@ describe('AlertsSettingsForm', () => {
findForm().trigger('submit');
- expect(wrapper.emitted('update-integration')[0]).toEqual([
- { type: typeSet.prometheus, variables: { apiUrl, active: true } },
- ]);
+ expect(wrapper.emitted('update-integration')[0][0]).toMatchObject({
+ type: typeSet.prometheus,
+ variables: { apiUrl, active: true },
+ });
});
});
});
@@ -247,7 +245,6 @@ describe('AlertsSettingsForm', () => {
beforeEach(() => {
createComponent({
data: {
- selectedIntegration: typeSet.http,
currentIntegration: { id: '1', name: 'Test' },
active: true,
},
@@ -262,7 +259,7 @@ describe('AlertsSettingsForm', () => {
await findJsonTextArea().setValue('Invalid JSON');
jest.runAllTimers();
- await wrapper.vm.$nextTick();
+ await nextTick();
const jsonTestSubmit = findJsonTestSubmit();
expect(jsonTestSubmit.exists()).toBe(true);
@@ -275,7 +272,7 @@ describe('AlertsSettingsForm', () => {
await findJsonTextArea().setValue('{ "value": "value" }');
jest.runAllTimers();
- await wrapper.vm.$nextTick();
+ await nextTick();
expect(findJsonTestSubmit().props('disabled')).toBe(false);
});
});
@@ -283,14 +280,13 @@ describe('AlertsSettingsForm', () => {
describe('Test payload section for HTTP integration', () => {
const validSamplePayload = JSON.stringify(alertFields);
const emptySamplePayload = '{}';
-
beforeEach(() => {
createComponent({
+ multiIntegrations: true,
data: {
+ integrationForm: { type: typeSet.http },
currentIntegration: {
- type: typeSet.http,
- payloadExample: validSamplePayload,
- payloadAttributeMappings: [],
+ payloadExample: emptySamplePayload,
},
active: false,
resetPayloadAndMappingConfirmed: false,
@@ -300,25 +296,25 @@ describe('AlertsSettingsForm', () => {
});
describe.each`
- active | resetPayloadAndMappingConfirmed | disabled
- ${true} | ${true} | ${undefined}
- ${false} | ${true} | ${'disabled'}
- ${true} | ${false} | ${'disabled'}
- ${false} | ${false} | ${'disabled'}
- `('', ({ active, resetPayloadAndMappingConfirmed, disabled }) => {
+ payload | resetPayloadAndMappingConfirmed | disabled
+ ${validSamplePayload} | ${true} | ${undefined}
+ ${emptySamplePayload} | ${true} | ${undefined}
+ ${validSamplePayload} | ${false} | ${'disabled'}
+ ${emptySamplePayload} | ${false} | ${undefined}
+ `('', ({ payload, resetPayloadAndMappingConfirmed, disabled }) => {
const payloadResetMsg = resetPayloadAndMappingConfirmed
? 'was confirmed'
: 'was not confirmed';
const enabledState = disabled === 'disabled' ? 'disabled' : 'enabled';
- const activeState = active ? 'active' : 'not active';
+ const validPayloadMsg = payload === emptySamplePayload ? 'not valid' : 'valid';
- it(`textarea should be ${enabledState} when payload reset ${payloadResetMsg} and current integration is ${activeState}`, async () => {
+ it(`textarea should be ${enabledState} when payload reset ${payloadResetMsg} and payload is ${validPayloadMsg}`, async () => {
wrapper.setData({
- selectedIntegration: typeSet.http,
- active,
+ currentIntegration: { payloadExample: payload },
resetPayloadAndMappingConfirmed,
});
- await wrapper.vm.$nextTick();
+
+ await nextTick();
expect(findSamplePayloadSection().find(GlFormTextarea).attributes('disabled')).toBe(
disabled,
);
@@ -329,9 +325,9 @@ describe('AlertsSettingsForm', () => {
describe.each`
resetPayloadAndMappingConfirmed | payloadExample | caption
${false} | ${validSamplePayload} | ${'Edit payload'}
- ${true} | ${emptySamplePayload} | ${'Parse payload for custom mapping'}
- ${true} | ${validSamplePayload} | ${'Parse payload for custom mapping'}
- ${false} | ${emptySamplePayload} | ${'Parse payload for custom mapping'}
+ ${true} | ${emptySamplePayload} | ${'Parse payload fields'}
+ ${true} | ${validSamplePayload} | ${'Parse payload fields'}
+ ${false} | ${emptySamplePayload} | ${'Parse payload fields'}
`('', ({ resetPayloadAndMappingConfirmed, payloadExample, caption }) => {
const samplePayloadMsg = payloadExample ? 'was provided' : 'was not provided';
const payloadResetMsg = resetPayloadAndMappingConfirmed
@@ -340,16 +336,12 @@ describe('AlertsSettingsForm', () => {
it(`shows ${caption} button when sample payload ${samplePayloadMsg} and payload reset ${payloadResetMsg}`, async () => {
wrapper.setData({
- selectedIntegration: typeSet.http,
currentIntegration: {
payloadExample,
- type: typeSet.http,
- active: true,
- payloadAttributeMappings: [],
},
resetPayloadAndMappingConfirmed,
});
- await wrapper.vm.$nextTick();
+ await nextTick();
expect(findActionBtn().text()).toBe(caption);
});
});
@@ -358,7 +350,6 @@ describe('AlertsSettingsForm', () => {
describe('Parsing payload', () => {
beforeEach(() => {
wrapper.setData({
- selectedIntegration: typeSet.http,
resetPayloadAndMappingConfirmed: true,
});
});
@@ -398,11 +389,12 @@ describe('AlertsSettingsForm', () => {
${true} | ${false} | ${1} | ${false}
${false} | ${true} | ${1} | ${false}
`('', ({ alertFieldsProvided, multiIntegrations, integrationOption, visible }) => {
- const visibleMsg = visible ? 'is rendered' : 'is not rendered';
- const alertFieldsMsg = alertFieldsProvided ? 'are provided' : 'are not provided';
+ const visibleMsg = visible ? 'rendered' : 'not rendered';
+ const alertFieldsMsg = alertFieldsProvided ? 'provided' : 'not provided';
const integrationType = integrationOption === 1 ? typeSet.http : typeSet.prometheus;
+ const multiIntegrationsEnabled = multiIntegrations ? 'enabled' : 'not enabled';
- it(`${visibleMsg} when integration type is ${integrationType} and alert fields ${alertFieldsMsg}`, async () => {
+ it(`is ${visibleMsg} when multiIntegrations are ${multiIntegrationsEnabled}, integration type is ${integrationType} and alert fields are ${alertFieldsMsg}`, async () => {
createComponent({
multiIntegrations,
props: {
@@ -411,8 +403,80 @@ describe('AlertsSettingsForm', () => {
});
await selectOptionAtIndex(integrationOption);
- expect(findMappingBuilderSection().exists()).toBe(visible);
+ expect(findMappingBuilder().exists()).toBe(visible);
+ });
+ });
+ });
+
+ describe('Form validation', () => {
+ beforeEach(() => {
+ createComponent();
+ });
+
+ it('should not be able to submit when no integration type is selected', async () => {
+ await selectOptionAtIndex(0);
+
+ expect(findSubmitButton().attributes('disabled')).toBe('disabled');
+ });
+
+ it('should not be able to submit when HTTP integration form is invalid', async () => {
+ await selectOptionAtIndex(1);
+ await findFormFields().at(0).vm.$emit('input', '');
+ expect(findSubmitButton().attributes('disabled')).toBe('disabled');
+ });
+
+ it('should be able to submit when HTTP integration form is valid', async () => {
+ await selectOptionAtIndex(1);
+ await findFormFields().at(0).vm.$emit('input', 'Name');
+ expect(findSubmitButton().attributes('disabled')).toBe(undefined);
+ });
+
+ it('should not be able to submit when Prometheus integration form is invalid', async () => {
+ await selectOptionAtIndex(2);
+ await findFormFields().at(0).vm.$emit('input', '');
+
+ expect(findSubmitButton().attributes('disabled')).toBe('disabled');
+ });
+
+ it('should be able to submit when Prometheus integration form is valid', async () => {
+ await selectOptionAtIndex(2);
+ await findFormFields().at(0).vm.$emit('input', 'http://valid.url');
+
+ expect(findSubmitButton().attributes('disabled')).toBe(undefined);
+ });
+
+ it('should be able to submit when form is dirty', async () => {
+ wrapper.setData({
+ currentIntegration: { type: typeSet.http, name: 'Existing integration' },
+ });
+ await nextTick();
+ await findFormFields().at(0).vm.$emit('input', 'Updated name');
+
+ expect(findSubmitButton().attributes('disabled')).toBe(undefined);
+ });
+
+ it('should not be able to submit when form is pristine', async () => {
+ wrapper.setData({
+ currentIntegration: { type: typeSet.http, name: 'Existing integration' },
});
+ await nextTick();
+
+ expect(findSubmitButton().attributes('disabled')).toBe('disabled');
+ });
+
+ it('should disable submit button after click on validation failure', async () => {
+ await selectOptionAtIndex(1);
+ findSubmitButton().trigger('click');
+ await nextTick();
+
+ expect(findSubmitButton().attributes('disabled')).toBe('disabled');
+ });
+
+ it('should scroll to invalid field on validation failure', async () => {
+ await selectOptionAtIndex(1);
+ findSubmitButton().trigger('click');
+
+ expect(scrollIntoViewMock).toHaveBeenCalledWith({ behavior: 'smooth', block: 'center' });
});
});
});