diff options
Diffstat (limited to 'spec/frontend/incidents/components/incidents_list_spec.js')
-rw-r--r-- | spec/frontend/incidents/components/incidents_list_spec.js | 211 |
1 files changed, 146 insertions, 65 deletions
diff --git a/spec/frontend/incidents/components/incidents_list_spec.js b/spec/frontend/incidents/components/incidents_list_spec.js index 307806e0a8a..1b98d488854 100644 --- a/spec/frontend/incidents/components/incidents_list_spec.js +++ b/spec/frontend/incidents/components/incidents_list_spec.js @@ -5,7 +5,6 @@ import { GlTable, GlAvatar, GlPagination, - GlSearchBoxByType, GlTab, GlTabs, GlBadge, @@ -15,13 +14,24 @@ import { visitUrl, joinPaths, mergeUrlParams } from '~/lib/utils/url_utility'; import IncidentsList from '~/incidents/components/incidents_list.vue'; import SeverityToken from '~/sidebar/components/severity/severity.vue'; import TimeAgoTooltip from '~/vue_shared/components/time_ago_tooltip.vue'; -import { I18N, INCIDENT_STATUS_TABS } from '~/incidents/constants'; +import FilteredSearchBar from '~/vue_shared/components/filtered_search_bar/filtered_search_bar_root.vue'; +import AuthorToken from '~/vue_shared/components/filtered_search_bar/tokens/author_token.vue'; +import { + I18N, + INCIDENT_STATUS_TABS, + TH_CREATED_AT_TEST_ID, + TH_SEVERITY_TEST_ID, + TH_PUBLISHED_TEST_ID, +} from '~/incidents/constants'; import mockIncidents from '../mocks/incidents.json'; +import mockFilters from '../mocks/incidents_filter.json'; jest.mock('~/lib/utils/url_utility', () => ({ visitUrl: jest.fn().mockName('visitUrlMock'), - joinPaths: jest.fn().mockName('joinPaths'), - mergeUrlParams: jest.fn().mockName('mergeUrlParams'), + joinPaths: jest.fn(), + mergeUrlParams: jest.fn(), + setUrlParams: jest.fn(), + updateHistory: jest.fn(), })); describe('Incidents List', () => { @@ -41,9 +51,7 @@ describe('Incidents List', () => { const findAlert = () => wrapper.find(GlAlert); const findLoader = () => wrapper.find(GlLoadingIcon); const findTimeAgo = () => wrapper.findAll(TimeAgoTooltip); - const findDateColumnHeader = () => - wrapper.find('[data-testid="incident-management-created-at-sort"]'); - const findSearch = () => wrapper.find(GlSearchBoxByType); + const findSearch = () => wrapper.find(FilteredSearchBar); const findAssingees = () => wrapper.findAll('[data-testid="incident-assignees"]'); const findCreateIncidentBtn = () => wrapper.find('[data-testid="createIncidentBtn"]'); const findClosedIcon = () => wrapper.findAll("[data-testid='incident-closed']"); @@ -73,9 +81,13 @@ describe('Incidents List', () => { newIssuePath, incidentTemplateName, incidentType, - issuePath: '/project/isssues', + issuePath: '/project/issues', publishedAvailable: true, emptyListSvgPath, + textQuery: '', + authorUsernamesQuery: '', + assigneeUsernamesQuery: '', + issuesIncidentDetails: false, }, stubs: { GlButton: true, @@ -171,13 +183,6 @@ describe('Incidents List', () => { expect(src).toBe(avatarUrl); }); - it('contains a link to the issue details', () => { - findTableRows() - .at(0) - .trigger('click'); - expect(visitUrl).toHaveBeenCalledWith(joinPaths(`/project/isssues/`, mockIncidents[0].iid)); - }); - it('renders a closed icon for closed incidents', () => { expect(findClosedIcon().length).toBe( mockIncidents.filter(({ state }) => state === 'closed').length, @@ -188,6 +193,30 @@ describe('Incidents List', () => { it('renders severity per row', () => { expect(findSeverity().length).toBe(mockIncidents.length); }); + + it('contains a link to the issue details page', () => { + findTableRows() + .at(0) + .trigger('click'); + expect(visitUrl).toHaveBeenCalledWith(joinPaths(`/project/issues/`, mockIncidents[0].iid)); + }); + + it('contains a link to the incident details page', async () => { + beforeEach(() => + mountComponent({ + data: { incidents: { list: mockIncidents }, incidentsCount: {} }, + loading: false, + provide: { glFeatures: { issuesIncidentDetails: true } }, + }), + ); + + findTableRows() + .at(0) + .trigger('click'); + expect(visitUrl).toHaveBeenCalledWith( + joinPaths(`/project/issues/incident`, mockIncidents[0].iid), + ); + }); }); describe('Create Incident', () => { @@ -207,11 +236,10 @@ describe('Incidents List', () => { ); }); - it('sets button loading on click', () => { + it('sets button loading on click', async () => { findCreateIncidentBtn().vm.$emit('click'); - return wrapper.vm.$nextTick().then(() => { - expect(findCreateIncidentBtn().attributes('loading')).toBe('true'); - }); + await wrapper.vm.$nextTick(); + expect(findCreateIncidentBtn().attributes('loading')).toBe('true'); }); it("doesn't show the button when list is empty", () => { @@ -243,51 +271,47 @@ describe('Incidents List', () => { }); describe('prevPage', () => { - it('returns prevPage button', () => { + it('returns prevPage button', async () => { findPagination().vm.$emit('input', 3); - return wrapper.vm.$nextTick(() => { - expect( - findPagination() - .findAll('.page-item') - .at(0) - .text(), - ).toBe('Prev'); - }); + await wrapper.vm.$nextTick(); + expect( + findPagination() + .findAll('.page-item') + .at(0) + .text(), + ).toBe('Prev'); }); - it('returns prevPage number', () => { + it('returns prevPage number', async () => { findPagination().vm.$emit('input', 3); - return wrapper.vm.$nextTick(() => { - expect(wrapper.vm.prevPage).toBe(2); - }); + await wrapper.vm.$nextTick(); + expect(wrapper.vm.prevPage).toBe(2); }); - it('returns 0 when it is the first page', () => { + it('returns 0 when it is the first page', async () => { findPagination().vm.$emit('input', 1); - return wrapper.vm.$nextTick(() => { - expect(wrapper.vm.prevPage).toBe(0); - }); + await wrapper.vm.$nextTick(); + expect(wrapper.vm.prevPage).toBe(0); }); }); describe('nextPage', () => { - it('returns nextPage button', () => { + it('returns nextPage button', async () => { findPagination().vm.$emit('input', 3); - return wrapper.vm.$nextTick(() => { - expect( - findPagination() - .findAll('.page-item') - .at(1) - .text(), - ).toBe('Next'); - }); + await wrapper.vm.$nextTick(); + expect( + findPagination() + .findAll('.page-item') + .at(1) + .text(), + ).toBe('Next'); }); - it('returns nextPage number', () => { + it('returns nextPage number', async () => { mountComponent({ data: { incidents: { @@ -301,21 +325,19 @@ describe('Incidents List', () => { }); findPagination().vm.$emit('input', 1); - return wrapper.vm.$nextTick(() => { - expect(wrapper.vm.nextPage).toBe(2); - }); + await wrapper.vm.$nextTick(); + expect(wrapper.vm.nextPage).toBe(2); }); - it('returns `null` when currentPage is already last page', () => { + it('returns `null` when currentPage is already last page', async () => { findStatusTabs().vm.$emit('input', 1); findPagination().vm.$emit('input', 1); - return wrapper.vm.$nextTick(() => { - expect(wrapper.vm.nextPage).toBeNull(); - }); + await wrapper.vm.$nextTick(); + expect(wrapper.vm.nextPage).toBeNull(); }); }); - describe('Search', () => { + describe('Filtered search component', () => { beforeEach(() => { mountComponent({ data: { @@ -331,15 +353,62 @@ describe('Incidents List', () => { }); it('renders the search component for incidents', () => { - expect(findSearch().exists()).toBe(true); + expect(findSearch().props('searchInputPlaceholder')).toBe('Search or filter results…'); + expect(findSearch().props('tokens')).toEqual([ + { + type: 'author_username', + icon: 'user', + title: 'Author', + unique: true, + symbol: '@', + token: AuthorToken, + operators: [{ value: '=', description: 'is', default: 'true' }], + fetchPath: '/project/path', + fetchAuthors: expect.any(Function), + }, + { + type: 'assignee_username', + icon: 'user', + title: 'Assignees', + unique: true, + symbol: '@', + token: AuthorToken, + operators: [{ value: '=', description: 'is', default: 'true' }], + fetchPath: '/project/path', + fetchAuthors: expect.any(Function), + }, + ]); + expect(findSearch().props('recentSearchesStorageKey')).toBe('incidents'); + }); + + it('returns correctly applied filter search values', async () => { + const searchTerm = 'foo'; + wrapper.setData({ + searchTerm, + }); + + await wrapper.vm.$nextTick(); + expect(wrapper.vm.filteredSearchValue).toEqual([searchTerm]); }); - it('sets the `searchTerm` graphql variable', () => { - const SEARCH_TERM = 'Simple Incident'; + it('updates props tied to getIncidents GraphQL query', () => { + wrapper.vm.handleFilterIncidents(mockFilters); - findSearch().vm.$emit('input', SEARCH_TERM); + expect(wrapper.vm.authorUsername).toBe('root'); + expect(wrapper.vm.assigneeUsernames).toEqual('root2'); + expect(wrapper.vm.searchTerm).toBe(mockFilters[2].value.data); + }); - expect(wrapper.vm.$data.searchTerm).toBe(SEARCH_TERM); + it('updates props `searchTerm` and `authorUsername` with empty values when passed filters param is empty', () => { + wrapper.setData({ + authorUsername: 'foo', + searchTerm: 'bar', + }); + + wrapper.vm.handleFilterIncidents([]); + + expect(wrapper.vm.authorUsername).toBe(''); + expect(wrapper.vm.searchTerm).toBe(''); }); }); @@ -383,13 +452,25 @@ describe('Incidents List', () => { }); }); - it('updates sort with new direction and column key', () => { - expect(findDateColumnHeader().attributes('aria-sort')).toBe('descending'); + const descSort = 'descending'; + const ascSort = 'ascending'; + const noneSort = 'none'; - findDateColumnHeader().trigger('click'); - return wrapper.vm.$nextTick(() => { - expect(findDateColumnHeader().attributes('aria-sort')).toBe('ascending'); - }); + it.each` + selector | initialSort | firstSort | nextSort + ${TH_CREATED_AT_TEST_ID} | ${descSort} | ${ascSort} | ${descSort} + ${TH_SEVERITY_TEST_ID} | ${noneSort} | ${descSort} | ${ascSort} + ${TH_PUBLISHED_TEST_ID} | ${noneSort} | ${descSort} | ${ascSort} + `('updates sort with new direction', async ({ selector, initialSort, firstSort, nextSort }) => { + const [[attr, value]] = Object.entries(selector); + const columnHeader = () => wrapper.find(`[${attr}="${value}"]`); + expect(columnHeader().attributes('aria-sort')).toBe(initialSort); + columnHeader().trigger('click'); + await wrapper.vm.$nextTick(); + expect(columnHeader().attributes('aria-sort')).toBe(firstSort); + columnHeader().trigger('click'); + await wrapper.vm.$nextTick(); + expect(columnHeader().attributes('aria-sort')).toBe(nextSort); }); }); }); |