Commit f1e0a004 authored by Nicolò Maria Mezzopera's avatar Nicolò Maria Mezzopera

Merge branch 'nfriend-add-graphql-releases-page-pagination' into 'master'

Step 4/4: Add pagination to GraphQL release page

See merge request gitlab-org/gitlab!41441
parents 06c6774a 82d51739
...@@ -6,14 +6,10 @@ import { ...@@ -6,14 +6,10 @@ import {
GlLink, GlLink,
GlButton, GlButton,
} from '@gitlab/ui'; } from '@gitlab/ui';
import { import { getParameterByName } from '~/lib/utils/common_utils';
getParameterByName,
historyPushState,
buildUrlWithCurrentLocation,
} from '~/lib/utils/common_utils';
import { __ } from '~/locale'; import { __ } from '~/locale';
import TablePagination from '~/vue_shared/components/pagination/table_pagination.vue';
import ReleaseBlock from './release_block.vue'; import ReleaseBlock from './release_block.vue';
import ReleasesPagination from './releases_pagination.vue';
export default { export default {
name: 'ReleasesApp', name: 'ReleasesApp',
...@@ -21,7 +17,7 @@ export default { ...@@ -21,7 +17,7 @@ export default {
GlSkeletonLoading, GlSkeletonLoading,
GlEmptyState, GlEmptyState,
ReleaseBlock, ReleaseBlock,
TablePagination, ReleasesPagination,
GlLink, GlLink,
GlButton, GlButton,
}, },
...@@ -33,7 +29,6 @@ export default { ...@@ -33,7 +29,6 @@ export default {
'isLoading', 'isLoading',
'releases', 'releases',
'hasError', 'hasError',
'pageInfo',
]), ]),
shouldRenderEmptyState() { shouldRenderEmptyState() {
return !this.releases.length && !this.hasError && !this.isLoading; return !this.releases.length && !this.hasError && !this.isLoading;
...@@ -48,15 +43,23 @@ export default { ...@@ -48,15 +43,23 @@ export default {
}, },
}, },
created() { created() {
this.fetchReleases({ this.fetchReleases();
page: getParameterByName('page'),
}); window.addEventListener('popstate', this.fetchReleases);
}, },
methods: { methods: {
...mapActions('list', ['fetchReleases']), ...mapActions('list', {
onChangePage(page) { fetchReleasesStoreAction: 'fetchReleases',
historyPushState(buildUrlWithCurrentLocation(`?page=${page}`)); }),
this.fetchReleases({ page }); fetchReleases() {
this.fetchReleasesStoreAction({
// these two parameters are only used in "GraphQL mode"
before: getParameterByName('before'),
after: getParameterByName('after'),
// this parameter is only used when in "REST mode"
page: getParameterByName('page'),
});
}, },
}, },
}; };
...@@ -105,7 +108,7 @@ export default { ...@@ -105,7 +108,7 @@ export default {
/> />
</div> </div>
<table-pagination v-if="!isLoading" :change="onChangePage" :page-info="pageInfo" /> <releases-pagination v-if="!isLoading" />
</div> </div>
</template> </template>
<style> <style>
......
...@@ -13,14 +13,14 @@ export default { ...@@ -13,14 +13,14 @@ export default {
}, },
}, },
methods: { methods: {
...mapActions('list', ['fetchReleasesGraphQl']), ...mapActions('list', ['fetchReleases']),
onPrev(before) { onPrev(before) {
historyPushState(buildUrlWithCurrentLocation(`?before=${before}`)); historyPushState(buildUrlWithCurrentLocation(`?before=${before}`));
this.fetchReleasesGraphQl({ before }); this.fetchReleases({ before });
}, },
onNext(after) { onNext(after) {
historyPushState(buildUrlWithCurrentLocation(`?after=${after}`)); historyPushState(buildUrlWithCurrentLocation(`?after=${after}`));
this.fetchReleasesGraphQl({ after }); this.fetchReleases({ after });
}, },
}, },
}; };
......
...@@ -7,18 +7,18 @@ export default { ...@@ -7,18 +7,18 @@ export default {
name: 'ReleasesPaginationRest', name: 'ReleasesPaginationRest',
components: { TablePagination }, components: { TablePagination },
computed: { computed: {
...mapState('list', ['pageInfo']), ...mapState('list', ['restPageInfo']),
}, },
methods: { methods: {
...mapActions('list', ['fetchReleasesRest']), ...mapActions('list', ['fetchReleases']),
onChangePage(page) { onChangePage(page) {
historyPushState(buildUrlWithCurrentLocation(`?page=${page}`)); historyPushState(buildUrlWithCurrentLocation(`?page=${page}`));
this.fetchReleasesRest({ page }); this.fetchReleases({ page });
}, },
}, },
}; };
</script> </script>
<template> <template>
<table-pagination :change="onChangePage" :page-info="pageInfo" /> <table-pagination :change="onChangePage" :page-info="restPageInfo" />
</template> </template>
...@@ -10,3 +10,5 @@ export const ASSET_LINK_TYPE = Object.freeze({ ...@@ -10,3 +10,5 @@ export const ASSET_LINK_TYPE = Object.freeze({
}); });
export const DEFAULT_ASSET_LINK_TYPE = ASSET_LINK_TYPE.OTHER; export const DEFAULT_ASSET_LINK_TYPE = ASSET_LINK_TYPE.OTHER;
export const PAGE_SIZE = 20;
query allReleases($fullPath: ID!) { query allReleases($fullPath: ID!, $first: Int, $last: Int, $before: String, $after: String) {
project(fullPath: $fullPath) { project(fullPath: $fullPath) {
releases(first: 20) { releases(first: $first, last: $last, before: $before, after: $after) {
count
nodes { nodes {
name name
tagName tagName
...@@ -64,6 +63,12 @@ query allReleases($fullPath: ID!) { ...@@ -64,6 +63,12 @@ query allReleases($fullPath: ID!) {
} }
} }
} }
pageInfo {
startCursor
hasPreviousPage
hasNextPage
endCursor
}
} }
} }
} }
/**
* @returns {Boolean} `true` if all the feature flags
* required to enable the GraphQL endpoint are enabled
*/
export const useGraphQLEndpoint = rootState => {
return Boolean(
rootState.featureFlags.graphqlReleaseData &&
rootState.featureFlags.graphqlReleasesPage &&
rootState.featureFlags.graphqlMilestoneStats,
);
};
import Vuex from 'vuex'; import Vuex from 'vuex';
import * as getters from './getters';
export default ({ modules, featureFlags }) => export default ({ modules, featureFlags }) =>
new Vuex.Store({ new Vuex.Store({
modules, modules,
state: { featureFlags }, state: { featureFlags },
getters,
}); });
...@@ -9,54 +9,89 @@ import { ...@@ -9,54 +9,89 @@ import {
} from '~/lib/utils/common_utils'; } from '~/lib/utils/common_utils';
import allReleasesQuery from '~/releases/queries/all_releases.query.graphql'; import allReleasesQuery from '~/releases/queries/all_releases.query.graphql';
import { gqClient, convertGraphQLResponse } from '../../../util'; import { gqClient, convertGraphQLResponse } from '../../../util';
import { PAGE_SIZE } from '../../../constants';
/** /**
* Commits a mutation to update the state while the main endpoint is being requested. * Gets a paginated list of releases from the server
*
* @param {Object} vuexParams
* @param {Object} actionParams
* @param {Number} [actionParams.page] The page number of results to fetch
* (this parameter is only used when fetching results from the REST API)
* @param {String} [actionParams.before] A GraphQL cursor. If provided,
* the items returned will proceed the provided cursor (this parameter is only
* used when fetching results from the GraphQL API).
* @param {String} [actionParams.after] A GraphQL cursor. If provided,
* the items returned will follow the provided cursor (this parameter is only
* used when fetching results from the GraphQL API).
*/ */
export const requestReleases = ({ commit }) => commit(types.REQUEST_RELEASES); export const fetchReleases = ({ dispatch, rootGetters }, { page = 1, before, after }) => {
if (rootGetters.useGraphQLEndpoint) {
dispatch('fetchReleasesGraphQl', { before, after });
} else {
dispatch('fetchReleasesRest', { page });
}
};
/** /**
* Fetches the main endpoint. * Gets a paginated list of releases from the GraphQL endpoint
* Will dispatch requestNamespace action before starting the request.
* Will dispatch receiveNamespaceSuccess if the request is successful
* Will dispatch receiveNamesapceError if the request returns an error
*
* @param {String} projectId
*/ */
export const fetchReleases = ({ dispatch, rootState, state }, { page = '1' }) => { export const fetchReleasesGraphQl = (
dispatch('requestReleases'); { dispatch, commit, state },
{ before = null, after = null },
) => {
commit(types.REQUEST_RELEASES);
let paginationParams;
if (!before && !after) {
paginationParams = { first: PAGE_SIZE };
} else if (before && !after) {
paginationParams = { last: PAGE_SIZE, before };
} else if (!before && after) {
paginationParams = { first: PAGE_SIZE, after };
} else {
throw new Error(
'Both a `before` and an `after` parameter were provided to fetchReleasesGraphQl. These parameters cannot be used together.',
);
}
if (
rootState.featureFlags.graphqlReleaseData &&
rootState.featureFlags.graphqlReleasesPage &&
rootState.featureFlags.graphqlMilestoneStats
) {
gqClient gqClient
.query({ .query({
query: allReleasesQuery, query: allReleasesQuery,
variables: { variables: {
fullPath: state.projectPath, fullPath: state.projectPath,
...paginationParams,
}, },
}) })
.then(response => { .then(response => {
dispatch('receiveReleasesSuccess', convertGraphQLResponse(response)); const { data, paginationInfo: graphQlPageInfo } = convertGraphQLResponse(response);
commit(types.RECEIVE_RELEASES_SUCCESS, {
data,
graphQlPageInfo,
});
}) })
.catch(() => dispatch('receiveReleasesError')); .catch(() => dispatch('receiveReleasesError'));
} else {
api
.releases(state.projectId, { page })
.then(response => dispatch('receiveReleasesSuccess', response))
.catch(() => dispatch('receiveReleasesError'));
}
}; };
export const receiveReleasesSuccess = ({ commit }, { data, headers }) => { /**
const pageInfo = parseIntPagination(normalizeHeaders(headers)); * Gets a paginated list of releases from the REST endpoint
*/
export const fetchReleasesRest = ({ dispatch, commit, state }, { page }) => {
commit(types.REQUEST_RELEASES);
api
.releases(state.projectId, { page })
.then(({ data, headers }) => {
const restPageInfo = parseIntPagination(normalizeHeaders(headers));
const camelCasedReleases = convertObjectPropsToCamelCase(data, { deep: true }); const camelCasedReleases = convertObjectPropsToCamelCase(data, { deep: true });
commit(types.RECEIVE_RELEASES_SUCCESS, { commit(types.RECEIVE_RELEASES_SUCCESS, {
data: camelCasedReleases, data: camelCasedReleases,
pageInfo, restPageInfo,
}); });
})
.catch(() => dispatch('receiveReleasesError'));
}; };
export const receiveReleasesError = ({ commit }) => { export const receiveReleasesError = ({ commit }) => {
......
...@@ -17,11 +17,12 @@ export default { ...@@ -17,11 +17,12 @@ export default {
* @param {Object} state * @param {Object} state
* @param {Object} resp * @param {Object} resp
*/ */
[types.RECEIVE_RELEASES_SUCCESS](state, { data, pageInfo }) { [types.RECEIVE_RELEASES_SUCCESS](state, { data, restPageInfo, graphQlPageInfo }) {
state.hasError = false; state.hasError = false;
state.isLoading = false; state.isLoading = false;
state.releases = data; state.releases = data;
state.pageInfo = pageInfo; state.restPageInfo = restPageInfo;
state.graphQlPageInfo = graphQlPageInfo;
}, },
/** /**
...@@ -35,5 +36,7 @@ export default { ...@@ -35,5 +36,7 @@ export default {
state.isLoading = false; state.isLoading = false;
state.releases = []; state.releases = [];
state.hasError = true; state.hasError = true;
state.restPageInfo = {};
state.graphQlPageInfo = {};
}, },
}; };
...@@ -14,5 +14,6 @@ export default ({ ...@@ -14,5 +14,6 @@ export default ({
isLoading: false, isLoading: false,
hasError: false, hasError: false,
releases: [], releases: [],
pageInfo: {}, restPageInfo: {},
graphQlPageInfo: {},
}); });
...@@ -126,5 +126,9 @@ export const convertGraphQLResponse = response => { ...@@ -126,5 +126,9 @@ export const convertGraphQLResponse = response => {
...convertMilestones(r), ...convertMilestones(r),
})); }));
return { data: releases }; const paginationInfo = {
...response.data.project.releases.pageInfo,
};
return { data: releases, paginationInfo };
}; };
...@@ -13,7 +13,7 @@ class Projects::ReleasesController < Projects::ApplicationController ...@@ -13,7 +13,7 @@ class Projects::ReleasesController < Projects::ApplicationController
push_frontend_feature_flag(:release_asset_link_type, project, default_enabled: true) push_frontend_feature_flag(:release_asset_link_type, project, default_enabled: true)
push_frontend_feature_flag(:graphql_release_data, project, default_enabled: true) push_frontend_feature_flag(:graphql_release_data, project, default_enabled: true)
push_frontend_feature_flag(:graphql_milestone_stats, project, default_enabled: true) push_frontend_feature_flag(:graphql_milestone_stats, project, default_enabled: true)
push_frontend_feature_flag(:graphql_releases_page, project, default_enabled: false) push_frontend_feature_flag(:graphql_releases_page, project, default_enabled: true)
end end
before_action :authorize_update_release!, only: %i[edit update] before_action :authorize_update_release!, only: %i[edit update]
before_action :authorize_create_release!, only: :new before_action :authorize_create_release!, only: :new
......
...@@ -109,5 +109,11 @@ Object { ...@@ -109,5 +109,11 @@ Object {
"upcomingRelease": false, "upcomingRelease": false,
}, },
], ],
"paginationInfo": Object {
"endCursor": "eyJpZCI6IjMiLCJyZWxlYXNlZF9hdCI6IjIwMjAtMDctMDkgMjA6MTE6MzMuODA0OTYxMDAwIFVUQyJ9",
"hasNextPage": true,
"hasPreviousPage": false,
"startCursor": "eyJpZCI6IjQ0IiwicmVsZWFzZWRfYXQiOiIyMDMwLTAzLTE1IDA4OjAwOjAwLjAwMDAwMDAwMCBVVEMifQ",
},
} }
`; `;
...@@ -13,7 +13,14 @@ import { ...@@ -13,7 +13,14 @@ import {
releases, releases,
} from '../mock_data'; } from '../mock_data';
import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils';
import TablePagination from '~/vue_shared/components/pagination/table_pagination.vue'; import ReleasesPagination from '~/releases/components/releases_pagination.vue';
jest.mock('~/lib/utils/common_utils', () => ({
...jest.requireActual('~/lib/utils/common_utils'),
getParameterByName: jest.fn().mockImplementation(paramName => {
return `${paramName}_param_value`;
}),
}));
const localVue = createLocalVue(); const localVue = createLocalVue();
localVue.use(Vuex); localVue.use(Vuex);
...@@ -22,7 +29,7 @@ describe('Releases App ', () => { ...@@ -22,7 +29,7 @@ describe('Releases App ', () => {
let wrapper; let wrapper;
let fetchReleaseSpy; let fetchReleaseSpy;
const releasesPagination = rge(21).map(index => ({ const paginatedReleases = rge(21).map(index => ({
...convertObjectPropsToCamelCase(release, { deep: true }), ...convertObjectPropsToCamelCase(release, { deep: true }),
tagName: `${index}.00`, tagName: `${index}.00`,
})); }));
...@@ -70,9 +77,13 @@ describe('Releases App ', () => { ...@@ -70,9 +77,13 @@ describe('Releases App ', () => {
createComponent(); createComponent();
}); });
it('calls fetchRelease with the page parameter', () => { it('calls fetchRelease with the page, before, and after parameters', () => {
expect(fetchReleaseSpy).toHaveBeenCalledTimes(1); expect(fetchReleaseSpy).toHaveBeenCalledTimes(1);
expect(fetchReleaseSpy).toHaveBeenCalledWith(expect.anything(), { page: null }); expect(fetchReleaseSpy).toHaveBeenCalledWith(expect.anything(), {
page: 'page_param_value',
before: 'before_param_value',
after: 'after_param_value',
});
}); });
}); });
...@@ -91,7 +102,7 @@ describe('Releases App ', () => { ...@@ -91,7 +102,7 @@ describe('Releases App ', () => {
expect(wrapper.contains('.js-loading')).toBe(true); expect(wrapper.contains('.js-loading')).toBe(true);
expect(wrapper.contains('.js-empty-state')).toBe(false); expect(wrapper.contains('.js-empty-state')).toBe(false);
expect(wrapper.contains('.js-success-state')).toBe(false); expect(wrapper.contains('.js-success-state')).toBe(false);
expect(wrapper.contains(TablePagination)).toBe(false); expect(wrapper.contains(ReleasesPagination)).toBe(false);
}); });
}); });
...@@ -108,7 +119,7 @@ describe('Releases App ', () => { ...@@ -108,7 +119,7 @@ describe('Releases App ', () => {
expect(wrapper.contains('.js-loading')).toBe(false); expect(wrapper.contains('.js-loading')).toBe(false);
expect(wrapper.contains('.js-empty-state')).toBe(false); expect(wrapper.contains('.js-empty-state')).toBe(false);
expect(wrapper.contains('.js-success-state')).toBe(true); expect(wrapper.contains('.js-success-state')).toBe(true);
expect(wrapper.contains(TablePagination)).toBe(true); expect(wrapper.contains(ReleasesPagination)).toBe(true);
}); });
}); });
...@@ -116,7 +127,7 @@ describe('Releases App ', () => { ...@@ -116,7 +127,7 @@ describe('Releases App ', () => {
beforeEach(() => { beforeEach(() => {
jest jest
.spyOn(api, 'releases') .spyOn(api, 'releases')
.mockResolvedValue({ data: releasesPagination, headers: pageInfoHeadersWithPagination }); .mockResolvedValue({ data: paginatedReleases, headers: pageInfoHeadersWithPagination });
createComponent(); createComponent();
}); });
...@@ -125,7 +136,7 @@ describe('Releases App ', () => { ...@@ -125,7 +136,7 @@ describe('Releases App ', () => {
expect(wrapper.contains('.js-loading')).toBe(false); expect(wrapper.contains('.js-loading')).toBe(false);
expect(wrapper.contains('.js-empty-state')).toBe(false); expect(wrapper.contains('.js-empty-state')).toBe(false);
expect(wrapper.contains('.js-success-state')).toBe(true); expect(wrapper.contains('.js-success-state')).toBe(true);
expect(wrapper.contains(TablePagination)).toBe(true); expect(wrapper.contains(ReleasesPagination)).toBe(true);
}); });
}); });
...@@ -154,7 +165,7 @@ describe('Releases App ', () => { ...@@ -154,7 +165,7 @@ describe('Releases App ', () => {
const newReleasePath = 'path/to/new/release'; const newReleasePath = 'path/to/new/release';
beforeEach(() => { beforeEach(() => {
createComponent({ ...defaultInitialState, newReleasePath }); createComponent({ newReleasePath });
}); });
it('renders the "New release" button', () => { it('renders the "New release" button', () => {
...@@ -174,4 +185,27 @@ describe('Releases App ', () => { ...@@ -174,4 +185,27 @@ describe('Releases App ', () => {
}); });
}); });
}); });
describe('when the back button is pressed', () => {
beforeEach(() => {
jest
.spyOn(api, 'releases')
.mockResolvedValue({ data: releases, headers: pageInfoHeadersWithoutPagination });
createComponent();
fetchReleaseSpy.mockClear();
window.dispatchEvent(new PopStateEvent('popstate'));
});
it('calls fetchRelease with the page parameter', () => {
expect(fetchReleaseSpy).toHaveBeenCalledTimes(1);
expect(fetchReleaseSpy).toHaveBeenCalledWith(expect.anything(), {
page: 'page_param_value',
before: 'before_param_value',
after: 'after_param_value',
});
});
});
}); });
...@@ -29,7 +29,7 @@ describe('~/releases/components/releases_pagination_graphql.vue', () => { ...@@ -29,7 +29,7 @@ describe('~/releases/components/releases_pagination_graphql.vue', () => {
listModule.state.graphQlPageInfo = pageInfo; listModule.state.graphQlPageInfo = pageInfo;
listModule.actions.fetchReleasesGraphQl = jest.fn(); listModule.actions.fetchReleases = jest.fn();
wrapper = mount(ReleasesPaginationGraphql, { wrapper = mount(ReleasesPaginationGraphql, {
store: createStore({ store: createStore({
...@@ -141,8 +141,8 @@ describe('~/releases/components/releases_pagination_graphql.vue', () => { ...@@ -141,8 +141,8 @@ describe('~/releases/components/releases_pagination_graphql.vue', () => {
findNextButton().trigger('click'); findNextButton().trigger('click');
}); });
it('calls fetchReleasesGraphQl with the correct after cursor', () => { it('calls fetchReleases with the correct after cursor', () => {
expect(listModule.actions.fetchReleasesGraphQl.mock.calls).toEqual([ expect(listModule.actions.fetchReleases.mock.calls).toEqual([
[expect.anything(), { after: cursors.endCursor }], [expect.anything(), { after: cursors.endCursor }],
]); ]);
}); });
...@@ -159,8 +159,8 @@ describe('~/releases/components/releases_pagination_graphql.vue', () => { ...@@ -159,8 +159,8 @@ describe('~/releases/components/releases_pagination_graphql.vue', () => {
findPrevButton().trigger('click'); findPrevButton().trigger('click');
}); });
it('calls fetchReleasesGraphQl with the correct before cursor', () => { it('calls fetchReleases with the correct before cursor', () => {
expect(listModule.actions.fetchReleasesGraphQl.mock.calls).toEqual([ expect(listModule.actions.fetchReleases.mock.calls).toEqual([
[expect.anything(), { before: cursors.startCursor }], [expect.anything(), { before: cursors.startCursor }],
]); ]);
}); });
......
...@@ -20,9 +20,9 @@ describe('~/releases/components/releases_pagination_rest.vue', () => { ...@@ -20,9 +20,9 @@ describe('~/releases/components/releases_pagination_rest.vue', () => {
const createComponent = pageInfo => { const createComponent = pageInfo => {
listModule = createListModule({ projectId }); listModule = createListModule({ projectId });
listModule.state.pageInfo = pageInfo; listModule.state.restPageInfo = pageInfo;
listModule.actions.fetchReleasesRest = jest.fn(); listModule.actions.fetchReleases = jest.fn();
wrapper = mount(ReleasesPaginationRest, { wrapper = mount(ReleasesPaginationRest, {
store: createStore({ store: createStore({
...@@ -57,8 +57,8 @@ describe('~/releases/components/releases_pagination_rest.vue', () => { ...@@ -57,8 +57,8 @@ describe('~/releases/components/releases_pagination_rest.vue', () => {
findGlPagination().vm.$emit('input', newPage); findGlPagination().vm.$emit('input', newPage);
}); });
it('calls fetchReleasesRest with the correct page', () => { it('calls fetchReleases with the correct page', () => {
expect(listModule.actions.fetchReleasesRest.mock.calls).toEqual([ expect(listModule.actions.fetchReleases.mock.calls).toEqual([
[expect.anything(), { page: newPage }], [expect.anything(), { page: newPage }],
]); ]);
}); });
......
...@@ -346,6 +346,14 @@ export const graphqlReleasesResponse = { ...@@ -346,6 +346,14 @@ export const graphqlReleasesResponse = {
}, },
}, },
], ],
pageInfo: {
startCursor:
'eyJpZCI6IjQ0IiwicmVsZWFzZWRfYXQiOiIyMDMwLTAzLTE1IDA4OjAwOjAwLjAwMDAwMDAwMCBVVEMifQ',
hasPreviousPage: false,
hasNextPage: true,
endCursor:
'eyJpZCI6IjMiLCJyZWxlYXNlZF9hdCI6IjIwMjAtMDctMDkgMjA6MTE6MzMuODA0OTYxMDAwIFVUQyJ9',
},
}, },
}, },
}, },
......
import * as getters from '~/releases/stores/getters';
describe('~/releases/stores/getters.js', () => {
it.each`
graphqlReleaseData | graphqlReleasesPage | graphqlMilestoneStats | result
${false} | ${false} | ${false} | ${false}
${false} | ${false} | ${true} | ${false}
${false} | ${true} | ${false} | ${false}
${false} | ${true} | ${true} | ${false}
${true} | ${false} | ${false} | ${false}
${true} | ${false} | ${true} | ${false}
${true} | ${true} | ${false} | ${false}
${true} | ${true} | ${true} | ${true}
`(
'returns $result with feature flag values graphqlReleaseData=$graphqlReleaseData, graphqlReleasesPage=$graphqlReleasesPage, and graphqlMilestoneStats=$graphqlMilestoneStats',
({ result: expectedResult, ...featureFlags }) => {
const actualResult = getters.useGraphQLEndpoint({ featureFlags });
expect(actualResult).toBe(expectedResult);
},
);
});
...@@ -2,15 +2,22 @@ import createState from '~/releases/stores/modules/list/state'; ...@@ -2,15 +2,22 @@ import createState from '~/releases/stores/modules/list/state';
import mutations from '~/releases/stores/modules/list/mutations'; import mutations from '~/releases/stores/modules/list/mutations';
import * as types from '~/releases/stores/modules/list/mutation_types'; import * as types from '~/releases/stores/modules/list/mutation_types';
import { parseIntPagination } from '~/lib/utils/common_utils'; import { parseIntPagination } from '~/lib/utils/common_utils';
import { pageInfoHeadersWithoutPagination, releases } from '../../../mock_data'; import {
pageInfoHeadersWithoutPagination,
releases,
graphqlReleasesResponse,
} from '../../../mock_data';
import { convertGraphQLResponse } from '~/releases/util';
describe('Releases Store Mutations', () => { describe('Releases Store Mutations', () => {
let stateCopy; let stateCopy;
let pageInfo; let restPageInfo;
let graphQlPageInfo;
beforeEach(() => { beforeEach(() => {
stateCopy = createState({}); stateCopy = createState({});
pageInfo = parseIntPagination(pageInfoHeadersWithoutPagination); restPageInfo = parseIntPagination(pageInfoHeadersWithoutPagination);
graphQlPageInfo = convertGraphQLResponse(graphqlReleasesResponse).paginationInfo;
}); });
describe('REQUEST_RELEASES', () => { describe('REQUEST_RELEASES', () => {
...@@ -23,7 +30,11 @@ describe('Releases Store Mutations', () => { ...@@ -23,7 +30,11 @@ describe('Releases Store Mutations', () => {
describe('RECEIVE_RELEASES_SUCCESS', () => { describe('RECEIVE_RELEASES_SUCCESS', () => {
beforeEach(() => { beforeEach(() => {
mutations[types.RECEIVE_RELEASES_SUCCESS](stateCopy, { pageInfo, data: releases }); mutations[types.RECEIVE_RELEASES_SUCCESS](stateCopy, {
restPageInfo,
graphQlPageInfo,
data: releases,
});
}); });
it('sets is loading to false', () => { it('sets is loading to false', () => {
...@@ -38,18 +49,29 @@ describe('Releases Store Mutations', () => { ...@@ -38,18 +49,29 @@ describe('Releases Store Mutations', () => {
expect(stateCopy.releases).toEqual(releases); expect(stateCopy.releases).toEqual(releases);
}); });
it('sets pageInfo', () => { it('sets restPageInfo', () => {
expect(stateCopy.pageInfo).toEqual(pageInfo); expect(stateCopy.restPageInfo).toEqual(restPageInfo);
});
it('sets graphQlPageInfo', () => {
expect(stateCopy.graphQlPageInfo).toEqual(graphQlPageInfo);
}); });
}); });
describe('RECEIVE_RELEASES_ERROR', () => { describe('RECEIVE_RELEASES_ERROR', () => {
it('resets data', () => { it('resets data', () => {
mutations[types.RECEIVE_RELEASES_SUCCESS](stateCopy, {
restPageInfo,
graphQlPageInfo,
data: releases,
});
mutations[types.RECEIVE_RELEASES_ERROR](stateCopy); mutations[types.RECEIVE_RELEASES_ERROR](stateCopy);
expect(stateCopy.isLoading).toEqual(false); expect(stateCopy.isLoading).toEqual(false);
expect(stateCopy.releases).toEqual([]); expect(stateCopy.releases).toEqual([]);
expect(stateCopy.pageInfo).toEqual({}); expect(stateCopy.restPageInfo).toEqual({});
expect(stateCopy.graphQlPageInfo).toEqual({});
}); });
}); });
}); });
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