diff options
author | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-28 00:10:59 +0300 |
---|---|---|
committer | GitLab Bot <gitlab-bot@gitlab.com> | 2021-05-28 00:10:59 +0300 |
commit | 95d309bfb847dbafbfb3784d1933a3eb269dde24 (patch) | |
tree | 8d3951664f3a856b8cd77b5111aceae3cda9a023 /spec/frontend/releases | |
parent | 479221aa79c2e18497589f0aef175a06fb5f5e29 (diff) |
Add latest changes from gitlab-org/gitlab@master
Diffstat (limited to 'spec/frontend/releases')
-rw-r--r-- | spec/frontend/releases/components/app_index_apollo_client_spec.js | 65 | ||||
-rw-r--r-- | spec/frontend/releases/components/releases_pagination_apollo_client_spec.js | 126 |
2 files changed, 187 insertions, 4 deletions
diff --git a/spec/frontend/releases/components/app_index_apollo_client_spec.js b/spec/frontend/releases/components/app_index_apollo_client_spec.js index 20ee2dabf1e..32ebeacbdff 100644 --- a/spec/frontend/releases/components/app_index_apollo_client_spec.js +++ b/spec/frontend/releases/components/app_index_apollo_client_spec.js @@ -8,6 +8,7 @@ import ReleasesIndexApolloClientApp from '~/releases/components/app_index_apollo import ReleaseBlock from '~/releases/components/release_block.vue'; import ReleaseSkeletonLoader from '~/releases/components/release_skeleton_loader.vue'; import ReleasesEmptyState from '~/releases/components/releases_empty_state.vue'; +import ReleasesPaginationApolloClient from '~/releases/components/releases_pagination_apollo_client.vue'; import { PAGE_SIZE } from '~/releases/constants'; import allReleasesQuery from '~/releases/graphql/queries/all_releases.query.graphql'; @@ -29,6 +30,8 @@ describe('app_index_apollo_client.vue', () => { ); const projectPath = 'project/path'; const newReleasePath = 'path/to/new/release/page'; + const before = 'beforeCursor'; + const after = 'afterCursor'; let wrapper; let allReleasesQueryResponse; @@ -64,6 +67,7 @@ describe('app_index_apollo_client.vue', () => { const findNewReleaseButton = () => wrapper.findByText(ReleasesIndexApolloClientApp.i18n.newRelease); const findAllReleaseBlocks = () => wrapper.findAllComponents(ReleaseBlock); + const findPagination = () => wrapper.findComponent(ReleasesPaginationApolloClient); // Expectations const expectLoadingIndicator = () => { @@ -119,6 +123,18 @@ describe('app_index_apollo_client.vue', () => { }); }; + const expectPagination = () => { + it('renders the pagination buttons', () => { + expect(findPagination().exists()).toBe(true); + }); + }; + + const expectNoPagination = () => { + it('does not render the pagination buttons', () => { + expect(findPagination().exists()).toBe(false); + }); + }; + // Tests describe('when the component is loading data', () => { beforeEach(() => { @@ -130,6 +146,7 @@ describe('app_index_apollo_client.vue', () => { expectNoFlashMessage(); expectNewReleaseButton(); expectReleases(0); + expectNoPagination(); }); describe('when the data has successfully loaded, but there are no releases', () => { @@ -143,6 +160,7 @@ describe('app_index_apollo_client.vue', () => { expectNoFlashMessage(); expectNewReleaseButton(); expectReleases(0); + expectNoPagination(); }); describe('when an error occurs while loading data', () => { @@ -155,9 +173,10 @@ describe('app_index_apollo_client.vue', () => { expectFlashMessage(); expectNewReleaseButton(); expectReleases(0); + expectNoPagination(); }); - describe('when the data has successfully loaded', () => { + describe('when the data has successfully loaded with a single page of results', () => { beforeEach(() => { createComponent(); }); @@ -167,12 +186,24 @@ describe('app_index_apollo_client.vue', () => { expectNoFlashMessage(); expectNewReleaseButton(); expectReleases(originalAllReleasesQueryResponse.data.project.releases.nodes.length); + expectNoPagination(); }); - describe('URL parameters', () => { - const before = 'beforeCursor'; - const after = 'afterCursor'; + describe('when the data has successfully loaded with multiple pages of results', () => { + beforeEach(() => { + allReleasesQueryResponse.data.project.releases.pageInfo.hasNextPage = true; + createComponent(Promise.resolve(allReleasesQueryResponse)); + }); + + expectNoLoadingIndicator(); + expectNoEmptyState(); + expectNoFlashMessage(); + expectNewReleaseButton(); + expectReleases(originalAllReleasesQueryResponse.data.project.releases.nodes.length); + expectPagination(); + }); + describe('URL parameters', () => { describe('when the URL contains no query parameters', () => { beforeEach(() => { createComponent(); @@ -241,4 +272,30 @@ describe('app_index_apollo_client.vue', () => { expect(findNewReleaseButton().attributes().href).toBe(newReleasePath); }); }); + + describe('pagination', () => { + beforeEach(async () => { + mockQueryParams = { before }; + + allReleasesQueryResponse.data.project.releases.pageInfo.hasNextPage = true; + createComponent(Promise.resolve(allReleasesQueryResponse)); + + await wrapper.vm.$nextTick(); + }); + + it('requeries the GraphQL endpoint when a pagination button is clicked', async () => { + expect(allReleasesQueryMock.mock.calls).toEqual([[expect.objectContaining({ before })]]); + + mockQueryParams = { after }; + + findPagination().vm.$emit('next', after); + + await wrapper.vm.$nextTick(); + + expect(allReleasesQueryMock.mock.calls).toEqual([ + [expect.objectContaining({ before })], + [expect.objectContaining({ after })], + ]); + }); + }); }); diff --git a/spec/frontend/releases/components/releases_pagination_apollo_client_spec.js b/spec/frontend/releases/components/releases_pagination_apollo_client_spec.js new file mode 100644 index 00000000000..a538afd5d38 --- /dev/null +++ b/spec/frontend/releases/components/releases_pagination_apollo_client_spec.js @@ -0,0 +1,126 @@ +import { mountExtended } from 'helpers/vue_test_utils_helper'; +import { historyPushState } from '~/lib/utils/common_utils'; +import ReleasesPaginationApolloClient from '~/releases/components/releases_pagination_apollo_client.vue'; + +jest.mock('~/lib/utils/common_utils', () => ({ + ...jest.requireActual('~/lib/utils/common_utils'), + historyPushState: jest.fn(), +})); + +describe('releases_pagination_apollo_client.vue', () => { + const startCursor = 'startCursor'; + const endCursor = 'endCursor'; + let wrapper; + let onPrev; + let onNext; + + const createComponent = (pageInfo) => { + onPrev = jest.fn(); + onNext = jest.fn(); + + wrapper = mountExtended(ReleasesPaginationApolloClient, { + propsData: { + pageInfo, + }, + listeners: { + prev: onPrev, + next: onNext, + }, + }); + }; + + afterEach(() => { + wrapper.destroy(); + }); + + const singlePageInfo = { + hasPreviousPage: false, + hasNextPage: false, + startCursor, + endCursor, + }; + + const onlyNextPageInfo = { + hasPreviousPage: false, + hasNextPage: true, + startCursor, + endCursor, + }; + + const onlyPrevPageInfo = { + hasPreviousPage: true, + hasNextPage: false, + startCursor, + endCursor, + }; + + const prevAndNextPageInfo = { + hasPreviousPage: true, + hasNextPage: true, + startCursor, + endCursor, + }; + + const findPrevButton = () => wrapper.findByTestId('prevButton'); + const findNextButton = () => wrapper.findByTestId('nextButton'); + + describe.each` + description | pageInfo | prevEnabled | nextEnabled + ${'when there is only one page of results'} | ${singlePageInfo} | ${false} | ${false} + ${'when there is a next page, but not a previous page'} | ${onlyNextPageInfo} | ${false} | ${true} + ${'when there is a previous page, but not a next page'} | ${onlyPrevPageInfo} | ${true} | ${false} + ${'when there is both a previous and next page'} | ${prevAndNextPageInfo} | ${true} | ${true} + `('component states', ({ description, pageInfo, prevEnabled, nextEnabled }) => { + describe(description, () => { + beforeEach(() => { + createComponent(pageInfo); + }); + + it(`renders the "Prev" button as ${prevEnabled ? 'enabled' : 'disabled'}`, () => { + expect(findPrevButton().attributes().disabled).toBe(prevEnabled ? undefined : 'disabled'); + }); + + it(`renders the "Next" button as ${nextEnabled ? 'enabled' : 'disabled'}`, () => { + expect(findNextButton().attributes().disabled).toBe(nextEnabled ? undefined : 'disabled'); + }); + }); + }); + + describe('button behavior', () => { + beforeEach(() => { + createComponent(prevAndNextPageInfo); + }); + + describe('next button behavior', () => { + beforeEach(() => { + findNextButton().trigger('click'); + }); + + it('emits an "next" event with the "after" cursor', () => { + expect(onNext.mock.calls).toEqual([[endCursor]]); + }); + + it('calls historyPushState with the new URL', () => { + expect(historyPushState.mock.calls).toEqual([ + [expect.stringContaining(`?after=${endCursor}`)], + ]); + }); + }); + + describe('prev button behavior', () => { + beforeEach(() => { + findPrevButton().trigger('click'); + }); + + it('emits an "prev" event with the "before" cursor', () => { + expect(onPrev.mock.calls).toEqual([[startCursor]]); + }); + + it('calls historyPushState with the new URL', () => { + expect(historyPushState.mock.calls).toEqual([ + [expect.stringContaining(`?before=${startCursor}`)], + ]); + }); + }); + }); +}); |