Commit 581f7a4b authored by Miguel Rincon's avatar Miguel Rincon

Merge branch '329074-use-smart-query-for-jira-issues-list' into 'master'

Use smart query for jira issues list

See merge request gitlab-org/gitlab!63762
parents cce7f49a fcf0adaf
...@@ -10,6 +10,7 @@ import { ...@@ -10,6 +10,7 @@ import {
AvailableSortOptions, AvailableSortOptions,
DEFAULT_PAGE_SIZE, DEFAULT_PAGE_SIZE,
} from '~/issuable_list/constants'; } from '~/issuable_list/constants';
import { ISSUES_LIST_FETCH_ERROR } from '../constants';
import getJiraIssuesQuery from '../graphql/queries/get_jira_issues.query.graphql'; import getJiraIssuesQuery from '../graphql/queries/get_jira_issues.query.graphql';
import JiraIssuesListEmptyState from './jira_issues_list_empty_state.vue'; import JiraIssuesListEmptyState from './jira_issues_list_empty_state.vue';
...@@ -48,8 +49,6 @@ export default { ...@@ -48,8 +49,6 @@ export default {
return { return {
jiraLogo, jiraLogo,
issues: [], issues: [],
issuesListLoading: false,
issuesListLoadFailed: false,
totalIssues: 0, totalIssues: 0,
currentState: this.initialState, currentState: this.initialState,
filterParams: this.initialFilterParams, filterParams: this.initialFilterParams,
...@@ -63,67 +62,61 @@ export default { ...@@ -63,67 +62,61 @@ export default {
}; };
}, },
computed: { computed: {
issuesListLoading() {
return this.$apollo.queries.jiraIssues.loading;
},
showPaginationControls() { showPaginationControls() {
return Boolean( return Boolean(!this.issuesListLoading && this.issues.length && this.totalIssues > 1);
!this.issuesListLoading &&
!this.issuesListLoadFailed &&
this.issues.length &&
this.totalIssues > 1,
);
}, },
hasFiltersApplied() { hasFiltersApplied() {
return Boolean(this.filterParams.search || this.filterParams.labels); return Boolean(this.filterParams.search || this.filterParams.labels);
}, },
urlParams() { urlParams() {
return { return {
state: this.currentState,
page: this.currentPage,
sort: this.sortedBy,
'labels[]': this.filterParams.labels, 'labels[]': this.filterParams.labels,
page: this.currentPage,
search: this.filterParams.search, search: this.filterParams.search,
sort: this.sortedBy,
state: this.currentState,
}; };
}, },
}, },
mounted() { apollo: {
this.fetchIssues(); jiraIssues: {
}, query: getJiraIssuesQuery,
methods: { variables() {
async fetchIssues() { return {
this.issuesListLoading = true; issuesFetchPath: this.issuesFetchPath,
this.issuesListLoadFailed = false; labels: this.filterParams.labels,
page: this.currentPage,
try { search: this.filterParams.search,
const { data } = await this.$apollo.query({ sort: this.sortedBy,
query: getJiraIssuesQuery, state: this.currentState,
variables: { };
issuesFetchPath: this.issuesFetchPath, },
search: this.filterParams.search, result({ data, error }) {
state: this.currentState, // let error() callback handle errors
sort: this.sortedBy, if (error) {
labels: this.filterParams.labels, return;
page: this.currentPage, }
},
});
const { pageInfo, nodes, errors } = data?.jiraIssues ?? {}; const { pageInfo, nodes, errors } = data?.jiraIssues ?? {};
if (errors?.length > 0) throw new Error(errors[0]); if (errors?.length > 0) {
this.onJiraIssuesQueryError(new Error(errors[0]));
return;
}
this.issues = nodes;
this.currentPage = pageInfo.page; this.currentPage = pageInfo.page;
this.totalIssues = pageInfo.total; this.totalIssues = pageInfo.total;
this.issues = nodes; this.issuesCount[this.currentState] = nodes.length;
this.issuesCount[this.currentState] = this.issues.length; },
} catch (error) { error() {
this.issuesListLoadFailed = true; this.onJiraIssuesQueryError(new Error(ISSUES_LIST_FETCH_ERROR));
},
createFlash({
message: error.message,
captureError: true,
error,
});
}
this.issuesListLoading = false;
}, },
},
methods: {
getFilteredSearchValue() { getFilteredSearchValue() {
return [ return [
{ {
...@@ -134,11 +127,23 @@ export default { ...@@ -134,11 +127,23 @@ export default {
}, },
]; ];
}, },
fetchIssuesBy(propsName, propValue) { onJiraIssuesQueryError(error) {
this[propsName] = propValue; createFlash({
this.fetchIssues(); message: error.message,
captureError: true,
error,
});
},
onIssuableListClickTab(selectedIssueState) {
this.currentState = selectedIssueState;
},
onIssuableListPageChange(selectedPage) {
this.currentPage = selectedPage;
},
onIssuableListSort(selectedSort) {
this.sortedBy = selectedSort;
}, },
handleFilterIssues(filters = []) { onIssuableListFilter(filters = []) {
const filterParams = {}; const filterParams = {};
const plainText = []; const plainText = [];
...@@ -153,7 +158,6 @@ export default { ...@@ -153,7 +158,6 @@ export default {
} }
this.filterParams = filterParams; this.filterParams = filterParams;
this.fetchIssues();
}, },
}, },
}; };
...@@ -180,10 +184,10 @@ export default { ...@@ -180,10 +184,10 @@ export default {
:url-params="urlParams" :url-params="urlParams"
label-filter-param="labels" label-filter-param="labels"
recent-searches-storage-key="jira_issues" recent-searches-storage-key="jira_issues"
@click-tab="fetchIssuesBy('currentState', $event)" @click-tab="onIssuableListClickTab"
@page-change="fetchIssuesBy('currentPage', $event)" @page-change="onIssuableListPageChange"
@sort="fetchIssuesBy('sortedBy', $event)" @sort="onIssuableListSort"
@filter="handleFilterIssues" @filter="onIssuableListFilter"
> >
<template #nav-actions> <template #nav-actions>
<gl-button :href="issueCreateUrl" target="_blank" class="gl-my-5"> <gl-button :href="issueCreateUrl" target="_blank" class="gl-my-5">
......
import { __ } from '~/locale';
export const ISSUES_LIST_FETCH_ERROR = __('An error occurred while loading issues');
import { DEFAULT_PAGE_SIZE } from '~/issuable_list/constants'; import { DEFAULT_PAGE_SIZE } from '~/issuable_list/constants';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import { __ } from '~/locale'; import { ISSUES_LIST_FETCH_ERROR } from '../../constants';
const transformJiraIssueAssignees = (jiraIssue) => { const transformJiraIssueAssignees = (jiraIssue) => {
return jiraIssue.assignees.map((assignee) => ({ return jiraIssue.assignees.map((assignee) => ({
...@@ -78,7 +78,7 @@ export default function jiraIssuesResolver( ...@@ -78,7 +78,7 @@ export default function jiraIssuesResolver(
.catch((error) => { .catch((error) => {
return { return {
__typename: 'JiraIssues', __typename: 'JiraIssues',
errors: error?.response?.data?.errors || [__('An error occurred while loading issues')], errors: error?.response?.data?.errors || [ISSUES_LIST_FETCH_ERROR],
pageInfo: transformJiraIssuePageInfo(), pageInfo: transformJiraIssuePageInfo(),
nodes: [], nodes: [],
}; };
......
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`JiraIssuesListRoot renders issuable-list component with correct props 1`] = ` exports[`JiraIssuesListRoot when request succeeds renders issuable-list component with correct props 1`] = `
Object { Object {
"currentPage": 1, "currentPage": 1,
"currentTab": "opened", "currentTab": "opened",
...@@ -12,14 +12,94 @@ Object { ...@@ -12,14 +12,94 @@ Object {
Object { Object {
"type": "filtered-search-term", "type": "filtered-search-term",
"value": Object { "value": Object {
"data": "foo", "data": "",
}, },
}, },
], ],
"initialSortBy": "created_desc", "initialSortBy": "created_desc",
"isManualOrdering": false, "isManualOrdering": false,
"issuableSymbol": "#", "issuableSymbol": "#",
"issuables": Array [], "issuables": Array [
Object {
"assignees": Array [
Object {
"avatarUrl": null,
"name": "Kushal Pandya",
"webUrl": "https://gitlab-jira.atlassian.net/people/1920938475",
},
],
"author": Object {
"avatarUrl": null,
"name": "jhope",
"webUrl": "https://gitlab-jira.atlassian.net/people/5e32f803e127810e82875bc1",
},
"closedAt": null,
"createdAt": "2020-03-19T14:31:51.281Z",
"externalTracker": "jira",
"gitlabWebUrl": "",
"id": 31596,
"labels": Array [
Object {
"color": "#0052CC",
"name": "backend",
"textColor": "#FFFFFF",
"title": "backend",
},
],
"projectId": 1,
"references": Object {
"relative": "IG-31596",
},
"status": "Selected for Development",
"title": "Eius fuga voluptates.",
"updatedAt": "2020-10-20T07:01:45.865Z",
"webUrl": "https://gitlab-jira.atlassian.net/browse/IG-31596",
},
Object {
"assignees": Array [],
"author": Object {
"avatarUrl": null,
"name": "Gabe Weaver",
"webUrl": "https://gitlab-jira.atlassian.net/people/5e320a31fe03e20c9d1dccde",
},
"closedAt": null,
"createdAt": "2020-03-19T14:31:50.677Z",
"externalTracker": "jira",
"gitlabWebUrl": "",
"id": 31595,
"labels": Array [],
"projectId": 1,
"references": Object {
"relative": "IG-31595",
},
"status": "Backlog",
"title": "Hic sit sint ducimus ea et sint.",
"updatedAt": "2020-03-19T14:31:50.677Z",
"webUrl": "https://gitlab-jira.atlassian.net/browse/IG-31595",
},
Object {
"assignees": Array [],
"author": Object {
"avatarUrl": null,
"name": "Gabe Weaver",
"webUrl": "https://gitlab-jira.atlassian.net/people/5e320a31fe03e20c9d1dccde",
},
"closedAt": null,
"createdAt": "2020-03-19T14:31:50.012Z",
"externalTracker": "jira",
"gitlabWebUrl": "",
"id": 31594,
"labels": Array [],
"projectId": 1,
"references": Object {
"relative": "IG-31594",
},
"status": "Backlog",
"title": "Alias ut modi est labore.",
"updatedAt": "2020-03-19T14:31:50.012Z",
"webUrl": "https://gitlab-jira.atlassian.net/browse/IG-31594",
},
],
"issuablesLoading": false, "issuablesLoading": false,
"labelFilterParam": "labels", "labelFilterParam": "labels",
"namespace": "gitlab-org/gitlab-test", "namespace": "gitlab-org/gitlab-test",
...@@ -29,7 +109,7 @@ Object { ...@@ -29,7 +109,7 @@ Object {
"searchInputPlaceholder": "Search Jira issues", "searchInputPlaceholder": "Search Jira issues",
"searchTokens": Array [], "searchTokens": Array [],
"showBulkEditSidebar": false, "showBulkEditSidebar": false,
"showPaginationControls": false, "showPaginationControls": true,
"sortOptions": Array [ "sortOptions": Array [
Object { Object {
"id": 1, "id": 1,
...@@ -69,11 +149,11 @@ Object { ...@@ -69,11 +149,11 @@ Object {
"titleTooltip": "Show all issues.", "titleTooltip": "Show all issues.",
}, },
], ],
"totalItems": 0, "totalItems": 3,
"urlParams": Object { "urlParams": Object {
"labels[]": undefined, "labels[]": undefined,
"page": 1, "page": 1,
"search": "foo", "search": undefined,
"sort": "created_desc", "sort": "created_desc",
"state": "opened", "state": "opened",
}, },
......
...@@ -3,6 +3,7 @@ import MockAdapter from 'axios-mock-adapter'; ...@@ -3,6 +3,7 @@ import MockAdapter from 'axios-mock-adapter';
import VueApollo from 'vue-apollo'; import VueApollo from 'vue-apollo';
import JiraIssuesListRoot from 'ee/integrations/jira/issues_list/components/jira_issues_list_root.vue'; import JiraIssuesListRoot from 'ee/integrations/jira/issues_list/components/jira_issues_list_root.vue';
import { ISSUES_LIST_FETCH_ERROR } from 'ee/integrations/jira/issues_list/constants';
import jiraIssues from 'ee/integrations/jira/issues_list/graphql/resolvers/jira_issues'; import jiraIssues from 'ee/integrations/jira/issues_list/graphql/resolvers/jira_issues';
import createMockApollo from 'helpers/mock_apollo_helper'; import createMockApollo from 'helpers/mock_apollo_helper';
...@@ -11,7 +12,6 @@ import waitForPromises from 'helpers/wait_for_promises'; ...@@ -11,7 +12,6 @@ import waitForPromises from 'helpers/wait_for_promises';
import createFlash from '~/flash'; import createFlash from '~/flash';
import IssuableList from '~/issuable_list/components/issuable_list_root.vue'; import IssuableList from '~/issuable_list/components/issuable_list_root.vue';
import axios from '~/lib/utils/axios_utils'; import axios from '~/lib/utils/axios_utils';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import httpStatus from '~/lib/utils/http_status'; import httpStatus from '~/lib/utils/http_status';
import { mockProvide, mockJiraIssues } from '../mock_data'; import { mockProvide, mockJiraIssues } from '../mock_data';
...@@ -27,7 +27,7 @@ jest.mock('~/issuable_list/constants', () => ({ ...@@ -27,7 +27,7 @@ jest.mock('~/issuable_list/constants', () => ({
const resolvedValue = { const resolvedValue = {
headers: { headers: {
'x-page': 1, 'x-page': 1,
'x-total': 3, 'x-total': mockJiraIssues.length,
}, },
data: mockJiraIssues, data: mockJiraIssues,
}; };
...@@ -40,25 +40,29 @@ const resolvers = { ...@@ -40,25 +40,29 @@ const resolvers = {
}, },
}; };
function createMockApolloProvider() { function createMockApolloProvider(mockResolvers = resolvers) {
localVue.use(VueApollo); localVue.use(VueApollo);
return createMockApollo([], resolvers); return createMockApollo([], mockResolvers);
} }
describe('JiraIssuesListRoot', () => { describe('JiraIssuesListRoot', () => {
let wrapper; let wrapper;
let mock; let mock;
const findIssuableList = () => wrapper.find(IssuableList); const findIssuableList = () => wrapper.findComponent(IssuableList);
const createComponent = ({ provide = mockProvide, initialFilterParams = {} } = {}) => { const createComponent = ({
apolloProvider = createMockApolloProvider(),
provide = mockProvide,
initialFilterParams = {},
} = {}) => {
wrapper = shallowMount(JiraIssuesListRoot, { wrapper = shallowMount(JiraIssuesListRoot, {
propsData: { propsData: {
initialFilterParams, initialFilterParams,
}, },
provide, provide,
localVue, localVue,
apolloProvider: createMockApolloProvider(), apolloProvider,
}); });
}; };
...@@ -71,76 +75,181 @@ describe('JiraIssuesListRoot', () => { ...@@ -71,76 +75,181 @@ describe('JiraIssuesListRoot', () => {
mock.restore(); mock.restore();
}); });
describe('on mount', () => { describe('while loading', () => {
describe('while loading', () => { it('sets issuesListLoading to `true`', async () => {
it('sets issuesListLoading to `true`', async () => { jest.spyOn(axios, 'get').mockResolvedValue(new Promise(() => {}));
jest.spyOn(axios, 'get').mockResolvedValue(new Promise(() => {}));
createComponent(); createComponent();
await wrapper.vm.$nextTick();
await wrapper.vm.$nextTick(); const issuableList = findIssuableList();
expect(issuableList.props('issuablesLoading')).toBe(true);
});
const issuableList = findIssuableList(); it('calls `axios.get` with `issuesFetchPath` and query params', async () => {
expect(issuableList.props('issuablesLoading')).toBe(true); jest.spyOn(axios, 'get');
});
it('calls `axios.get` with `issuesFetchPath` and query params', async () => { createComponent();
jest.spyOn(axios, 'get'); await waitForPromises();
createComponent();
await waitForPromises(); expect(axios.get).toHaveBeenCalledWith(
mockProvide.issuesFetchPath,
expect.objectContaining({
params: {
with_labels_details: true,
page: wrapper.vm.currentPage,
per_page: wrapper.vm.$options.defaultPageSize,
state: wrapper.vm.currentState,
sort: wrapper.vm.sortedBy,
search: wrapper.vm.filterParams.search,
},
}),
);
});
});
expect(axios.get).toHaveBeenCalledWith( describe('with `initialFilterParams` prop', () => {
mockProvide.issuesFetchPath, const mockSearchTerm = 'foo';
expect.objectContaining({
params: { beforeEach(async () => {
with_labels_details: true, jest.spyOn(axios, 'get').mockResolvedValue(resolvedValue);
page: wrapper.vm.currentPage,
per_page: wrapper.vm.$options.defaultPageSize, createComponent({ initialFilterParams: { search: mockSearchTerm } });
state: wrapper.vm.currentState, await waitForPromises();
sort: wrapper.vm.sortedBy,
search: wrapper.vm.filterParams.search,
},
}),
);
});
}); });
describe('when request succeeds', () => { it('renders issuable-list component with correct props', () => {
beforeEach(async () => { const issuableList = findIssuableList();
jest.spyOn(axios, 'get').mockResolvedValue(resolvedValue);
createComponent(); expect(issuableList.props('initialFilterValue')).toEqual([
{ type: 'filtered-search-term', value: { data: mockSearchTerm } },
]);
expect(issuableList.props('urlParams').search).toBe(mockSearchTerm);
});
});
describe('when request succeeds', () => {
beforeEach(async () => {
jest.spyOn(axios, 'get').mockResolvedValue(resolvedValue);
createComponent();
await waitForPromises();
});
it('renders issuable-list component with correct props', () => {
const issuableList = findIssuableList();
expect(issuableList.exists()).toBe(true);
expect(issuableList.props()).toMatchSnapshot();
});
describe('issuable-list events', () => {
it('"click-tab" event executes GET request correctly', async () => {
const issuableList = findIssuableList();
issuableList.vm.$emit('click-tab', 'closed');
await waitForPromises(); await waitForPromises();
expect(axios.get).toHaveBeenCalledWith(mockProvide.issuesFetchPath, {
params: {
labels: undefined,
page: 1,
per_page: 2,
search: undefined,
sort: 'created_desc',
state: 'closed',
with_labels_details: true,
},
});
expect(issuableList.props('currentTab')).toBe('closed');
}); });
it('sets `currentPage` and `totalIssues` from response headers and `issues` & `issuesCount` from response body when request is successful', async () => { it('"page-change" event executes GET request correctly', async () => {
const mockPage = 2;
const issuableList = findIssuableList(); const issuableList = findIssuableList();
const issuablesProp = issuableList.props('issuables'); jest.spyOn(axios, 'get').mockResolvedValue({
...resolvedValue,
headers: { 'x-page': mockPage, 'x-total': mockJiraIssues.length },
});
issuableList.vm.$emit('page-change', mockPage);
await waitForPromises();
expect(axios.get).toHaveBeenCalledWith(mockProvide.issuesFetchPath, {
params: {
labels: undefined,
page: mockPage,
per_page: 2,
search: undefined,
sort: 'created_desc',
state: 'opened',
with_labels_details: true,
},
});
await wrapper.vm.$nextTick();
expect(issuableList.props()).toMatchObject({ expect(issuableList.props()).toMatchObject({
currentPage: resolvedValue.headers['x-page'], currentPage: mockPage,
previousPage: resolvedValue.headers['x-page'] - 1, previousPage: mockPage - 1,
nextPage: resolvedValue.headers['x-page'] + 1, nextPage: mockPage + 1,
totalItems: resolvedValue.headers['x-total'],
}); });
});
expect(issuablesProp).toMatchObject( it('"sort" event executes GET request correctly', async () => {
convertObjectPropsToCamelCase(mockJiraIssues, { deep: true }), const mockSortBy = 'updated_asc';
); const issuableList = findIssuableList();
issuableList.vm.$emit('sort', mockSortBy);
await waitForPromises();
expect(axios.get).toHaveBeenCalledWith(mockProvide.issuesFetchPath, {
params: {
labels: undefined,
page: 1,
per_page: 2,
search: undefined,
sort: 'created_desc',
state: 'opened',
with_labels_details: true,
},
});
expect(issuableList.props('initialSortBy')).toBe(mockSortBy);
}); });
it('sets issuesListLoading to `false`', () => { it('filter event sets `filterParams` value and calls fetchIssues', async () => {
const mockFilterTerm = 'foo';
const issuableList = findIssuableList(); const issuableList = findIssuableList();
expect(issuableList.props('issuablesLoading')).toBe(false);
issuableList.vm.$emit('filter', [
{
type: 'filtered-search-term',
value: {
data: mockFilterTerm,
},
},
]);
await waitForPromises();
expect(axios.get).toHaveBeenCalledWith(mockProvide.issuesFetchPath, {
params: {
labels: undefined,
page: 1,
per_page: 2,
search: mockFilterTerm,
sort: 'created_desc',
state: 'opened',
with_labels_details: true,
},
});
}); });
}); });
});
describe('error handling', () => {
describe('when request fails', () => { describe('when request fails', () => {
it.each` it.each`
APIErrors | expectedRenderedErrorMessage APIErrors | expectedRenderedErrorMessage
${['API error']} | ${'API error'} ${['API error']} | ${'API error'}
${undefined} | ${'An error occurred while loading issues'} ${undefined} | ${ISSUES_LIST_FETCH_ERROR}
`( `(
'calls `createFlash` with "$expectedRenderedErrorMessage" when API responds with "$APIErrors"', 'calls `createFlash` with "$expectedRenderedErrorMessage" when API responds with "$APIErrors"',
async ({ APIErrors, expectedRenderedErrorMessage }) => { async ({ APIErrors, expectedRenderedErrorMessage }) => {
...@@ -150,7 +259,6 @@ describe('JiraIssuesListRoot', () => { ...@@ -150,7 +259,6 @@ describe('JiraIssuesListRoot', () => {
.replyOnce(httpStatus.INTERNAL_SERVER_ERROR, { errors: APIErrors }); .replyOnce(httpStatus.INTERNAL_SERVER_ERROR, { errors: APIErrors });
createComponent(); createComponent();
await waitForPromises(); await waitForPromises();
expect(createFlash).toHaveBeenCalledWith({ expect(createFlash).toHaveBeenCalledWith({
...@@ -161,115 +269,23 @@ describe('JiraIssuesListRoot', () => { ...@@ -161,115 +269,23 @@ describe('JiraIssuesListRoot', () => {
}, },
); );
}); });
});
it('renders issuable-list component with correct props', async () => {
createComponent({ initialFilterParams: { search: 'foo' } });
await waitForPromises();
const issuableList = findIssuableList();
expect(issuableList.exists()).toBe(true);
expect(issuableList.props()).toMatchSnapshot();
});
describe('issuable-list events', () => {
beforeEach(async () => {
jest.spyOn(axios, 'get');
createComponent();
await waitForPromises();
});
it('"click-tab" event executes GET request correctly', async () => {
const issuableList = findIssuableList();
issuableList.vm.$emit('click-tab', 'closed'); describe('when GraphQL network error is encountered', () => {
await waitForPromises(); it('calls `createFlash` correctly with default error message', async () => {
createComponent({
expect(axios.get).toHaveBeenCalledWith(mockProvide.issuesFetchPath, { apolloProvider: createMockApolloProvider({
params: { Query: {
labels: undefined, jiraIssues: jest.fn().mockRejectedValue(new Error('GraphQL networkError')),
page: 1, },
per_page: 2, }),
search: undefined, });
sort: 'created_desc', await waitForPromises();
state: 'closed',
with_labels_details: true,
},
});
expect(issuableList.props('currentTab')).toBe('closed');
});
it('"page-change" event executes GET request correctly', async () => {
const mockPage = 2;
const issuableList = findIssuableList();
issuableList.vm.$emit('page-change', mockPage);
await waitForPromises();
expect(axios.get).toHaveBeenCalledWith(mockProvide.issuesFetchPath, {
params: {
labels: undefined,
page: mockPage,
per_page: 2,
search: undefined,
sort: 'created_desc',
state: 'opened',
with_labels_details: true,
},
});
expect(issuableList.props()).toMatchObject({
currentPage: mockPage,
previousPage: mockPage - 1,
nextPage: mockPage + 1,
});
});
it('"sort" event executes GET request correctly', async () => {
const mockSortBy = 'updated_asc';
const issuableList = findIssuableList();
issuableList.vm.$emit('sort', mockSortBy);
await waitForPromises();
expect(axios.get).toHaveBeenCalledWith(mockProvide.issuesFetchPath, {
params: {
labels: undefined,
page: 1,
per_page: 2,
search: undefined,
sort: 'created_desc',
state: 'opened',
with_labels_details: true,
},
});
expect(issuableList.props('initialSortBy')).toBe(mockSortBy);
});
it('filter event sets `filterParams` value and calls fetchIssues', async () => {
const mockFilterTerm = 'foo';
const issuableList = findIssuableList();
issuableList.vm.$emit('filter', [
{
type: 'filtered-search-term',
value: {
data: mockFilterTerm,
},
},
]);
await waitForPromises();
expect(axios.get).toHaveBeenCalledWith(mockProvide.issuesFetchPath, { expect(createFlash).toHaveBeenCalledWith({
params: { message: ISSUES_LIST_FETCH_ERROR,
labels: undefined, captureError: true,
page: 1, error: expect.any(Object),
per_page: 2, });
search: mockFilterTerm,
sort: 'created_desc',
state: 'opened',
with_labels_details: true,
},
}); });
}); });
}); });
...@@ -291,12 +307,11 @@ describe('JiraIssuesListRoot', () => { ...@@ -291,12 +307,11 @@ describe('JiraIssuesListRoot', () => {
issues, issues,
{ {
'x-page': 1, 'x-page': 1,
'x-total': 3, 'x-total': issues.length,
}, },
); );
createComponent(); createComponent();
await waitForPromises(); await waitForPromises();
expect(findIssuableList().props('showPaginationControls')).toBe( expect(findIssuableList().props('showPaginationControls')).toBe(
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment