diff options
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.js | 227 |
1 files changed, 130 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 02229b3d3da..d2dcff14432 100644 --- a/spec/frontend/alerts_settings/components/alerts_settings_form_spec.js +++ b/spec/frontend/alerts_settings/components/alerts_settings_form_spec.js @@ -1,29 +1,18 @@ -import { - GlForm, - GlFormSelect, - GlCollapse, - GlFormInput, - GlToggle, - GlFormTextarea, -} from '@gitlab/ui'; +import { GlForm, GlFormSelect, GlFormInput, GlToggle, GlFormTextarea, GlTab } from '@gitlab/ui'; import { mount } from '@vue/test-utils'; 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'; import { typeSet } from '~/alerts_settings/constants'; -import alertFields from '../mocks/alertFields.json'; +import alertFields from '../mocks/alert_fields.json'; +import parsedMapping from '../mocks/parsed_mapping.json'; import { defaultAlertSettingsConfig } from './util'; describe('AlertsSettingsForm', () => { let wrapper; const mockToastShow = jest.fn(); - const createComponent = ({ - data = {}, - props = {}, - multipleHttpIntegrationsCustomMapping = false, - multiIntegrations = true, - } = {}) => { + const createComponent = ({ data = {}, props = {}, multiIntegrations = true } = {}) => { wrapper = mount(AlertsSettingsForm, { data() { return { ...data }; @@ -35,10 +24,12 @@ describe('AlertsSettingsForm', () => { }, provide: { ...defaultAlertSettingsConfig, - glFeatures: { multipleHttpIntegrationsCustomMapping }, multiIntegrations, }, mocks: { + $apollo: { + query: jest.fn(), + }, $toast: { show: mockToastShow, }, @@ -46,20 +37,20 @@ describe('AlertsSettingsForm', () => { }); }; - const findForm = () => wrapper.find(GlForm); - const findSelect = () => wrapper.find(GlFormSelect); - const findFormSteps = () => wrapper.find(GlCollapse); - const findFormFields = () => wrapper.findAll(GlFormInput); - const findFormToggle = () => wrapper.find(GlToggle); - const findTestPayloadSection = () => wrapper.find(`[id = "test-integration"]`); + 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 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="integration-test-and-submit"]`); + const findJsonTestSubmit = () => wrapper.find(`[data-testid="send-test-alert"]`); const findJsonTextArea = () => wrapper.find(`[id = "test-payload"]`); const findActionBtn = () => wrapper.find(`[data-testid="payload-action-btn"]`); + const findTabs = () => wrapper.findAllComponents(GlTab); afterEach(() => { if (wrapper) { @@ -91,7 +82,7 @@ describe('AlertsSettingsForm', () => { expect(findForm().exists()).toBe(true); expect(findSelect().exists()).toBe(true); expect(findMultiSupportText().exists()).toBe(false); - expect(findFormSteps().attributes('visible')).toBeUndefined(); + expect(findFormFields()).toHaveLength(0); }); it('shows the rest of the form when the dropdown is used', async () => { @@ -106,37 +97,47 @@ describe('AlertsSettingsForm', () => { expect(findMultiSupportText().exists()).toBe(true); }); - it('disabled the name input when the selected value is prometheus', async () => { + it('hides the name input when the selected value is prometheus', async () => { createComponent(); await selectOptionAtIndex(2); - - expect(findFormFields().at(0).attributes('disabled')).toBe('disabled'); + expect(findFormFields().at(0).attributes('id')).not.toBe('name-integration'); }); - }); - - describe('submitting integration form', () => { - describe('HTTP', () => { - it('create', async () => { - createComponent(); - const integrationName = 'Test integration'; - await selectOptionAtIndex(1); - enableIntegration(0, integrationName); - - const submitBtn = findSubmitButton(); - expect(submitBtn.exists()).toBe(true); - expect(submitBtn.text()).toBe('Save integration'); + describe('form tabs', () => { + it('renders 3 tabs', () => { + expect(findTabs()).toHaveLength(3); + }); - findForm().trigger('submit'); + it('only first tab is enabled on integration create', () => { + createComponent({ + data: { + currentIntegration: null, + }, + }); + const tabs = findTabs(); + expect(tabs.at(0).find('[role="tabpanel"]').classes('disabled')).toBe(false); + expect(tabs.at(1).find('[role="tabpanel"]').classes('disabled')).toBe(true); + expect(tabs.at(2).find('[role="tabpanel"]').classes('disabled')).toBe(true); + }); - expect(wrapper.emitted('create-new-integration')[0]).toEqual([ - { type: typeSet.http, variables: { name: integrationName, active: true } }, - ]); + it('all tabs are enabled on integration edit', () => { + createComponent({ + data: { + currentIntegration: { id: 1 }, + }, + }); + const tabs = findTabs(); + expect(tabs.at(0).find('[role="tabpanel"]').classes('disabled')).toBe(false); + expect(tabs.at(1).find('[role="tabpanel"]').classes('disabled')).toBe(false); + expect(tabs.at(2).find('[role="tabpanel"]').classes('disabled')).toBe(false); }); + }); + }); + describe('submitting integration form', () => { + describe('HTTP', () => { it('create with custom mapping', async () => { createComponent({ - multipleHttpIntegrationsCustomMapping: true, multiIntegrations: true, props: { alertFields }, }); @@ -146,7 +147,7 @@ describe('AlertsSettingsForm', () => { enableIntegration(0, integrationName); - const sampleMapping = { field: 'test' }; + const sampleMapping = parsedMapping.payloadAttributeMappings; findMappingBuilder().vm.$emit('onMappingUpdate', sampleMapping); findForm().trigger('submit'); @@ -157,7 +158,7 @@ describe('AlertsSettingsForm', () => { name: integrationName, active: true, payloadAttributeMappings: sampleMapping, - payloadExample: null, + payloadExample: '{}', }, }, ]); @@ -182,23 +183,28 @@ describe('AlertsSettingsForm', () => { findForm().trigger('submit'); - expect(wrapper.emitted('update-integration')[0]).toEqual([ - { type: typeSet.http, variables: { name: updatedIntegrationName, active: true } }, - ]); + expect(wrapper.emitted('update-integration')[0]).toEqual( + expect.arrayContaining([ + { + type: typeSet.http, + variables: { + name: updatedIntegrationName, + active: true, + payloadAttributeMappings: [], + payloadExample: '{}', + }, + }, + ]), + ); }); }); describe('PROMETHEUS', () => { it('create', async () => { createComponent(); - await selectOptionAtIndex(2); - const apiUrl = 'https://test.com'; - enableIntegration(1, apiUrl); - - findFormToggle().trigger('click'); - + enableIntegration(0, apiUrl); const submitBtn = findSubmitButton(); expect(submitBtn.exists()).toBe(true); expect(submitBtn.text()).toBe('Save integration'); @@ -222,7 +228,7 @@ describe('AlertsSettingsForm', () => { }); const apiUrl = 'https://test-post.com'; - enableIntegration(1, apiUrl); + enableIntegration(0, apiUrl); const submitBtn = findSubmitButton(); expect(submitBtn.exists()).toBe(true); @@ -260,7 +266,7 @@ describe('AlertsSettingsForm', () => { const jsonTestSubmit = findJsonTestSubmit(); expect(jsonTestSubmit.exists()).toBe(true); - expect(jsonTestSubmit.text()).toBe('Save and test payload'); + expect(jsonTestSubmit.text()).toBe('Send'); expect(jsonTestSubmit.props('disabled')).toBe(true); }); @@ -275,56 +281,73 @@ describe('AlertsSettingsForm', () => { }); describe('Test payload section for HTTP integration', () => { + const validSamplePayload = JSON.stringify(alertFields); + const emptySamplePayload = '{}'; + beforeEach(() => { createComponent({ - multipleHttpIntegrationsCustomMapping: true, - props: { + data: { currentIntegration: { type: typeSet.http, + payloadExample: validSamplePayload, + payloadAttributeMappings: [], }, - alertFields, + active: false, + resetPayloadAndMappingConfirmed: false, }, + props: { alertFields }, }); }); describe.each` - active | resetSamplePayloadConfirmed | disabled - ${true} | ${true} | ${undefined} - ${false} | ${true} | ${'disabled'} - ${true} | ${false} | ${'disabled'} - ${false} | ${false} | ${'disabled'} - `('', ({ active, resetSamplePayloadConfirmed, disabled }) => { - const payloadResetMsg = resetSamplePayloadConfirmed ? 'was confirmed' : 'was not confirmed'; + active | resetPayloadAndMappingConfirmed | disabled + ${true} | ${true} | ${undefined} + ${false} | ${true} | ${'disabled'} + ${true} | ${false} | ${'disabled'} + ${false} | ${false} | ${'disabled'} + `('', ({ active, resetPayloadAndMappingConfirmed, disabled }) => { + const payloadResetMsg = resetPayloadAndMappingConfirmed + ? 'was confirmed' + : 'was not confirmed'; const enabledState = disabled === 'disabled' ? 'disabled' : 'enabled'; const activeState = active ? 'active' : 'not active'; it(`textarea should be ${enabledState} when payload reset ${payloadResetMsg} and current integration is ${activeState}`, async () => { wrapper.setData({ - customMapping: { samplePayload: true }, + selectedIntegration: typeSet.http, active, - resetSamplePayloadConfirmed, + resetPayloadAndMappingConfirmed, }); await wrapper.vm.$nextTick(); - expect(findTestPayloadSection().find(GlFormTextarea).attributes('disabled')).toBe(disabled); + expect(findSamplePayloadSection().find(GlFormTextarea).attributes('disabled')).toBe( + disabled, + ); }); }); describe('action buttons for sample payload', () => { describe.each` - resetSamplePayloadConfirmed | samplePayload | caption - ${false} | ${true} | ${'Edit payload'} - ${true} | ${false} | ${'Submit payload'} - ${true} | ${true} | ${'Submit payload'} - ${false} | ${false} | ${'Submit payload'} - `('', ({ resetSamplePayloadConfirmed, samplePayload, caption }) => { - const samplePayloadMsg = samplePayload ? 'was provided' : 'was not provided'; - const payloadResetMsg = resetSamplePayloadConfirmed ? 'was confirmed' : 'was not confirmed'; + 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'} + `('', ({ resetPayloadAndMappingConfirmed, payloadExample, caption }) => { + const samplePayloadMsg = payloadExample ? 'was provided' : 'was not provided'; + const payloadResetMsg = resetPayloadAndMappingConfirmed + ? 'was confirmed' + : 'was not confirmed'; it(`shows ${caption} button when sample payload ${samplePayloadMsg} and payload reset ${payloadResetMsg}`, async () => { wrapper.setData({ selectedIntegration: typeSet.http, - customMapping: { samplePayload }, - resetSamplePayloadConfirmed, + currentIntegration: { + payloadExample, + type: typeSet.http, + active: true, + payloadAttributeMappings: [], + }, + resetPayloadAndMappingConfirmed, }); await wrapper.vm.$nextTick(); expect(findActionBtn().text()).toBe(caption); @@ -333,16 +356,20 @@ describe('AlertsSettingsForm', () => { }); describe('Parsing payload', () => { - it('displays a toast message on successful parse', async () => { - jest.useFakeTimers(); + beforeEach(() => { wrapper.setData({ selectedIntegration: typeSet.http, - customMapping: { samplePayload: false }, + resetPayloadAndMappingConfirmed: true, }); - await wrapper.vm.$nextTick(); + }); + it('displays a toast message on successful parse', async () => { + jest.spyOn(wrapper.vm.$apollo, 'query').mockResolvedValue({ + data: { + project: { alertManagementPayloadFields: [] }, + }, + }); findActionBtn().vm.$emit('click'); - jest.advanceTimersByTime(1000); await waitForPromises(); @@ -350,27 +377,33 @@ describe('AlertsSettingsForm', () => { 'Sample payload has been parsed. You can now map the fields.', ); }); + + it('displays an error message under payload field on unsuccessful parse', async () => { + const errorMessage = 'Error parsing paylod'; + jest.spyOn(wrapper.vm.$apollo, 'query').mockRejectedValue({ message: errorMessage }); + findActionBtn().vm.$emit('click'); + + await waitForPromises(); + + expect(findSamplePayloadSection().find('.invalid-feedback').text()).toBe(errorMessage); + }); }); }); describe('Mapping builder section', () => { describe.each` - alertFieldsProvided | multiIntegrations | featureFlag | integrationOption | visible - ${true} | ${true} | ${true} | ${1} | ${true} - ${true} | ${true} | ${true} | ${2} | ${false} - ${true} | ${true} | ${false} | ${1} | ${false} - ${true} | ${true} | ${false} | ${2} | ${false} - ${true} | ${false} | ${true} | ${1} | ${false} - ${false} | ${true} | ${true} | ${1} | ${false} - `('', ({ alertFieldsProvided, multiIntegrations, featureFlag, integrationOption, visible }) => { + alertFieldsProvided | multiIntegrations | integrationOption | visible + ${true} | ${true} | ${1} | ${true} + ${true} | ${true} | ${2} | ${false} + ${true} | ${false} | ${1} | ${false} + ${false} | ${true} | ${1} | ${false} + `('', ({ alertFieldsProvided, multiIntegrations, integrationOption, visible }) => { const visibleMsg = visible ? 'is rendered' : 'is not rendered'; - const featureFlagMsg = featureFlag ? 'is enabled' : 'is disabled'; const alertFieldsMsg = alertFieldsProvided ? 'are provided' : 'are not provided'; const integrationType = integrationOption === 1 ? typeSet.http : typeSet.prometheus; - it(`${visibleMsg} when multipleHttpIntegrationsCustomMapping feature flag ${featureFlagMsg} and integration type is ${integrationType} and alert fields ${alertFieldsMsg}`, async () => { + it(`${visibleMsg} when integration type is ${integrationType} and alert fields ${alertFieldsMsg}`, async () => { createComponent({ - multipleHttpIntegrationsCustomMapping: featureFlag, multiIntegrations, props: { alertFields: alertFieldsProvided ? alertFields : [], |