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')
-rw-r--r--spec/frontend/alerts_settings/__snapshots__/alerts_settings_form_spec.js.snap98
-rw-r--r--spec/frontend/alerts_settings/components/__snapshots__/alerts_settings_form_spec.js.snap406
-rw-r--r--spec/frontend/alerts_settings/components/alert_mapping_builder_spec.js (renamed from spec/frontend/alerts_settings/alert_mapping_builder_spec.js)49
-rw-r--r--spec/frontend/alerts_settings/components/alerts_integrations_list_spec.js (renamed from spec/frontend/alerts_settings/alerts_integrations_list_spec.js)2
-rw-r--r--spec/frontend/alerts_settings/components/alerts_settings_form_spec.js (renamed from spec/frontend/alerts_settings/alerts_settings_form_spec.js)242
-rw-r--r--spec/frontend/alerts_settings/components/alerts_settings_wrapper_spec.js (renamed from spec/frontend/alerts_settings/alerts_settings_wrapper_spec.js)24
-rw-r--r--spec/frontend/alerts_settings/components/mocks/apollo_mock.js (renamed from spec/frontend/alerts_settings/mocks/apollo_mock.js)0
-rw-r--r--spec/frontend/alerts_settings/components/mocks/integrations.json (renamed from spec/frontend/alerts_settings/mocks/integrations.json)0
-rw-r--r--spec/frontend/alerts_settings/components/util.js (renamed from spec/frontend/alerts_settings/util.js)0
-rw-r--r--spec/frontend/alerts_settings/mocks/alertFields.json123
-rw-r--r--spec/frontend/alerts_settings/utils/mapping_transformations_spec.js81
11 files changed, 790 insertions, 235 deletions
diff --git a/spec/frontend/alerts_settings/__snapshots__/alerts_settings_form_spec.js.snap b/spec/frontend/alerts_settings/__snapshots__/alerts_settings_form_spec.js.snap
deleted file mode 100644
index ef68a6a2c32..00000000000
--- a/spec/frontend/alerts_settings/__snapshots__/alerts_settings_form_spec.js.snap
+++ /dev/null
@@ -1,98 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`AlertsSettingsFormNew with default values renders the initial template 1`] = `
-"<form class=\\"gl-mt-6\\">
- <h5 class=\\"gl-font-lg gl-my-5\\">Add new integrations</h5>
- <div id=\\"integration-type\\" role=\\"group\\" class=\\"form-group gl-form-group\\"><label id=\\"integration-type__BV_label_\\" for=\\"integration-type\\" class=\\"d-block col-form-label\\">1. Select integration type</label>
- <div class=\\"bv-no-focus-ring\\"><select class=\\"gl-form-select mw-100 custom-select\\" id=\\"__BVID__8\\">
- <option value=\\"\\">Select integration type</option>
- <option value=\\"HTTP\\">HTTP Endpoint</option>
- <option value=\\"PROMETHEUS\\">External Prometheus</option>
- </select>
- <!---->
- <!---->
- <!---->
- <!---->
- </div>
- </div>
- <transition-stub css=\\"true\\" enterclass=\\"\\" leaveclass=\\"collapse show\\" entertoclass=\\"collapse show\\" leavetoclass=\\"collapse\\" enteractiveclass=\\"collapsing\\" leaveactiveclass=\\"collapsing\\" class=\\"gl-mt-3\\">
- <div class=\\"collapse\\" style=\\"display: none;\\" id=\\"__BVID__10\\">
- <div>
- <div id=\\"name-integration\\" role=\\"group\\" class=\\"form-group gl-form-group\\"><label id=\\"name-integration__BV_label_\\" for=\\"name-integration\\" class=\\"d-block col-form-label\\">2. Name integration</label>
- <div class=\\"bv-no-focus-ring\\"><input type=\\"text\\" placeholder=\\"Enter integration name\\" class=\\"gl-form-input form-control\\" id=\\"__BVID__15\\">
- <!---->
- <!---->
- <!---->
- </div>
- </div>
- <div id=\\"integration-webhook\\" role=\\"group\\" class=\\"form-group gl-form-group\\"><label id=\\"integration-webhook__BV_label_\\" for=\\"integration-webhook\\" class=\\"d-block col-form-label\\">3. Set up webhook</label>
- <div class=\\"bv-no-focus-ring\\"><span>Utilize the URL and authorization key below to authorize an external service to send alerts to GitLab. Review your external service's documentation to learn where to add these details, and the <a rel=\\"noopener noreferrer\\" target=\\"_blank\\" href=\\"https://docs.gitlab.com/ee/operations/incident_management/alert_integrations.html\\" class=\\"gl-link gl-display-inline-block\\">GitLab documentation</a> to learn more about configuring your endpoint.</span> <label class=\\"gl-display-flex gl-flex-direction-column gl-mb-0 gl-w-max-content gl-my-4 gl-font-weight-normal\\">
- <div class=\\"gl-toggle-wrapper\\"><span class=\\"gl-toggle-label\\">Active</span>
- <!----> <button aria-label=\\"Active\\" type=\\"button\\" class=\\"gl-toggle\\"><span class=\\"toggle-icon\\"><svg data-testid=\\"close-icon\\" aria-hidden=\\"true\\" class=\\"gl-icon s16\\"><use href=\\"#close\\"></use></svg></span></button></div>
- <!---->
- </label>
- <!---->
- <div class=\\"gl-my-4\\"><span class=\\"gl-font-weight-bold\\">
- Webhook URL
- </span>
- <div id=\\"url\\" readonly=\\"readonly\\">
- <div role=\\"group\\" class=\\"input-group\\">
- <!---->
- <!----> <input id=\\"url\\" type=\\"text\\" readonly=\\"readonly\\" class=\\"gl-form-input form-control\\">
- <div class=\\"input-group-append\\"><button title=\\"Copy\\" data-clipboard-text=\\"\\" aria-label=\\"Copy this value\\" type=\\"button\\" class=\\"btn gl-m-0! btn-default btn-md gl-button btn-default-secondary btn-icon\\">
- <!----> <svg data-testid=\\"copy-to-clipboard-icon\\" aria-hidden=\\"true\\" class=\\"gl-button-icon gl-icon s16\\">
- <use href=\\"#copy-to-clipboard\\"></use>
- </svg>
- <!----></button></div>
- <!---->
- </div>
- </div>
- </div>
- <div class=\\"gl-my-4\\"><span class=\\"gl-font-weight-bold\\">
- Authorization key
- </span>
- <div id=\\"authorization-key\\" readonly=\\"readonly\\" class=\\"gl-mb-3\\">
- <div role=\\"group\\" class=\\"input-group\\">
- <!---->
- <!----> <input id=\\"authorization-key\\" type=\\"text\\" readonly=\\"readonly\\" class=\\"gl-form-input form-control\\">
- <div class=\\"input-group-append\\"><button title=\\"Copy\\" data-clipboard-text=\\"\\" aria-label=\\"Copy this value\\" type=\\"button\\" class=\\"btn gl-m-0! btn-default btn-md gl-button btn-default-secondary btn-icon\\">
- <!----> <svg data-testid=\\"copy-to-clipboard-icon\\" aria-hidden=\\"true\\" class=\\"gl-button-icon gl-icon s16\\">
- <use href=\\"#copy-to-clipboard\\"></use>
- </svg>
- <!----></button></div>
- <!---->
- </div>
- </div> <button type=\\"button\\" disabled=\\"disabled\\" class=\\"btn btn-default btn-md disabled gl-button\\">
- <!---->
- <!----> <span class=\\"gl-button-text\\">
- Reset Key
- </span></button>
- <!---->
- </div>
- <!---->
- <!---->
- <!---->
- </div>
- </div>
- <div id=\\"test-integration\\" role=\\"group\\" class=\\"form-group gl-form-group\\"><label id=\\"test-integration__BV_label_\\" for=\\"test-integration\\" class=\\"d-block col-form-label\\">4. Sample alert payload (optional)</label>
- <div class=\\"bv-no-focus-ring\\"><span>Provide an example payload from the monitoring tool you intend to integrate with. This payload can be used to test the integration (optional).</span> <textarea id=\\"test-payload\\" disabled=\\"disabled\\" placeholder=\\"{ &quot;events&quot;: [{ &quot;application&quot;: &quot;Name of application&quot; }] }\\" wrap=\\"soft\\" class=\\"gl-form-input gl-form-textarea gl-my-3 form-control is-valid\\" style=\\"resize: none; overflow-y: scroll;\\"></textarea>
- <!---->
- <!---->
- <!---->
- </div>
- </div>
- <!---->
- <!---->
- </div>
- <div class=\\"gl-display-flex gl-justify-content-start gl-py-3\\"><button data-testid=\\"integration-form-submit\\" type=\\"submit\\" class=\\"btn js-no-auto-disable btn-success btn-md gl-button\\">
- <!---->
- <!----> <span class=\\"gl-button-text\\">Save integration
- </span></button> <button data-testid=\\"integration-test-and-submit\\" type=\\"button\\" disabled=\\"disabled\\" class=\\"btn gl-mx-3 js-no-auto-disable btn-success btn-md disabled gl-button btn-success-secondary\\">
- <!---->
- <!----> <span class=\\"gl-button-text\\">Save and test payload</span></button> <button type=\\"reset\\" class=\\"btn js-no-auto-disable btn-default btn-md gl-button\\">
- <!---->
- <!----> <span class=\\"gl-button-text\\">Cancel</span></button></div>
- </div>
- </transition-stub>
-</form>"
-`;
diff --git a/spec/frontend/alerts_settings/components/__snapshots__/alerts_settings_form_spec.js.snap b/spec/frontend/alerts_settings/components/__snapshots__/alerts_settings_form_spec.js.snap
new file mode 100644
index 00000000000..eb2b82a0211
--- /dev/null
+++ b/spec/frontend/alerts_settings/components/__snapshots__/alerts_settings_form_spec.js.snap
@@ -0,0 +1,406 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`AlertsSettingsForm with default values renders the initial template 1`] = `
+<form
+ class="gl-mt-6"
+>
+ <h5
+ class="gl-font-lg gl-my-5"
+ >
+ Add new integrations
+ </h5>
+
+ <div
+ class="form-group gl-form-group"
+ id="integration-type"
+ role="group"
+ >
+ <label
+ class="d-block col-form-label"
+ for="integration-type"
+ id="integration-type__BV_label_"
+ >
+ 1. Select integration type
+ </label>
+ <div
+ class="bv-no-focus-ring"
+ >
+ <select
+ class="gl-form-select mw-100 custom-select"
+ id="__BVID__8"
+ >
+ <option
+ value=""
+ >
+ Select integration type
+ </option>
+ <option
+ value="HTTP"
+ >
+ HTTP Endpoint
+ </option>
+ <option
+ value="PROMETHEUS"
+ >
+ External Prometheus
+ </option>
+ </select>
+
+ <!---->
+ <!---->
+ <!---->
+ <!---->
+ </div>
+ </div>
+
+ <transition-stub
+ class="gl-mt-3"
+ css="true"
+ enteractiveclass="collapsing"
+ enterclass=""
+ entertoclass="collapse show"
+ leaveactiveclass="collapsing"
+ leaveclass="collapse show"
+ leavetoclass="collapse"
+ >
+ <div
+ class="collapse"
+ id="__BVID__10"
+ style="display: none;"
+ >
+ <div>
+ <div
+ class="form-group gl-form-group"
+ id="name-integration"
+ role="group"
+ >
+ <label
+ class="d-block col-form-label"
+ for="name-integration"
+ id="name-integration__BV_label_"
+ >
+ 2. Name integration
+ </label>
+ <div
+ class="bv-no-focus-ring"
+ >
+ <input
+ class="gl-form-input form-control"
+ id="__BVID__15"
+ placeholder="Enter integration name"
+ type="text"
+ />
+ <!---->
+ <!---->
+ <!---->
+ </div>
+ </div>
+
+ <div
+ class="form-group gl-form-group"
+ id="integration-webhook"
+ role="group"
+ >
+ <label
+ class="d-block col-form-label"
+ for="integration-webhook"
+ id="integration-webhook__BV_label_"
+ >
+ 3. Set up webhook
+ </label>
+ <div
+ class="bv-no-focus-ring"
+ >
+ <span>
+ Utilize the URL and authorization key below to authorize an external service to send alerts to GitLab. Review your external service's documentation to learn where to add these details, and the
+ <a
+ class="gl-link gl-display-inline-block"
+ href="https://docs.gitlab.com/ee/operations/incident_management/alert_integrations.html"
+ rel="noopener noreferrer"
+ target="_blank"
+ >
+ GitLab documentation
+ </a>
+ to learn more about configuring your endpoint.
+ </span>
+
+ <label
+ class="gl-display-flex gl-flex-direction-column gl-mb-0 gl-w-max-content gl-my-4 gl-font-weight-normal"
+ >
+ <span
+ class="gl-toggle-wrapper"
+ >
+ <span
+ class="gl-toggle-label"
+ data-testid="toggle-label"
+ >
+ Active
+ </span>
+
+ <!---->
+
+ <button
+ aria-label="Active"
+ class="gl-toggle"
+ role="switch"
+ type="button"
+ >
+ <span
+ class="toggle-icon"
+ >
+ <svg
+ aria-hidden="true"
+ class="gl-icon s16"
+ data-testid="close-icon"
+ >
+ <use
+ href="#close"
+ />
+ </svg>
+ </span>
+ </button>
+ </span>
+
+ <!---->
+ </label>
+
+ <!---->
+
+ <div
+ class="gl-my-4"
+ >
+ <span
+ class="gl-font-weight-bold"
+ >
+
+ Webhook URL
+
+ </span>
+
+ <div
+ id="url"
+ readonly="readonly"
+ >
+ <div
+ class="input-group"
+ role="group"
+ >
+ <!---->
+ <!---->
+
+ <input
+ class="gl-form-input form-control"
+ id="url"
+ readonly="readonly"
+ type="text"
+ />
+
+ <div
+ class="input-group-append"
+ >
+ <button
+ aria-label="Copy this value"
+ class="btn gl-m-0! btn-default btn-md gl-button btn-default-secondary btn-icon"
+ data-clipboard-text=""
+ title="Copy"
+ type="button"
+ >
+ <!---->
+
+ <svg
+ aria-hidden="true"
+ class="gl-button-icon gl-icon s16"
+ data-testid="copy-to-clipboard-icon"
+ >
+ <use
+ href="#copy-to-clipboard"
+ />
+ </svg>
+
+ <!---->
+ </button>
+ </div>
+ <!---->
+ </div>
+ </div>
+ </div>
+
+ <div
+ class="gl-my-4"
+ >
+ <span
+ class="gl-font-weight-bold"
+ >
+
+ Authorization key
+
+ </span>
+
+ <div
+ class="gl-mb-3"
+ id="authorization-key"
+ readonly="readonly"
+ >
+ <div
+ class="input-group"
+ role="group"
+ >
+ <!---->
+ <!---->
+
+ <input
+ class="gl-form-input form-control"
+ id="authorization-key"
+ readonly="readonly"
+ type="text"
+ />
+
+ <div
+ class="input-group-append"
+ >
+ <button
+ aria-label="Copy this value"
+ class="btn gl-m-0! btn-default btn-md gl-button btn-default-secondary btn-icon"
+ data-clipboard-text=""
+ title="Copy"
+ type="button"
+ >
+ <!---->
+
+ <svg
+ aria-hidden="true"
+ class="gl-button-icon gl-icon s16"
+ data-testid="copy-to-clipboard-icon"
+ >
+ <use
+ href="#copy-to-clipboard"
+ />
+ </svg>
+
+ <!---->
+ </button>
+ </div>
+ <!---->
+ </div>
+ </div>
+
+ <button
+ class="btn btn-default btn-md disabled gl-button"
+ disabled="disabled"
+ type="button"
+ >
+ <!---->
+
+ <!---->
+
+ <span
+ class="gl-button-text"
+ >
+
+ Reset Key
+
+ </span>
+ </button>
+
+ <!---->
+ </div>
+ <!---->
+ <!---->
+ <!---->
+ </div>
+ </div>
+
+ <div
+ class="form-group gl-form-group"
+ id="test-integration"
+ role="group"
+ >
+ <label
+ class="d-block col-form-label"
+ for="test-integration"
+ id="test-integration__BV_label_"
+ >
+ 4. Sample alert payload (optional)
+ </label>
+ <div
+ class="bv-no-focus-ring"
+ >
+ <span>
+ Provide an example payload from the monitoring tool you intend to integrate with. This payload can be used to test the integration (optional).
+ </span>
+
+ <textarea
+ class="gl-form-input gl-form-textarea gl-my-3 form-control is-valid"
+ disabled="disabled"
+ id="test-payload"
+ placeholder="{ \\"events\\": [{ \\"application\\": \\"Name of application\\" }] }"
+ style="resize: none; overflow-y: scroll;"
+ wrap="soft"
+ />
+ <!---->
+ <!---->
+ <!---->
+ </div>
+ </div>
+
+ <!---->
+
+ <!---->
+ </div>
+
+ <div
+ class="gl-display-flex gl-justify-content-start gl-py-3"
+ >
+ <button
+ class="btn js-no-auto-disable btn-success btn-md gl-button"
+ data-testid="integration-form-submit"
+ type="submit"
+ >
+ <!---->
+
+ <!---->
+
+ <span
+ class="gl-button-text"
+ >
+ Save integration
+
+ </span>
+ </button>
+
+ <button
+ class="btn gl-mx-3 js-no-auto-disable btn-success btn-md disabled gl-button btn-success-secondary"
+ data-testid="integration-test-and-submit"
+ disabled="disabled"
+ type="button"
+ >
+ <!---->
+
+ <!---->
+
+ <span
+ class="gl-button-text"
+ >
+ Save and test payload
+ </span>
+ </button>
+
+ <button
+ class="btn js-no-auto-disable btn-default btn-md gl-button"
+ type="reset"
+ >
+ <!---->
+
+ <!---->
+
+ <span
+ class="gl-button-text"
+ >
+ Cancel
+ </span>
+ </button>
+ </div>
+ </div>
+ </transition-stub>
+</form>
+`;
diff --git a/spec/frontend/alerts_settings/alert_mapping_builder_spec.js b/spec/frontend/alerts_settings/components/alert_mapping_builder_spec.js
index 5d48ff02e35..7e1d1acb62c 100644
--- a/spec/frontend/alerts_settings/alert_mapping_builder_spec.js
+++ b/spec/frontend/alerts_settings/components/alert_mapping_builder_spec.js
@@ -1,8 +1,10 @@
import { GlIcon, GlFormInput, GlDropdown, GlSearchBoxByType, GlDropdownItem } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import AlertMappingBuilder, { i18n } from '~/alerts_settings/components/alert_mapping_builder.vue';
-import gitlabFields from '~/alerts_settings/components/mocks/gitlabFields.json';
import parsedMapping from '~/alerts_settings/components/mocks/parsedMapping.json';
+import * as transformationUtils from '~/alerts_settings/utils/mapping_transformations';
+import { capitalizeFirstCharacter } from '~/lib/utils/text_utility';
+import alertFields from '../mocks/alertFields.json';
describe('AlertMappingBuilder', () => {
let wrapper;
@@ -10,8 +12,9 @@ describe('AlertMappingBuilder', () => {
function mountComponent() {
wrapper = shallowMount(AlertMappingBuilder, {
propsData: {
- payloadFields: parsedMapping.samplePayload.payloadAlerFields.nodes,
- mapping: parsedMapping.storedMapping.nodes,
+ parsedPayload: parsedMapping.samplePayload.payloadAlerFields.nodes,
+ savedMapping: parsedMapping.storedMapping.nodes,
+ alertFields,
},
});
}
@@ -42,52 +45,58 @@ describe('AlertMappingBuilder', () => {
});
it('renders disabled form input for each mapped field', () => {
- gitlabFields.forEach((field, index) => {
+ alertFields.forEach((field, index) => {
const input = findColumnInRow(index + 1, 0).find(GlFormInput);
- expect(input.attributes('value')).toBe(`${field.label} (${field.type.join(' or ')})`);
+ const types = field.types.map((t) => capitalizeFirstCharacter(t.toLowerCase())).join(' or ');
+ expect(input.attributes('value')).toBe(`${field.label} (${types})`);
expect(input.attributes('disabled')).toBe('');
});
});
it('renders right arrow next to each input', () => {
- gitlabFields.forEach((field, index) => {
+ alertFields.forEach((field, index) => {
const arrow = findColumnInRow(index + 1, 1).find('.right-arrow');
expect(arrow.exists()).toBe(true);
});
});
it('renders mapping dropdown for each field', () => {
- gitlabFields.forEach(({ compatibleTypes }, index) => {
+ alertFields.forEach(({ types }, index) => {
const dropdown = findColumnInRow(index + 1, 2).find(GlDropdown);
- const searchBox = dropdown.find(GlSearchBoxByType);
- const dropdownItems = dropdown.findAll(GlDropdownItem);
+ const searchBox = dropdown.findComponent(GlSearchBoxByType);
+ const dropdownItems = dropdown.findAllComponents(GlDropdownItem);
const { nodes } = parsedMapping.samplePayload.payloadAlerFields;
- const numberOfMappingOptions = nodes.filter(({ type }) =>
- type.some((t) => compatibleTypes.includes(t)),
- );
+ const mappingOptions = nodes.filter(({ type }) => types.includes(type));
expect(dropdown.exists()).toBe(true);
expect(searchBox.exists()).toBe(true);
- expect(dropdownItems).toHaveLength(numberOfMappingOptions.length);
+ expect(dropdownItems).toHaveLength(mappingOptions.length);
});
});
it('renders fallback dropdown only for the fields that have fallback', () => {
- gitlabFields.forEach(({ compatibleTypes, numberOfFallbacks }, index) => {
+ alertFields.forEach(({ types, numberOfFallbacks }, index) => {
const dropdown = findColumnInRow(index + 1, 3).find(GlDropdown);
expect(dropdown.exists()).toBe(Boolean(numberOfFallbacks));
if (numberOfFallbacks) {
- const searchBox = dropdown.find(GlSearchBoxByType);
- const dropdownItems = dropdown.findAll(GlDropdownItem);
+ const searchBox = dropdown.findComponent(GlSearchBoxByType);
+ const dropdownItems = dropdown.findAllComponents(GlDropdownItem);
const { nodes } = parsedMapping.samplePayload.payloadAlerFields;
- const numberOfMappingOptions = nodes.filter(({ type }) =>
- type.some((t) => compatibleTypes.includes(t)),
- );
+ const mappingOptions = nodes.filter(({ type }) => types.includes(type));
expect(searchBox.exists()).toBe(Boolean(numberOfFallbacks));
- expect(dropdownItems).toHaveLength(numberOfMappingOptions.length);
+ expect(dropdownItems).toHaveLength(mappingOptions.length);
}
});
});
+
+ it('emits event with selected mapping', () => {
+ const mappingToSave = { fieldName: 'TITLE', mapping: 'PARSED_TITLE' };
+ jest.spyOn(transformationUtils, 'transformForSave').mockReturnValue(mappingToSave);
+ const dropdown = findColumnInRow(1, 2).find(GlDropdown);
+ const option = dropdown.find(GlDropdownItem);
+ option.vm.$emit('click');
+ expect(wrapper.emitted('onMappingUpdate')[0]).toEqual([mappingToSave]);
+ });
});
diff --git a/spec/frontend/alerts_settings/alerts_integrations_list_spec.js b/spec/frontend/alerts_settings/components/alerts_integrations_list_spec.js
index 5a3874d055b..c43d78a1cf3 100644
--- a/spec/frontend/alerts_settings/alerts_integrations_list_spec.js
+++ b/spec/frontend/alerts_settings/components/alerts_integrations_list_spec.js
@@ -1,11 +1,11 @@
import { GlTable, GlIcon, GlButton } from '@gitlab/ui';
import { mount } from '@vue/test-utils';
import { useMockIntersectionObserver } from 'helpers/mock_dom_observer';
-import Tracking from '~/tracking';
import AlertIntegrationsList, {
i18n,
} from '~/alerts_settings/components/alerts_integrations_list.vue';
import { trackAlertIntegrationsViewsOptions } from '~/alerts_settings/constants';
+import Tracking from '~/tracking';
const mockIntegrations = [
{
diff --git a/spec/frontend/alerts_settings/alerts_settings_form_spec.js b/spec/frontend/alerts_settings/components/alerts_settings_form_spec.js
index 21cdec6f94c..02229b3d3da 100644
--- a/spec/frontend/alerts_settings/alerts_settings_form_spec.js
+++ b/spec/frontend/alerts_settings/components/alerts_settings_form_spec.js
@@ -1,4 +1,3 @@
-import { mount } from '@vue/test-utils';
import {
GlForm,
GlFormSelect,
@@ -7,12 +6,15 @@ import {
GlToggle,
GlFormTextarea,
} 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 { defaultAlertSettingsConfig } from './util';
import { typeSet } from '~/alerts_settings/constants';
+import alertFields from '../mocks/alertFields.json';
+import { defaultAlertSettingsConfig } from './util';
-describe('AlertsSettingsFormNew', () => {
+describe('AlertsSettingsForm', () => {
let wrapper;
const mockToastShow = jest.fn();
@@ -20,6 +22,7 @@ describe('AlertsSettingsFormNew', () => {
data = {},
props = {},
multipleHttpIntegrationsCustomMapping = false,
+ multiIntegrations = true,
} = {}) => {
wrapper = mount(AlertsSettingsForm, {
data() {
@@ -31,8 +34,9 @@ describe('AlertsSettingsFormNew', () => {
...props,
},
provide: {
- glFeatures: { multipleHttpIntegrationsCustomMapping },
...defaultAlertSettingsConfig,
+ glFeatures: { multipleHttpIntegrationsCustomMapping },
+ multiIntegrations,
},
mocks: {
$toast: {
@@ -49,6 +53,7 @@ describe('AlertsSettingsFormNew', () => {
const findFormToggle = () => wrapper.find(GlToggle);
const findTestPayloadSection = () => wrapper.find(`[id = "test-integration"]`);
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"]`);
@@ -63,13 +68,23 @@ describe('AlertsSettingsFormNew', () => {
}
});
+ const selectOptionAtIndex = async (index) => {
+ const options = findSelect().findAll('option');
+ await options.at(index).setSelected();
+ };
+
+ const enableIntegration = (index, value) => {
+ findFormFields().at(index).setValue(value);
+ findFormToggle().trigger('click');
+ };
+
describe('with default values', () => {
beforeEach(() => {
createComponent();
});
it('renders the initial template', () => {
- expect(wrapper.html()).toMatchSnapshot();
+ expect(wrapper.element).toMatchSnapshot();
});
it('render the initial form with only an integration type dropdown', () => {
@@ -80,10 +95,7 @@ describe('AlertsSettingsFormNew', () => {
});
it('shows the rest of the form when the dropdown is used', async () => {
- const options = findSelect().findAll('option');
- await options.at(1).setSelected();
-
- await wrapper.vm.$nextTick();
+ await selectOptionAtIndex(1);
expect(findFormFields().at(0).isVisible()).toBe(true);
});
@@ -96,120 +108,132 @@ describe('AlertsSettingsFormNew', () => {
it('disabled the name input when the selected value is prometheus', async () => {
createComponent();
- const options = findSelect().findAll('option');
- await options.at(2).setSelected();
+ await selectOptionAtIndex(2);
expect(findFormFields().at(0).attributes('disabled')).toBe('disabled');
});
});
describe('submitting integration form', () => {
- it('allows for create-new-integration with the correct form values for HTTP', async () => {
- createComponent();
-
- const options = findSelect().findAll('option');
- await options.at(1).setSelected();
-
- await findFormFields().at(0).setValue('Test integration');
- await findFormToggle().trigger('click');
+ describe('HTTP', () => {
+ it('create', async () => {
+ createComponent();
- await wrapper.vm.$nextTick();
-
- expect(findSubmitButton().exists()).toBe(true);
- expect(findSubmitButton().text()).toBe('Save integration');
+ const integrationName = 'Test integration';
+ await selectOptionAtIndex(1);
+ enableIntegration(0, integrationName);
- findForm().trigger('submit');
+ const submitBtn = findSubmitButton();
+ expect(submitBtn.exists()).toBe(true);
+ expect(submitBtn.text()).toBe('Save integration');
- await wrapper.vm.$nextTick();
+ findForm().trigger('submit');
- expect(wrapper.emitted('create-new-integration')).toBeTruthy();
- expect(wrapper.emitted('create-new-integration')[0]).toEqual([
- { type: typeSet.http, variables: { name: 'Test integration', active: true } },
- ]);
- });
+ expect(wrapper.emitted('create-new-integration')[0]).toEqual([
+ { type: typeSet.http, variables: { name: integrationName, active: true } },
+ ]);
+ });
- it('allows for create-new-integration with the correct form values for PROMETHEUS', async () => {
- createComponent();
+ it('create with custom mapping', async () => {
+ createComponent({
+ multipleHttpIntegrationsCustomMapping: true,
+ multiIntegrations: true,
+ props: { alertFields },
+ });
- const options = findSelect().findAll('option');
- await options.at(2).setSelected();
+ const integrationName = 'Test integration';
+ await selectOptionAtIndex(1);
- await findFormFields().at(0).setValue('Test integration');
- await findFormFields().at(1).setValue('https://test.com');
- await findFormToggle().trigger('click');
+ enableIntegration(0, integrationName);
- await wrapper.vm.$nextTick();
+ const sampleMapping = { field: 'test' };
+ findMappingBuilder().vm.$emit('onMappingUpdate', sampleMapping);
+ findForm().trigger('submit');
- expect(findSubmitButton().exists()).toBe(true);
- expect(findSubmitButton().text()).toBe('Save integration');
+ expect(wrapper.emitted('create-new-integration')[0]).toEqual([
+ {
+ type: typeSet.http,
+ variables: {
+ name: integrationName,
+ active: true,
+ payloadAttributeMappings: sampleMapping,
+ payloadExample: null,
+ },
+ },
+ ]);
+ });
- findForm().trigger('submit');
+ it('update', () => {
+ createComponent({
+ data: {
+ selectedIntegration: typeSet.http,
+ currentIntegration: { id: '1', name: 'Test integration pre' },
+ },
+ props: {
+ loading: false,
+ },
+ });
+ const updatedIntegrationName = 'Test integration post';
+ enableIntegration(0, updatedIntegrationName);
- await wrapper.vm.$nextTick();
+ const submitBtn = findSubmitButton();
+ expect(submitBtn.exists()).toBe(true);
+ expect(submitBtn.text()).toBe('Save integration');
- expect(wrapper.emitted('create-new-integration')).toBeTruthy();
- expect(wrapper.emitted('create-new-integration')[0]).toEqual([
- { type: typeSet.prometheus, variables: { apiUrl: 'https://test.com', active: true } },
- ]);
- });
+ findForm().trigger('submit');
- it('allows for update-integration with the correct form values for HTTP', async () => {
- createComponent({
- data: {
- selectedIntegration: typeSet.http,
- currentIntegration: { id: '1', name: 'Test integration pre' },
- },
- props: {
- loading: false,
- },
+ expect(wrapper.emitted('update-integration')[0]).toEqual([
+ { type: typeSet.http, variables: { name: updatedIntegrationName, active: true } },
+ ]);
});
+ });
- await findFormFields().at(0).setValue('Test integration post');
- await findFormToggle().trigger('click');
+ describe('PROMETHEUS', () => {
+ it('create', async () => {
+ createComponent();
- await wrapper.vm.$nextTick();
+ await selectOptionAtIndex(2);
- expect(findSubmitButton().exists()).toBe(true);
- expect(findSubmitButton().text()).toBe('Save integration');
+ const apiUrl = 'https://test.com';
+ enableIntegration(1, apiUrl);
- findForm().trigger('submit');
+ findFormToggle().trigger('click');
- await wrapper.vm.$nextTick();
+ const submitBtn = findSubmitButton();
+ expect(submitBtn.exists()).toBe(true);
+ expect(submitBtn.text()).toBe('Save integration');
- expect(wrapper.emitted('update-integration')).toBeTruthy();
- expect(wrapper.emitted('update-integration')[0]).toEqual([
- { type: typeSet.http, variables: { name: 'Test integration post', active: true } },
- ]);
- });
+ findForm().trigger('submit');
- it('allows for update-integration with the correct form values for PROMETHEUS', async () => {
- createComponent({
- data: {
- selectedIntegration: typeSet.prometheus,
- currentIntegration: { id: '1', apiUrl: 'https://test-pre.com' },
- },
- props: {
- loading: false,
- },
+ expect(wrapper.emitted('create-new-integration')[0]).toEqual([
+ { type: typeSet.prometheus, variables: { apiUrl, active: true } },
+ ]);
});
- await findFormFields().at(0).setValue('Test integration');
- await findFormFields().at(1).setValue('https://test-post.com');
- await findFormToggle().trigger('click');
-
- await wrapper.vm.$nextTick();
+ it('update', () => {
+ createComponent({
+ data: {
+ selectedIntegration: typeSet.prometheus,
+ currentIntegration: { id: '1', apiUrl: 'https://test-pre.com' },
+ },
+ props: {
+ loading: false,
+ },
+ });
- expect(findSubmitButton().exists()).toBe(true);
- expect(findSubmitButton().text()).toBe('Save integration');
+ const apiUrl = 'https://test-post.com';
+ enableIntegration(1, apiUrl);
- findForm().trigger('submit');
+ const submitBtn = findSubmitButton();
+ expect(submitBtn.exists()).toBe(true);
+ expect(submitBtn.text()).toBe('Save integration');
- await wrapper.vm.$nextTick();
+ findForm().trigger('submit');
- expect(wrapper.emitted('update-integration')).toBeTruthy();
- expect(wrapper.emitted('update-integration')[0]).toEqual([
- { type: typeSet.prometheus, variables: { apiUrl: 'https://test-post.com', active: true } },
- ]);
+ expect(wrapper.emitted('update-integration')[0]).toEqual([
+ { type: typeSet.prometheus, variables: { apiUrl, active: true } },
+ ]);
+ });
});
});
@@ -234,9 +258,10 @@ describe('AlertsSettingsFormNew', () => {
jest.runAllTimers();
await wrapper.vm.$nextTick();
- expect(findJsonTestSubmit().exists()).toBe(true);
- expect(findJsonTestSubmit().text()).toBe('Save and test payload');
- expect(findJsonTestSubmit().props('disabled')).toBe(true);
+ const jsonTestSubmit = findJsonTestSubmit();
+ expect(jsonTestSubmit.exists()).toBe(true);
+ expect(jsonTestSubmit.text()).toBe('Save and test payload');
+ expect(jsonTestSubmit.props('disabled')).toBe(true);
});
it('should allow for the form to be automatically saved if the test payload is successfully submitted', async () => {
@@ -257,6 +282,7 @@ describe('AlertsSettingsFormNew', () => {
currentIntegration: {
type: typeSet.http,
},
+ alertFields,
},
});
});
@@ -329,21 +355,29 @@ describe('AlertsSettingsFormNew', () => {
describe('Mapping builder section', () => {
describe.each`
- featureFlag | integrationOption | visible
- ${true} | ${1} | ${true}
- ${true} | ${2} | ${false}
- ${false} | ${1} | ${false}
- ${false} | ${2} | ${false}
- `('', ({ featureFlag, integrationOption, visible }) => {
+ 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 }) => {
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}`, async () => {
- createComponent({ multipleHttpIntegrationsCustomMapping: featureFlag });
- const options = findSelect().findAll('option');
- options.at(integrationOption).setSelected();
- await wrapper.vm.$nextTick();
+ it(`${visibleMsg} when multipleHttpIntegrationsCustomMapping feature flag ${featureFlagMsg} and integration type is ${integrationType} and alert fields ${alertFieldsMsg}`, async () => {
+ createComponent({
+ multipleHttpIntegrationsCustomMapping: featureFlag,
+ multiIntegrations,
+ props: {
+ alertFields: alertFieldsProvided ? alertFields : [],
+ },
+ });
+ await selectOptionAtIndex(integrationOption);
+
expect(findMappingBuilderSection().exists()).toBe(visible);
});
});
diff --git a/spec/frontend/alerts_settings/alerts_settings_wrapper_spec.js b/spec/frontend/alerts_settings/components/alerts_settings_wrapper_spec.js
index 4d0732ca76c..80293597ab6 100644
--- a/spec/frontend/alerts_settings/alerts_settings_wrapper_spec.js
+++ b/spec/frontend/alerts_settings/components/alerts_settings_wrapper_spec.js
@@ -1,23 +1,22 @@
-import VueApollo from 'vue-apollo';
+import { GlLoadingIcon } from '@gitlab/ui';
import { mount, createLocalVue } from '@vue/test-utils';
import AxiosMockAdapter from 'axios-mock-adapter';
+import VueApollo from 'vue-apollo';
import createMockApollo from 'helpers/mock_apollo_helper';
-import waitForPromises from 'helpers/wait_for_promises';
import { useMockIntersectionObserver } from 'helpers/mock_dom_observer';
-import { GlLoadingIcon } from '@gitlab/ui';
-import axios from '~/lib/utils/axios_utils';
-import AlertsSettingsWrapper from '~/alerts_settings/components/alerts_settings_wrapper.vue';
-import AlertsSettingsForm from '~/alerts_settings/components/alerts_settings_form.vue';
+import waitForPromises from 'helpers/wait_for_promises';
import IntegrationsList from '~/alerts_settings/components/alerts_integrations_list.vue';
-import getIntegrationsQuery from '~/alerts_settings/graphql/queries/get_integrations.query.graphql';
+import AlertsSettingsForm from '~/alerts_settings/components/alerts_settings_form.vue';
+import AlertsSettingsWrapper from '~/alerts_settings/components/alerts_settings_wrapper.vue';
+import { typeSet } from '~/alerts_settings/constants';
import createHttpIntegrationMutation from '~/alerts_settings/graphql/mutations/create_http_integration.mutation.graphql';
import createPrometheusIntegrationMutation from '~/alerts_settings/graphql/mutations/create_prometheus_integration.mutation.graphql';
-import updateHttpIntegrationMutation from '~/alerts_settings/graphql/mutations/update_http_integration.mutation.graphql';
-import updatePrometheusIntegrationMutation from '~/alerts_settings/graphql/mutations/update_prometheus_integration.mutation.graphql';
import destroyHttpIntegrationMutation from '~/alerts_settings/graphql/mutations/destroy_http_integration.mutation.graphql';
import resetHttpTokenMutation from '~/alerts_settings/graphql/mutations/reset_http_token.mutation.graphql';
import resetPrometheusTokenMutation from '~/alerts_settings/graphql/mutations/reset_prometheus_token.mutation.graphql';
-import { typeSet } from '~/alerts_settings/constants';
+import updateHttpIntegrationMutation from '~/alerts_settings/graphql/mutations/update_http_integration.mutation.graphql';
+import updatePrometheusIntegrationMutation from '~/alerts_settings/graphql/mutations/update_prometheus_integration.mutation.graphql';
+import getIntegrationsQuery from '~/alerts_settings/graphql/queries/get_integrations.query.graphql';
import {
ADD_INTEGRATION_ERROR,
RESET_INTEGRATION_TOKEN_ERROR,
@@ -26,8 +25,7 @@ import {
DELETE_INTEGRATION_ERROR,
} from '~/alerts_settings/utils/error_messages';
import createFlash from '~/flash';
-import { defaultAlertSettingsConfig } from './util';
-import mockIntegrations from './mocks/integrations.json';
+import axios from '~/lib/utils/axios_utils';
import {
createHttpVariables,
updateHttpVariables,
@@ -40,6 +38,8 @@ import {
integrationToDestroy,
destroyIntegrationResponseWithErrors,
} from './mocks/apollo_mock';
+import mockIntegrations from './mocks/integrations.json';
+import { defaultAlertSettingsConfig } from './util';
jest.mock('~/flash');
diff --git a/spec/frontend/alerts_settings/mocks/apollo_mock.js b/spec/frontend/alerts_settings/components/mocks/apollo_mock.js
index e0eba1e8421..e0eba1e8421 100644
--- a/spec/frontend/alerts_settings/mocks/apollo_mock.js
+++ b/spec/frontend/alerts_settings/components/mocks/apollo_mock.js
diff --git a/spec/frontend/alerts_settings/mocks/integrations.json b/spec/frontend/alerts_settings/components/mocks/integrations.json
index b1284fc55a2..b1284fc55a2 100644
--- a/spec/frontend/alerts_settings/mocks/integrations.json
+++ b/spec/frontend/alerts_settings/components/mocks/integrations.json
diff --git a/spec/frontend/alerts_settings/util.js b/spec/frontend/alerts_settings/components/util.js
index 5c07f22f1c9..5c07f22f1c9 100644
--- a/spec/frontend/alerts_settings/util.js
+++ b/spec/frontend/alerts_settings/components/util.js
diff --git a/spec/frontend/alerts_settings/mocks/alertFields.json b/spec/frontend/alerts_settings/mocks/alertFields.json
new file mode 100644
index 00000000000..ffe59dd0c05
--- /dev/null
+++ b/spec/frontend/alerts_settings/mocks/alertFields.json
@@ -0,0 +1,123 @@
+[
+ {
+ "name": "title",
+ "label": "Title",
+ "type": [
+ "string"
+ ],
+ "types": [
+ "string",
+ "number",
+ "datetime"
+ ],
+ "numberOfFallbacks": 1
+ },
+ {
+ "name": "description",
+ "label": "Description",
+ "type": [
+ "string"
+ ],
+ "types": [
+ "string",
+ "number",
+ "datetime"
+ ]
+ },
+ {
+ "name": "start_time",
+ "label": "Start time",
+ "type": [
+ "datetime"
+ ],
+ "types": [
+ "number",
+ "datetime"
+ ]
+ },
+ {
+ "name": "end_time",
+ "label": "End time",
+ "type": [
+ "datetime"
+ ],
+ "types": [
+ "number",
+ "datetime"
+ ]
+ },
+ {
+ "name": "service",
+ "label": "Service",
+ "type": [
+ "string"
+ ],
+ "types": [
+ "string",
+ "number",
+ "datetime"
+ ]
+ },
+ {
+ "name": "monitoring_tool",
+ "label": "Monitoring tool",
+ "type": [
+ "string"
+ ],
+ "types": [
+ "string",
+ "number",
+ "datetime"
+ ]
+ },
+ {
+ "name": "hosts",
+ "label": "Hosts",
+ "type": [
+ "string",
+ "ARRAY"
+ ],
+ "types": [
+ "string",
+ "ARRAY",
+ "number",
+ "datetime"
+ ]
+ },
+ {
+ "name": "severity",
+ "label": "Severity",
+ "type": [
+ "string"
+ ],
+ "types": [
+ "string",
+ "number",
+ "datetime"
+ ]
+ },
+ {
+ "name": "fingerprint",
+ "label": "Fingerprint",
+ "type": [
+ "string"
+ ],
+ "types": [
+ "string",
+ "number",
+ "datetime"
+ ]
+ },
+ {
+ "name": "gitlab_environment_name",
+ "label": "Environment",
+ "type": [
+ "string"
+ ],
+ "types": [
+ "string",
+ "number",
+ "datetime"
+ ]
+ }
+]
diff --git a/spec/frontend/alerts_settings/utils/mapping_transformations_spec.js b/spec/frontend/alerts_settings/utils/mapping_transformations_spec.js
new file mode 100644
index 00000000000..8c1977ffebe
--- /dev/null
+++ b/spec/frontend/alerts_settings/utils/mapping_transformations_spec.js
@@ -0,0 +1,81 @@
+import parsedMapping from '~/alerts_settings/components/mocks/parsedMapping.json';
+import {
+ getMappingData,
+ getPayloadFields,
+ transformForSave,
+} from '~/alerts_settings/utils/mapping_transformations';
+import alertFields from '../mocks/alertFields.json';
+
+describe('Mapping Transformation Utilities', () => {
+ const nameField = {
+ label: 'Name',
+ path: ['alert', 'name'],
+ type: 'string',
+ };
+ const dashboardField = {
+ label: 'Dashboard Id',
+ path: ['alert', 'dashboardId'],
+ type: 'string',
+ };
+
+ describe('getMappingData', () => {
+ it('should return mapping data', () => {
+ const result = getMappingData(
+ alertFields,
+ getPayloadFields(parsedMapping.samplePayload.payloadAlerFields.nodes.slice(0, 3)),
+ parsedMapping.storedMapping.nodes.slice(0, 3),
+ );
+
+ result.forEach((data, index) => {
+ expect(data).toEqual(
+ expect.objectContaining({
+ ...alertFields[index],
+ searchTerm: '',
+ fallbackSearchTerm: '',
+ }),
+ );
+ });
+ });
+ });
+
+ describe('transformForSave', () => {
+ it('should transform mapped data for save', () => {
+ const fieldName = 'title';
+ const mockMappingData = [
+ {
+ name: fieldName,
+ mapping: 'alert_name',
+ mappingFields: getPayloadFields([dashboardField, nameField]),
+ },
+ ];
+ const result = transformForSave(mockMappingData);
+ const { path, type, label } = nameField;
+ expect(result).toEqual([
+ { fieldName: fieldName.toUpperCase(), path, type: type.toUpperCase(), label },
+ ]);
+ });
+
+ it('should return empty array if no mapping provided', () => {
+ const fieldName = 'title';
+ const mockMappingData = [
+ {
+ name: fieldName,
+ mapping: null,
+ mappingFields: getPayloadFields([nameField, dashboardField]),
+ },
+ ];
+ const result = transformForSave(mockMappingData);
+ expect(result).toEqual([]);
+ });
+ });
+
+ describe('getPayloadFields', () => {
+ it('should add name field to each payload field', () => {
+ const result = getPayloadFields([nameField, dashboardField]);
+ expect(result).toEqual([
+ { ...nameField, name: 'alert_name' },
+ { ...dashboardField, name: 'alert_dashboardId' },
+ ]);
+ });
+ });
+});