summaryrefslogtreecommitdiff
path: root/spec/frontend/alert_management
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/alert_management')
-rw-r--r--spec/frontend/alert_management/components/alert_management_detail_spec.js31
-rw-r--r--spec/frontend/alert_management/components/alert_management_empty_state_spec.js54
-rw-r--r--spec/frontend/alert_management/components/alert_management_list_wrapper_spec.js57
-rw-r--r--spec/frontend/alert_management/components/alert_management_sidebar_todo_spec.js76
-rw-r--r--spec/frontend/alert_management/components/alert_management_table_spec.js (renamed from spec/frontend/alert_management/components/alert_management_list_spec.js)175
-rw-r--r--spec/frontend/alert_management/components/alert_metrics_spec.js67
-rw-r--r--spec/frontend/alert_management/components/alert_sidebar_status_spec.js107
-rw-r--r--spec/frontend/alert_management/components/sidebar/alert_managment_sidebar_assignees_spec.js (renamed from spec/frontend/alert_management/components/alert_managment_sidebar_assignees_spec.js)29
-rw-r--r--spec/frontend/alert_management/components/sidebar/alert_sidebar_spec.js (renamed from spec/frontend/alert_management/components/alert_sidebar_spec.js)27
-rw-r--r--spec/frontend/alert_management/components/sidebar/alert_sidebar_status_spec.js129
-rw-r--r--spec/frontend/alert_management/components/system_notes/alert_management_system_note_spec.js (renamed from spec/frontend/alert_management/components/alert_management_system_note_spec.js)8
-rw-r--r--spec/frontend/alert_management/mocks/alerts.json4
12 files changed, 594 insertions, 170 deletions
diff --git a/spec/frontend/alert_management/components/alert_management_detail_spec.js b/spec/frontend/alert_management/components/alert_management_detail_spec.js
index 14e45a4f563..daa730d3b9f 100644
--- a/spec/frontend/alert_management/components/alert_management_detail_spec.js
+++ b/spec/frontend/alert_management/components/alert_management_detail_spec.js
@@ -3,7 +3,7 @@ import { GlAlert, GlLoadingIcon, GlTable } from '@gitlab/ui';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import AlertDetails from '~/alert_management/components/alert_details.vue';
-import createIssueQuery from '~/alert_management/graphql/mutations/create_issue_from_alert.graphql';
+import createIssueMutation from '~/alert_management/graphql/mutations/create_issue_from_alert.mutation.graphql';
import { joinPaths } from '~/lib/utils/url_utility';
import {
trackAlertsDetailsViewsOptions,
@@ -19,18 +19,20 @@ describe('AlertDetails', () => {
let mock;
const projectPath = 'root/alerts';
const projectIssuesPath = 'root/alerts/-/issues';
+ const projectId = '1';
const findDetailsTable = () => wrapper.find(GlTable);
function mountComponent({ data, loading = false, mountMethod = shallowMount, stubs = {} } = {}) {
wrapper = mountMethod(AlertDetails, {
- propsData: {
+ provide: {
alertId: 'alertId',
projectPath,
projectIssuesPath,
+ projectId,
},
data() {
- return { alert: { ...mockAlert }, ...data };
+ return { alert: { ...mockAlert }, sidebarStatus: false, ...data };
},
mocks: {
$apollo: {
@@ -39,6 +41,7 @@ describe('AlertDetails', () => {
alert: {
loading,
},
+ sidebarStatus: {},
},
},
},
@@ -52,9 +55,7 @@ describe('AlertDetails', () => {
afterEach(() => {
if (wrapper) {
- if (wrapper) {
- wrapper.destroy();
- }
+ wrapper.destroy();
}
mock.restore();
});
@@ -133,7 +134,7 @@ describe('AlertDetails', () => {
it('should display "View issue" button that links the issue page when issue exists', () => {
const issueIid = '3';
mountComponent({
- data: { alert: { ...mockAlert, issueIid } },
+ data: { alert: { ...mockAlert, issueIid }, sidebarStatus: false },
});
expect(findViewIssueBtn().exists()).toBe(true);
expect(findViewIssueBtn().attributes('href')).toBe(joinPaths(projectIssuesPath, issueIid));
@@ -146,8 +147,11 @@ describe('AlertDetails', () => {
mountMethod: mount,
data: { alert: { ...mockAlert, issueIid } },
});
- expect(findViewIssueBtn().exists()).toBe(false);
- expect(findCreateIssueBtn().exists()).toBe(true);
+
+ return wrapper.vm.$nextTick().then(() => {
+ expect(findViewIssueBtn().exists()).toBe(false);
+ expect(findCreateIssueBtn().exists()).toBe(true);
+ });
});
it('calls `$apollo.mutate` with `createIssueQuery`', () => {
@@ -158,7 +162,7 @@ describe('AlertDetails', () => {
findCreateIssueBtn().trigger('click');
expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
- mutation: createIssueQuery,
+ mutation: createIssueMutation,
variables: {
iid: mockAlert.iid,
projectPath,
@@ -208,6 +212,13 @@ describe('AlertDetails', () => {
expect(wrapper.find(GlAlert).exists()).toBe(true);
});
+ it('renders html-errors correctly', () => {
+ mountComponent({
+ data: { errored: true, sidebarErrorMessage: '<span data-testid="htmlError" />' },
+ });
+ expect(wrapper.find('[data-testid="htmlError"]').exists()).toBe(true);
+ });
+
it('does not display an error when dismissed', () => {
mountComponent({ data: { errored: true, isErrorDismissed: true } });
expect(wrapper.find(GlAlert).exists()).toBe(false);
diff --git a/spec/frontend/alert_management/components/alert_management_empty_state_spec.js b/spec/frontend/alert_management/components/alert_management_empty_state_spec.js
new file mode 100644
index 00000000000..0d1214211d3
--- /dev/null
+++ b/spec/frontend/alert_management/components/alert_management_empty_state_spec.js
@@ -0,0 +1,54 @@
+import { shallowMount } from '@vue/test-utils';
+import { GlEmptyState } from '@gitlab/ui';
+import AlertManagementEmptyState from '~/alert_management/components/alert_management_empty_state.vue';
+
+describe('AlertManagementEmptyState', () => {
+ let wrapper;
+
+ function mountComponent({
+ props = {
+ alertManagementEnabled: false,
+ userCanEnableAlertManagement: false,
+ },
+ stubs = {},
+ } = {}) {
+ wrapper = shallowMount(AlertManagementEmptyState, {
+ propsData: {
+ enableAlertManagementPath: '/link',
+ emptyAlertSvgPath: 'illustration/path',
+ ...props,
+ },
+ stubs,
+ });
+ }
+
+ beforeEach(() => {
+ mountComponent();
+ });
+
+ afterEach(() => {
+ if (wrapper) {
+ wrapper.destroy();
+ }
+ });
+
+ const EmptyState = () => wrapper.find(GlEmptyState);
+
+ describe('Empty state', () => {
+ it('shows empty state', () => {
+ expect(EmptyState().exists()).toBe(true);
+ });
+
+ it('show OpsGenie integration state when OpsGenie mcv is true', () => {
+ mountComponent({
+ props: {
+ alertManagementEnabled: false,
+ userCanEnableAlertManagement: false,
+ opsgenieMvcEnabled: true,
+ opsgenieMvcTargetUrl: 'https://opsgenie-url.com',
+ },
+ });
+ expect(EmptyState().props('title')).toBe('Opsgenie is enabled');
+ });
+ });
+});
diff --git a/spec/frontend/alert_management/components/alert_management_list_wrapper_spec.js b/spec/frontend/alert_management/components/alert_management_list_wrapper_spec.js
new file mode 100644
index 00000000000..4644406c037
--- /dev/null
+++ b/spec/frontend/alert_management/components/alert_management_list_wrapper_spec.js
@@ -0,0 +1,57 @@
+import { shallowMount } from '@vue/test-utils';
+import AlertManagementList from '~/alert_management/components/alert_management_list_wrapper.vue';
+import { trackAlertListViewsOptions } from '~/alert_management/constants';
+import mockAlerts from '../mocks/alerts.json';
+import Tracking from '~/tracking';
+
+describe('AlertManagementList', () => {
+ let wrapper;
+
+ function mountComponent({
+ props = {
+ alertManagementEnabled: false,
+ userCanEnableAlertManagement: false,
+ },
+ data = {},
+ stubs = {},
+ } = {}) {
+ wrapper = shallowMount(AlertManagementList, {
+ propsData: {
+ projectPath: 'gitlab-org/gitlab',
+ enableAlertManagementPath: '/link',
+ populatingAlertsHelpUrl: '/help/help-page.md#populating-alert-data',
+ emptyAlertSvgPath: 'illustration/path',
+ ...props,
+ },
+ data() {
+ return data;
+ },
+ stubs,
+ });
+ }
+
+ beforeEach(() => {
+ mountComponent();
+ });
+
+ afterEach(() => {
+ if (wrapper) {
+ wrapper.destroy();
+ }
+ });
+
+ describe('Snowplow tracking', () => {
+ beforeEach(() => {
+ jest.spyOn(Tracking, 'event');
+ mountComponent({
+ props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
+ data: { alerts: { list: mockAlerts } },
+ });
+ });
+
+ it('should track alert list page views', () => {
+ const { category, action } = trackAlertListViewsOptions;
+ expect(Tracking.event).toHaveBeenCalledWith(category, action);
+ });
+ });
+});
diff --git a/spec/frontend/alert_management/components/alert_management_sidebar_todo_spec.js b/spec/frontend/alert_management/components/alert_management_sidebar_todo_spec.js
new file mode 100644
index 00000000000..fe08cf2c10a
--- /dev/null
+++ b/spec/frontend/alert_management/components/alert_management_sidebar_todo_spec.js
@@ -0,0 +1,76 @@
+import { mount } from '@vue/test-utils';
+import SidebarTodo from '~/alert_management/components/sidebar/sidebar_todo.vue';
+import AlertMarkTodo from '~/alert_management/graphql/mutations/alert_todo_create.graphql';
+import mockAlerts from '../mocks/alerts.json';
+
+const mockAlert = mockAlerts[0];
+
+describe('Alert Details Sidebar To Do', () => {
+ let wrapper;
+
+ function mountComponent({ data, sidebarCollapsed = true, loading = false, stubs = {} } = {}) {
+ wrapper = mount(SidebarTodo, {
+ propsData: {
+ alert: { ...mockAlert },
+ ...data,
+ sidebarCollapsed,
+ projectPath: 'projectPath',
+ },
+ mocks: {
+ $apollo: {
+ mutate: jest.fn(),
+ queries: {
+ alert: {
+ loading,
+ },
+ },
+ },
+ },
+ stubs,
+ });
+ }
+
+ afterEach(() => {
+ wrapper.destroy();
+ });
+
+ describe('updating the alert to do', () => {
+ const mockUpdatedMutationResult = {
+ data: {
+ updateAlertTodo: {
+ errors: [],
+ alert: {},
+ },
+ },
+ };
+
+ beforeEach(() => {
+ mountComponent({
+ data: { alert: mockAlert },
+ sidebarCollapsed: false,
+ loading: false,
+ });
+ });
+
+ it('renders a button for adding a To Do', () => {
+ return wrapper.vm.$nextTick().then(() => {
+ expect(wrapper.find('[data-testid="alert-todo-button"]').text()).toBe('Add a To Do');
+ });
+ });
+
+ it('calls `$apollo.mutate` with `AlertMarkTodo` mutation and variables containing `iid`, `todoEvent`, & `projectPath`', () => {
+ jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(mockUpdatedMutationResult);
+
+ return wrapper.vm.$nextTick().then(() => {
+ wrapper.find('button').trigger('click');
+ expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
+ mutation: AlertMarkTodo,
+ variables: {
+ iid: '1527542',
+ projectPath: 'projectPath',
+ },
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/alert_management/components/alert_management_list_spec.js b/spec/frontend/alert_management/components/alert_management_table_spec.js
index 0154e5fa112..f316126432e 100644
--- a/spec/frontend/alert_management/components/alert_management_list_spec.js
+++ b/spec/frontend/alert_management/components/alert_management_table_spec.js
@@ -1,6 +1,5 @@
import { mount } from '@vue/test-utils';
import {
- GlEmptyState,
GlTable,
GlAlert,
GlLoadingIcon,
@@ -11,28 +10,22 @@ import {
GlTab,
GlBadge,
GlPagination,
+ GlSearchBoxByType,
} from '@gitlab/ui';
import { visitUrl } from '~/lib/utils/url_utility';
import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue';
-import createFlash from '~/flash';
-import AlertManagementList from '~/alert_management/components/alert_management_list.vue';
-import {
- ALERTS_STATUS_TABS,
- trackAlertListViewsOptions,
- trackAlertStatusUpdateOptions,
-} from '~/alert_management/constants';
-import updateAlertStatus from '~/alert_management/graphql/mutations/update_alert_status.graphql';
+import AlertManagementTable from '~/alert_management/components/alert_management_table.vue';
+import { ALERTS_STATUS_TABS, trackAlertStatusUpdateOptions } from '~/alert_management/constants';
+import updateAlertStatus from '~/alert_management/graphql/mutations/update_alert_status.mutation.graphql';
import mockAlerts from '../mocks/alerts.json';
import Tracking from '~/tracking';
-jest.mock('~/flash');
-
jest.mock('~/lib/utils/url_utility', () => ({
visitUrl: jest.fn().mockName('visitUrlMock'),
joinPaths: jest.requireActual('~/lib/utils/url_utility').joinPaths,
}));
-describe('AlertManagementList', () => {
+describe('AlertManagementTable', () => {
let wrapper;
const findAlertsTable = () => wrapper.find(GlTable);
@@ -49,6 +42,8 @@ describe('AlertManagementList', () => {
const findSeverityFields = () => wrapper.findAll('[data-testid="severityField"]');
const findSeverityColumnHeader = () => wrapper.findAll('th').at(0);
const findPagination = () => wrapper.find(GlPagination);
+ const findSearch = () => wrapper.find(GlSearchBoxByType);
+ const findIssueFields = () => wrapper.findAll('[data-testid="issueField"]');
const alertsCount = {
open: 14,
triggered: 10,
@@ -66,11 +61,10 @@ describe('AlertManagementList', () => {
loading = false,
stubs = {},
} = {}) {
- wrapper = mount(AlertManagementList, {
+ wrapper = mount(AlertManagementTable, {
propsData: {
projectPath: 'gitlab-org/gitlab',
- enableAlertManagementPath: '/link',
- emptyAlertSvgPath: 'illustration/path',
+ populatingAlertsHelpUrl: '/help/help-page.md#populating-alert-data',
...props,
},
data() {
@@ -92,7 +86,7 @@ describe('AlertManagementList', () => {
}
beforeEach(() => {
- mountComponent();
+ mountComponent({ data: { alerts: mockAlerts, alertsCount } });
});
afterEach(() => {
@@ -101,12 +95,6 @@ describe('AlertManagementList', () => {
}
});
- describe('Empty state', () => {
- it('shows empty state', () => {
- expect(wrapper.find(GlEmptyState).exists()).toBe(true);
- });
- });
-
describe('Status Filter Tabs', () => {
beforeEach(() => {
mountComponent({
@@ -206,6 +194,15 @@ describe('AlertManagementList', () => {
expect(findStatusDropdown().exists()).toBe(true);
});
+ it('does not display a dropdown status header', () => {
+ mountComponent({
+ props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
+ data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
+ loading: false,
+ });
+ expect(findStatusDropdown().contains('.dropdown-title')).toBe(false);
+ });
+
it('shows correct severity icons', () => {
mountComponent({
props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
@@ -278,6 +275,37 @@ describe('AlertManagementList', () => {
expect(visitUrl).toHaveBeenCalledWith('/1527542/details');
});
+ describe('alert issue links', () => {
+ beforeEach(() => {
+ mountComponent({
+ props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
+ data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
+ loading: false,
+ });
+ });
+
+ it('shows "None" when no link exists', () => {
+ expect(
+ findIssueFields()
+ .at(0)
+ .text(),
+ ).toBe('None');
+ });
+
+ it('renders a link when one exists', () => {
+ expect(
+ findIssueFields()
+ .at(1)
+ .text(),
+ ).toBe('#1');
+ expect(
+ findIssueFields()
+ .at(1)
+ .attributes('href'),
+ ).toBe('/gitlab-org/gitlab/-/issues/1');
+ });
+ });
+
describe('handle date fields', () => {
it('should display time ago dates when values provided', () => {
mountComponent({
@@ -289,7 +317,6 @@ describe('AlertManagementList', () => {
iid: 1,
status: 'acknowledged',
startedAt: '2020-03-17T23:18:14.996Z',
- endedAt: '2020-04-17T23:18:14.996Z',
severity: 'high',
assignees: { nodes: [] },
},
@@ -300,7 +327,7 @@ describe('AlertManagementList', () => {
},
loading: false,
});
- expect(findDateFields().length).toBe(2);
+ expect(findDateFields().length).toBe(1);
});
it('should not display time ago dates when values not provided', () => {
@@ -312,7 +339,6 @@ describe('AlertManagementList', () => {
iid: 1,
status: 'acknowledged',
startedAt: null,
- endedAt: null,
severity: 'high',
},
],
@@ -323,6 +349,40 @@ describe('AlertManagementList', () => {
});
expect(findDateFields().exists()).toBe(false);
});
+
+ describe('New Alert indicator', () => {
+ const oldAlert = mockAlerts[0];
+
+ const newAlert = { ...oldAlert, isNew: true };
+
+ it('should highlight the row when alert is new', () => {
+ mountComponent({
+ props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
+ data: { alerts: { list: [newAlert] }, alertsCount, errored: false },
+ loading: false,
+ });
+
+ expect(
+ findAlerts()
+ .at(0)
+ .classes(),
+ ).toContain('new-alert');
+ });
+
+ it('should not highlight the row when alert is not new', () => {
+ mountComponent({
+ props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
+ data: { alerts: { list: [oldAlert] }, alertsCount, errored: false },
+ loading: false,
+ });
+
+ expect(
+ findAlerts()
+ .at(0)
+ .classes(),
+ ).not.toContain('new-alert');
+ });
+ });
});
});
@@ -388,14 +448,38 @@ describe('AlertManagementList', () => {
});
});
- it('calls `createFlash` when request fails', () => {
+ it('shows an error when request fails', () => {
jest.spyOn(wrapper.vm.$apollo, 'mutate').mockReturnValue(Promise.reject(new Error()));
findFirstStatusOption().vm.$emit('click');
+ wrapper.setData({
+ errored: true,
+ });
- setImmediate(() => {
- expect(createFlash).toHaveBeenCalledWith(
- 'There was an error while updating the status of the alert. Please try again.',
- );
+ return wrapper.vm.$nextTick(() => {
+ expect(wrapper.find('[data-testid="alert-error"]').exists()).toBe(true);
+ });
+ });
+
+ it('shows an error when response includes HTML errors', () => {
+ const mockUpdatedMutationErrorResult = {
+ data: {
+ updateAlertStatus: {
+ errors: ['<span data-testid="htmlError" />'],
+ alert: {
+ iid,
+ status: 'acknowledged',
+ },
+ },
+ },
+ };
+
+ jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(mockUpdatedMutationErrorResult);
+ findFirstStatusOption().vm.$emit('click');
+ wrapper.setData({ errored: true });
+
+ return wrapper.vm.$nextTick(() => {
+ expect(wrapper.contains('[data-testid="alert-error"]')).toBe(true);
+ expect(wrapper.contains('[data-testid="htmlError"]')).toBe(true);
});
});
});
@@ -410,11 +494,6 @@ describe('AlertManagementList', () => {
});
});
- it('should track alert list page views', () => {
- const { category, action } = trackAlertListViewsOptions;
- expect(Tracking.event).toHaveBeenCalledWith(category, action);
- });
-
it('should track alert status updates', () => {
Tracking.event.mockClear();
jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue({});
@@ -438,14 +517,14 @@ describe('AlertManagementList', () => {
it('does NOT show pagination control when list is smaller than default page size', () => {
findStatusTabs().vm.$emit('input', 3);
- wrapper.vm.$nextTick(() => {
+ return wrapper.vm.$nextTick(() => {
expect(findPagination().exists()).toBe(false);
});
});
it('shows pagination control when list is larger than default page size', () => {
findStatusTabs().vm.$emit('input', 0);
- wrapper.vm.$nextTick(() => {
+ return wrapper.vm.$nextTick(() => {
expect(findPagination().exists()).toBe(true);
});
});
@@ -486,4 +565,26 @@ describe('AlertManagementList', () => {
});
});
});
+
+ describe('Search', () => {
+ beforeEach(() => {
+ mountComponent({
+ props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
+ data: { alerts: { list: mockAlerts }, alertsCount, errored: false },
+ loading: false,
+ });
+ });
+
+ it('renders the search component', () => {
+ expect(findSearch().exists()).toBe(true);
+ });
+
+ it('sets the `searchTerm` graphql variable', () => {
+ const SEARCH_TERM = 'Simple Alert';
+
+ findSearch().vm.$emit('input', SEARCH_TERM);
+
+ expect(wrapper.vm.$data.searchTerm).toBe(SEARCH_TERM);
+ });
+ });
});
diff --git a/spec/frontend/alert_management/components/alert_metrics_spec.js b/spec/frontend/alert_management/components/alert_metrics_spec.js
new file mode 100644
index 00000000000..c188363ddc2
--- /dev/null
+++ b/spec/frontend/alert_management/components/alert_metrics_spec.js
@@ -0,0 +1,67 @@
+import { shallowMount } from '@vue/test-utils';
+import waitForPromises from 'helpers/wait_for_promises';
+import AlertMetrics from '~/alert_management/components/alert_metrics.vue';
+import MockAdapter from 'axios-mock-adapter';
+import axios from 'axios';
+
+jest.mock('~/monitoring/stores', () => ({
+ monitoringDashboard: {},
+}));
+
+const mockEmbedName = 'MetricsEmbedStub';
+
+jest.mock('~/monitoring/components/embeds/metric_embed.vue', () => ({
+ name: mockEmbedName,
+ render(h) {
+ return h('div');
+ },
+}));
+
+describe('Alert Metrics', () => {
+ let wrapper;
+ const mock = new MockAdapter(axios);
+
+ function mountComponent({ props } = {}) {
+ wrapper = shallowMount(AlertMetrics, {
+ propsData: {
+ ...props,
+ },
+ stubs: {
+ MetricEmbed: true,
+ },
+ });
+ }
+
+ const findChart = () => wrapper.find({ name: mockEmbedName });
+ const findEmptyState = () => wrapper.find({ ref: 'emptyState' });
+
+ afterEach(() => {
+ if (wrapper) {
+ wrapper.destroy();
+ }
+ });
+
+ afterAll(() => {
+ mock.restore();
+ });
+
+ describe('Empty state', () => {
+ it('should display a message when metrics dashboard url is not provided ', () => {
+ mountComponent();
+ expect(findChart().exists()).toBe(false);
+ expect(findEmptyState().text()).toBe("Metrics weren't available in the alerts payload.");
+ });
+ });
+
+ describe('Chart', () => {
+ it('should be rendered when dashboard url is provided', async () => {
+ mountComponent({ props: { dashboardUrl: 'metrics.url' } });
+
+ await waitForPromises();
+ await wrapper.vm.$nextTick();
+
+ expect(findEmptyState().exists()).toBe(false);
+ expect(findChart().exists()).toBe(true);
+ });
+ });
+});
diff --git a/spec/frontend/alert_management/components/alert_sidebar_status_spec.js b/spec/frontend/alert_management/components/alert_sidebar_status_spec.js
deleted file mode 100644
index 94643966a43..00000000000
--- a/spec/frontend/alert_management/components/alert_sidebar_status_spec.js
+++ /dev/null
@@ -1,107 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { GlDropdownItem, GlLoadingIcon } from '@gitlab/ui';
-import { trackAlertStatusUpdateOptions } from '~/alert_management/constants';
-import AlertSidebarStatus from '~/alert_management/components/sidebar/sidebar_status.vue';
-import updateAlertStatus from '~/alert_management/graphql/mutations/update_alert_status.graphql';
-import Tracking from '~/tracking';
-import mockAlerts from '../mocks/alerts.json';
-
-const mockAlert = mockAlerts[0];
-
-describe('Alert Details Sidebar Status', () => {
- let wrapper;
- const findStatusDropdownItem = () => wrapper.find(GlDropdownItem);
- const findStatusLoadingIcon = () => wrapper.find(GlLoadingIcon);
-
- function mountComponent({ data, sidebarCollapsed = true, loading = false, stubs = {} } = {}) {
- wrapper = shallowMount(AlertSidebarStatus, {
- propsData: {
- alert: { ...mockAlert },
- ...data,
- sidebarCollapsed,
- projectPath: 'projectPath',
- },
- mocks: {
- $apollo: {
- mutate: jest.fn(),
- queries: {
- alert: {
- loading,
- },
- },
- },
- },
- stubs,
- });
- }
-
- afterEach(() => {
- if (wrapper) {
- wrapper.destroy();
- }
- });
-
- describe('updating the alert status', () => {
- const mockUpdatedMutationResult = {
- data: {
- updateAlertStatus: {
- errors: [],
- alert: {
- status: 'acknowledged',
- },
- },
- },
- };
-
- beforeEach(() => {
- mountComponent({
- data: { alert: mockAlert },
- sidebarCollapsed: false,
- loading: false,
- });
- });
-
- it('calls `$apollo.mutate` with `updateAlertStatus` mutation and variables containing `iid`, `status`, & `projectPath`', () => {
- jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(mockUpdatedMutationResult);
- findStatusDropdownItem().vm.$emit('click');
-
- expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
- mutation: updateAlertStatus,
- variables: {
- iid: '1527542',
- status: 'TRIGGERED',
- projectPath: 'projectPath',
- },
- });
- });
-
- it('stops updating when the request fails', () => {
- jest.spyOn(wrapper.vm.$apollo, 'mutate').mockReturnValue(Promise.reject(new Error()));
- findStatusDropdownItem().vm.$emit('click');
- expect(findStatusLoadingIcon().exists()).toBe(false);
- expect(wrapper.find('[data-testid="status"]').text()).toBe('Triggered');
- });
- });
-
- describe('Snowplow tracking', () => {
- beforeEach(() => {
- jest.spyOn(Tracking, 'event');
- mountComponent({
- props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
- data: { alert: mockAlert },
- loading: false,
- });
- });
-
- it('should track alert status updates', () => {
- Tracking.event.mockClear();
- jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue({});
- findStatusDropdownItem().vm.$emit('click');
- const status = findStatusDropdownItem().text();
- setImmediate(() => {
- const { category, action, label } = trackAlertStatusUpdateOptions;
- expect(Tracking.event).toHaveBeenCalledWith(category, action, { label, property: status });
- });
- });
- });
-});
diff --git a/spec/frontend/alert_management/components/alert_managment_sidebar_assignees_spec.js b/spec/frontend/alert_management/components/sidebar/alert_managment_sidebar_assignees_spec.js
index 5dbd83dbdac..db086782424 100644
--- a/spec/frontend/alert_management/components/alert_managment_sidebar_assignees_spec.js
+++ b/spec/frontend/alert_management/components/sidebar/alert_managment_sidebar_assignees_spec.js
@@ -4,8 +4,8 @@ import MockAdapter from 'axios-mock-adapter';
import { GlDropdownItem } from '@gitlab/ui';
import SidebarAssignee from '~/alert_management/components/sidebar/sidebar_assignee.vue';
import SidebarAssignees from '~/alert_management/components/sidebar/sidebar_assignees.vue';
-import AlertSetAssignees from '~/alert_management/graphql/mutations/alert_set_assignees.graphql';
-import mockAlerts from '../mocks/alerts.json';
+import AlertSetAssignees from '~/alert_management/graphql/mutations/alert_set_assignees.mutation.graphql';
+import mockAlerts from '../../mocks/alerts.json';
const mockAlert = mockAlerts[0];
@@ -33,6 +33,7 @@ describe('Alert Details Sidebar Assignees', () => {
...data,
sidebarCollapsed,
projectPath: 'projectPath',
+ projectId: '1',
},
mocks: {
$apollo: {
@@ -58,7 +59,7 @@ describe('Alert Details Sidebar Assignees', () => {
describe('updating the alert status', () => {
const mockUpdatedMutationResult = {
data: {
- updateAlertStatus: {
+ alertSetAssignees: {
errors: [],
alert: {
assigneeUsernames: ['root'],
@@ -69,7 +70,7 @@ describe('Alert Details Sidebar Assignees', () => {
beforeEach(() => {
mock = new MockAdapter(axios);
- const path = '/autocomplete/users.json';
+ const path = '/-/autocomplete/users.json';
const users = [
{
avatar_url:
@@ -124,6 +125,26 @@ describe('Alert Details Sidebar Assignees', () => {
});
});
+ it('shows an error when request contains error messages', () => {
+ wrapper.setData({ isDropdownSearching: false });
+ const errorMutationResult = {
+ data: {
+ alertSetAssignees: {
+ errors: ['There was a problem for sure.'],
+ alert: {},
+ },
+ },
+ };
+
+ jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(errorMutationResult);
+
+ return wrapper.vm.$nextTick().then(() => {
+ const SideBarAssigneeItem = wrapper.findAll(SidebarAssignee).at(0);
+ SideBarAssigneeItem.vm.$emit('click');
+ expect(wrapper.emitted('alert-refresh')).toBeUndefined();
+ });
+ });
+
it('stops updating and cancels loading when the request fails', () => {
jest.spyOn(wrapper.vm.$apollo, 'mutate').mockReturnValue(Promise.reject(new Error()));
wrapper.vm.updateAlertAssignees('root');
diff --git a/spec/frontend/alert_management/components/alert_sidebar_spec.js b/spec/frontend/alert_management/components/sidebar/alert_sidebar_spec.js
index 80c4d9e0650..5235ae63fee 100644
--- a/spec/frontend/alert_management/components/alert_sidebar_spec.js
+++ b/spec/frontend/alert_management/components/sidebar/alert_sidebar_spec.js
@@ -3,7 +3,7 @@ import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import AlertSidebar from '~/alert_management/components/alert_sidebar.vue';
import SidebarAssignees from '~/alert_management/components/sidebar/sidebar_assignees.vue';
-import mockAlerts from '../mocks/alerts.json';
+import mockAlerts from '../../mocks/alerts.json';
const mockAlert = mockAlerts[0];
@@ -11,19 +11,28 @@ describe('Alert Details Sidebar', () => {
let wrapper;
let mock;
- function mountComponent({
- sidebarCollapsed = true,
- mountMethod = shallowMount,
- stubs = {},
- alert = {},
- } = {}) {
+ function mountComponent({ mountMethod = shallowMount, stubs = {}, alert = {} } = {}) {
wrapper = mountMethod(AlertSidebar, {
+ data() {
+ return {
+ sidebarStatus: false,
+ };
+ },
propsData: {
alert,
- sidebarCollapsed,
+ },
+ provide: {
projectPath: 'projectPath',
+ projectId: '1',
},
stubs,
+ mocks: {
+ $apollo: {
+ queries: {
+ sidebarStatus: {},
+ },
+ },
+ },
});
}
@@ -41,7 +50,7 @@ describe('Alert Details Sidebar', () => {
});
it('open as default', () => {
- expect(wrapper.props('sidebarCollapsed')).toBe(true);
+ expect(wrapper.classes('right-sidebar-expanded')).toBe(true);
});
it('should render side bar assignee dropdown', () => {
diff --git a/spec/frontend/alert_management/components/sidebar/alert_sidebar_status_spec.js b/spec/frontend/alert_management/components/sidebar/alert_sidebar_status_spec.js
new file mode 100644
index 00000000000..c2eaf540e9c
--- /dev/null
+++ b/spec/frontend/alert_management/components/sidebar/alert_sidebar_status_spec.js
@@ -0,0 +1,129 @@
+import { mount } from '@vue/test-utils';
+import { GlDropdown, GlDropdownItem, GlLoadingIcon } from '@gitlab/ui';
+import { trackAlertStatusUpdateOptions } from '~/alert_management/constants';
+import AlertSidebarStatus from '~/alert_management/components/sidebar/sidebar_status.vue';
+import updateAlertStatus from '~/alert_management/graphql/mutations/update_alert_status.mutation.graphql';
+import Tracking from '~/tracking';
+import mockAlerts from '../../mocks/alerts.json';
+
+const mockAlert = mockAlerts[0];
+
+describe('Alert Details Sidebar Status', () => {
+ let wrapper;
+ const findStatusDropdown = () => wrapper.find(GlDropdown);
+ const findStatusDropdownItem = () => wrapper.find(GlDropdownItem);
+ const findStatusLoadingIcon = () => wrapper.find(GlLoadingIcon);
+
+ function mountComponent({ data, sidebarCollapsed = true, loading = false, stubs = {} } = {}) {
+ wrapper = mount(AlertSidebarStatus, {
+ propsData: {
+ alert: { ...mockAlert },
+ ...data,
+ sidebarCollapsed,
+ projectPath: 'projectPath',
+ },
+ mocks: {
+ $apollo: {
+ mutate: jest.fn(),
+ queries: {
+ alert: {
+ loading,
+ },
+ },
+ },
+ },
+ stubs,
+ });
+ }
+
+ afterEach(() => {
+ if (wrapper) {
+ wrapper.destroy();
+ }
+ });
+
+ describe('Alert Sidebar Dropdown Status', () => {
+ beforeEach(() => {
+ mountComponent({
+ data: { alert: mockAlert },
+ sidebarCollapsed: false,
+ loading: false,
+ });
+ });
+
+ it('displays status dropdown', () => {
+ expect(findStatusDropdown().exists()).toBe(true);
+ });
+
+ it('displays the dropdown status header', () => {
+ expect(findStatusDropdown().contains('.dropdown-title')).toBe(true);
+ });
+
+ describe('updating the alert status', () => {
+ const mockUpdatedMutationResult = {
+ data: {
+ updateAlertStatus: {
+ errors: [],
+ alert: {
+ status: 'acknowledged',
+ },
+ },
+ },
+ };
+
+ beforeEach(() => {
+ mountComponent({
+ data: { alert: mockAlert },
+ sidebarCollapsed: false,
+ loading: false,
+ });
+ });
+
+ it('calls `$apollo.mutate` with `updateAlertStatus` mutation and variables containing `iid`, `status`, & `projectPath`', () => {
+ jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(mockUpdatedMutationResult);
+ findStatusDropdownItem().vm.$emit('click');
+
+ expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({
+ mutation: updateAlertStatus,
+ variables: {
+ iid: '1527542',
+ status: 'TRIGGERED',
+ projectPath: 'projectPath',
+ },
+ });
+ });
+
+ it('stops updating when the request fails', () => {
+ jest.spyOn(wrapper.vm.$apollo, 'mutate').mockReturnValue(Promise.reject(new Error()));
+ findStatusDropdownItem().vm.$emit('click');
+ expect(findStatusLoadingIcon().exists()).toBe(false);
+ expect(wrapper.find('[data-testid="status"]').text()).toBe('Triggered');
+ });
+ });
+
+ describe('Snowplow tracking', () => {
+ beforeEach(() => {
+ jest.spyOn(Tracking, 'event');
+ mountComponent({
+ props: { alertManagementEnabled: true, userCanEnableAlertManagement: true },
+ data: { alert: mockAlert },
+ loading: false,
+ });
+ });
+
+ it('should track alert status updates', () => {
+ Tracking.event.mockClear();
+ jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue({});
+ findStatusDropdownItem().vm.$emit('click');
+ const status = findStatusDropdownItem().text();
+ setImmediate(() => {
+ const { category, action, label } = trackAlertStatusUpdateOptions;
+ expect(Tracking.event).toHaveBeenCalledWith(category, action, {
+ label,
+ property: status,
+ });
+ });
+ });
+ });
+ });
+});
diff --git a/spec/frontend/alert_management/components/alert_management_system_note_spec.js b/spec/frontend/alert_management/components/system_notes/alert_management_system_note_spec.js
index 87dc36cc7cb..8dd663e55d9 100644
--- a/spec/frontend/alert_management/components/alert_management_system_note_spec.js
+++ b/spec/frontend/alert_management/components/system_notes/alert_management_system_note_spec.js
@@ -1,6 +1,6 @@
import { shallowMount } from '@vue/test-utils';
import SystemNote from '~/alert_management/components/system_notes/system_note.vue';
-import mockAlerts from '../mocks/alerts.json';
+import mockAlerts from '../../mocks/alerts.json';
const mockAlert = mockAlerts[1];
@@ -28,7 +28,11 @@ describe('Alert Details System Note', () => {
});
it('renders the correct system note', () => {
- expect(wrapper.find('.note-wrapper').attributes('id')).toBe('note_1628');
+ const noteId = wrapper.find('.note-wrapper').attributes('id');
+ const iconRoute = wrapper.find('use').attributes('href');
+
+ expect(noteId).toBe('note_1628');
+ expect(iconRoute.includes('user')).toBe(true);
});
});
});
diff --git a/spec/frontend/alert_management/mocks/alerts.json b/spec/frontend/alert_management/mocks/alerts.json
index 312d1756790..f63019d1e5c 100644
--- a/spec/frontend/alert_management/mocks/alerts.json
+++ b/spec/frontend/alert_management/mocks/alerts.json
@@ -20,6 +20,7 @@
"endedAt": "2020-04-17T23:18:14.996Z",
"status": "ACKNOWLEDGED",
"assignees": { "nodes": [{ "username": "root" }] },
+ "issueIid": "1",
"notes": {
"nodes": [
{
@@ -32,7 +33,8 @@
"name": "Administrator",
"username": "root",
"webUrl": "http://192.168.1.4:3000/root"
- }
+ },
+ "systemNoteIconName": "user"
}
]
}