diff options
Diffstat (limited to 'spec/frontend/import_entities/import_groups/graphql')
5 files changed, 159 insertions, 552 deletions
diff --git a/spec/frontend/import_entities/import_groups/graphql/client_factory_spec.js b/spec/frontend/import_entities/import_groups/graphql/client_factory_spec.js index e1d65095888..f3447494578 100644 --- a/spec/frontend/import_entities/import_groups/graphql/client_factory_spec.js +++ b/spec/frontend/import_entities/import_groups/graphql/client_factory_spec.js @@ -2,32 +2,27 @@ 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 createFlash from '~/flash'; import { STATUSES } from '~/import_entities/constants'; import { clientTypenames, createResolvers, } from '~/import_entities/import_groups/graphql/client_factory'; -import addValidationErrorMutation from '~/import_entities/import_groups/graphql/mutations/add_validation_error.mutation.graphql'; +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 removeValidationErrorMutation from '~/import_entities/import_groups/graphql/mutations/remove_validation_error.mutation.graphql'; -import setImportProgressMutation from '~/import_entities/import_groups/graphql/mutations/set_import_progress.mutation.graphql'; -import setImportTargetMutation from '~/import_entities/import_groups/graphql/mutations/set_import_target.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 bulkImportSourceGroupQuery from '~/import_entities/import_groups/graphql/queries/bulk_import_source_group.query.graphql'; import bulkImportSourceGroupsQuery from '~/import_entities/import_groups/graphql/queries/bulk_import_source_groups.query.graphql'; -import groupAndProjectQuery from '~/import_entities/import_groups/graphql/queries/group_and_project.query.graphql'; -import { StatusPoller } from '~/import_entities/import_groups/graphql/services/status_poller'; 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/status_poller', () => ({ - StatusPoller: jest.fn().mockImplementation(function mock() { - this.startPolling = jest.fn(); +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(); }), })); @@ -38,13 +33,6 @@ const FAKE_ENDPOINTS = { jobs: '/fake_jobs', }; -const FAKE_GROUP_AND_PROJECTS_QUERY_HANDLER = jest.fn().mockResolvedValue({ - data: { - existingGroup: null, - existingProject: null, - }, -}); - describe('Bulk import resolvers', () => { let axiosMockAdapter; let client; @@ -58,14 +46,28 @@ describe('Bulk import resolvers', () => { resolvers: createResolvers({ endpoints: FAKE_ENDPOINTS, ...extraResolverArgs }), }); - mockedClient.setRequestHandler(groupAndProjectQuery, FAKE_GROUP_AND_PROJECTS_QUERY_HANDLER); - return mockedClient; }; - beforeEach(() => { + 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(() => { @@ -74,104 +76,41 @@ describe('Bulk import resolvers', () => { describe('queries', () => { describe('availableNamespaces', () => { - let results; - + let namespacesResults; beforeEach(async () => { - axiosMockAdapter - .onGet(FAKE_ENDPOINTS.availableNamespaces) - .reply(httpStatus.OK, availableNamespacesFixture); - const response = await client.query({ query: availableNamespacesQuery }); - results = response.data.availableNamespaces; + namespacesResults = response.data.availableNamespaces; }); it('mirrors REST endpoint response fields', () => { const extractRelevantFields = (obj) => ({ id: obj.id, full_path: obj.full_path }); - expect(results.map(extractRelevantFields)).toStrictEqual( + expect(namespacesResults.map(extractRelevantFields)).toStrictEqual( availableNamespacesFixture.map(extractRelevantFields), ); }); }); - describe('bulkImportSourceGroup', () => { - beforeEach(async () => { - axiosMockAdapter.onGet(FAKE_ENDPOINTS.status).reply(httpStatus.OK, statusEndpointFixture); - axiosMockAdapter - .onGet(FAKE_ENDPOINTS.availableNamespaces) - .reply(httpStatus.OK, availableNamespacesFixture); - - return client.query({ - query: bulkImportSourceGroupsQuery, - }); - }); - - it('returns group', async () => { - const { id } = statusEndpointFixture.importable_data[0]; - const { - data: { bulkImportSourceGroup: group }, - } = await client.query({ - query: bulkImportSourceGroupQuery, - variables: { id: id.toString() }, - }); - - expect(group).toMatchObject(statusEndpointFixture.importable_data[0]); - }); - }); - describe('bulkImportSourceGroups', () => { - let results; - - beforeEach(async () => { - axiosMockAdapter.onGet(FAKE_ENDPOINTS.status).reply(httpStatus.OK, statusEndpointFixture); - axiosMockAdapter - .onGet(FAKE_ENDPOINTS.availableNamespaces) - .reply(httpStatus.OK, availableNamespacesFixture); - }); - it('respects cached import state when provided by group manager', async () => { - const FAKE_JOB_ID = '1'; - const FAKE_STATUS = 'DEMO_STATUS'; - const FAKE_IMPORT_TARGET = { - new_name: 'test-name', - target_namespace: 'test-namespace', + const [localStorageCache] = LocalStorageCache.mock.instances; + const CACHED_DATA = { + progress: { + id: 'DEMO', + status: 'cached', + }, }; - const TARGET_INDEX = 0; + localStorageCache.get.mockReturnValueOnce(CACHED_DATA); - const clientWithMockedManager = createClient({ - GroupsManager: jest.fn().mockImplementation(() => ({ - getImportStateFromStorageByGroupId(groupId) { - if (groupId === statusEndpointFixture.importable_data[TARGET_INDEX].id) { - return { - jobId: FAKE_JOB_ID, - importState: { - status: FAKE_STATUS, - importTarget: FAKE_IMPORT_TARGET, - }, - }; - } - - return null; - }, - })), - }); - - const clientResponse = await clientWithMockedManager.query({ + const updatedResults = await client.query({ query: bulkImportSourceGroupsQuery, + fetchPolicy: 'no-cache', }); - const clientResults = clientResponse.data.bulkImportSourceGroups.nodes; - - expect(clientResults[TARGET_INDEX].import_target).toStrictEqual(FAKE_IMPORT_TARGET); - expect(clientResults[TARGET_INDEX].progress.status).toBe(FAKE_STATUS); - }); - - it('populates each result instance with empty import_target when there are no available namespaces', async () => { - axiosMockAdapter.onGet(FAKE_ENDPOINTS.availableNamespaces).reply(httpStatus.OK, []); - - const response = await client.query({ query: bulkImportSourceGroupsQuery }); - results = response.data.bulkImportSourceGroups.nodes; - expect(results.every((r) => r.import_target.target_namespace === '')).toBe(true); + expect(updatedResults.data.bulkImportSourceGroups.nodes[0].progress).toStrictEqual({ + __typename: clientTypenames.BulkImportProgress, + ...CACHED_DATA.progress, + }); }); describe('when called', () => { @@ -181,37 +120,23 @@ describe('Bulk import resolvers', () => { }); it('mirrors REST endpoint response fields', () => { - const MIRRORED_FIELDS = ['id', 'full_name', 'full_path', 'web_url']; + 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] === statusEndpointFixture.importable_data[idx][field], + (field) => r[field.to] === statusEndpointFixture.importable_data[idx][field.from], ), ), ).toBe(true); }); - it('populates each result instance with status default to none', () => { - expect(results.every((r) => r.progress.status === STATUSES.NONE)).toBe(true); - }); - - it('populates each result instance with import_target defaulted to first available namespace', () => { - expect( - results.every( - (r) => r.import_target.target_namespace === availableNamespacesFixture[0].full_path, - ), - ).toBe(true); - }); - - it('starts polling when request completes', async () => { - const [statusPoller] = StatusPoller.mock.instances; - expect(statusPoller.startPolling).toHaveBeenCalled(); - }); - - it('requests validation status when request completes', async () => { - expect(FAKE_GROUP_AND_PROJECTS_QUERY_HANDLER).not.toHaveBeenCalled(); - jest.runOnlyPendingTimers(); - expect(FAKE_GROUP_AND_PROJECTS_QUERY_HANDLER).toHaveBeenCalled(); + it('populates each result instance with empty status', () => { + expect(results.every((r) => r.progress === null)).toBe(true); }); }); @@ -223,6 +148,7 @@ describe('Bulk import resolvers', () => { `( 'properly passes GraphQL variable $variable as REST $queryParam query parameter', async ({ variable, queryParam, value }) => { + axiosMockAdapter.resetHistory(); await client.query({ query: bulkImportSourceGroupsQuery, variables: { [variable]: value }, @@ -237,275 +163,61 @@ describe('Bulk import resolvers', () => { }); describe('mutations', () => { - const GROUP_ID = 1; - beforeEach(() => { - client.writeQuery({ - query: bulkImportSourceGroupsQuery, - data: { - bulkImportSourceGroups: { - nodes: [ - { - __typename: clientTypenames.BulkImportSourceGroup, - id: GROUP_ID, - progress: { - id: `test-${GROUP_ID}`, - status: STATUSES.NONE, - }, - web_url: 'https://fake.host/1', - full_path: 'fake_group_1', - full_name: 'fake_name_1', - import_target: { - target_namespace: 'root', - new_name: 'group1', - }, - last_import_target: { - target_namespace: 'root', - new_name: 'group1', - }, - validation_errors: [], - }, - ], - pageInfo: { - page: 1, - perPage: 20, - total: 37, - totalPages: 2, - }, - }, - }, - }); + axiosMockAdapter.onPost(FAKE_ENDPOINTS.createBulkImport).reply(httpStatus.OK, { id: 1 }); }); - describe('setImportTarget', () => { - it('updates group target namespace and name', async () => { - const NEW_TARGET_NAMESPACE = 'target'; - const NEW_NAME = 'new'; - - const { - data: { - setImportTarget: { - id: idInResponse, - import_target: { target_namespace: namespaceInResponse, new_name: newNameInResponse }, - }, - }, - } = await client.mutate({ - mutation: setImportTargetMutation, - variables: { - sourceGroupId: GROUP_ID, - targetNamespace: NEW_TARGET_NAMESPACE, - newName: NEW_NAME, - }, - }); - - expect(idInResponse).toBe(GROUP_ID); - expect(namespaceInResponse).toBe(NEW_TARGET_NAMESPACE); - expect(newNameInResponse).toBe(NEW_NAME); - }); - - it('invokes validation', async () => { - const NEW_TARGET_NAMESPACE = 'target'; - const NEW_NAME = 'new'; - + describe('importGroup', () => { + it('sets import status to CREATED when request completes', async () => { await client.mutate({ - mutation: setImportTargetMutation, + mutation: importGroupsMutation, variables: { - sourceGroupId: GROUP_ID, - targetNamespace: NEW_TARGET_NAMESPACE, - newName: NEW_NAME, + importRequests: [ + { + sourceGroupId: statusEndpointFixture.importable_data[0].id, + newName: 'test', + targetNamespace: 'root', + }, + ], }, }); - expect(FAKE_GROUP_AND_PROJECTS_QUERY_HANDLER).toHaveBeenCalledWith({ - fullPath: `${NEW_TARGET_NAMESPACE}/${NEW_NAME}`, - }); - }); - }); - - describe('importGroup', () => { - it('sets status to SCHEDULING when request initiates', async () => { - axiosMockAdapter.onPost(FAKE_ENDPOINTS.createBulkImport).reply(() => new Promise(() => {})); - - client.mutate({ - mutation: importGroupsMutation, - variables: { sourceGroupIds: [GROUP_ID] }, - }); - await waitForPromises(); - - const { - bulkImportSourceGroups: { nodes: intermediateResults }, - } = client.readQuery({ - query: bulkImportSourceGroupsQuery, - }); - - expect(intermediateResults[0].progress.status).toBe(STATUSES.SCHEDULING); - }); - - describe('when request completes', () => { - let results; - - beforeEach(() => { - client - .watchQuery({ - query: bulkImportSourceGroupsQuery, - fetchPolicy: 'cache-only', - }) - .subscribe(({ data }) => { - results = data.bulkImportSourceGroups.nodes; - }); - }); - - it('sets import status to CREATED when request completes', async () => { - axiosMockAdapter.onPost(FAKE_ENDPOINTS.createBulkImport).reply(httpStatus.OK, { id: 1 }); - await client.mutate({ - mutation: importGroupsMutation, - variables: { sourceGroupIds: [GROUP_ID] }, - }); - await waitForPromises(); - - expect(results[0].progress.status).toBe(STATUSES.CREATED); - }); - - it('resets status to NONE if request fails', async () => { - axiosMockAdapter - .onPost(FAKE_ENDPOINTS.createBulkImport) - .reply(httpStatus.INTERNAL_SERVER_ERROR); - - client - .mutate({ - mutation: [importGroupsMutation], - variables: { sourceGroupIds: [GROUP_ID] }, - }) - .catch(() => {}); - await waitForPromises(); - - expect(results[0].progress.status).toBe(STATUSES.NONE); - }); - }); - - it('shows default error message when server error is not provided', async () => { - axiosMockAdapter - .onPost(FAKE_ENDPOINTS.createBulkImport) - .reply(httpStatus.INTERNAL_SERVER_ERROR); - - client - .mutate({ - mutation: importGroupsMutation, - variables: { sourceGroupIds: [GROUP_ID] }, - }) - .catch(() => {}); - await waitForPromises(); - - expect(createFlash).toHaveBeenCalledWith({ message: 'Importing the group failed' }); - }); - - it('shows provided error message when error is included in backend response', async () => { - const CUSTOM_MESSAGE = 'custom message'; - - axiosMockAdapter - .onPost(FAKE_ENDPOINTS.createBulkImport) - .reply(httpStatus.INTERNAL_SERVER_ERROR, { error: CUSTOM_MESSAGE }); - - client - .mutate({ - mutation: importGroupsMutation, - variables: { sourceGroupIds: [GROUP_ID] }, - }) - .catch(() => {}); - await waitForPromises(); - - expect(createFlash).toHaveBeenCalledWith({ message: CUSTOM_MESSAGE }); + await axios.waitForAll(); + expect(results[0].progress.status).toBe(STATUSES.CREATED); }); }); - it('setImportProgress updates group progress and sets import target', async () => { + it('updateImportStatus updates status', async () => { const NEW_STATUS = 'dummy'; - const FAKE_JOB_ID = 5; - const IMPORT_TARGET = { - __typename: 'ClientBulkImportTarget', - new_name: 'fake_name', - target_namespace: 'fake_target', - }; - const { - data: { - setImportProgress: { progress, last_import_target: lastImportTarget }, - }, - } = await client.mutate({ - mutation: setImportProgressMutation, + await client.mutate({ + mutation: importGroupsMutation, variables: { - sourceGroupId: GROUP_ID, - status: NEW_STATUS, - jobId: FAKE_JOB_ID, - importTarget: IMPORT_TARGET, + importRequests: [ + { + sourceGroupId: statusEndpointFixture.importable_data[0].id, + newName: 'test', + targetNamespace: 'root', + }, + ], }, }); + await axios.waitForAll(); + await waitForPromises(); - expect(lastImportTarget).toStrictEqual(IMPORT_TARGET); - - expect(progress).toStrictEqual({ - __typename: clientTypenames.BulkImportProgress, - id: FAKE_JOB_ID, - status: NEW_STATUS, - }); - }); + const { id } = results[0].progress; - it('updateImportStatus returns new status', async () => { - const NEW_STATUS = 'dummy'; - const FAKE_JOB_ID = 5; const { data: { updateImportStatus: statusInResponse }, } = await client.mutate({ mutation: updateImportStatusMutation, - variables: { id: FAKE_JOB_ID, status: NEW_STATUS }, + variables: { id, status: NEW_STATUS }, }); expect(statusInResponse).toStrictEqual({ __typename: clientTypenames.BulkImportProgress, - id: FAKE_JOB_ID, + id, status: NEW_STATUS, }); }); - - it('addValidationError adds error to group', async () => { - const FAKE_FIELD = 'some-field'; - const FAKE_MESSAGE = 'some-message'; - const { - data: { - addValidationError: { validation_errors: validationErrors }, - }, - } = await client.mutate({ - mutation: addValidationErrorMutation, - variables: { sourceGroupId: GROUP_ID, field: FAKE_FIELD, message: FAKE_MESSAGE }, - }); - - expect(validationErrors).toStrictEqual([ - { - __typename: clientTypenames.BulkImportValidationError, - field: FAKE_FIELD, - message: FAKE_MESSAGE, - }, - ]); - }); - - it('removeValidationError removes error from group', async () => { - const FAKE_FIELD = 'some-field'; - const FAKE_MESSAGE = 'some-message'; - - await client.mutate({ - mutation: addValidationErrorMutation, - variables: { sourceGroupId: GROUP_ID, field: FAKE_FIELD, message: FAKE_MESSAGE }, - }); - - const { - data: { - removeValidationError: { validation_errors: validationErrors }, - }, - } = await client.mutate({ - mutation: removeValidationErrorMutation, - variables: { sourceGroupId: GROUP_ID, field: FAKE_FIELD }, - }); - - expect(validationErrors).toStrictEqual([]); - }); }); }); diff --git a/spec/frontend/import_entities/import_groups/graphql/fixtures.js b/spec/frontend/import_entities/import_groups/graphql/fixtures.js index d1bd52693b6..5f6f9987a8f 100644 --- a/spec/frontend/import_entities/import_groups/graphql/fixtures.js +++ b/spec/frontend/import_entities/import_groups/graphql/fixtures.js @@ -1,24 +1,24 @@ +import { STATUSES } from '~/import_entities/constants'; import { clientTypenames } from '~/import_entities/import_groups/graphql/client_factory'; export const generateFakeEntry = ({ id, status, ...rest }) => ({ __typename: clientTypenames.BulkImportSourceGroup, - web_url: `https://fake.host/${id}`, - full_path: `fake_group_${id}`, - full_name: `fake_name_${id}`, - import_target: { - target_namespace: 'root', - new_name: `group${id}`, - }, - last_import_target: { - target_namespace: 'root', - new_name: `last-group${id}`, + webUrl: `https://fake.host/${id}`, + fullPath: `fake_group_${id}`, + fullName: `fake_name_${id}`, + lastImportTarget: { + id, + targetNamespace: 'root', + newName: `group${id}`, }, id, - progress: { - id: `test-${id}`, - status, - }, - validation_errors: [], + progress: + status === STATUSES.NONE || status === STATUSES.PENDING + ? null + : { + id, + status, + }, ...rest, }); @@ -51,9 +51,9 @@ export const statusEndpointFixture = { ], }; -export const availableNamespacesFixture = [ - { id: 24, full_path: 'Commit451' }, - { id: 22, full_path: 'gitlab-org' }, - { id: 23, full_path: 'gnuwget' }, - { id: 25, full_path: 'jashkenas' }, -]; +export const availableNamespacesFixture = Object.freeze([ + { id: 24, fullPath: 'Commit451' }, + { id: 22, fullPath: 'gitlab-org' }, + { id: 23, fullPath: 'gnuwget' }, + { id: 25, fullPath: 'jashkenas' }, +]); diff --git a/spec/frontend/import_entities/import_groups/graphql/services/local_storage_cache_spec.js b/spec/frontend/import_entities/import_groups/graphql/services/local_storage_cache_spec.js new file mode 100644 index 00000000000..b44a2767ad8 --- /dev/null +++ b/spec/frontend/import_entities/import_groups/graphql/services/local_storage_cache_spec.js @@ -0,0 +1,61 @@ +import { + KEY, + LocalStorageCache, +} from '~/import_entities/import_groups/graphql/services/local_storage_cache'; + +describe('Local storage cache', () => { + let cache; + let storage; + + beforeEach(() => { + storage = { + getItem: jest.fn(), + setItem: jest.fn(), + }; + + cache = new LocalStorageCache({ storage }); + }); + + describe('storage management', () => { + const IMPORT_URL = 'http://fake.url'; + + it('loads state from storage on creation', () => { + expect(storage.getItem).toHaveBeenCalledWith(KEY); + }); + + it('saves to storage when set is called', () => { + const STORAGE_CONTENT = { fake: 'content ' }; + cache.set(IMPORT_URL, STORAGE_CONTENT); + expect(storage.setItem).toHaveBeenCalledWith( + KEY, + JSON.stringify({ [IMPORT_URL]: STORAGE_CONTENT }), + ); + }); + + it('updates status by job id', () => { + const CHANGED_STATUS = 'changed'; + const JOB_ID = 2; + + cache.set(IMPORT_URL, { + progress: { + id: JOB_ID, + status: 'original', + }, + }); + + cache.updateStatusByJobId(JOB_ID, CHANGED_STATUS); + + expect(storage.setItem).toHaveBeenCalledWith( + KEY, + JSON.stringify({ + [IMPORT_URL]: { + progress: { + id: JOB_ID, + status: CHANGED_STATUS, + }, + }, + }), + ); + }); + }); +}); diff --git a/spec/frontend/import_entities/import_groups/graphql/services/source_groups_manager_spec.js b/spec/frontend/import_entities/import_groups/graphql/services/source_groups_manager_spec.js deleted file mode 100644 index f06babcb149..00000000000 --- a/spec/frontend/import_entities/import_groups/graphql/services/source_groups_manager_spec.js +++ /dev/null @@ -1,64 +0,0 @@ -import { - KEY, - SourceGroupsManager, -} from '~/import_entities/import_groups/graphql/services/source_groups_manager'; - -const FAKE_SOURCE_URL = 'http://demo.host'; - -describe('SourceGroupsManager', () => { - let manager; - let storage; - - beforeEach(() => { - storage = { - getItem: jest.fn(), - setItem: jest.fn(), - }; - - manager = new SourceGroupsManager({ storage, sourceUrl: FAKE_SOURCE_URL }); - }); - - describe('storage management', () => { - const IMPORT_ID = 1; - const IMPORT_TARGET = { new_name: 'demo', target_namespace: 'foo' }; - const STATUS = 'FAKE_STATUS'; - const FAKE_GROUP = { id: 1, import_target: IMPORT_TARGET, status: STATUS }; - - it('loads state from storage on creation', () => { - expect(storage.getItem).toHaveBeenCalledWith(KEY); - }); - - it('saves to storage when createImportState is called', () => { - const FAKE_STATUS = 'fake;'; - manager.createImportState(IMPORT_ID, { status: FAKE_STATUS, groups: [FAKE_GROUP] }); - const storedObject = JSON.parse(storage.setItem.mock.calls[0][1]); - expect(Object.values(storedObject)[0]).toStrictEqual({ - status: FAKE_STATUS, - groups: [ - { - id: FAKE_GROUP.id, - importTarget: IMPORT_TARGET, - }, - ], - }); - }); - - it('updates storage when previous state is available', () => { - const CHANGED_STATUS = 'changed'; - - manager.createImportState(IMPORT_ID, { status: STATUS, groups: [FAKE_GROUP] }); - - manager.updateImportProgress(IMPORT_ID, CHANGED_STATUS); - const storedObject = JSON.parse(storage.setItem.mock.calls[1][1]); - expect(Object.values(storedObject)[0]).toStrictEqual({ - status: CHANGED_STATUS, - groups: [ - { - id: FAKE_GROUP.id, - importTarget: IMPORT_TARGET, - }, - ], - }); - }); - }); -}); diff --git a/spec/frontend/import_entities/import_groups/graphql/services/status_poller_spec.js b/spec/frontend/import_entities/import_groups/graphql/services/status_poller_spec.js deleted file mode 100644 index 9c47647c430..00000000000 --- a/spec/frontend/import_entities/import_groups/graphql/services/status_poller_spec.js +++ /dev/null @@ -1,102 +0,0 @@ -import MockAdapter from 'axios-mock-adapter'; -import Visibility from 'visibilityjs'; -import createFlash from '~/flash'; -import { STATUSES } from '~/import_entities/constants'; -import { StatusPoller } from '~/import_entities/import_groups/graphql/services/status_poller'; -import axios from '~/lib/utils/axios_utils'; -import Poll from '~/lib/utils/poll'; - -jest.mock('visibilityjs'); -jest.mock('~/flash'); -jest.mock('~/lib/utils/poll'); -jest.mock('~/import_entities/import_groups/graphql/services/source_groups_manager', () => ({ - SourceGroupsManager: jest.fn().mockImplementation(function mock() { - this.setImportStatus = jest.fn(); - this.findByImportId = jest.fn(); - }), -})); - -const FAKE_POLL_PATH = '/fake/poll/path'; - -describe('Bulk import status poller', () => { - let poller; - let mockAdapter; - let updateImportStatus; - - const getPollHistory = () => mockAdapter.history.get.filter((x) => x.url === FAKE_POLL_PATH); - - beforeEach(() => { - mockAdapter = new MockAdapter(axios); - mockAdapter.onGet(FAKE_POLL_PATH).reply(200, {}); - updateImportStatus = jest.fn(); - poller = new StatusPoller({ updateImportStatus, pollPath: FAKE_POLL_PATH }); - }); - - it('creates poller with proper config', () => { - expect(Poll.mock.calls).toHaveLength(1); - const [[pollConfig]] = Poll.mock.calls; - expect(typeof pollConfig.method).toBe('string'); - - const pollOperation = pollConfig.resource[pollConfig.method]; - expect(typeof pollOperation).toBe('function'); - }); - - it('invokes axios when polling is performed', async () => { - const [[pollConfig]] = Poll.mock.calls; - const pollOperation = pollConfig.resource[pollConfig.method]; - expect(getPollHistory()).toHaveLength(0); - - pollOperation(); - await axios.waitForAll(); - - expect(getPollHistory()).toHaveLength(1); - }); - - it('subscribes to visibility changes', () => { - expect(Visibility.change).toHaveBeenCalled(); - }); - - it.each` - isHidden | action - ${true} | ${'stop'} - ${false} | ${'restart'} - `('$action polling when hidden is $isHidden', ({ action, isHidden }) => { - const [pollInstance] = Poll.mock.instances; - const [[changeHandler]] = Visibility.change.mock.calls; - Visibility.hidden.mockReturnValue(isHidden); - expect(pollInstance[action]).not.toHaveBeenCalled(); - - changeHandler(); - - expect(pollInstance[action]).toHaveBeenCalled(); - }); - - it('does not perform polling when constructed', async () => { - await axios.waitForAll(); - - expect(getPollHistory()).toHaveLength(0); - }); - - it('immediately start polling when requested', async () => { - const [pollInstance] = Poll.mock.instances; - - poller.startPolling(); - - expect(pollInstance.makeRequest).toHaveBeenCalled(); - }); - - it('when error occurs shows flash with error', () => { - const [[pollConfig]] = Poll.mock.calls; - pollConfig.errorCallback(); - expect(createFlash).toHaveBeenCalled(); - }); - - it('when success response arrives updates relevant group status', () => { - const FAKE_ID = 5; - const [[pollConfig]] = Poll.mock.calls; - const FAKE_RESPONSE = { id: FAKE_ID, status_name: STATUSES.FINISHED }; - pollConfig.successCallback({ data: [FAKE_RESPONSE] }); - - expect(updateImportStatus).toHaveBeenCalledWith(FAKE_RESPONSE); - }); -}); |