diff options
Diffstat (limited to 'spec/frontend/alert_management/components/alert_management_table_spec.js')
-rw-r--r-- | spec/frontend/alert_management/components/alert_management_table_spec.js | 370 |
1 files changed, 74 insertions, 296 deletions
diff --git a/spec/frontend/alert_management/components/alert_management_table_spec.js b/spec/frontend/alert_management/components/alert_management_table_spec.js index bcad415eb19..f7a629142f9 100644 --- a/spec/frontend/alert_management/components/alert_management_table_spec.js +++ b/spec/frontend/alert_management/components/alert_management_table_spec.js @@ -1,26 +1,13 @@ import { mount } from '@vue/test-utils'; -import { - GlTable, - GlAlert, - GlLoadingIcon, - GlDeprecatedDropdown, - GlDeprecatedDropdownItem, - GlIcon, - GlTabs, - GlTab, - GlBadge, - GlPagination, - GlSearchBoxByType, - GlAvatar, -} from '@gitlab/ui'; -import waitForPromises from 'helpers/wait_for_promises'; +import { GlTable, GlAlert, GlLoadingIcon, GlDropdown, GlIcon, GlAvatar } from '@gitlab/ui'; +import axios from 'axios'; +import MockAdapter from 'axios-mock-adapter'; import { visitUrl } from '~/lib/utils/url_utility'; import TimeAgo from '~/vue_shared/components/time_ago_tooltip.vue'; 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 FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue'; import mockAlerts from '../mocks/alerts.json'; -import Tracking from '~/tracking'; +import defaultProvideValues from '../mocks/alerts_provide_config.json'; jest.mock('~/lib/utils/url_utility', () => ({ visitUrl: jest.fn().mockName('visitUrlMock'), @@ -29,26 +16,21 @@ jest.mock('~/lib/utils/url_utility', () => ({ describe('AlertManagementTable', () => { let wrapper; + let mock; const findAlertsTable = () => wrapper.find(GlTable); const findAlerts = () => wrapper.findAll('table tbody tr'); const findAlert = () => wrapper.find(GlAlert); const findLoader = () => wrapper.find(GlLoadingIcon); - const findStatusDropdown = () => wrapper.find(GlDeprecatedDropdown); - const findStatusFilterTabs = () => wrapper.findAll(GlTab); - const findStatusTabs = () => wrapper.find(GlTabs); - const findStatusFilterBadge = () => wrapper.findAll(GlBadge); + const findStatusDropdown = () => wrapper.find(GlDropdown); const findDateFields = () => wrapper.findAll(TimeAgo); - const findFirstStatusOption = () => findStatusDropdown().find(GlDeprecatedDropdownItem); - const findPagination = () => wrapper.find(GlPagination); - const findSearch = () => wrapper.find(GlSearchBoxByType); + const findSearch = () => wrapper.find(FilteredSearchBar); const findSeverityColumnHeader = () => wrapper.find('[data-testid="alert-management-severity-sort"]'); const findFirstIDField = () => wrapper.findAll('[data-testid="idField"]').at(0); const findAssignees = () => wrapper.findAll('[data-testid="assigneesField"]'); const findSeverityFields = () => wrapper.findAll('[data-testid="severityField"]'); const findIssueFields = () => wrapper.findAll('[data-testid="issueField"]'); - const findAlertError = () => wrapper.find('[data-testid="alert-error"]'); const alertsCount = { open: 24, triggered: 20, @@ -56,26 +38,14 @@ describe('AlertManagementTable', () => { resolved: 11, all: 26, }; - const selectFirstStatusOption = () => { - findFirstStatusOption().vm.$emit('click'); - return waitForPromises(); - }; - - function mountComponent({ - props = { - alertManagementEnabled: false, - userCanEnableAlertManagement: false, - }, - data = {}, - loading = false, - stubs = {}, - } = {}) { + function mountComponent({ provide = {}, data = {}, loading = false, stubs = {} } = {}) { wrapper = mount(AlertManagementTable, { - propsData: { - projectPath: 'gitlab-org/gitlab', - populatingAlertsHelpUrl: '/help/help-page.md#populating-alert-data', - ...props, + provide: { + ...defaultProvideValues, + alertManagementEnabled: true, + userCanEnableAlertManagement: true, + ...provide, }, data() { return data; @@ -95,41 +65,21 @@ describe('AlertManagementTable', () => { }); } + beforeEach(() => { + mock = new MockAdapter(axios); + }); + afterEach(() => { if (wrapper) { wrapper.destroy(); wrapper = null; } - }); - - describe('Status Filter Tabs', () => { - beforeEach(() => { - mountComponent({ - props: { alertManagementEnabled: true, userCanEnableAlertManagement: true }, - data: { alerts: mockAlerts, alertsCount }, - loading: false, - stubs: { - GlTab: true, - }, - }); - }); - - it('should display filter tabs with alerts count badge for each status', () => { - const tabs = findStatusFilterTabs().wrappers; - const badges = findStatusFilterBadge(); - - tabs.forEach((tab, i) => { - const status = ALERTS_STATUS_TABS[i].status.toLowerCase(); - expect(tab.text()).toContain(ALERTS_STATUS_TABS[i].title); - expect(badges.at(i).text()).toContain(alertsCount[status]); - }); - }); + mock.restore(); }); describe('Alerts table', () => { it('loading state', () => { mountComponent({ - props: { alertManagementEnabled: true, userCanEnableAlertManagement: true }, data: { alerts: {}, alertsCount: null }, loading: true, }); @@ -144,8 +94,7 @@ describe('AlertManagementTable', () => { it('error state', () => { mountComponent({ - props: { alertManagementEnabled: true, userCanEnableAlertManagement: true }, - data: { alerts: { errors: ['error'] }, alertsCount: null, hasError: true }, + data: { alerts: { errors: ['error'] }, alertsCount: null, errored: true }, loading: false, }); expect(findAlertsTable().exists()).toBe(true); @@ -161,10 +110,17 @@ describe('AlertManagementTable', () => { it('empty state', () => { mountComponent({ - props: { alertManagementEnabled: true, userCanEnableAlertManagement: true }, - data: { alerts: { list: [], pageInfo: {} }, alertsCount: { all: 0 }, hasError: false }, + data: { + alerts: { list: [], pageInfo: {} }, + alertsCount: { all: 0 }, + errored: false, + isErrorAlertDismissed: false, + searchTerm: '', + assigneeUsername: '', + }, loading: false, }); + expect(findAlertsTable().exists()).toBe(true); expect(findAlertsTable().text()).toContain('No alerts to display'); expect(findLoader().exists()).toBe(false); @@ -178,8 +134,7 @@ describe('AlertManagementTable', () => { it('has data state', () => { mountComponent({ - props: { alertManagementEnabled: true, userCanEnableAlertManagement: true }, - data: { alerts: { list: mockAlerts }, alertsCount, hasError: false }, + data: { alerts: { list: mockAlerts }, alertsCount, errored: false }, loading: false, }); expect(findLoader().exists()).toBe(false); @@ -194,8 +149,7 @@ describe('AlertManagementTable', () => { it('displays the alert ID and title formatted correctly', () => { mountComponent({ - props: { alertManagementEnabled: true, userCanEnableAlertManagement: true }, - data: { alerts: { list: mockAlerts }, alertsCount, hasError: false }, + data: { alerts: { list: mockAlerts }, alertsCount, errored: false }, loading: false, }); @@ -205,8 +159,7 @@ describe('AlertManagementTable', () => { it('displays status dropdown', () => { mountComponent({ - props: { alertManagementEnabled: true, userCanEnableAlertManagement: true }, - data: { alerts: { list: mockAlerts }, alertsCount, hasError: false }, + data: { alerts: { list: mockAlerts }, alertsCount, errored: false }, loading: false, }); expect(findStatusDropdown().exists()).toBe(true); @@ -214,8 +167,7 @@ describe('AlertManagementTable', () => { it('does not display a dropdown status header', () => { mountComponent({ - props: { alertManagementEnabled: true, userCanEnableAlertManagement: true }, - data: { alerts: { list: mockAlerts }, alertsCount, hasError: false }, + data: { alerts: { list: mockAlerts }, alertsCount, errored: false }, loading: false, }); expect( @@ -225,27 +177,25 @@ describe('AlertManagementTable', () => { ).toBe(false); }); - it('shows correct severity icons', () => { + it('shows correct severity icons', async () => { mountComponent({ - props: { alertManagementEnabled: true, userCanEnableAlertManagement: true }, - data: { alerts: { list: mockAlerts }, alertsCount, hasError: false }, + data: { alerts: { list: mockAlerts }, alertsCount, errored: false }, loading: false, }); - return wrapper.vm.$nextTick().then(() => { - expect(wrapper.find(GlTable).exists()).toBe(true); - expect( - findAlertsTable() - .find(GlIcon) - .classes('icon-critical'), - ).toBe(true); - }); + await wrapper.vm.$nextTick(); + + expect(wrapper.find(GlTable).exists()).toBe(true); + expect( + findAlertsTable() + .find(GlIcon) + .classes('icon-critical'), + ).toBe(true); }); it('renders severity text', () => { mountComponent({ - props: { alertManagementEnabled: true, userCanEnableAlertManagement: true }, - data: { alerts: { list: mockAlerts }, alertsCount, hasError: false }, + data: { alerts: { list: mockAlerts }, alertsCount, errored: false }, loading: false, }); @@ -258,8 +208,7 @@ describe('AlertManagementTable', () => { it('renders Unassigned when no assignee(s) present', () => { mountComponent({ - props: { alertManagementEnabled: true, userCanEnableAlertManagement: true }, - data: { alerts: { list: mockAlerts }, alertsCount, hasError: false }, + data: { alerts: { list: mockAlerts }, alertsCount, errored: false }, loading: false, }); @@ -272,8 +221,7 @@ describe('AlertManagementTable', () => { it('renders user avatar when assignee present', () => { mountComponent({ - props: { alertManagementEnabled: true, userCanEnableAlertManagement: true }, - data: { alerts: { list: mockAlerts }, alertsCount, hasError: false }, + data: { alerts: { list: mockAlerts }, alertsCount, errored: false }, loading: false, }); @@ -290,22 +238,39 @@ describe('AlertManagementTable', () => { it('navigates to the detail page when alert row is clicked', () => { mountComponent({ - props: { alertManagementEnabled: true, userCanEnableAlertManagement: true }, - data: { alerts: { list: mockAlerts }, alertsCount, hasError: false }, + data: { alerts: { list: mockAlerts }, alertsCount, errored: false }, loading: false, }); + expect(visitUrl).not.toHaveBeenCalled(); + findAlerts() .at(0) .trigger('click'); - expect(visitUrl).toHaveBeenCalledWith('/1527542/details'); + expect(visitUrl).toHaveBeenCalledWith('/1527542/details', false); + }); + + it('navigates to the detail page in new tab when alert row is clicked with the metaKey', () => { + mountComponent({ + data: { alerts: { list: mockAlerts }, alertsCount, errored: false }, + loading: false, + }); + + expect(visitUrl).not.toHaveBeenCalled(); + + findAlerts() + .at(0) + .trigger('click', { + metaKey: true, + }); + + expect(visitUrl).toHaveBeenCalledWith('/1527542/details', true); }); describe('alert issue links', () => { beforeEach(() => { mountComponent({ - props: { alertManagementEnabled: true, userCanEnableAlertManagement: true }, - data: { alerts: { list: mockAlerts }, alertsCount, hasError: false }, + data: { alerts: { list: mockAlerts }, alertsCount, errored: false }, loading: false, }); }); @@ -335,7 +300,6 @@ describe('AlertManagementTable', () => { describe('handle date fields', () => { it('should display time ago dates when values provided', () => { mountComponent({ - props: { alertManagementEnabled: true, userCanEnableAlertManagement: true }, data: { alerts: { list: [ @@ -349,7 +313,7 @@ describe('AlertManagementTable', () => { ], }, alertsCount, - hasError: false, + errored: false, }, loading: false, }); @@ -358,7 +322,6 @@ describe('AlertManagementTable', () => { it('should not display time ago dates when values not provided', () => { mountComponent({ - props: { alertManagementEnabled: true, userCanEnableAlertManagement: true }, data: { alerts: [ { @@ -369,7 +332,7 @@ describe('AlertManagementTable', () => { }, ], alertsCount, - hasError: false, + errored: false, }, loading: false, }); @@ -383,8 +346,7 @@ describe('AlertManagementTable', () => { it('should highlight the row when alert is new', () => { mountComponent({ - props: { alertManagementEnabled: true, userCanEnableAlertManagement: true }, - data: { alerts: { list: [newAlert] }, alertsCount, hasError: false }, + data: { alerts: { list: [newAlert] }, alertsCount, errored: false }, loading: false, }); @@ -397,8 +359,7 @@ describe('AlertManagementTable', () => { it('should not highlight the row when alert is not new', () => { mountComponent({ - props: { alertManagementEnabled: true, userCanEnableAlertManagement: true }, - data: { alerts: { list: [oldAlert] }, alertsCount, hasError: false }, + data: { alerts: { list: [oldAlert] }, alertsCount, errored: false }, loading: false, }); @@ -415,10 +376,9 @@ describe('AlertManagementTable', () => { describe('sorting the alert list by column', () => { beforeEach(() => { mountComponent({ - props: { alertManagementEnabled: true, userCanEnableAlertManagement: true }, data: { alerts: { list: mockAlerts }, - hasError: false, + errored: false, sort: 'STARTED_AT_DESC', alertsCount, }, @@ -438,184 +398,10 @@ describe('AlertManagementTable', () => { }); }); - describe('updating the alert status', () => { - const iid = '1527542'; - const mockUpdatedMutationResult = { - data: { - updateAlertStatus: { - errors: [], - alert: { - iid, - status: 'acknowledged', - }, - }, - }, - }; - - beforeEach(() => { - mountComponent({ - props: { alertManagementEnabled: true, userCanEnableAlertManagement: true }, - data: { alerts: { list: mockAlerts }, alertsCount, hasError: false }, - loading: false, - }); - }); - - it('calls `$apollo.mutate` with `updateAlertStatus` mutation and variables containing `iid`, `status`, & `projectPath`', () => { - jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(mockUpdatedMutationResult); - findFirstStatusOption().vm.$emit('click'); - - expect(wrapper.vm.$apollo.mutate).toHaveBeenCalledWith({ - mutation: updateAlertStatus, - variables: { - iid, - status: 'TRIGGERED', - projectPath: 'gitlab-org/gitlab', - }, - }); - }); - - describe('when a request fails', () => { - beforeEach(() => { - jest.spyOn(wrapper.vm.$apollo, 'mutate').mockReturnValue(Promise.reject(new Error())); - }); - - it('shows an error', async () => { - await selectFirstStatusOption(); - - expect(findAlertError().text()).toContain( - 'There was an error while updating the status of the alert.', - ); - }); - - it('shows an error when triggered a second time', async () => { - await selectFirstStatusOption(); - - wrapper.find(GlAlert).vm.$emit('dismiss'); - - await wrapper.vm.$nextTick(); - - // Assert that the error has been dismissed in the setup - expect(findAlertError().exists()).toBe(false); - - await selectFirstStatusOption(); - - expect(findAlertError().exists()).toBe(true); - }); - }); - - it('shows an error when response includes HTML errors', async () => { - const mockUpdatedMutationErrorResult = { - data: { - updateAlertStatus: { - errors: ['<span data-testid="htmlError" />'], - alert: { - iid, - status: 'acknowledged', - }, - }, - }, - }; - - jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue(mockUpdatedMutationErrorResult); - - await selectFirstStatusOption(); - - expect(findAlertError().exists()).toBe(true); - expect( - findAlertError() - .find('[data-testid="htmlError"]') - .exists(), - ).toBe(true); - }); - }); - - describe('Snowplow tracking', () => { - beforeEach(() => { - jest.spyOn(Tracking, 'event'); - mountComponent({ - props: { alertManagementEnabled: true, userCanEnableAlertManagement: true }, - data: { alerts: { list: mockAlerts }, alertsCount }, - loading: false, - }); - }); - - it('should track alert status updates', () => { - Tracking.event.mockClear(); - jest.spyOn(wrapper.vm.$apollo, 'mutate').mockResolvedValue({}); - findFirstStatusOption().vm.$emit('click'); - const status = findFirstStatusOption().text(); - setImmediate(() => { - const { category, action, label } = trackAlertStatusUpdateOptions; - expect(Tracking.event).toHaveBeenCalledWith(category, action, { label, property: status }); - }); - }); - }); - - describe('Pagination', () => { - beforeEach(() => { - mountComponent({ - props: { alertManagementEnabled: true, userCanEnableAlertManagement: true }, - data: { alerts: { list: mockAlerts, pageInfo: {} }, alertsCount, hasError: false }, - loading: false, - }); - }); - - it('does NOT show pagination control when list is smaller than default page size', () => { - findStatusTabs().vm.$emit('input', 3); - 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); - return wrapper.vm.$nextTick(() => { - expect(findPagination().exists()).toBe(true); - }); - }); - - describe('prevPage', () => { - it('returns prevPage number', () => { - findPagination().vm.$emit('input', 3); - - return wrapper.vm.$nextTick(() => { - expect(wrapper.vm.prevPage).toBe(2); - }); - }); - - it('returns 0 when it is the first page', () => { - findPagination().vm.$emit('input', 1); - - return wrapper.vm.$nextTick(() => { - expect(wrapper.vm.prevPage).toBe(0); - }); - }); - }); - - describe('nextPage', () => { - it('returns nextPage number', () => { - findPagination().vm.$emit('input', 1); - - return wrapper.vm.$nextTick(() => { - expect(wrapper.vm.nextPage).toBe(2); - }); - }); - - it('returns `null` when currentPage is already last page', () => { - findStatusTabs().vm.$emit('input', 3); - findPagination().vm.$emit('input', 1); - return wrapper.vm.$nextTick(() => { - expect(wrapper.vm.nextPage).toBeNull(); - }); - }); - }); - }); - describe('Search', () => { beforeEach(() => { mountComponent({ - props: { alertManagementEnabled: true, userCanEnableAlertManagement: true }, - data: { alerts: { list: mockAlerts }, alertsCount, hasError: false }, + data: { alerts: { list: mockAlerts }, alertsCount, errored: false }, loading: false, }); }); @@ -623,13 +409,5 @@ describe('AlertManagementTable', () => { 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); - }); }); }); |