diff options
Diffstat (limited to 'spec/frontend/alert_settings')
3 files changed, 148 insertions, 40 deletions
diff --git a/spec/frontend/alert_settings/__snapshots__/alert_settings_form_spec.js.snap b/spec/frontend/alert_settings/__snapshots__/alert_settings_form_spec.js.snap index 16e92bf505a..5800b160efe 100644 --- a/spec/frontend/alert_settings/__snapshots__/alert_settings_form_spec.js.snap +++ b/spec/frontend/alert_settings/__snapshots__/alert_settings_form_spec.js.snap @@ -2,48 +2,48 @@ exports[`AlertsSettingsForm with default values renders the initial template 1`] = ` "<div> - <!----> - <div data-testid=\\"alert-settings-description\\" class=\\"gl-mt-5\\"> - <p> - <gl-sprintf-stub message=\\"You must provide this URL and authorization key to authorize an external service to send alerts to GitLab. You can provide this URL and key to multiple services. After configuring an external service, alerts from your service will display on the GitLab %{linkStart}Alerts%{linkEnd} page.\\"></gl-sprintf-stub> - </p> - <p> - <gl-sprintf-stub message=\\"Review your external service's documentation to learn where to provide this information to your external service, and the %{linkStart}GitLab documentation%{linkEnd} to learn more about configuring your endpoint.\\"></gl-sprintf-stub> - </p> - </div> + <integrations-list-stub integrations=\\"[object Object],[object Object]\\"></integrations-list-stub> <gl-form-stub> - <gl-form-group-stub label=\\"Integrations\\" label-for=\\"integrations\\" label-class=\\"label-bold\\"> - <gl-form-select-stub options=\\"[object Object],[object Object],[object Object]\\" data-testid=\\"alert-settings-select\\" value=\\"generic\\"></gl-form-select-stub> <span class=\\"gl-text-gray-200\\"><gl-sprintf-stub message=\\"Learn more about our %{linkStart}upcoming integrations%{linkEnd}\\"></gl-sprintf-stub></span> + <h5 class=\\"gl-font-lg gl-my-5\\">Add new integrations</h5> + <!----> + <div data-testid=\\"alert-settings-description\\"> + <p> + <gl-sprintf-stub message=\\"You must provide this URL and authorization key to authorize an external service to send alerts to GitLab. You can provide this URL and key to multiple services. After configuring an external service, alerts from your service will display on the GitLab %{linkStart}Alerts%{linkEnd} page.\\"></gl-sprintf-stub> + </p> + <p> + <gl-sprintf-stub message=\\"Review your external service's documentation to learn where to provide this information to your external service, and the %{linkStart}GitLab documentation%{linkEnd} to learn more about configuring your endpoint.\\"></gl-sprintf-stub> + </p> + </div> + <gl-form-group-stub label-for=\\"integration-type\\" label=\\"Integration\\"> + <gl-form-select-stub id=\\"integration-type\\" options=\\"[object Object],[object Object],[object Object]\\" data-testid=\\"alert-settings-select\\" value=\\"generic\\"></gl-form-select-stub> <span class=\\"gl-text-gray-500\\"><gl-sprintf-stub message=\\"Learn more about our improvements for %{linkStart}integrations%{linkEnd}\\"></gl-sprintf-stub></span> </gl-form-group-stub> - <gl-form-group-stub label=\\"Active\\" label-for=\\"activated\\" label-class=\\"label-bold\\"> + <gl-form-group-stub label=\\"Active\\" label-for=\\"activated\\"> <toggle-button-stub id=\\"activated\\"></toggle-button-stub> </gl-form-group-stub> <!----> - <gl-form-group-stub label=\\"Webhook URL\\" label-for=\\"url\\" label-class=\\"label-bold\\"> - <gl-form-input-group-stub value=\\"/alerts/notify.json\\" predefinedoptions=\\"[object Object]\\" id=\\"url\\" readonly=\\"\\"></gl-form-input-group-stub> <span class=\\"gl-text-gray-200\\"> + <gl-form-group-stub label=\\"Webhook URL\\" label-for=\\"url\\"> + <gl-form-input-group-stub value=\\"/alerts/notify.json\\" predefinedoptions=\\"[object Object]\\" id=\\"url\\" readonly=\\"\\"></gl-form-input-group-stub> <span class=\\"gl-text-gray-500\\"> </span> </gl-form-group-stub> - <gl-form-group-stub label=\\"Authorization key\\" label-for=\\"authorization-key\\" label-class=\\"label-bold\\"> + <gl-form-group-stub label=\\"Authorization key\\" label-for=\\"authorization-key\\"> <gl-form-input-group-stub value=\\"abcedfg123\\" predefinedoptions=\\"[object Object]\\" id=\\"authorization-key\\" readonly=\\"\\" class=\\"gl-mb-2\\"></gl-form-input-group-stub> - <gl-button-stub category=\\"primary\\" variant=\\"default\\" size=\\"medium\\" icon=\\"\\" disabled=\\"true\\" class=\\"gl-mt-3\\" role=\\"button\\" tabindex=\\"0\\">Reset key</gl-button-stub> + <gl-button-stub category=\\"primary\\" variant=\\"default\\" size=\\"medium\\" icon=\\"\\" buttontextclasses=\\"\\" disabled=\\"true\\" class=\\"gl-mt-3\\" role=\\"button\\" tabindex=\\"0\\">Reset key</gl-button-stub> <gl-modal-stub modalid=\\"authKeyModal\\" titletag=\\"h4\\" modalclass=\\"\\" size=\\"md\\" title=\\"Reset key\\" ok-title=\\"Reset key\\" ok-variant=\\"danger\\"> Resetting the authorization key for this project will require updating the authorization key in every alert source it is enabled in. </gl-modal-stub> </gl-form-group-stub> - <gl-form-group-stub label=\\"Alert test payload\\" label-for=\\"alert-json\\" label-class=\\"label-bold\\"> + <gl-form-group-stub label=\\"Alert test payload\\" label-for=\\"alert-json\\"> <gl-form-textarea-stub noresize=\\"true\\" id=\\"alert-json\\" disabled=\\"true\\" state=\\"true\\" placeholder=\\"Enter test alert JSON....\\" rows=\\"6\\" max-rows=\\"10\\"></gl-form-textarea-stub> </gl-form-group-stub> - <div class=\\"gl-display-flex gl-justify-content-end\\"> - <gl-button-stub category=\\"primary\\" variant=\\"default\\" size=\\"medium\\" icon=\\"\\" disabled=\\"true\\">Test alert payload</gl-button-stub> - </div> + <gl-button-stub category=\\"primary\\" variant=\\"default\\" size=\\"medium\\" icon=\\"\\" buttontextclasses=\\"\\" disabled=\\"true\\">Test alert payload</gl-button-stub> <div class=\\"footer-block row-content-block gl-display-flex gl-justify-content-space-between\\"> - <gl-button-stub category=\\"primary\\" variant=\\"default\\" size=\\"medium\\" icon=\\"\\" disabled=\\"true\\"> - Cancel - </gl-button-stub> - <gl-button-stub category=\\"primary\\" variant=\\"success\\" size=\\"medium\\" icon=\\"\\" disabled=\\"true\\"> + <gl-button-stub category=\\"primary\\" variant=\\"success\\" size=\\"medium\\" icon=\\"\\" buttontextclasses=\\"\\" disabled=\\"true\\"> Save changes </gl-button-stub> + <gl-button-stub category=\\"primary\\" variant=\\"default\\" size=\\"medium\\" icon=\\"\\" buttontextclasses=\\"\\" disabled=\\"true\\"> + Cancel + </gl-button-stub> </div> </gl-form-stub> </div>" diff --git a/spec/frontend/alert_settings/alert_settings_form_spec.js b/spec/frontend/alert_settings/alert_settings_form_spec.js index 87a631bda56..6e1ea31ed6a 100644 --- a/spec/frontend/alert_settings/alert_settings_form_spec.js +++ b/spec/frontend/alert_settings/alert_settings_form_spec.js @@ -1,9 +1,12 @@ -import axios from 'axios'; -import MockAdapter from 'axios-mock-adapter'; import { shallowMount } from '@vue/test-utils'; import { GlModal, GlAlert } from '@gitlab/ui'; import AlertsSettingsForm from '~/alerts_settings/components/alerts_settings_form.vue'; +import IntegrationsList from '~/alerts_settings/components/alerts_integrations_list.vue'; import ToggleButton from '~/vue_shared/components/toggle_button.vue'; +import { i18n } from '~/alerts_settings/constants'; +import service from '~/alerts_settings/services'; + +jest.mock('~/alerts_settings/services'); const PROMETHEUS_URL = '/prometheus/alerts/notify.json'; const GENERIC_URL = '/alerts/notify.json'; @@ -13,7 +16,6 @@ const ACTIVATED = false; describe('AlertsSettingsForm', () => { let wrapper; - let mockAxios; const createComponent = ({ methods } = {}, data) => { wrapper = shallowMount(AlertsSettingsForm, { @@ -53,7 +55,6 @@ describe('AlertsSettingsForm', () => { const findApiUrl = () => wrapper.find('#api-url'); beforeEach(() => { - mockAxios = new MockAdapter(axios); setFixtures(` <div> <span class="js-service-active-status fa fa-circle" data-value="true"></span> @@ -63,7 +64,6 @@ describe('AlertsSettingsForm', () => { afterEach(() => { wrapper.destroy(); - mockAxios.restore(); }); describe('with default values', () => { @@ -76,6 +76,11 @@ describe('AlertsSettingsForm', () => { }); }); + it('renders alerts integrations list', () => { + createComponent(); + expect(wrapper.find(IntegrationsList).exists()).toBe(true); + }); + describe('reset key', () => { it('triggers resetKey method', () => { const resetKey = jest.fn(); @@ -99,8 +104,7 @@ describe('AlertsSettingsForm', () => { }); it('shows a alert message on error', () => { - const formPath = 'some/path'; - mockAxios.onPut(formPath).replyOnce(404); + service.updateGenericKey.mockRejectedValueOnce({}); createComponent(); @@ -122,8 +126,7 @@ describe('AlertsSettingsForm', () => { describe('error is encountered', () => { it('restores previous value', () => { - const formPath = 'some/path'; - mockAxios.onPut(formPath).replyOnce(500); + service.updateGenericKey.mockRejectedValueOnce({}); createComponent(); return wrapper.vm.resetKey().then(() => { expect(wrapper.find(ToggleButton).props('value')).toBe(false); @@ -193,18 +196,34 @@ describe('AlertsSettingsForm', () => { }); describe('alert service is toggled', () => { - it('should show a error alert if failed', () => { - const formPath = 'some/path'; + describe('error handling', () => { const toggleService = true; - mockAxios.onPut(formPath).replyOnce(422, { - errors: 'Error message to display', - }); - createComponent(); + it('should show generic error', async () => { + service.updateGenericActive.mockRejectedValueOnce({}); + + createComponent(); - return wrapper.vm.toggleActivated(toggleService).then(() => { + await wrapper.vm.toggleActivated(toggleService); expect(wrapper.vm.active).toBe(false); expect(wrapper.find(GlAlert).attributes('variant')).toBe('danger'); + expect(wrapper.find(GlAlert).text()).toBe(i18n.errorMsg); + }); + + it('should show first field specific error when available', async () => { + const err1 = "can't be blank"; + const err2 = 'is not a valid URL'; + const key = 'api_url'; + service.updateGenericActive.mockRejectedValueOnce({ + response: { data: { errors: { [key]: [err1, err2] } } }, + }); + + createComponent(); + + await wrapper.vm.toggleActivated(toggleService); + + expect(wrapper.find(GlAlert).text()).toContain(i18n.errorMsg); + expect(wrapper.find(GlAlert).text()).toContain(`${key} ${err1}`); }); }); }); diff --git a/spec/frontend/alert_settings/alerts_integrations_list_spec.js b/spec/frontend/alert_settings/alerts_integrations_list_spec.js new file mode 100644 index 00000000000..6fc9901db2a --- /dev/null +++ b/spec/frontend/alert_settings/alerts_integrations_list_spec.js @@ -0,0 +1,89 @@ +import { GlTable, GlIcon } from '@gitlab/ui'; +import { mount } from '@vue/test-utils'; +import Tracking from '~/tracking'; +import AlertIntegrationsList, { + i18n, +} from '~/alerts_settings/components/alerts_integrations_list.vue'; +import { trackAlertIntergrationsViewsOptions } from '~/alerts_settings/constants'; + +const mockIntegrations = [ + { + activated: true, + name: 'Integration 1', + type: 'HTTP endpoint', + }, + { + activated: false, + name: 'Integration 2', + type: 'HTTP endpoint', + }, +]; + +describe('AlertIntegrationsList', () => { + let wrapper; + + function mountComponent(propsData = {}) { + wrapper = mount(AlertIntegrationsList, { + propsData: { + integrations: mockIntegrations, + ...propsData, + }, + stubs: { + GlIcon: true, + }, + }); + } + + afterEach(() => { + if (wrapper) { + wrapper.destroy(); + wrapper = null; + } + }); + + beforeEach(() => { + mountComponent(); + }); + + const findTableComponent = () => wrapper.find(GlTable); + const finsStatusCell = () => wrapper.findAll('[data-testid="integration-activated-status"]'); + + it('renders a table', () => { + expect(findTableComponent().exists()).toBe(true); + }); + + it('renders an empty state when no integrations provided', () => { + mountComponent({ integrations: [] }); + expect(findTableComponent().text()).toContain(i18n.emptyState); + }); + + describe('integration status', () => { + it('enabled', () => { + const cell = finsStatusCell().at(0); + const activatedIcon = cell.find(GlIcon); + expect(cell.text()).toBe(i18n.status.enabled.name); + expect(activatedIcon.attributes('name')).toBe('check-circle-filled'); + expect(activatedIcon.attributes('title')).toBe(i18n.status.enabled.tooltip); + }); + + it('disabled', () => { + const cell = finsStatusCell().at(1); + const notActivatedIcon = cell.find(GlIcon); + expect(cell.text()).toBe(i18n.status.disabled.name); + expect(notActivatedIcon.attributes('name')).toBe('warning-solid'); + expect(notActivatedIcon.attributes('title')).toBe(i18n.status.disabled.tooltip); + }); + }); + + describe('Snowplow tracking', () => { + beforeEach(() => { + jest.spyOn(Tracking, 'event'); + mountComponent(); + }); + + it('should track alert list page views', () => { + const { category, action } = trackAlertIntergrationsViewsOptions; + expect(Tracking.event).toHaveBeenCalledWith(category, action); + }); + }); +}); |