summaryrefslogtreecommitdiff
path: root/spec/frontend/import_entities/import_groups
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-02-18 10:34:06 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-02-18 10:34:06 +0000
commit859a6fb938bb9ee2a317c46dfa4fcc1af49608f0 (patch)
treed7f2700abe6b4ffcb2dcfc80631b2d87d0609239 /spec/frontend/import_entities/import_groups
parent446d496a6d000c73a304be52587cd9bbc7493136 (diff)
downloadgitlab-ce-859a6fb938bb9ee2a317c46dfa4fcc1af49608f0.tar.gz
Add latest changes from gitlab-org/gitlab@13-9-stable-eev13.9.0-rc42
Diffstat (limited to 'spec/frontend/import_entities/import_groups')
-rw-r--r--spec/frontend/import_entities/import_groups/components/import_table_row_spec.js6
-rw-r--r--spec/frontend/import_entities/import_groups/components/import_table_spec.js167
-rw-r--r--spec/frontend/import_entities/import_groups/graphql/client_factory_spec.js137
-rw-r--r--spec/frontend/import_entities/import_groups/graphql/services/source_groups_manager_spec.js4
-rw-r--r--spec/frontend/import_entities/import_groups/graphql/services/status_poller_spec.js276
5 files changed, 331 insertions, 259 deletions
diff --git a/spec/frontend/import_entities/import_groups/components/import_table_row_spec.js b/spec/frontend/import_entities/import_groups/components/import_table_row_spec.js
index ac8b73aeb49..cdef4b1ee62 100644
--- a/spec/frontend/import_entities/import_groups/components/import_table_row_spec.js
+++ b/spec/frontend/import_entities/import_groups/components/import_table_row_spec.js
@@ -1,8 +1,8 @@
-import { shallowMount } from '@vue/test-utils';
import { GlButton, GlLink, GlFormInput } from '@gitlab/ui';
-import Select2Select from '~/vue_shared/components/select2_select.vue';
-import ImportTableRow from '~/import_entities/import_groups/components/import_table_row.vue';
+import { shallowMount } from '@vue/test-utils';
import { STATUSES } from '~/import_entities/constants';
+import ImportTableRow from '~/import_entities/import_groups/components/import_table_row.vue';
+import Select2Select from '~/vue_shared/components/select2_select.vue';
import { availableNamespacesFixture } from '../graphql/fixtures';
const getFakeGroup = (status) => ({
diff --git a/spec/frontend/import_entities/import_groups/components/import_table_spec.js b/spec/frontend/import_entities/import_groups/components/import_table_spec.js
index cd184bb65cc..dd734782169 100644
--- a/spec/frontend/import_entities/import_groups/components/import_table_spec.js
+++ b/spec/frontend/import_entities/import_groups/components/import_table_spec.js
@@ -1,15 +1,15 @@
+import { GlEmptyState, GlLoadingIcon, GlSearchBoxByClick, GlSprintf } from '@gitlab/ui';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import VueApollo from 'vue-apollo';
-import { GlLoadingIcon } from '@gitlab/ui';
-import waitForPromises from 'helpers/wait_for_promises';
import createMockApollo from 'helpers/mock_apollo_helper';
-import ImportTableRow from '~/import_entities/import_groups/components/import_table_row.vue';
+import waitForPromises from 'helpers/wait_for_promises';
+import { STATUSES } from '~/import_entities/constants';
import ImportTable from '~/import_entities/import_groups/components/import_table.vue';
-import setTargetNamespaceMutation from '~/import_entities/import_groups/graphql/mutations/set_target_namespace.mutation.graphql';
-import setNewNameMutation from '~/import_entities/import_groups/graphql/mutations/set_new_name.mutation.graphql';
+import ImportTableRow from '~/import_entities/import_groups/components/import_table_row.vue';
import importGroupMutation from '~/import_entities/import_groups/graphql/mutations/import_group.mutation.graphql';
-
-import { STATUSES } from '~/import_entities/constants';
+import setNewNameMutation from '~/import_entities/import_groups/graphql/mutations/set_new_name.mutation.graphql';
+import setTargetNamespaceMutation from '~/import_entities/import_groups/graphql/mutations/set_target_namespace.mutation.graphql';
+import PaginationLinks from '~/vue_shared/components/pagination_links.vue';
import { availableNamespacesFixture, generateFakeEntry } from '../graphql/fixtures';
@@ -20,6 +20,9 @@ describe('import table', () => {
let wrapper;
let apolloProvider;
+ const FAKE_GROUP = generateFakeEntry({ id: 1, status: STATUSES.NONE });
+ const FAKE_PAGE_INFO = { page: 1, perPage: 20, total: 40, totalPages: 2 };
+
const createComponent = ({ bulkImportSourceGroups }) => {
apolloProvider = createMockApollo([], {
Query: {
@@ -34,6 +37,12 @@ describe('import table', () => {
});
wrapper = shallowMount(ImportTable, {
+ propsData: {
+ sourceUrl: 'https://demo.host',
+ },
+ stubs: {
+ GlSprintf,
+ },
localVue,
apolloProvider,
});
@@ -62,25 +71,50 @@ describe('import table', () => {
expect(wrapper.find(GlLoadingIcon).exists()).toBe(false);
});
+ it('renders message about empty state when no groups are available for import', async () => {
+ createComponent({
+ bulkImportSourceGroups: () => ({
+ nodes: [],
+ pageInfo: FAKE_PAGE_INFO,
+ }),
+ });
+ await waitForPromises();
+
+ expect(wrapper.find(GlEmptyState).props().title).toBe('No groups available for import');
+ });
+
it('renders import row for each group in response', async () => {
const FAKE_GROUPS = [
generateFakeEntry({ id: 1, status: STATUSES.NONE }),
generateFakeEntry({ id: 2, status: STATUSES.FINISHED }),
];
createComponent({
- bulkImportSourceGroups: () => FAKE_GROUPS,
+ bulkImportSourceGroups: () => ({
+ nodes: FAKE_GROUPS,
+ pageInfo: FAKE_PAGE_INFO,
+ }),
});
await waitForPromises();
expect(wrapper.findAll(ImportTableRow)).toHaveLength(FAKE_GROUPS.length);
});
- describe('converts row events to mutation invocations', () => {
- const FAKE_GROUP = generateFakeEntry({ id: 1, status: STATUSES.NONE });
+ it('does not render status string when result list is empty', async () => {
+ createComponent({
+ bulkImportSourceGroups: jest.fn().mockResolvedValue({
+ nodes: [],
+ pageInfo: FAKE_PAGE_INFO,
+ }),
+ });
+ await waitForPromises();
+
+ expect(wrapper.text()).not.toContain('Showing 1-0');
+ });
+ describe('converts row events to mutation invocations', () => {
beforeEach(() => {
createComponent({
- bulkImportSourceGroups: () => [FAKE_GROUP],
+ bulkImportSourceGroups: () => ({ nodes: [FAKE_GROUP], pageInfo: FAKE_PAGE_INFO }),
});
return waitForPromises();
});
@@ -100,4 +134,115 @@ describe('import table', () => {
});
});
});
+
+ describe('pagination', () => {
+ const bulkImportSourceGroupsQueryMock = jest
+ .fn()
+ .mockResolvedValue({ nodes: [FAKE_GROUP], pageInfo: FAKE_PAGE_INFO });
+
+ beforeEach(() => {
+ createComponent({
+ bulkImportSourceGroups: bulkImportSourceGroupsQueryMock,
+ });
+ return waitForPromises();
+ });
+
+ it('correctly passes pagination info from query', () => {
+ expect(wrapper.find(PaginationLinks).props().pageInfo).toStrictEqual(FAKE_PAGE_INFO);
+ });
+
+ it('updates page when page change is requested', async () => {
+ const REQUESTED_PAGE = 2;
+ wrapper.find(PaginationLinks).props().change(REQUESTED_PAGE);
+
+ await waitForPromises();
+ expect(bulkImportSourceGroupsQueryMock).toHaveBeenCalledWith(
+ expect.anything(),
+ expect.objectContaining({ page: REQUESTED_PAGE }),
+ expect.anything(),
+ expect.anything(),
+ );
+ });
+
+ it('updates status text when page is changed', async () => {
+ const REQUESTED_PAGE = 2;
+ bulkImportSourceGroupsQueryMock.mockResolvedValue({
+ nodes: [FAKE_GROUP],
+ pageInfo: {
+ page: 2,
+ total: 38,
+ perPage: 20,
+ totalPages: 2,
+ },
+ });
+ wrapper.find(PaginationLinks).props().change(REQUESTED_PAGE);
+ await waitForPromises();
+
+ expect(wrapper.text()).toContain('Showing 21-21 of 38');
+ });
+ });
+
+ describe('filters', () => {
+ const bulkImportSourceGroupsQueryMock = jest
+ .fn()
+ .mockResolvedValue({ nodes: [FAKE_GROUP], pageInfo: FAKE_PAGE_INFO });
+
+ beforeEach(() => {
+ createComponent({
+ bulkImportSourceGroups: bulkImportSourceGroupsQueryMock,
+ });
+ return waitForPromises();
+ });
+
+ const findFilterInput = () => wrapper.find(GlSearchBoxByClick);
+
+ it('properly passes filter to graphql query when search box is submitted', async () => {
+ createComponent({
+ bulkImportSourceGroups: bulkImportSourceGroupsQueryMock,
+ });
+ await waitForPromises();
+
+ const FILTER_VALUE = 'foo';
+ findFilterInput().vm.$emit('submit', FILTER_VALUE);
+ await waitForPromises();
+
+ expect(bulkImportSourceGroupsQueryMock).toHaveBeenCalledWith(
+ expect.anything(),
+ expect.objectContaining({ filter: FILTER_VALUE }),
+ expect.anything(),
+ expect.anything(),
+ );
+ });
+
+ it('updates status string when search box is submitted', async () => {
+ createComponent({
+ bulkImportSourceGroups: bulkImportSourceGroupsQueryMock,
+ });
+ await waitForPromises();
+
+ const FILTER_VALUE = 'foo';
+ findFilterInput().vm.$emit('submit', FILTER_VALUE);
+ await waitForPromises();
+
+ expect(wrapper.text()).toContain('Showing 1-1 of 40 groups matching filter "foo"');
+ });
+
+ it('properly resets filter in graphql query when search box is cleared', async () => {
+ const FILTER_VALUE = 'foo';
+ findFilterInput().vm.$emit('submit', FILTER_VALUE);
+ await waitForPromises();
+
+ bulkImportSourceGroupsQueryMock.mockClear();
+ await apolloProvider.defaultClient.resetStore();
+ findFilterInput().vm.$emit('clear');
+ await waitForPromises();
+
+ expect(bulkImportSourceGroupsQueryMock).toHaveBeenCalledWith(
+ expect.anything(),
+ expect.objectContaining({ filter: '' }),
+ expect.anything(),
+ expect.anything(),
+ );
+ });
+ });
});
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 514ed411138..4d3d2c41bbe 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
@@ -1,20 +1,20 @@
-import MockAdapter from 'axios-mock-adapter';
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 axios from '~/lib/utils/axios_utils';
+import { STATUSES } from '~/import_entities/constants';
import {
clientTypenames,
createResolvers,
} from '~/import_entities/import_groups/graphql/client_factory';
+import importGroupMutation from '~/import_entities/import_groups/graphql/mutations/import_group.mutation.graphql';
+import setNewNameMutation from '~/import_entities/import_groups/graphql/mutations/set_new_name.mutation.graphql';
+import setTargetNamespaceMutation from '~/import_entities/import_groups/graphql/mutations/set_target_namespace.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 { StatusPoller } from '~/import_entities/import_groups/graphql/services/status_poller';
-import { STATUSES } from '~/import_entities/constants';
-import bulkImportSourceGroupsQuery from '~/import_entities/import_groups/graphql/queries/bulk_import_source_groups.query.graphql';
-import availableNamespacesQuery from '~/import_entities/import_groups/graphql/queries/available_namespaces.query.graphql';
-import setTargetNamespaceMutation from '~/import_entities/import_groups/graphql/mutations/set_target_namespace.mutation.graphql';
-import setNewNameMutation from '~/import_entities/import_groups/graphql/mutations/set_new_name.mutation.graphql';
-import importGroupMutation from '~/import_entities/import_groups/graphql/mutations/import_group.mutation.graphql';
+import axios from '~/lib/utils/axios_utils';
import httpStatus from '~/lib/utils/http_status';
import { statusEndpointFixture, availableNamespacesFixture } from './fixtures';
@@ -28,6 +28,7 @@ const FAKE_ENDPOINTS = {
status: '/fake_status_url',
availableNamespaces: '/fake_available_namespaces',
createBulkImport: '/fake_create_bulk_import',
+ jobs: '/fake_jobs',
};
describe('Bulk import resolvers', () => {
@@ -79,33 +80,61 @@ describe('Bulk import resolvers', () => {
axiosMockAdapter
.onGet(FAKE_ENDPOINTS.availableNamespaces)
.reply(httpStatus.OK, availableNamespacesFixture);
-
- const response = await client.query({ query: bulkImportSourceGroupsQuery });
- results = response.data.bulkImportSourceGroups;
});
- it('mirrors REST endpoint response fields', () => {
- const MIRRORED_FIELDS = ['id', 'full_name', 'full_path', 'web_url'];
- expect(
- results.every((r, idx) =>
- MIRRORED_FIELDS.every(
- (field) => r[field] === statusEndpointFixture.importable_data[idx][field],
+ 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 = ['id', 'full_name', 'full_path', 'web_url'];
+ expect(
+ results.every((r, idx) =>
+ MIRRORED_FIELDS.every(
+ (field) => r[field] === statusEndpointFixture.importable_data[idx][field],
+ ),
),
- ),
- ).toBe(true);
- });
+ ).toBe(true);
+ });
- it('populates each result instance with status field default to none', () => {
- expect(results.every((r) => r.status === STATUSES.NONE)).toBe(true);
- });
+ it('populates each result instance with status field default to none', () => {
+ expect(results.every((r) => r.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('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.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 }) => {
+ 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);
+ },
+ );
});
});
@@ -117,20 +146,28 @@ describe('Bulk import resolvers', () => {
client.writeQuery({
query: bulkImportSourceGroupsQuery,
data: {
- bulkImportSourceGroups: [
- {
- __typename: clientTypenames.BulkImportSourceGroup,
- id: 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',
+ bulkImportSourceGroups: {
+ nodes: [
+ {
+ __typename: clientTypenames.BulkImportSourceGroup,
+ id: 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',
+ },
},
+ ],
+ pageInfo: {
+ page: 1,
+ perPage: 20,
+ total: 37,
+ totalPages: 2,
},
- ],
+ },
},
});
@@ -140,7 +177,7 @@ describe('Bulk import resolvers', () => {
fetchPolicy: 'cache-only',
})
.subscribe(({ data }) => {
- results = data.bulkImportSourceGroups;
+ results = data.bulkImportSourceGroups.nodes;
});
});
@@ -174,7 +211,9 @@ describe('Bulk import resolvers', () => {
});
await waitForPromises();
- const { bulkImportSourceGroups: intermediateResults } = client.readQuery({
+ const {
+ bulkImportSourceGroups: { nodes: intermediateResults },
+ } = client.readQuery({
query: bulkImportSourceGroupsQuery,
});
@@ -182,7 +221,7 @@ describe('Bulk import resolvers', () => {
});
it('sets group status to STARTED when request completes', async () => {
- axiosMockAdapter.onPost(FAKE_ENDPOINTS.createBulkImport).reply(httpStatus.OK);
+ axiosMockAdapter.onPost(FAKE_ENDPOINTS.createBulkImport).reply(httpStatus.OK, { id: 1 });
await client.mutate({
mutation: importGroupMutation,
variables: { sourceGroupId: GROUP_ID },
@@ -191,16 +230,6 @@ describe('Bulk import resolvers', () => {
expect(results[0].status).toBe(STATUSES.STARTED);
});
- it('starts polling when request completes', async () => {
- axiosMockAdapter.onPost(FAKE_ENDPOINTS.createBulkImport).reply(httpStatus.OK);
- await client.mutate({
- mutation: importGroupMutation,
- variables: { sourceGroupId: GROUP_ID },
- });
- const [statusPoller] = StatusPoller.mock.instances;
- expect(statusPoller.startPolling).toHaveBeenCalled();
- });
-
it('resets status to NONE if request fails', async () => {
axiosMockAdapter
.onPost(FAKE_ENDPOINTS.createBulkImport)
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
index 5940ea544ea..ca987ab3ab4 100644
--- 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
@@ -1,7 +1,7 @@
import { defaultDataIdFromObject } from 'apollo-cache-inmemory';
-import { SourceGroupsManager } from '~/import_entities/import_groups/graphql/services/source_groups_manager';
-import ImportSourceGroupFragment from '~/import_entities/import_groups/graphql/fragments/bulk_import_source_group_item.fragment.graphql';
import { clientTypenames } from '~/import_entities/import_groups/graphql/client_factory';
+import ImportSourceGroupFragment from '~/import_entities/import_groups/graphql/fragments/bulk_import_source_group_item.fragment.graphql';
+import { SourceGroupsManager } from '~/import_entities/import_groups/graphql/services/source_groups_manager';
describe('SourceGroupsManager', () => {
let manager;
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
index e7f1626f81d..a5fc4e18a02 100644
--- 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
@@ -1,215 +1,113 @@
-import { createMockClient } from 'mock-apollo-client';
-import { InMemoryCache } from 'apollo-cache-inmemory';
-import waitForPromises from 'helpers/wait_for_promises';
-
+import MockAdapter from 'axios-mock-adapter';
+import Visibility from 'visibilityjs';
import createFlash from '~/flash';
-import { StatusPoller } from '~/import_entities/import_groups/graphql/services/status_poller';
-import bulkImportSourceGroupsQuery from '~/import_entities/import_groups/graphql/queries/bulk_import_source_groups.query.graphql';
import { STATUSES } from '~/import_entities/constants';
import { SourceGroupsManager } from '~/import_entities/import_groups/graphql/services/source_groups_manager';
-import { generateFakeEntry } from '../fixtures';
+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 TEST_POLL_INTERVAL = 1000;
+const FAKE_POLL_PATH = '/fake/poll/path';
+const CLIENT_MOCK = {};
describe('Bulk import status poller', () => {
let poller;
- let clientMock;
+ let mockAdapter;
- const listQueryCacheCalls = () =>
- clientMock.readQuery.mock.calls.filter((call) => call[0].query === bulkImportSourceGroupsQuery);
+ const getPollHistory = () => mockAdapter.history.get.filter((x) => x.url === FAKE_POLL_PATH);
beforeEach(() => {
- clientMock = createMockClient({
- cache: new InMemoryCache({
- fragmentMatcher: { match: () => true },
- }),
- });
-
- jest.spyOn(clientMock, 'readQuery');
-
- poller = new StatusPoller({
- client: clientMock,
- interval: TEST_POLL_INTERVAL,
- });
+ mockAdapter = new MockAdapter(axios);
+ mockAdapter.onGet(FAKE_POLL_PATH).reply(200, {});
+ poller = new StatusPoller({ client: CLIENT_MOCK, pollPath: FAKE_POLL_PATH });
});
- describe('general behavior', () => {
- beforeEach(() => {
- clientMock.cache.writeQuery({
- query: bulkImportSourceGroupsQuery,
- data: { bulkImportSourceGroups: [] },
- });
- });
-
- it('does not perform polling when constructed', () => {
- jest.runOnlyPendingTimers();
- expect(listQueryCacheCalls()).toHaveLength(0);
- });
-
- it('immediately start polling when requested', async () => {
- await poller.startPolling();
- expect(listQueryCacheCalls()).toHaveLength(1);
- });
-
- it('constantly polls when started', async () => {
- poller.startPolling();
- expect(listQueryCacheCalls()).toHaveLength(1);
-
- jest.advanceTimersByTime(TEST_POLL_INTERVAL);
- expect(listQueryCacheCalls()).toHaveLength(2);
-
- jest.advanceTimersByTime(TEST_POLL_INTERVAL);
- expect(listQueryCacheCalls()).toHaveLength(3);
- });
-
- it('does not start polling when requested multiple times', async () => {
- poller.startPolling();
- expect(listQueryCacheCalls()).toHaveLength(1);
-
- poller.startPolling();
- expect(listQueryCacheCalls()).toHaveLength(1);
- });
-
- it('stops polling when requested', async () => {
- poller.startPolling();
- expect(listQueryCacheCalls()).toHaveLength(1);
-
- poller.stopPolling();
- jest.runOnlyPendingTimers();
- expect(listQueryCacheCalls()).toHaveLength(1);
- });
-
- it('does not query server when list is empty', async () => {
- jest.spyOn(clientMock, 'query');
- poller.startPolling();
- expect(clientMock.query).not.toHaveBeenCalled();
- });
+ it('creates source group manager with proper client', () => {
+ expect(SourceGroupsManager.mock.calls).toHaveLength(1);
+ const [[{ client }]] = SourceGroupsManager.mock.calls;
+ expect(client).toBe(CLIENT_MOCK);
});
- it('does not query server when no groups have STARTED status', async () => {
- clientMock.cache.writeQuery({
- query: bulkImportSourceGroupsQuery,
- data: {
- bulkImportSourceGroups: [STATUSES.NONE, STATUSES.FINISHED].map((status, idx) =>
- generateFakeEntry({ status, id: idx }),
- ),
- },
- });
-
- jest.spyOn(clientMock, 'query');
+ 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(clientMock.query).not.toHaveBeenCalled();
+
+ expect(pollInstance.makeRequest).toHaveBeenCalled();
+ });
+
+ it('when error occurs shows flash with error', () => {
+ const [[pollConfig]] = Poll.mock.calls;
+ pollConfig.errorCallback();
+ expect(createFlash).toHaveBeenCalled();
});
- describe('when there are groups which have STARTED status', () => {
- const TARGET_NAMESPACE = 'root';
-
- const STARTED_GROUP_1 = {
- status: STATUSES.STARTED,
- id: 'started1',
- import_target: {
- target_namespace: TARGET_NAMESPACE,
- new_name: 'group1',
- },
- };
-
- const STARTED_GROUP_2 = {
- status: STATUSES.STARTED,
- id: 'started2',
- import_target: {
- target_namespace: TARGET_NAMESPACE,
- new_name: 'group2',
- },
- };
-
- const NOT_STARTED_GROUP = {
- status: STATUSES.NONE,
- id: 'not_started',
- import_target: {
- target_namespace: TARGET_NAMESPACE,
- new_name: 'group3',
- },
- };
-
- it('query server only for groups with STATUSES.STARTED', async () => {
- clientMock.cache.writeQuery({
- query: bulkImportSourceGroupsQuery,
- data: {
- bulkImportSourceGroups: [
- STARTED_GROUP_1,
- NOT_STARTED_GROUP,
- STARTED_GROUP_2,
- ].map((group) => generateFakeEntry(group)),
- },
- });
-
- clientMock.query = jest.fn().mockResolvedValue({ data: {} });
- poller.startPolling();
-
- expect(clientMock.query).toHaveBeenCalledTimes(1);
- await waitForPromises();
- const [[doc]] = clientMock.query.mock.calls;
- const { selections } = doc.query.definitions[0].selectionSet;
- expect(selections.every((field) => field.name.value === 'group')).toBeTruthy();
- expect(selections).toHaveLength(2);
- expect(selections.map((sel) => sel.arguments[0].value.value)).toStrictEqual([
- `${TARGET_NAMESPACE}/${STARTED_GROUP_1.import_target.new_name}`,
- `${TARGET_NAMESPACE}/${STARTED_GROUP_2.import_target.new_name}`,
- ]);
- });
-
- it('updates statuses only for groups in response', async () => {
- clientMock.cache.writeQuery({
- query: bulkImportSourceGroupsQuery,
- data: {
- bulkImportSourceGroups: [STARTED_GROUP_1, STARTED_GROUP_2].map((group) =>
- generateFakeEntry(group),
- ),
- },
- });
-
- clientMock.query = jest.fn().mockResolvedValue({ data: { group0: {} } });
- poller.startPolling();
- await waitForPromises();
- const [managerInstance] = SourceGroupsManager.mock.instances;
- expect(managerInstance.setImportStatus).toHaveBeenCalledTimes(1);
- expect(managerInstance.setImportStatus).toHaveBeenCalledWith(
- expect.objectContaining({ id: STARTED_GROUP_1.id }),
- STATUSES.FINISHED,
- );
- });
-
- describe('when error occurs', () => {
- beforeEach(() => {
- clientMock.cache.writeQuery({
- query: bulkImportSourceGroupsQuery,
- data: {
- bulkImportSourceGroups: [STARTED_GROUP_1, STARTED_GROUP_2].map((group) =>
- generateFakeEntry(group),
- ),
- },
- });
-
- clientMock.query = jest.fn().mockRejectedValue(new Error('dummy error'));
- poller.startPolling();
- return waitForPromises();
- });
-
- it('reports an error', () => {
- expect(createFlash).toHaveBeenCalled();
- });
-
- it('continues polling', async () => {
- jest.advanceTimersByTime(TEST_POLL_INTERVAL);
- expect(listQueryCacheCalls()).toHaveLength(2);
- });
- });
+ it('when success response arrives updates relevant group status', () => {
+ const FAKE_ID = 5;
+ const [[pollConfig]] = Poll.mock.calls;
+ const [managerInstance] = SourceGroupsManager.mock.instances;
+ managerInstance.findByImportId.mockReturnValue({ id: FAKE_ID });
+
+ pollConfig.successCallback({ data: [{ id: FAKE_ID, status_name: STATUSES.FINISHED }] });
+
+ expect(managerInstance.setImportStatus).toHaveBeenCalledWith(
+ expect.objectContaining({ id: FAKE_ID }),
+ STATUSES.FINISHED,
+ );
});
});