diff options
Diffstat (limited to 'spec/frontend/import_entities/import_groups')
6 files changed, 127 insertions, 12 deletions
diff --git a/spec/frontend/import_entities/import_groups/components/import_history_link_spec.js b/spec/frontend/import_entities/import_groups/components/import_history_link_spec.js new file mode 100644 index 00000000000..5f530f2c3be --- /dev/null +++ b/spec/frontend/import_entities/import_groups/components/import_history_link_spec.js @@ -0,0 +1,34 @@ +import { shallowMount } from '@vue/test-utils'; +import { GlLink } from '@gitlab/ui'; + +import ImportHistoryLink from '~/import_entities/import_groups/components/import_history_link.vue'; + +describe('import history link', () => { + let wrapper; + + const mockHistoryPath = '/import/history'; + + const createComponent = ({ props } = {}) => { + wrapper = shallowMount(ImportHistoryLink, { + propsData: { + historyPath: mockHistoryPath, + ...props, + }, + }); + }; + + const findGlLink = () => wrapper.findComponent(GlLink); + + it('renders link with href', () => { + const mockId = 174; + + createComponent({ + props: { + id: mockId, + }, + }); + + expect(findGlLink().text()).toBe('View details'); + expect(findGlLink().attributes('href')).toBe('/import/history?bulk_import_id=174'); + }); +}); 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 4fab22e316a..84f149b4dd5 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 @@ -9,9 +9,12 @@ import { createMockDirective, getBinding } from 'helpers/vue_mock_directive'; import { createAlert } from '~/alert'; import { HTTP_STATUS_OK, HTTP_STATUS_TOO_MANY_REQUESTS } from '~/lib/utils/http_status'; import axios from '~/lib/utils/axios_utils'; + import { STATUSES } from '~/import_entities/constants'; -import { i18n, ROOT_NAMESPACE } from '~/import_entities/import_groups/constants'; +import { ROOT_NAMESPACE } from '~/import_entities/import_groups/constants'; import ImportTable from '~/import_entities/import_groups/components/import_table.vue'; +import ImportStatus from '~/import_entities/import_groups/components/import_status.vue'; +import ImportHistoryLink from '~/import_entities/import_groups/components//import_history_link.vue'; import importGroupsMutation from '~/import_entities/import_groups/graphql/mutations/import_groups.mutation.graphql'; import PaginationBar from '~/vue_shared/components/pagination_bar/pagination_bar.vue'; import PaginationLinks from '~/vue_shared/components/pagination_links.vue'; @@ -39,6 +42,7 @@ describe('import table', () => { generateFakeEntry({ id: 1, status: STATUSES.NONE }), generateFakeEntry({ id: 2, status: STATUSES.FINISHED }), generateFakeEntry({ id: 3, status: STATUSES.NONE }), + generateFakeEntry({ id: 4, status: STATUSES.FINISHED, hasFailures: true }), ]; const FAKE_PAGE_INFO = { page: 1, perPage: 20, total: 40, totalPages: 2 }; @@ -64,6 +68,7 @@ describe('import table', () => { const findSelectionCount = () => wrapper.find('[data-test-id="selection-count"]'); const findNewPathCol = () => wrapper.find('[data-test-id="new-path-col"]'); const findUnavailableFeaturesWarning = () => wrapper.findByTestId('unavailable-features-alert'); + const findAllImportStatuses = () => wrapper.findAllComponents(ImportStatus); const triggerSelectAllCheckbox = (checked = true) => wrapper.find('thead input[type=checkbox]').setChecked(checked); @@ -144,7 +149,7 @@ describe('import table', () => { }); await waitForPromises(); - expect(wrapper.findComponent(GlEmptyState).props().title).toBe(i18n.NO_GROUPS_FOUND); + expect(wrapper.findComponent(GlEmptyState).props().title).toBe('No groups found'); }); }); @@ -161,6 +166,38 @@ describe('import table', () => { expect(wrapper.findAll('tbody tr')).toHaveLength(FAKE_GROUPS.length); }); + it('renders correct import status for each group', async () => { + const expectedStatuses = ['Not started', 'Complete', 'Not started', 'Partially completed']; + + createComponent({ + bulkImportSourceGroups: () => ({ + nodes: FAKE_GROUPS, + pageInfo: FAKE_PAGE_INFO, + versionValidation: FAKE_VERSION_VALIDATION, + }), + }); + await waitForPromises(); + + expect(findAllImportStatuses().wrappers.map((w) => w.text())).toEqual(expectedStatuses); + }); + + it('renders import history link for imports with id', async () => { + createComponent({ + bulkImportSourceGroups: () => ({ + nodes: FAKE_GROUPS, + pageInfo: FAKE_PAGE_INFO, + versionValidation: FAKE_VERSION_VALIDATION, + }), + }); + await waitForPromises(); + + const importHistoryLinks = wrapper.findAllComponents(ImportHistoryLink); + + expect(importHistoryLinks).toHaveLength(2); + expect(importHistoryLinks.at(0).props('id')).toBe(FAKE_GROUPS[1].id); + expect(importHistoryLinks.at(1).props('id')).toBe(FAKE_GROUPS[3].id); + }); + it('correctly maintains root namespace as last import target', async () => { createComponent({ bulkImportSourceGroups: () => ({ @@ -260,6 +297,42 @@ describe('import table', () => { }); }); + describe('when importGroup query is using stale data from LocalStorageCache', () => { + it('displays error', async () => { + const mockMutationWithProgressInvalid = jest.fn().mockResolvedValue({ + __typename: 'ClientBulkImportSourceGroup', + id: 1, + lastImportTarget: { id: 1, targetNamespace: 'root', newName: 'group1' }, + progress: { + __typename: 'ClientBulkImportProgress', + id: null, + status: 'failed', + message: '', + }, + }); + + createComponent({ + bulkImportSourceGroups: () => ({ + nodes: [FAKE_GROUP], + pageInfo: FAKE_PAGE_INFO, + versionValidation: FAKE_VERSION_VALIDATION, + }), + importGroups: mockMutationWithProgressInvalid, + }); + + await waitForPromises(); + await findRowImportDropdownAtIndex(0).trigger('click'); + await waitForPromises(); + + expect(mockMutationWithProgressInvalid).toHaveBeenCalled(); + expect(createAlert).toHaveBeenCalledWith({ + message: 'Importing the group failed.', + captureError: true, + error: expect.any(Error), + }); + }); + }); + it('displays error if importing group fails', async () => { createComponent({ bulkImportSourceGroups: () => ({ @@ -276,11 +349,11 @@ describe('import table', () => { await findRowImportDropdownAtIndex(0).trigger('click'); await waitForPromises(); - expect(createAlert).toHaveBeenCalledWith( - expect.objectContaining({ - message: i18n.ERROR_IMPORT, - }), - ); + expect(createAlert).toHaveBeenCalledWith({ + message: 'Importing the group failed.', + captureError: true, + error: expect.any(Error), + }); }); it('displays inline error if importing group reports rate limit', async () => { @@ -302,7 +375,9 @@ describe('import table', () => { await waitForPromises(); expect(createAlert).not.toHaveBeenCalled(); - expect(wrapper.find('tbody tr').text()).toContain(i18n.ERROR_TOO_MANY_REQUESTS); + expect(wrapper.find('tbody tr').text()).toContain( + 'Over six imports in one minute were attempted. Wait at least one minute and try again.', + ); }); it('displays inline error if backend returns validation error', async () => { @@ -316,6 +391,7 @@ describe('import table', () => { __typename: 'ClientBulkImportProgress', id: null, status: 'failed', + hasFailures: true, message: mockValidationError, }, }); 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 540c42a2854..0976a3294c2 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 @@ -72,6 +72,7 @@ describe('Bulk import resolvers', () => { progress: { id: 'DEMO', status: 'cached', + hasFailures: true, }, }; localStorageCache.get.mockReturnValueOnce(CACHED_DATA); @@ -234,7 +235,7 @@ describe('Bulk import resolvers', () => { data: { updateImportStatus: statusInResponse }, } = await client.mutate({ mutation: updateImportStatusMutation, - variables: { id, status: NEW_STATUS }, + variables: { id, status: NEW_STATUS, hasFailures: true }, }); expect(statusInResponse).toStrictEqual({ @@ -242,6 +243,7 @@ describe('Bulk import resolvers', () => { id, message: null, status: NEW_STATUS, + hasFailures: true, }); }); }); diff --git a/spec/frontend/import_entities/import_groups/graphql/fixtures.js b/spec/frontend/import_entities/import_groups/graphql/fixtures.js index 7530e9fc348..edc2d1a2381 100644 --- a/spec/frontend/import_entities/import_groups/graphql/fixtures.js +++ b/spec/frontend/import_entities/import_groups/graphql/fixtures.js @@ -1,7 +1,7 @@ import { STATUSES } from '~/import_entities/constants'; import { clientTypenames } from '~/import_entities/import_groups/graphql/client_factory'; -export const generateFakeEntry = ({ id, status, message, ...rest }) => ({ +export const generateFakeEntry = ({ id, status, hasFailures = false, message, ...rest }) => ({ __typename: clientTypenames.BulkImportSourceGroup, webUrl: `https://fake.host/${id}`, fullPath: `fake_group_${id}`, @@ -19,6 +19,7 @@ export const generateFakeEntry = ({ id, status, message, ...rest }) => ({ __typename: clientTypenames.BulkImportProgress, id, status, + hasFailures, message: message || '', }, ...rest, 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 index b44a2767ad8..d1ecd47b498 100644 --- 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 @@ -40,10 +40,11 @@ describe('Local storage cache', () => { progress: { id: JOB_ID, status: 'original', + hasFailures: false, }, }); - cache.updateStatusByJobId(JOB_ID, CHANGED_STATUS); + cache.updateStatusByJobId(JOB_ID, CHANGED_STATUS, true); expect(storage.setItem).toHaveBeenCalledWith( KEY, @@ -52,6 +53,7 @@ describe('Local storage cache', () => { progress: { id: JOB_ID, status: CHANGED_STATUS, + hasFailures: true, }, }, }), diff --git a/spec/frontend/import_entities/import_groups/utils_spec.js b/spec/frontend/import_entities/import_groups/utils_spec.js index 2892c5c217b..3db57170ed3 100644 --- a/spec/frontend/import_entities/import_groups/utils_spec.js +++ b/spec/frontend/import_entities/import_groups/utils_spec.js @@ -5,7 +5,7 @@ const FINISHED_STATUSES = [STATUSES.FINISHED, STATUSES.FAILED, STATUSES.TIMEOUT] const OTHER_STATUSES = Object.values(STATUSES).filter( (status) => !FINISHED_STATUSES.includes(status), ); -describe('gitlab migration status utils', () => { +describe('Direct transfer status utils', () => { describe('isFinished', () => { it.each(FINISHED_STATUSES.map((s) => [s]))( 'reports group as finished when import status is %s', |