diff options
Diffstat (limited to 'spec/frontend/vue_shared/components/entity_select/organization_select_spec.js')
-rw-r--r-- | spec/frontend/vue_shared/components/entity_select/organization_select_spec.js | 155 |
1 files changed, 91 insertions, 64 deletions
diff --git a/spec/frontend/vue_shared/components/entity_select/organization_select_spec.js b/spec/frontend/vue_shared/components/entity_select/organization_select_spec.js index ea029ba4f27..6dc38bbd0c6 100644 --- a/spec/frontend/vue_shared/components/entity_select/organization_select_spec.js +++ b/spec/frontend/vue_shared/components/entity_select/organization_select_spec.js @@ -1,35 +1,35 @@ import VueApollo from 'vue-apollo'; -import Vue, { nextTick } from 'vue'; -import { GlCollapsibleListbox } from '@gitlab/ui'; -import { shallowMountExtended } from 'helpers/vue_test_utils_helper'; +import Vue from 'vue'; +import { GlCollapsibleListbox, GlAlert } from '@gitlab/ui'; +import { chunk } from 'lodash'; +import { mountExtended } from 'helpers/vue_test_utils_helper'; import OrganizationSelect from '~/vue_shared/components/entity_select/organization_select.vue'; import EntitySelect from '~/vue_shared/components/entity_select/entity_select.vue'; +import { DEFAULT_PER_PAGE } from '~/api'; import { ORGANIZATION_TOGGLE_TEXT, ORGANIZATION_HEADER_TEXT, FETCH_ORGANIZATIONS_ERROR, FETCH_ORGANIZATION_ERROR, } from '~/vue_shared/components/entity_select/constants'; -import resolvers from '~/organizations/shared/graphql/resolvers'; -import organizationsQuery from '~/organizations/index/graphql/organizations.query.graphql'; -import { organizations as organizationsMock } from '~/organizations/mock_data'; +import getCurrentUserOrganizationsQuery from '~/organizations/shared/graphql/queries/organizations.query.graphql'; +import getOrganizationQuery from '~/organizations/shared/graphql/queries/organization.query.graphql'; +import { organizations as nodes, pageInfo, pageInfoEmpty } from '~/organizations/mock_data'; import waitForPromises from 'helpers/wait_for_promises'; import createMockApollo from 'helpers/mock_apollo_helper'; +import { getIdFromGraphQLId } from '~/graphql_shared/utils'; Vue.use(VueApollo); -jest.useFakeTimers(); - describe('OrganizationSelect', () => { let wrapper; let mockApollo; // Mocks - const [organizationMock] = organizationsMock; - - // Stubs - const GlAlert = { - template: '<div><slot /></div>', + const [organization] = nodes; + const organizations = { + nodes, + pageInfo, }; // Props @@ -44,23 +44,26 @@ describe('OrganizationSelect', () => { const findEntitySelect = () => wrapper.findComponent(EntitySelect); const findAlert = () => wrapper.findComponent(GlAlert); + // Mock handlers const handleInput = jest.fn(); + const getCurrentUserOrganizationsQueryHandler = jest.fn().mockResolvedValue({ + data: { currentUser: { id: 'gid://gitlab/User/1', __typename: 'CurrentUser', organizations } }, + }); + const getOrganizationQueryHandler = jest.fn().mockResolvedValue({ + data: { organization }, + }); // Helpers - const createComponent = ({ props = {}, mockResolvers = resolvers, handlers } = {}) => { - mockApollo = createMockApollo( - handlers || [ - [ - organizationsQuery, - jest.fn().mockResolvedValueOnce({ - data: { currentUser: { id: 1, organizations: { nodes: organizationsMock } } }, - }), - ], - ], - mockResolvers, - ); - - wrapper = shallowMountExtended(OrganizationSelect, { + const createComponent = ({ + props = {}, + handlers = [ + [getCurrentUserOrganizationsQuery, getCurrentUserOrganizationsQueryHandler], + [getOrganizationQuery, getOrganizationQueryHandler], + ], + } = {}) => { + mockApollo = createMockApollo(handlers); + + wrapper = mountExtended(OrganizationSelect, { apolloProvider: mockApollo, propsData: { label, @@ -70,10 +73,6 @@ describe('OrganizationSelect', () => { toggleClass, ...props, }, - stubs: { - GlAlert, - EntitySelect, - }, listeners: { input: handleInput, }, @@ -81,10 +80,6 @@ describe('OrganizationSelect', () => { }; const openListbox = () => findListbox().vm.$emit('shown'); - afterEach(() => { - mockApollo = null; - }); - describe('entity_select props', () => { beforeEach(() => { createComponent(); @@ -107,40 +102,31 @@ describe('OrganizationSelect', () => { describe('on mount', () => { it('fetches organizations when the listbox is opened', async () => { createComponent(); - await nextTick(); - jest.runAllTimers(); - await waitForPromises(); - openListbox(); - jest.runAllTimers(); await waitForPromises(); - expect(findListbox().props('items')).toEqual([ - { text: organizationsMock[0].name, value: 1 }, - { text: organizationsMock[1].name, value: 2 }, - { text: organizationsMock[2].name, value: 3 }, - ]); + + const expectedItems = nodes.map((node) => ({ + ...node, + text: node.name, + value: getIdFromGraphQLId(node.id), + })); + + expect(findListbox().props('items')).toEqual(expectedItems); }); describe('with an initial selection', () => { it("fetches the initially selected value's name", async () => { - createComponent({ props: { initialSelection: organizationMock.id } }); - await nextTick(); - jest.runAllTimers(); + createComponent({ props: { initialSelection: organization.id } }); await waitForPromises(); - expect(findListbox().props('toggleText')).toBe(organizationMock.name); + expect(findListbox().props('toggleText')).toBe(organization.name); }); it('show an error if fetching initially selected fails', async () => { - const mockResolvers = { - Query: { - organization: jest.fn().mockRejectedValueOnce(new Error()), - }, - }; - - createComponent({ props: { initialSelection: organizationMock.id }, mockResolvers }); - await nextTick(); - jest.runAllTimers(); + createComponent({ + props: { initialSelection: organization.id }, + handlers: [[getOrganizationQuery, jest.fn().mockRejectedValueOnce()]], + }); expect(findAlert().exists()).toBe(false); @@ -152,18 +138,59 @@ describe('OrganizationSelect', () => { }); }); + describe('when listbox bottom is reached and there are more organizations to load', () => { + const [firstPage, secondPage] = chunk(nodes, Math.ceil(nodes.length / 2)); + const getCurrentUserOrganizationsQueryMultiplePagesHandler = jest + .fn() + .mockResolvedValueOnce({ + data: { + currentUser: { + id: 'gid://gitlab/User/1', + __typename: 'CurrentUser', + organizations: { nodes: firstPage, pageInfo }, + }, + }, + }) + .mockResolvedValueOnce({ + data: { + currentUser: { + id: 'gid://gitlab/User/1', + __typename: 'CurrentUser', + organizations: { nodes: secondPage, pageInfo: pageInfoEmpty }, + }, + }, + }); + + beforeEach(async () => { + createComponent({ + handlers: [ + [getCurrentUserOrganizationsQuery, getCurrentUserOrganizationsQueryMultiplePagesHandler], + [getOrganizationQuery, getOrganizationQueryHandler], + ], + }); + openListbox(); + await waitForPromises(); + + findListbox().vm.$emit('bottom-reached'); + await waitForPromises(); + }); + + it('calls graphQL query correct `after` variable', () => { + expect(getCurrentUserOrganizationsQueryMultiplePagesHandler).toHaveBeenCalledWith({ + after: pageInfo.endCursor, + first: DEFAULT_PER_PAGE, + }); + expect(findListbox().props('infiniteScroll')).toBe(false); + }); + }); + it('shows an error when fetching organizations fails', async () => { createComponent({ - handlers: [[organizationsQuery, jest.fn().mockRejectedValueOnce(new Error())]], + handlers: [[getCurrentUserOrganizationsQuery, jest.fn().mockRejectedValueOnce()]], }); - await nextTick(); - jest.runAllTimers(); - await waitForPromises(); - openListbox(); expect(findAlert().exists()).toBe(false); - jest.runAllTimers(); await waitForPromises(); expect(findAlert().exists()).toBe(true); |