import { InMemoryCache } from 'apollo-cache-inmemory'; import MockAdapter from 'axios-mock-adapter'; import { createMockClient } from 'mock-apollo-client'; import waitForPromises from 'helpers/wait_for_promises'; import { STATUSES } from '~/import_entities/constants'; import { clientTypenames, createResolvers, } from '~/import_entities/import_groups/graphql/client_factory'; import { LocalStorageCache } from '~/import_entities/import_groups/graphql/services/local_storage_cache'; import importGroupsMutation from '~/import_entities/import_groups/graphql/mutations/import_groups.mutation.graphql'; import updateImportStatusMutation from '~/import_entities/import_groups/graphql/mutations/update_import_status.mutation.graphql'; import availableNamespacesQuery from '~/import_entities/import_groups/graphql/queries/available_namespaces.query.graphql'; import bulkImportSourceGroupsQuery from '~/import_entities/import_groups/graphql/queries/bulk_import_source_groups.query.graphql'; import axios from '~/lib/utils/axios_utils'; import httpStatus from '~/lib/utils/http_status'; import { statusEndpointFixture, availableNamespacesFixture } from './fixtures'; jest.mock('~/flash'); jest.mock('~/import_entities/import_groups/graphql/services/local_storage_cache', () => ({ LocalStorageCache: jest.fn().mockImplementation(function mock() { this.get = jest.fn(); this.set = jest.fn(); this.updateStatusByJobId = jest.fn(); }), })); const FAKE_ENDPOINTS = { status: '/fake_status_url', availableNamespaces: '/fake_available_namespaces', createBulkImport: '/fake_create_bulk_import', jobs: '/fake_jobs', }; describe('Bulk import resolvers', () => { let axiosMockAdapter; let client; const createClient = (extraResolverArgs) => { const mockedClient = createMockClient({ cache: new InMemoryCache({ fragmentMatcher: { match: () => true }, addTypename: false, }), resolvers: createResolvers({ endpoints: FAKE_ENDPOINTS, ...extraResolverArgs }), }); return mockedClient; }; let results; beforeEach(async () => { axiosMockAdapter = new MockAdapter(axios); client = createClient(); axiosMockAdapter.onGet(FAKE_ENDPOINTS.status).reply(httpStatus.OK, statusEndpointFixture); axiosMockAdapter.onGet(FAKE_ENDPOINTS.availableNamespaces).reply( httpStatus.OK, availableNamespacesFixture.map((ns) => ({ id: ns.id, full_path: ns.fullPath, })), ); client.watchQuery({ query: bulkImportSourceGroupsQuery }).subscribe(({ data }) => { results = data.bulkImportSourceGroups.nodes; }); return waitForPromises(); }); afterEach(() => { axiosMockAdapter.restore(); }); describe('queries', () => { describe('availableNamespaces', () => { let namespacesResults; beforeEach(async () => { const response = await client.query({ query: availableNamespacesQuery }); namespacesResults = response.data.availableNamespaces; }); it('mirrors REST endpoint response fields', () => { const extractRelevantFields = (obj) => ({ id: obj.id, full_path: obj.full_path }); expect(namespacesResults.map(extractRelevantFields)).toStrictEqual( availableNamespacesFixture.map(extractRelevantFields), ); }); }); describe('bulkImportSourceGroups', () => { it('respects cached import state when provided by group manager', async () => { const [localStorageCache] = LocalStorageCache.mock.instances; const CACHED_DATA = { progress: { id: 'DEMO', status: 'cached', }, }; localStorageCache.get.mockReturnValueOnce(CACHED_DATA); const updatedResults = await client.query({ query: bulkImportSourceGroupsQuery, fetchPolicy: 'no-cache', }); expect(updatedResults.data.bulkImportSourceGroups.nodes[0].progress).toStrictEqual({ __typename: clientTypenames.BulkImportProgress, ...CACHED_DATA.progress, }); }); describe('when called', () => { beforeEach(async () => { const response = await client.query({ query: bulkImportSourceGroupsQuery }); results = response.data.bulkImportSourceGroups.nodes; }); it('mirrors REST endpoint response fields', () => { const MIRRORED_FIELDS = [ { from: 'id', to: 'id' }, { from: 'full_name', to: 'fullName' }, { from: 'full_path', to: 'fullPath' }, { from: 'web_url', to: 'webUrl' }, ]; expect( results.every((r, idx) => MIRRORED_FIELDS.every( (field) => r[field.to] === statusEndpointFixture.importable_data[idx][field.from], ), ), ).toBe(true); }); it('populates each result instance with empty status', () => { expect(results.every((r) => r.progress === null)).toBe(true); }); }); it.each` variable | queryParam | value ${'filter'} | ${'filter'} | ${'demo'} ${'perPage'} | ${'per_page'} | ${30} ${'page'} | ${'page'} | ${3} `( 'properly passes GraphQL variable $variable as REST $queryParam query parameter', async ({ variable, queryParam, value }) => { axiosMockAdapter.resetHistory(); await client.query({ query: bulkImportSourceGroupsQuery, variables: { [variable]: value }, }); const restCall = axiosMockAdapter.history.get.find( (q) => q.url === FAKE_ENDPOINTS.status, ); expect(restCall.params[queryParam]).toBe(value); }, ); }); }); describe('mutations', () => { beforeEach(() => { axiosMockAdapter.onPost(FAKE_ENDPOINTS.createBulkImport).reply(httpStatus.OK, { id: 1 }); }); describe('importGroup', () => { it('sets import status to CREATED when request completes', async () => { await client.mutate({ mutation: importGroupsMutation, variables: { importRequests: [ { sourceGroupId: statusEndpointFixture.importable_data[0].id, newName: 'test', targetNamespace: 'root', }, ], }, }); await axios.waitForAll(); expect(results[0].progress.status).toBe(STATUSES.CREATED); }); }); it('updateImportStatus updates status', async () => { const NEW_STATUS = 'dummy'; await client.mutate({ mutation: importGroupsMutation, variables: { importRequests: [ { sourceGroupId: statusEndpointFixture.importable_data[0].id, newName: 'test', targetNamespace: 'root', }, ], }, }); await axios.waitForAll(); await waitForPromises(); const { id } = results[0].progress; const { data: { updateImportStatus: statusInResponse }, } = await client.mutate({ mutation: updateImportStatusMutation, variables: { id, status: NEW_STATUS }, }); expect(statusInResponse).toStrictEqual({ __typename: clientTypenames.BulkImportProgress, id, status: NEW_STATUS, }); }); }); });