summaryrefslogtreecommitdiff
path: root/spec/frontend/issues/list/components/issues_list_app_spec.js
diff options
context:
space:
mode:
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.js161
1 files changed, 115 insertions, 46 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 66428ee0492..88652ddc3cc 100644
--- a/spec/frontend/issues/list/components/issues_list_app_spec.js
+++ b/spec/frontend/issues/list/components/issues_list_app_spec.js
@@ -16,6 +16,8 @@ import {
getIssuesQueryResponse,
filteredTokens,
locationSearch,
+ setSortPreferenceMutationResponse,
+ setSortPreferenceMutationResponseWithErrors,
urlParams,
} from 'jest/issues/list/mock_data';
import createFlash, { FLASH_TYPES } from '~/flash';
@@ -28,8 +30,6 @@ import IssuesListApp from '~/issues/list/components/issues_list_app.vue';
import NewIssueDropdown from '~/issues/list/components/new_issue_dropdown.vue';
import {
CREATED_DESC,
- DUE_DATE_OVERDUE,
- PARAM_DUE_DATE,
RELATIVE_POSITION,
RELATIVE_POSITION_ASC,
TOKEN_TYPE_ASSIGNEE,
@@ -43,16 +43,15 @@ import {
urlSortParams,
} from '~/issues/list/constants';
import eventHub from '~/issues/list/eventhub';
-import { getSortOptions } from '~/issues/list/utils';
+import setSortPreferenceMutation from '~/issues/list/queries/set_sort_preference.mutation.graphql';
+import { getSortKey, getSortOptions } from '~/issues/list/utils';
import axios from '~/lib/utils/axios_utils';
import { scrollUp } from '~/lib/utils/scroll_utils';
import { joinPaths } from '~/lib/utils/url_utility';
jest.mock('@sentry/browser');
jest.mock('~/flash');
-jest.mock('~/lib/utils/scroll_utils', () => ({
- scrollUp: jest.fn().mockName('scrollUpMock'),
-}));
+jest.mock('~/lib/utils/scroll_utils', () => ({ scrollUp: jest.fn() }));
describe('CE IssuesListApp component', () => {
let axiosMock;
@@ -61,6 +60,7 @@ describe('CE IssuesListApp component', () => {
Vue.use(VueApollo);
const defaultProvide = {
+ autocompleteAwardEmojisPath: 'autocomplete/award/emojis/path',
calendarPath: 'calendar/path',
canBulkUpdate: false,
emptyStateSvgPath: 'empty-state.svg',
@@ -72,10 +72,16 @@ describe('CE IssuesListApp component', () => {
hasIssuableHealthStatusFeature: true,
hasIssueWeightsFeature: true,
hasIterationsFeature: true,
+ hasMultipleIssueAssigneesFeature: true,
+ initialEmail: 'email@example.com',
+ initialSort: CREATED_DESC,
+ isAnonymousSearchDisabled: false,
+ isIssueRepositioningDisabled: false,
isProject: true,
isSignedIn: true,
jiraIntegrationPath: 'jira/integration/path',
newIssuePath: 'new/issue/path',
+ releasesPath: 'releases/path',
rssPath: 'rss/path',
showNewIssueLink: true,
signInPath: 'sign/in/path',
@@ -103,11 +109,13 @@ describe('CE IssuesListApp component', () => {
provide = {},
issuesQueryResponse = jest.fn().mockResolvedValue(defaultQueryResponse),
issuesCountsQueryResponse = jest.fn().mockResolvedValue(getIssuesCountsQueryResponse),
+ sortPreferenceMutationResponse = jest.fn().mockResolvedValue(setSortPreferenceMutationResponse),
mountFn = shallowMount,
} = {}) => {
const requestHandlers = [
[getIssuesQuery, issuesQueryResponse],
[getIssuesCountsQuery, issuesCountsQueryResponse],
+ [setSortPreferenceMutation, sortPreferenceMutationResponse],
];
const apolloProvider = createMockApollo(requestHandlers);
@@ -131,9 +139,10 @@ describe('CE IssuesListApp component', () => {
});
describe('IssuableList', () => {
- beforeEach(() => {
+ beforeEach(async () => {
wrapper = mountComponent();
jest.runOnlyPendingTimers();
+ await waitForPromises();
});
it('renders', () => {
@@ -167,8 +176,9 @@ describe('CE IssuesListApp component', () => {
});
describe('header action buttons', () => {
- it('renders rss button', () => {
+ it('renders rss button', async () => {
wrapper = mountComponent({ mountFn: mount });
+ await waitForPromises();
expect(findGlButtonAt(0).props('icon')).toBe('rss');
expect(findGlButtonAt(0).attributes()).toMatchObject({
@@ -177,8 +187,9 @@ describe('CE IssuesListApp component', () => {
});
});
- it('renders calendar button', () => {
+ it('renders calendar button', async () => {
wrapper = mountComponent({ mountFn: mount });
+ await waitForPromises();
expect(findGlButtonAt(1).props('icon')).toBe('calendar');
expect(findGlButtonAt(1).attributes()).toMatchObject({
@@ -189,19 +200,21 @@ describe('CE IssuesListApp component', () => {
describe('csv import/export component', () => {
describe('when user is signed in', () => {
- const search = '?search=refactor&sort=created_date&state=opened';
+ beforeEach(async () => {
+ setWindowLocation('?search=refactor&state=opened');
- beforeEach(() => {
- setWindowLocation(search);
-
- wrapper = mountComponent({ provide: { isSignedIn: true }, mountFn: mount });
+ wrapper = mountComponent({
+ provide: { initialSortBy: CREATED_DESC, isSignedIn: true },
+ mountFn: mount,
+ });
jest.runOnlyPendingTimers();
+ await waitForPromises();
});
it('renders', () => {
expect(findCsvImportExportButtons().props()).toMatchObject({
- exportCsvPath: `${defaultProvide.exportCsvPath}${search}`,
+ exportCsvPath: `${defaultProvide.exportCsvPath}?search=refactor&sort=created_date&state=opened`,
issuableCount: 1,
});
});
@@ -281,16 +294,6 @@ describe('CE IssuesListApp component', () => {
});
describe('initial url params', () => {
- describe('due_date', () => {
- it('is set from the url params', () => {
- setWindowLocation(`?${PARAM_DUE_DATE}=${DUE_DATE_OVERDUE}`);
-
- wrapper = mountComponent();
-
- expect(findIssuableList().props('urlParams')).toMatchObject({ due_date: DUE_DATE_OVERDUE });
- });
- });
-
describe('search', () => {
it('is set from the url params', () => {
setWindowLocation(locationSearch);
@@ -302,31 +305,57 @@ describe('CE IssuesListApp component', () => {
});
describe('sort', () => {
- it.each(Object.keys(urlSortParams))('is set as %s from the url params', (sortKey) => {
- setWindowLocation(`?sort=${urlSortParams[sortKey]}`);
+ describe('when initial sort value uses old enum values', () => {
+ const oldEnumSortValues = Object.values(urlSortParams);
- wrapper = mountComponent();
+ it.each(oldEnumSortValues)('initial sort is set with value %s', (sort) => {
+ wrapper = mountComponent({ provide: { initialSort: sort } });
- expect(findIssuableList().props()).toMatchObject({
- initialSortBy: sortKey,
- urlParams: {
- sort: urlSortParams[sortKey],
- },
+ expect(findIssuableList().props()).toMatchObject({
+ initialSortBy: getSortKey(sort),
+ urlParams: { sort },
+ });
+ });
+ });
+
+ describe('when initial sort value uses new GraphQL enum values', () => {
+ const graphQLEnumSortValues = Object.keys(urlSortParams);
+
+ 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] },
+ });
});
});
- describe('when issue repositioning is disabled and the sort is manual', () => {
+ describe('when initial sort value is invalid', () => {
+ it.each(['', 'asdf', null, undefined])(
+ 'initial sort is set to value CREATED_DESC',
+ (sort) => {
+ wrapper = mountComponent({ provide: { initialSort: sort } });
+
+ expect(findIssuableList().props()).toMatchObject({
+ initialSortBy: CREATED_DESC,
+ urlParams: { sort: urlSortParams[CREATED_DESC] },
+ });
+ },
+ );
+ });
+
+ describe('when sort is manual and issue repositioning is disabled', () => {
beforeEach(() => {
- setWindowLocation(`?sort=${RELATIVE_POSITION}`);
- wrapper = mountComponent({ provide: { isIssueRepositioningDisabled: true } });
+ wrapper = mountComponent({
+ provide: { initialSort: RELATIVE_POSITION, isIssueRepositioningDisabled: true },
+ });
});
it('changes the sort to the default of created descending', () => {
expect(findIssuableList().props()).toMatchObject({
initialSortBy: CREATED_DESC,
- urlParams: {
- sort: urlSortParams[CREATED_DESC],
- },
+ urlParams: { sort: urlSortParams[CREATED_DESC] },
});
});
@@ -585,16 +614,17 @@ 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(() => {
+ beforeEach(async () => {
wrapper = mountComponent({
[mountOption]: jest.fn().mockRejectedValue(new Error('ERROR')),
});
jest.runOnlyPendingTimers();
+ await waitForPromises();
});
it('shows an error message', () => {
expect(findIssuableList().props('error')).toBe(message);
- expect(Sentry.captureException).toHaveBeenCalledWith(new Error('Network error: ERROR'));
+ expect(Sentry.captureException).toHaveBeenCalledWith(new Error('ERROR'));
});
});
@@ -687,12 +717,13 @@ describe('CE IssuesListApp component', () => {
`(
'when moving issue $description',
({ issueToMove, oldIndex, newIndex, moveBeforeId, moveAfterId }) => {
- beforeEach(() => {
+ beforeEach(async () => {
wrapper = mountComponent({
provide: { isProject },
issuesQueryResponse: jest.fn().mockResolvedValue(response(isProject)),
});
jest.runOnlyPendingTimers();
+ await waitForPromises();
});
it('makes API call to reorder the issue', async () => {
@@ -705,7 +736,6 @@ describe('CE IssuesListApp component', () => {
data: JSON.stringify({
move_before_id: getIdFromGraphQLId(moveBeforeId),
move_after_id: getIdFromGraphQLId(moveAfterId),
- group_full_path: isProject ? undefined : defaultProvide.fullPath,
}),
});
});
@@ -715,11 +745,12 @@ describe('CE IssuesListApp component', () => {
});
describe('when unsuccessful', () => {
- beforeEach(() => {
+ beforeEach(async () => {
wrapper = mountComponent({
issuesQueryResponse: jest.fn().mockResolvedValue(response()),
});
jest.runOnlyPendingTimers();
+ await waitForPromises();
});
it('displays an error message', async () => {
@@ -758,8 +789,9 @@ describe('CE IssuesListApp component', () => {
const initialSort = CREATED_DESC;
beforeEach(() => {
- setWindowLocation(`?sort=${initialSort}`);
- wrapper = mountComponent({ provide: { isIssueRepositioningDisabled: true } });
+ wrapper = mountComponent({
+ provide: { initialSort, isIssueRepositioningDisabled: true },
+ });
findIssuableList().vm.$emit('sort', RELATIVE_POSITION_ASC);
});
@@ -777,6 +809,43 @@ describe('CE IssuesListApp component', () => {
});
});
});
+
+ describe('when user is signed in', () => {
+ it('calls mutation to save sort preference', () => {
+ const mutationMock = jest.fn().mockResolvedValue(setSortPreferenceMutationResponse);
+ wrapper = mountComponent({ sortPreferenceMutationResponse: mutationMock });
+
+ findIssuableList().vm.$emit('sort', CREATED_DESC);
+
+ expect(mutationMock).toHaveBeenCalledWith({ input: { issuesSort: CREATED_DESC } });
+ });
+
+ it('captures error when mutation response has errors', async () => {
+ const mutationMock = jest
+ .fn()
+ .mockResolvedValue(setSortPreferenceMutationResponseWithErrors);
+ wrapper = mountComponent({ sortPreferenceMutationResponse: mutationMock });
+
+ findIssuableList().vm.$emit('sort', CREATED_DESC);
+ await waitForPromises();
+
+ expect(Sentry.captureException).toHaveBeenCalledWith(new Error('oh no!'));
+ });
+ });
+
+ describe('when user is signed out', () => {
+ it('does not call mutation to save sort preference', () => {
+ const mutationMock = jest.fn().mockResolvedValue(setSortPreferenceMutationResponse);
+ wrapper = mountComponent({
+ provide: { isSignedIn: false },
+ sortPreferenceMutationResponse: mutationMock,
+ });
+
+ findIssuableList().vm.$emit('sort', CREATED_DESC);
+
+ expect(mutationMock).not.toHaveBeenCalled();
+ });
+ });
});
describe('when "update-legacy-bulk-edit" event is emitted by IssuableList', () => {