diff options
Diffstat (limited to 'spec/frontend/issues/list/components/issues_list_app_spec.js')
-rw-r--r-- | spec/frontend/issues/list/components/issues_list_app_spec.js | 175 |
1 files changed, 96 insertions, 79 deletions
diff --git a/spec/frontend/issues/list/components/issues_list_app_spec.js b/spec/frontend/issues/list/components/issues_list_app_spec.js index 5a9bd1ff8e4..d92ba527b5c 100644 --- a/spec/frontend/issues/list/components/issues_list_app_spec.js +++ b/spec/frontend/issues/list/components/issues_list_app_spec.js @@ -5,8 +5,11 @@ import AxiosMockAdapter from 'axios-mock-adapter'; import { cloneDeep } from 'lodash'; import Vue, { nextTick } from 'vue'; import VueApollo from 'vue-apollo'; +import VueRouter from 'vue-router'; import getIssuesQuery from 'ee_else_ce/issues/list/queries/get_issues.query.graphql'; import getIssuesCountsQuery from 'ee_else_ce/issues/list/queries/get_issues_counts.query.graphql'; +import getIssuesWithoutCrmQuery from 'ee_else_ce/issues/list/queries/get_issues_without_crm.query.graphql'; +import getIssuesCountsWithoutCrmQuery from 'ee_else_ce/issues/list/queries/get_issues_counts_without_crm.query.graphql'; import createMockApollo from 'helpers/mock_apollo_helper'; import setWindowLocation from 'helpers/set_window_location_helper'; import { TEST_HOST } from 'helpers/test_constants'; @@ -58,6 +61,7 @@ describe('CE IssuesListApp component', () => { let wrapper; Vue.use(VueApollo); + Vue.use(VueRouter); const defaultProvide = { autocompleteAwardEmojisPath: 'autocomplete/award/emojis/path', @@ -78,6 +82,7 @@ describe('CE IssuesListApp component', () => { isAnonymousSearchDisabled: false, isIssueRepositioningDisabled: false, isProject: true, + isPublicVisibilityRestricted: false, isSignedIn: true, jiraIntegrationPath: 'jira/integration/path', newIssuePath: 'new/issue/path', @@ -107,6 +112,7 @@ describe('CE IssuesListApp component', () => { const mountComponent = ({ provide = {}, + data = {}, issuesQueryResponse = jest.fn().mockResolvedValue(defaultQueryResponse), issuesCountsQueryResponse = jest.fn().mockResolvedValue(getIssuesCountsQueryResponse), sortPreferenceMutationResponse = jest.fn().mockResolvedValue(setSortPreferenceMutationResponse), @@ -115,16 +121,21 @@ describe('CE IssuesListApp component', () => { const requestHandlers = [ [getIssuesQuery, issuesQueryResponse], [getIssuesCountsQuery, issuesCountsQueryResponse], + [getIssuesWithoutCrmQuery, issuesQueryResponse], + [getIssuesCountsWithoutCrmQuery, issuesCountsQueryResponse], [setSortPreferenceMutation, sortPreferenceMutationResponse], ]; - const apolloProvider = createMockApollo(requestHandlers); return mountFn(IssuesListApp, { - apolloProvider, + apolloProvider: createMockApollo(requestHandlers), + router: new VueRouter({ mode: 'history' }), provide: { ...defaultProvide, ...provide, }, + data() { + return data; + }, }); }; @@ -139,10 +150,10 @@ describe('CE IssuesListApp component', () => { }); describe('IssuableList', () => { - beforeEach(async () => { + beforeEach(() => { wrapper = mountComponent(); jest.runOnlyPendingTimers(); - await waitForPromises(); + return waitForPromises(); }); it('renders', () => { @@ -167,10 +178,6 @@ describe('CE IssuesListApp component', () => { useKeysetPagination: true, hasPreviousPage: getIssuesQueryResponse.data.project.issues.pageInfo.hasPreviousPage, hasNextPage: getIssuesQueryResponse.data.project.issues.pageInfo.hasNextPage, - urlParams: { - sort: urlSortParams[CREATED_DESC], - state: IssuableStates.Opened, - }, }); }); }); @@ -200,7 +207,7 @@ describe('CE IssuesListApp component', () => { describe('csv import/export component', () => { describe('when user is signed in', () => { - beforeEach(async () => { + beforeEach(() => { setWindowLocation('?search=refactor&state=opened'); wrapper = mountComponent({ @@ -209,12 +216,12 @@ describe('CE IssuesListApp component', () => { }); jest.runOnlyPendingTimers(); - await waitForPromises(); + return waitForPromises(); }); it('renders', () => { expect(findCsvImportExportButtons().props()).toMatchObject({ - exportCsvPath: `${defaultProvide.exportCsvPath}?search=refactor&sort=created_date&state=opened`, + exportCsvPath: `${defaultProvide.exportCsvPath}?search=refactor&state=opened`, issuableCount: 1, }); }); @@ -252,11 +259,9 @@ describe('CE IssuesListApp component', () => { it('emits "issuables:enableBulkEdit" event to legacy bulk edit class', async () => { wrapper = mountComponent({ provide: { canBulkUpdate: true }, mountFn: mount }); - jest.spyOn(eventHub, '$emit'); findGlButtonAt(2).vm.$emit('click'); - await waitForPromises(); expect(eventHub.$emit).toHaveBeenCalledWith('issuables:enableBulkEdit'); @@ -297,32 +302,25 @@ describe('CE IssuesListApp component', () => { describe('page', () => { it('page_after is set from the url params', () => { setWindowLocation('?page_after=randomCursorString'); - wrapper = mountComponent(); - expect(findIssuableList().props('urlParams')).toMatchObject({ - page_after: 'randomCursorString', - }); + expect(wrapper.vm.$route.query).toMatchObject({ page_after: 'randomCursorString' }); }); it('page_before is set from the url params', () => { setWindowLocation('?page_before=anotherRandomCursorString'); - wrapper = mountComponent(); - expect(findIssuableList().props('urlParams')).toMatchObject({ - page_before: 'anotherRandomCursorString', - }); + expect(wrapper.vm.$route.query).toMatchObject({ page_before: 'anotherRandomCursorString' }); }); }); describe('search', () => { it('is set from the url params', () => { setWindowLocation(locationSearch); - wrapper = mountComponent(); - expect(findIssuableList().props('urlParams')).toMatchObject({ search: 'find issues' }); + expect(wrapper.vm.$route.query).toMatchObject({ search: 'find issues' }); }); }); @@ -333,10 +331,7 @@ describe('CE IssuesListApp component', () => { it.each(oldEnumSortValues)('initial sort is set with value %s', (sort) => { wrapper = mountComponent({ provide: { initialSort: sort } }); - expect(findIssuableList().props()).toMatchObject({ - initialSortBy: getSortKey(sort), - urlParams: { sort }, - }); + expect(findIssuableList().props('initialSortBy')).toBe(getSortKey(sort)); }); }); @@ -346,10 +341,7 @@ describe('CE IssuesListApp component', () => { it.each(graphQLEnumSortValues)('initial sort is set with value %s', (sort) => { wrapper = mountComponent({ provide: { initialSort: sort.toLowerCase() } }); - expect(findIssuableList().props()).toMatchObject({ - initialSortBy: sort, - urlParams: { sort: urlSortParams[sort] }, - }); + expect(findIssuableList().props('initialSortBy')).toBe(sort); }); }); @@ -359,10 +351,7 @@ describe('CE IssuesListApp component', () => { (sort) => { wrapper = mountComponent({ provide: { initialSort: sort } }); - expect(findIssuableList().props()).toMatchObject({ - initialSortBy: CREATED_DESC, - urlParams: { sort: urlSortParams[CREATED_DESC] }, - }); + expect(findIssuableList().props('initialSortBy')).toBe(CREATED_DESC); }, ); }); @@ -375,10 +364,7 @@ describe('CE IssuesListApp component', () => { }); it('changes the sort to the default of created descending', () => { - expect(findIssuableList().props()).toMatchObject({ - initialSortBy: CREATED_DESC, - urlParams: { sort: urlSortParams[CREATED_DESC] }, - }); + expect(findIssuableList().props('initialSortBy')).toBe(CREATED_DESC); }); it('shows an alert to tell the user that manual reordering is disabled', () => { @@ -393,9 +379,7 @@ describe('CE IssuesListApp component', () => { describe('state', () => { it('is set from the url params', () => { const initialState = IssuableStates.All; - setWindowLocation(`?state=${initialState}`); - wrapper = mountComponent(); expect(findIssuableList().props('currentTab')).toBe(initialState); @@ -405,7 +389,6 @@ describe('CE IssuesListApp component', () => { describe('filter tokens', () => { it('is set from the url params', () => { setWindowLocation(locationSearch); - wrapper = mountComponent(); expect(findIssuableList().props('initialFilterValue')).toEqual(filteredTokens); @@ -414,7 +397,6 @@ describe('CE IssuesListApp component', () => { describe('when anonymous searching is performed', () => { beforeEach(() => { setWindowLocation(locationSearch); - wrapper = mountComponent({ provide: { isAnonymousSearchDisabled: true, isSignedIn: false }, }); @@ -649,12 +631,12 @@ describe('CE IssuesListApp component', () => { ${'fetching issues'} | ${'issuesQueryResponse'} | ${IssuesListApp.i18n.errorFetchingIssues} ${'fetching issue counts'} | ${'issuesCountsQueryResponse'} | ${IssuesListApp.i18n.errorFetchingCounts} `('when there is an error $error', ({ mountOption, message }) => { - beforeEach(async () => { + beforeEach(() => { wrapper = mountComponent({ [mountOption]: jest.fn().mockRejectedValue(new Error('ERROR')), }); jest.runOnlyPendingTimers(); - await waitForPromises(); + return waitForPromises(); }); it('shows an error message', () => { @@ -676,29 +658,51 @@ describe('CE IssuesListApp component', () => { describe('when "click-tab" event is emitted by IssuableList', () => { beforeEach(() => { wrapper = mountComponent(); + jest.spyOn(wrapper.vm.$router, 'push'); findIssuableList().vm.$emit('click-tab', IssuableStates.Closed); }); - it('updates to the new tab', () => { + it('updates ui to the new tab', () => { expect(findIssuableList().props('currentTab')).toBe(IssuableStates.Closed); }); - }); - describe.each(['next-page', 'previous-page'])( - 'when "%s" event is emitted by IssuableList', - (event) => { - beforeEach(() => { - wrapper = mountComponent(); + it('updates url to the new tab', () => { + expect(wrapper.vm.$router.push).toHaveBeenCalledWith({ + query: expect.objectContaining({ state: IssuableStates.Closed }), + }); + }); + }); - findIssuableList().vm.$emit(event); + describe.each` + event | paramName | paramValue + ${'next-page'} | ${'page_after'} | ${'endCursor'} + ${'previous-page'} | ${'page_before'} | ${'startCursor'} + `('when "$event" event is emitted by IssuableList', ({ event, paramName, paramValue }) => { + beforeEach(() => { + wrapper = mountComponent({ + data: { + pageInfo: { + endCursor: 'endCursor', + startCursor: 'startCursor', + }, + }, }); + jest.spyOn(wrapper.vm.$router, 'push'); + + findIssuableList().vm.$emit(event); + }); + + it('scrolls to the top', () => { + expect(scrollUp).toHaveBeenCalled(); + }); - it('scrolls to the top', () => { - expect(scrollUp).toHaveBeenCalled(); + it(`updates url with "${paramName}" param`, () => { + expect(wrapper.vm.$router.push).toHaveBeenCalledWith({ + query: expect.objectContaining({ [paramName]: paramValue }), }); - }, - ); + }); + }); describe('when "reorder" event is emitted by IssuableList', () => { const issueOne = { @@ -752,18 +756,17 @@ describe('CE IssuesListApp component', () => { `( 'when moving issue $description', ({ issueToMove, oldIndex, newIndex, moveBeforeId, moveAfterId }) => { - beforeEach(async () => { + beforeEach(() => { wrapper = mountComponent({ provide: { isProject }, issuesQueryResponse: jest.fn().mockResolvedValue(response(isProject)), }); jest.runOnlyPendingTimers(); - await waitForPromises(); + return waitForPromises(); }); it('makes API call to reorder the issue', async () => { findIssuableList().vm.$emit('reorder', { oldIndex, newIndex }); - await waitForPromises(); expect(axiosMock.history.put[0]).toMatchObject({ @@ -780,19 +783,18 @@ describe('CE IssuesListApp component', () => { }); describe('when unsuccessful', () => { - beforeEach(async () => { + beforeEach(() => { wrapper = mountComponent({ issuesQueryResponse: jest.fn().mockResolvedValue(response()), }); jest.runOnlyPendingTimers(); - await waitForPromises(); + return waitForPromises(); }); it('displays an error message', async () => { axiosMock.onPut(joinPaths(issueOne.webPath, 'reorder')).reply(500); findIssuableList().vm.$emit('reorder', { oldIndex: 0, newIndex: 1 }); - await waitForPromises(); expect(findIssuableList().props('error')).toBe(IssuesListApp.i18n.reorderError); @@ -808,14 +810,14 @@ describe('CE IssuesListApp component', () => { 'updates to the new sort when payload is `%s`', async (sortKey) => { wrapper = mountComponent(); + jest.spyOn(wrapper.vm.$router, 'push'); findIssuableList().vm.$emit('sort', sortKey); - jest.runOnlyPendingTimers(); await nextTick(); - expect(findIssuableList().props('urlParams')).toMatchObject({ - sort: urlSortParams[sortKey], + expect(wrapper.vm.$router.push).toHaveBeenCalledWith({ + query: expect.objectContaining({ sort: urlSortParams[sortKey] }), }); }, ); @@ -827,14 +829,13 @@ describe('CE IssuesListApp component', () => { wrapper = mountComponent({ provide: { initialSort, isIssueRepositioningDisabled: true }, }); + jest.spyOn(wrapper.vm.$router, 'push'); findIssuableList().vm.$emit('sort', RELATIVE_POSITION_ASC); }); it('does not update the sort to manual', () => { - expect(findIssuableList().props('urlParams')).toMatchObject({ - sort: urlSortParams[initialSort], - }); + expect(wrapper.vm.$router.push).not.toHaveBeenCalled(); }); it('shows an alert to tell the user that manual reordering is disabled', () => { @@ -899,11 +900,14 @@ describe('CE IssuesListApp component', () => { describe('when "filter" event is emitted by IssuableList', () => { it('updates IssuableList with url params', async () => { wrapper = mountComponent(); + jest.spyOn(wrapper.vm.$router, 'push'); findIssuableList().vm.$emit('filter', filteredTokens); await nextTick(); - expect(findIssuableList().props('urlParams')).toMatchObject(urlParams); + expect(wrapper.vm.$router.push).toHaveBeenCalledWith({ + query: expect.objectContaining(urlParams), + }); }); describe('when anonymous searching is performed', () => { @@ -911,19 +915,13 @@ describe('CE IssuesListApp component', () => { wrapper = mountComponent({ provide: { isAnonymousSearchDisabled: true, isSignedIn: false }, }); + jest.spyOn(wrapper.vm.$router, 'push'); findIssuableList().vm.$emit('filter', filteredTokens); }); - it('does not update IssuableList with url params ', async () => { - const defaultParams = { - page_after: null, - page_before: null, - sort: 'created_date', - state: 'opened', - }; - - expect(findIssuableList().props('urlParams')).toEqual(defaultParams); + it('does not update url params', () => { + expect(wrapper.vm.$router.push).not.toHaveBeenCalled(); }); it('shows an alert to tell the user they must be signed in to search', () => { @@ -935,4 +933,23 @@ describe('CE IssuesListApp component', () => { }); }); }); + + describe('public visibility', () => { + it.each` + description | isPublicVisibilityRestricted | isSignedIn | hideUsers + ${'shows users when public visibility is not restricted and is not signed in'} | ${false} | ${false} | ${false} + ${'shows users when public visibility is not restricted and is signed in'} | ${false} | ${true} | ${false} + ${'hides users when public visibility is restricted and is not signed in'} | ${true} | ${false} | ${true} + ${'shows users when public visibility is restricted and is signed in'} | ${true} | ${true} | ${false} + `('$description', ({ isPublicVisibilityRestricted, isSignedIn, hideUsers }) => { + const mockQuery = jest.fn().mockResolvedValue(defaultQueryResponse); + wrapper = mountComponent({ + provide: { isPublicVisibilityRestricted, isSignedIn }, + issuesQueryResponse: mockQuery, + }); + jest.runOnlyPendingTimers(); + + expect(mockQuery).toHaveBeenCalledWith(expect.objectContaining({ hideUsers })); + }); + }); }); |