Welcome to mirror list, hosted at ThFree Co, Russian Federation.

gitlab.com/gitlab-org/gitlab-foss.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/issues/dashboard')
-rw-r--r--spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js173
-rw-r--r--spec/frontend/issues/dashboard/utils_spec.js88
2 files changed, 204 insertions, 57 deletions
diff --git a/spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js b/spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js
index 3f40772f7fc..841cea28ffc 100644
--- a/spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js
+++ b/spec/frontend/issues/dashboard/components/issues_dashboard_app_spec.js
@@ -27,6 +27,9 @@ import { scrollUp } from '~/lib/utils/scroll_utils';
import {
TOKEN_TYPE_ASSIGNEE,
TOKEN_TYPE_AUTHOR,
+ TOKEN_TYPE_LABEL,
+ TOKEN_TYPE_MILESTONE,
+ TOKEN_TYPE_MY_REACTION,
} from '~/vue_shared/components/filtered_search_bar/constants';
import IssuableList from '~/vue_shared/issuable/list/components/issuable_list_root.vue';
import { IssuableStates } from '~/vue_shared/issuable/list/constants';
@@ -42,8 +45,12 @@ describe('IssuesDashboardApp component', () => {
Vue.use(VueApollo);
const defaultProvide = {
+ autocompleteAwardEmojisPath: 'autocomplete/award/emojis/path',
calendarPath: 'calendar/path',
- emptyStateSvgPath: 'empty-state.svg',
+ dashboardLabelsPath: 'dashboard/labels/path',
+ dashboardMilestonesPath: 'dashboard/milestones/path',
+ emptyStateWithFilterSvgPath: 'empty/state/with/filter/svg/path.svg',
+ emptyStateWithoutFilterSvgPath: 'empty/state/with/filter/svg/path.svg',
hasBlockedIssuesFeature: true,
hasIssuableHealthStatusFeature: true,
hasIssueWeightsFeature: true,
@@ -97,74 +104,122 @@ describe('IssuesDashboardApp component', () => {
axiosMock.reset();
});
- it('renders IssuableList component', async () => {
- mountComponent();
- jest.runOnlyPendingTimers();
- await waitForPromises();
-
- expect(findIssuableList().props()).toMatchObject({
- currentTab: IssuableStates.Opened,
- hasNextPage: true,
- hasPreviousPage: false,
- hasScopedLabelsFeature: defaultProvide.hasScopedLabelsFeature,
- initialSortBy: CREATED_DESC,
- issuables: issuesQueryResponse.data.issues.nodes,
- issuablesLoading: false,
- namespace: 'dashboard',
- recentSearchesStorageKey: 'issues',
- searchInputPlaceholder: IssuesDashboardApp.i18n.searchInputPlaceholder,
- showPaginationControls: true,
- sortOptions: getSortOptions({
- hasBlockedIssuesFeature: defaultProvide.hasBlockedIssuesFeature,
- hasIssuableHealthStatusFeature: defaultProvide.hasIssuableHealthStatusFeature,
- hasIssueWeightsFeature: defaultProvide.hasIssueWeightsFeature,
- }),
- tabs: IssuesDashboardApp.IssuableListTabs,
- urlParams: {
- sort: urlSortParams[CREATED_DESC],
- state: IssuableStates.Opened,
- },
- useKeysetPagination: true,
+ describe('UI components', () => {
+ beforeEach(() => {
+ setWindowLocation(locationSearch);
+ mountComponent();
+ jest.runOnlyPendingTimers();
+ return waitForPromises();
});
- });
- it('renders RSS button link', () => {
- mountComponent();
+ it('renders IssuableList component', () => {
+ expect(findIssuableList().props()).toMatchObject({
+ currentTab: IssuableStates.Opened,
+ hasNextPage: true,
+ hasPreviousPage: false,
+ hasScopedLabelsFeature: defaultProvide.hasScopedLabelsFeature,
+ initialSortBy: CREATED_DESC,
+ issuables: issuesQueryResponse.data.issues.nodes,
+ issuablesLoading: false,
+ namespace: 'dashboard',
+ recentSearchesStorageKey: 'issues',
+ searchInputPlaceholder: IssuesDashboardApp.i18n.searchInputPlaceholder,
+ showPaginationControls: true,
+ sortOptions: getSortOptions({
+ hasBlockedIssuesFeature: defaultProvide.hasBlockedIssuesFeature,
+ hasIssuableHealthStatusFeature: defaultProvide.hasIssuableHealthStatusFeature,
+ hasIssueWeightsFeature: defaultProvide.hasIssueWeightsFeature,
+ }),
+ tabs: IssuesDashboardApp.IssuableListTabs,
+ urlParams: {
+ sort: urlSortParams[CREATED_DESC],
+ state: IssuableStates.Opened,
+ },
+ useKeysetPagination: true,
+ });
+ });
- expect(findRssButton().attributes('href')).toBe(defaultProvide.rssPath);
- expect(findRssButton().props('icon')).toBe('rss');
- });
+ it('renders RSS button link', () => {
+ expect(findRssButton().attributes('href')).toBe(defaultProvide.rssPath);
+ });
- it('renders calendar button link', () => {
- mountComponent();
+ it('renders calendar button link', () => {
+ expect(findCalendarButton().attributes('href')).toBe(defaultProvide.calendarPath);
+ });
+
+ it('renders issue time information', () => {
+ expect(findIssueCardTimeInfo().exists()).toBe(true);
+ });
- expect(findCalendarButton().attributes('href')).toBe(defaultProvide.calendarPath);
- expect(findCalendarButton().props('icon')).toBe('calendar');
+ it('renders issue statistics', () => {
+ expect(findIssueCardStatistics().exists()).toBe(true);
+ });
});
- it('renders issue time information', async () => {
- mountComponent();
- jest.runOnlyPendingTimers();
- await waitForPromises();
+ describe('fetching issues', () => {
+ describe('with a search query', () => {
+ describe('when there are issues returned', () => {
+ beforeEach(() => {
+ setWindowLocation(locationSearch);
+ mountComponent();
+ jest.runOnlyPendingTimers();
+ return waitForPromises();
+ });
- expect(findIssueCardTimeInfo().exists()).toBe(true);
- });
+ it('renders the issues', () => {
+ expect(findIssuableList().props('issuables')).toEqual(
+ defaultQueryResponse.data.issues.nodes,
+ );
+ });
- it('renders issue statistics', async () => {
- mountComponent();
- jest.runOnlyPendingTimers();
- await waitForPromises();
+ it('does not render empty state', () => {
+ expect(findEmptyState().exists()).toBe(false);
+ });
+ });
- expect(findIssueCardStatistics().exists()).toBe(true);
- });
+ describe('when there are no issues returned', () => {
+ beforeEach(() => {
+ setWindowLocation(locationSearch);
+ mountComponent({
+ issuesQueryHandler: jest.fn().mockResolvedValue(emptyIssuesQueryResponse),
+ });
+ return waitForPromises();
+ });
+
+ it('renders no issues', () => {
+ expect(findIssuableList().props('issuables')).toEqual([]);
+ });
+
+ it('renders empty state', () => {
+ expect(findEmptyState().props()).toMatchObject({
+ description: IssuesDashboardApp.i18n.emptyStateWithFilterDescription,
+ svgPath: defaultProvide.emptyStateWithFilterSvgPath,
+ title: IssuesDashboardApp.i18n.emptyStateWithFilterTitle,
+ });
+ });
+ });
+ });
+
+ describe('with no search query', () => {
+ let issuesQueryHandler;
+
+ beforeEach(() => {
+ issuesQueryHandler = jest.fn().mockResolvedValue(defaultQueryResponse);
+ mountComponent({ issuesQueryHandler });
+ return waitForPromises();
+ });
- it('renders empty state', async () => {
- mountComponent({ issuesQueryHandler: jest.fn().mockResolvedValue(emptyIssuesQueryResponse) });
- await waitForPromises();
+ it('does not call issues query', () => {
+ expect(issuesQueryHandler).not.toHaveBeenCalled();
+ });
- expect(findEmptyState().props()).toMatchObject({
- svgPath: defaultProvide.emptyStateSvgPath,
- title: IssuesDashboardApp.i18n.emptyStateTitle,
+ it('renders empty state', () => {
+ expect(findEmptyState().props()).toMatchObject({
+ description: null,
+ svgPath: defaultProvide.emptyStateWithoutFilterSvgPath,
+ title: IssuesDashboardApp.i18n.emptyStateWithoutFilterTitle,
+ });
+ });
});
});
@@ -233,6 +288,7 @@ describe('IssuesDashboardApp component', () => {
describe('when there is an error fetching issues', () => {
beforeEach(() => {
+ setWindowLocation(locationSearch);
mountComponent({ issuesQueryHandler: jest.fn().mockRejectedValue(new Error('ERROR')) });
jest.runOnlyPendingTimers();
return waitForPromises();
@@ -281,6 +337,9 @@ describe('IssuesDashboardApp component', () => {
expect(findIssuableList().props('searchTokens')).toMatchObject([
{ type: TOKEN_TYPE_ASSIGNEE, preloadedUsers },
{ type: TOKEN_TYPE_AUTHOR, preloadedUsers },
+ { type: TOKEN_TYPE_LABEL },
+ { type: TOKEN_TYPE_MILESTONE },
+ { type: TOKEN_TYPE_MY_REACTION },
]);
});
});
diff --git a/spec/frontend/issues/dashboard/utils_spec.js b/spec/frontend/issues/dashboard/utils_spec.js
new file mode 100644
index 00000000000..08d00eee3e3
--- /dev/null
+++ b/spec/frontend/issues/dashboard/utils_spec.js
@@ -0,0 +1,88 @@
+import AxiosMockAdapter from 'axios-mock-adapter';
+import fuzzaldrinPlus from 'fuzzaldrin-plus';
+import { AutocompleteCache } from '~/issues/dashboard/utils';
+import { MAX_LIST_SIZE } from '~/issues/list/constants';
+import axios from '~/lib/utils/axios_utils';
+
+describe('AutocompleteCache', () => {
+ let autocompleteCache;
+ let axiosMock;
+ const cacheName = 'name';
+ const searchProperty = 'property';
+ const url = 'url';
+
+ const data = [
+ { [searchProperty]: 'one' },
+ { [searchProperty]: 'two' },
+ { [searchProperty]: 'three' },
+ { [searchProperty]: 'four' },
+ { [searchProperty]: 'five' },
+ { [searchProperty]: 'six' },
+ { [searchProperty]: 'seven' },
+ { [searchProperty]: 'eight' },
+ { [searchProperty]: 'nine' },
+ { [searchProperty]: 'ten' },
+ { [searchProperty]: 'eleven' },
+ { [searchProperty]: 'twelve' },
+ { [searchProperty]: 'thirteen' },
+ { [searchProperty]: 'fourteen' },
+ { [searchProperty]: 'fifteen' },
+ ];
+
+ beforeEach(() => {
+ autocompleteCache = new AutocompleteCache();
+ axiosMock = new AxiosMockAdapter(axios);
+ });
+
+ afterEach(() => {
+ axiosMock.reset();
+ });
+
+ describe('when there is no cached data', () => {
+ let response;
+
+ beforeEach(async () => {
+ axiosMock.onGet(url).replyOnce(200, data);
+ response = await autocompleteCache.fetch({ url, cacheName, searchProperty });
+ });
+
+ it('fetches items via the API', () => {
+ expect(axiosMock.history.get[0].url).toBe(url);
+ });
+
+ it('returns a maximum of 10 items', () => {
+ expect(response).toHaveLength(MAX_LIST_SIZE);
+ });
+ });
+
+ describe('when there is cached data', () => {
+ let response;
+
+ beforeEach(async () => {
+ axiosMock.onGet(url).replyOnce(200, data);
+ jest.spyOn(fuzzaldrinPlus, 'filter');
+ // Populate cache
+ await autocompleteCache.fetch({ url, cacheName, searchProperty });
+ // Execute filtering on cache data
+ response = await autocompleteCache.fetch({ url, cacheName, searchProperty, search: 'een' });
+ });
+
+ it('returns filtered items based on search characters', () => {
+ expect(response).toEqual([
+ { [searchProperty]: 'fifteen' },
+ { [searchProperty]: 'thirteen' },
+ { [searchProperty]: 'fourteen' },
+ { [searchProperty]: 'eleven' },
+ { [searchProperty]: 'seven' },
+ ]);
+ });
+
+ it('filters using fuzzaldrinPlus', () => {
+ expect(fuzzaldrinPlus.filter).toHaveBeenCalled();
+ });
+
+ it('does not call the API', () => {
+ expect(axiosMock.history.get[1]).toBeUndefined();
+ });
+ });
+});