diff options
Diffstat (limited to 'spec/frontend/issues_list')
-rw-r--r-- | spec/frontend/issues_list/components/issuables_list_app_spec.js | 4 | ||||
-rw-r--r-- | spec/frontend/issues_list/components/issues_list_app_spec.js | 74 | ||||
-rw-r--r-- | spec/frontend/issues_list/mock_data.js | 77 | ||||
-rw-r--r-- | spec/frontend/issues_list/utils_spec.js | 29 |
4 files changed, 113 insertions, 71 deletions
diff --git a/spec/frontend/issues_list/components/issuables_list_app_spec.js b/spec/frontend/issues_list/components/issuables_list_app_spec.js index a7f3dd81517..86112dad444 100644 --- a/spec/frontend/issues_list/components/issuables_list_app_spec.js +++ b/spec/frontend/issues_list/components/issuables_list_app_spec.js @@ -8,7 +8,7 @@ import axios from 'axios'; import MockAdapter from 'axios-mock-adapter'; import { TEST_HOST } from 'helpers/test_constants'; import waitForPromises from 'helpers/wait_for_promises'; -import { deprecatedCreateFlash as flash } from '~/flash'; +import createFlash from '~/flash'; import Issuable from '~/issues_list/components/issuable.vue'; import IssuablesListApp from '~/issues_list/components/issuables_list_app.vue'; import { PAGE_SIZE, PAGE_SIZE_MANUAL, RELATIVE_POSITION } from '~/issues_list/constants'; @@ -104,7 +104,7 @@ describe('Issuables list component', () => { }); it('flashes an error', () => { - expect(flash).toHaveBeenCalledTimes(1); + expect(createFlash).toHaveBeenCalledTimes(1); }); }); 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 a3ac57ee1bb..846236e1fb5 100644 --- a/spec/frontend/issues_list/components/issues_list_app_spec.js +++ b/spec/frontend/issues_list/components/issues_list_app_spec.js @@ -5,6 +5,7 @@ import { cloneDeep } from 'lodash'; import { nextTick } from 'vue'; import VueApollo from 'vue-apollo'; import getIssuesQuery from 'ee_else_ce/issues_list/queries/get_issues.query.graphql'; +import getIssuesCountQuery from 'ee_else_ce/issues_list/queries/get_issues_count.query.graphql'; import createMockApollo from 'helpers/mock_apollo_helper'; import { TEST_HOST } from 'helpers/test_constants'; import waitForPromises from 'helpers/wait_for_promises'; @@ -13,15 +14,16 @@ import { filteredTokens, locationSearch, urlParams, + getIssuesCountQueryResponse, } from 'jest/issues_list/mock_data'; import createFlash from '~/flash'; +import { convertToGraphQLId } from '~/graphql_shared/utils'; import CsvImportExportButtons from '~/issuable/components/csv_import_export_buttons.vue'; import IssuableByEmail from '~/issuable/components/issuable_by_email.vue'; import IssuableList from '~/issuable_list/components/issuable_list_root.vue'; import { IssuableListTabs, IssuableStates } from '~/issuable_list/constants'; import IssuesListApp from '~/issues_list/components/issues_list_app.vue'; import { - apiSortParams, CREATED_DESC, DUE_DATE_OVERDUE, PARAM_DUE_DATE, @@ -55,19 +57,18 @@ describe('IssuesListApp component', () => { localVue.use(VueApollo); const defaultProvide = { - autocompleteUsersPath: 'autocomplete/users/path', calendarPath: 'calendar/path', canBulkUpdate: false, emptyStateSvgPath: 'empty-state.svg', exportCsvPath: 'export/csv/path', hasBlockedIssuesFeature: true, hasIssueWeightsFeature: true, + hasIterationsFeature: true, hasProjectIssues: true, - isSignedIn: false, + isSignedIn: true, issuesPath: 'path/to/issues', jiraIntegrationPath: 'jira/integration/path', newIssuePath: 'new/issue/path', - projectLabelsPath: 'project/labels/path', projectPath: 'path/to/project', rssPath: 'rss/path', showNewIssueLink: true, @@ -77,7 +78,7 @@ describe('IssuesListApp component', () => { let defaultQueryResponse = getIssuesQueryResponse; if (IS_EE) { defaultQueryResponse = cloneDeep(getIssuesQueryResponse); - defaultQueryResponse.data.project.issues.nodes[0].blockedByCount = 1; + defaultQueryResponse.data.project.issues.nodes[0].blockingCount = 1; defaultQueryResponse.data.project.issues.nodes[0].healthStatus = null; defaultQueryResponse.data.project.issues.nodes[0].weight = 5; } @@ -93,10 +94,14 @@ describe('IssuesListApp component', () => { const mountComponent = ({ provide = {}, - response = defaultQueryResponse, + issuesQueryResponse = jest.fn().mockResolvedValue(defaultQueryResponse), + issuesQueryCountResponse = jest.fn().mockResolvedValue(getIssuesCountQueryResponse), mountFn = shallowMount, } = {}) => { - const requestHandlers = [[getIssuesQuery, jest.fn().mockResolvedValue(response)]]; + const requestHandlers = [ + [getIssuesQuery, issuesQueryResponse], + [getIssuesCountQuery, issuesQueryCountResponse], + ]; const apolloProvider = createMockApollo(requestHandlers); return mountFn(IssuesListApp, { @@ -137,8 +142,8 @@ describe('IssuesListApp component', () => { currentTab: IssuableStates.Opened, tabCounts: { opened: 1, - closed: undefined, - all: undefined, + closed: 1, + all: 1, }, issuablesLoading: false, isManualOrdering: false, @@ -148,8 +153,8 @@ describe('IssuesListApp component', () => { hasPreviousPage: getIssuesQueryResponse.data.project.issues.pageInfo.hasPreviousPage, hasNextPage: getIssuesQueryResponse.data.project.issues.pageInfo.hasNextPage, urlParams: { + sort: urlSortParams[CREATED_DESC], state: IssuableStates.Opened, - ...urlSortParams[CREATED_DESC], }, }); }); @@ -178,7 +183,7 @@ describe('IssuesListApp component', () => { describe('csv import/export component', () => { describe('when user is signed in', () => { - const search = '?search=refactor&state=opened&sort=created_date'; + const search = '?search=refactor&sort=created_date&state=opened'; beforeEach(() => { global.jsdom.reconfigure({ url: `${TEST_HOST}${search}` }); @@ -273,13 +278,17 @@ describe('IssuesListApp component', () => { describe('sort', () => { it.each(Object.keys(urlSortParams))('is set as %s from the url params', (sortKey) => { - global.jsdom.reconfigure({ url: setUrlParams(urlSortParams[sortKey], TEST_HOST) }); + global.jsdom.reconfigure({ + url: setUrlParams({ sort: urlSortParams[sortKey] }, TEST_HOST), + }); wrapper = mountComponent(); expect(findIssuableList().props()).toMatchObject({ initialSortBy: sortKey, - urlParams: urlSortParams[sortKey], + urlParams: { + sort: urlSortParams[sortKey], + }, }); }); }); @@ -542,9 +551,13 @@ describe('IssuesListApp component', () => { }); it('renders all tokens', () => { + const preloadedAuthors = [ + { ...mockCurrentUser, id: convertToGraphQLId('User', mockCurrentUser.id) }, + ]; + expect(findIssuableList().props('searchTokens')).toMatchObject([ - { type: TOKEN_TYPE_AUTHOR, preloadedAuthors: [mockCurrentUser] }, - { type: TOKEN_TYPE_ASSIGNEE, preloadedAuthors: [mockCurrentUser] }, + { type: TOKEN_TYPE_AUTHOR, preloadedAuthors }, + { type: TOKEN_TYPE_ASSIGNEE, preloadedAuthors }, { type: TOKEN_TYPE_MILESTONE }, { type: TOKEN_TYPE_LABEL }, { type: TOKEN_TYPE_MY_REACTION }, @@ -557,6 +570,29 @@ describe('IssuesListApp component', () => { }); }); + describe('errors', () => { + describe.each` + error | mountOption | message + ${'fetching issues'} | ${'issuesQueryResponse'} | ${IssuesListApp.i18n.errorFetchingIssues} + ${'fetching issue counts'} | ${'issuesQueryCountResponse'} | ${IssuesListApp.i18n.errorFetchingCounts} + `('when there is an error $error', ({ mountOption, message }) => { + beforeEach(() => { + wrapper = mountComponent({ + [mountOption]: jest.fn().mockRejectedValue(new Error('ERROR')), + }); + jest.runOnlyPendingTimers(); + }); + + it('shows an error message', () => { + expect(createFlash).toHaveBeenCalledWith({ + captureError: true, + error: new Error('Network error: ERROR'), + message, + }); + }); + }); + }); + describe('events', () => { describe('when "click-tab" event is emitted by IssuableList', () => { beforeEach(() => { @@ -622,7 +658,7 @@ describe('IssuesListApp component', () => { }; beforeEach(() => { - wrapper = mountComponent({ response }); + wrapper = mountComponent({ issuesQueryResponse: jest.fn().mockResolvedValue(response) }); jest.runOnlyPendingTimers(); }); @@ -640,7 +676,7 @@ describe('IssuesListApp component', () => { }); describe('when "sort" event is emitted by IssuableList', () => { - it.each(Object.keys(apiSortParams))( + it.each(Object.keys(urlSortParams))( 'updates to the new sort when payload is `%s`', async (sortKey) => { wrapper = mountComponent(); @@ -650,7 +686,9 @@ describe('IssuesListApp component', () => { jest.runOnlyPendingTimers(); await nextTick(); - expect(findIssuableList().props('urlParams')).toMatchObject(urlSortParams[sortKey]); + expect(findIssuableList().props('urlParams')).toMatchObject({ + sort: urlSortParams[sortKey], + }); }, ); }); diff --git a/spec/frontend/issues_list/mock_data.js b/spec/frontend/issues_list/mock_data.js index 6c669e02070..fd59241fd1d 100644 --- a/spec/frontend/issues_list/mock_data.js +++ b/spec/frontend/issues_list/mock_data.js @@ -7,9 +7,8 @@ export const getIssuesQueryResponse = { data: { project: { issues: { - count: 1, pageInfo: { - hasNextPage: false, + hasNextPage: true, hasPreviousPage: false, startCursor: 'startcursor', endCursor: 'endcursor', @@ -70,6 +69,16 @@ export const getIssuesQueryResponse = { }, }; +export const getIssuesCountQueryResponse = { + data: { + project: { + issues: { + count: 1, + }, + }, + }, +}; + export const locationSearch = [ '?search=find+issues', 'author_username=homer', @@ -86,10 +95,10 @@ export const locationSearch = [ 'not[label_name][]=drama', 'my_reaction_emoji=thumbsup', 'confidential=no', - 'iteration_title=season:+%234', - 'not[iteration_title]=season:+%2320', - 'epic_id=gitlab-org%3A%3A%2612', - 'not[epic_id]=gitlab-org%3A%3A%2634', + 'iteration_id=4', + 'not[iteration_id]=20', + 'epic_id=12', + 'not[epic_id]=34', 'weight=1', 'not[weight]=3', ].join('&'); @@ -118,10 +127,10 @@ export const filteredTokens = [ { type: 'labels', value: { data: 'drama', operator: OPERATOR_IS_NOT } }, { type: 'my_reaction_emoji', value: { data: 'thumbsup', operator: OPERATOR_IS } }, { type: 'confidential', value: { data: 'no', operator: OPERATOR_IS } }, - { type: 'iteration', value: { data: 'season: #4', operator: OPERATOR_IS } }, - { type: 'iteration', value: { data: 'season: #20', operator: OPERATOR_IS_NOT } }, - { type: 'epic_id', value: { data: 'gitlab-org::&12', operator: OPERATOR_IS } }, - { type: 'epic_id', value: { data: 'gitlab-org::&34', operator: OPERATOR_IS_NOT } }, + { type: 'iteration', value: { data: '4', operator: OPERATOR_IS } }, + { type: 'iteration', value: { data: '20', operator: OPERATOR_IS_NOT } }, + { type: 'epic_id', value: { data: '12', operator: OPERATOR_IS } }, + { type: 'epic_id', value: { data: '34', operator: OPERATOR_IS_NOT } }, { type: 'weight', value: { data: '1', operator: OPERATOR_IS } }, { type: 'weight', value: { data: '3', operator: OPERATOR_IS_NOT } }, { type: 'filtered-search-term', value: { data: 'find' } }, @@ -138,30 +147,32 @@ export const filteredTokensWithSpecialValues = [ ]; export const apiParams = { - author_username: 'homer', - 'not[author_username]': 'marge', - assignee_username: ['bart', 'lisa'], - 'not[assignee_username]': ['patty', 'selma'], - milestone: 'season 4', - 'not[milestone]': 'season 20', - labels: ['cartoon', 'tv'], - 'not[labels]': ['live action', 'drama'], - my_reaction_emoji: 'thumbsup', + authorUsername: 'homer', + assigneeUsernames: ['bart', 'lisa'], + milestoneTitle: 'season 4', + labelName: ['cartoon', 'tv'], + myReactionEmoji: 'thumbsup', confidential: 'no', - iteration_title: 'season: #4', - 'not[iteration_title]': 'season: #20', - epic_id: '12', - 'not[epic_id]': 'gitlab-org::&34', + iterationId: '4', + epicId: '12', weight: '1', - 'not[weight]': '3', + not: { + authorUsername: 'marge', + assigneeUsernames: ['patty', 'selma'], + milestoneTitle: 'season 20', + labelName: ['live action', 'drama'], + iterationId: '20', + epicId: '34', + weight: '3', + }, }; export const apiParamsWithSpecialValues = { - assignee_id: '123', - assignee_username: 'bart', - my_reaction_emoji: 'None', - iteration_id: 'Current', - epic_id: 'None', + assigneeId: '123', + assigneeUsernames: 'bart', + myReactionEmoji: 'None', + iterationWildcardId: 'CURRENT', + epicId: 'None', weight: 'None', }; @@ -176,10 +187,10 @@ export const urlParams = { 'not[label_name][]': ['live action', 'drama'], my_reaction_emoji: 'thumbsup', confidential: 'no', - iteration_title: 'season: #4', - 'not[iteration_title]': 'season: #20', - epic_id: 'gitlab-org%3A%3A%2612', - 'not[epic_id]': 'gitlab-org::&34', + iteration_id: '4', + 'not[iteration_id]': '20', + epic_id: '12', + 'not[epic_id]': '34', weight: '1', 'not[weight]': '3', }; diff --git a/spec/frontend/issues_list/utils_spec.js b/spec/frontend/issues_list/utils_spec.js index e377c35a0aa..b7863068570 100644 --- a/spec/frontend/issues_list/utils_spec.js +++ b/spec/frontend/issues_list/utils_spec.js @@ -8,10 +8,11 @@ import { urlParams, urlParamsWithSpecialValues, } from 'jest/issues_list/mock_data'; -import { API_PARAM, DUE_DATE_VALUES, URL_PARAM, urlSortParams } from '~/issues_list/constants'; +import { DUE_DATE_VALUES, urlSortParams } from '~/issues_list/constants'; import { - convertToParams, + convertToApiParams, convertToSearchQuery, + convertToUrlParams, getDueDateValue, getFilterTokens, getSortKey, @@ -20,7 +21,7 @@ import { describe('getSortKey', () => { it.each(Object.keys(urlSortParams))('returns %s given the correct inputs', (sortKey) => { - const { sort } = urlSortParams[sortKey]; + const sort = urlSortParams[sortKey]; expect(getSortKey(sort)).toBe(sortKey); }); }); @@ -80,31 +81,23 @@ describe('getFilterTokens', () => { }); }); -describe('convertToParams', () => { +describe('convertToApiParams', () => { it('returns api params given filtered tokens', () => { - expect(convertToParams(filteredTokens, API_PARAM)).toEqual({ - ...apiParams, - epic_id: 'gitlab-org::&12', - }); + expect(convertToApiParams(filteredTokens)).toEqual(apiParams); }); it('returns api params given filtered tokens with special values', () => { - expect(convertToParams(filteredTokensWithSpecialValues, API_PARAM)).toEqual( - apiParamsWithSpecialValues, - ); + expect(convertToApiParams(filteredTokensWithSpecialValues)).toEqual(apiParamsWithSpecialValues); }); +}); +describe('convertToUrlParams', () => { it('returns url params given filtered tokens', () => { - expect(convertToParams(filteredTokens, URL_PARAM)).toEqual({ - ...urlParams, - epic_id: 'gitlab-org::&12', - }); + expect(convertToUrlParams(filteredTokens)).toEqual(urlParams); }); it('returns url params given filtered tokens with special values', () => { - expect(convertToParams(filteredTokensWithSpecialValues, URL_PARAM)).toEqual( - urlParamsWithSpecialValues, - ); + expect(convertToUrlParams(filteredTokensWithSpecialValues)).toEqual(urlParamsWithSpecialValues); }); }); |