summaryrefslogtreecommitdiff
path: root/spec/frontend/import_projects
diff options
context:
space:
mode:
Diffstat (limited to 'spec/frontend/import_projects')
-rw-r--r--spec/frontend/import_projects/components/bitbucket_status_table_spec.js2
-rw-r--r--spec/frontend/import_projects/components/import_projects_table_spec.js114
-rw-r--r--spec/frontend/import_projects/components/imported_project_table_row_spec.js44
-rw-r--r--spec/frontend/import_projects/components/page_query_param_sync_spec.js87
-rw-r--r--spec/frontend/import_projects/components/provider_repo_table_row_spec.js151
-rw-r--r--spec/frontend/import_projects/store/actions_spec.js66
-rw-r--r--spec/frontend/import_projects/store/getters_spec.js27
-rw-r--r--spec/frontend/import_projects/store/mutations_spec.js178
-rw-r--r--spec/frontend/import_projects/utils_spec.js47
9 files changed, 378 insertions, 338 deletions
diff --git a/spec/frontend/import_projects/components/bitbucket_status_table_spec.js b/spec/frontend/import_projects/components/bitbucket_status_table_spec.js
index 132ccd0e324..b65b388fd5f 100644
--- a/spec/frontend/import_projects/components/bitbucket_status_table_spec.js
+++ b/spec/frontend/import_projects/components/bitbucket_status_table_spec.js
@@ -33,7 +33,7 @@ describe('BitbucketStatusTable', () => {
it('renders import table component', () => {
createComponent({ providerTitle: 'Test' });
- expect(wrapper.contains(ImportProjectsTable)).toBe(true);
+ expect(wrapper.find(ImportProjectsTable).exists()).toBe(true);
});
it('passes alert in incompatible-repos-warning slot', () => {
diff --git a/spec/frontend/import_projects/components/import_projects_table_spec.js b/spec/frontend/import_projects/components/import_projects_table_spec.js
index b217242968a..1dbad588ec4 100644
--- a/spec/frontend/import_projects/components/import_projects_table_spec.js
+++ b/spec/frontend/import_projects/components/import_projects_table_spec.js
@@ -1,15 +1,12 @@
import { nextTick } from 'vue';
import Vuex from 'vuex';
import { createLocalVue, shallowMount } from '@vue/test-utils';
-import { GlLoadingIcon, GlButton } from '@gitlab/ui';
+import { GlLoadingIcon, GlButton, GlIntersectionObserver } from '@gitlab/ui';
import state from '~/import_projects/store/state';
import * as getters from '~/import_projects/store/getters';
import { STATUSES } from '~/import_projects/constants';
import ImportProjectsTable from '~/import_projects/components/import_projects_table.vue';
-import ImportedProjectTableRow from '~/import_projects/components/imported_project_table_row.vue';
import ProviderRepoTableRow from '~/import_projects/components/provider_repo_table_row.vue';
-import IncompatibleRepoTableRow from '~/import_projects/components/incompatible_repo_table_row.vue';
-import PageQueryParamSync from '~/import_projects/components/page_query_param_sync.vue';
describe('ImportProjectsTable', () => {
let wrapper;
@@ -18,16 +15,26 @@ describe('ImportProjectsTable', () => {
wrapper.find('input[data-qa-selector="githubish_import_filter_field"]');
const providerTitle = 'THE PROVIDER';
- const providerRepo = { id: 10, sanitizedName: 'sanitizedName', fullName: 'fullName' };
+ const providerRepo = {
+ importSource: {
+ id: 10,
+ sanitizedName: 'sanitizedName',
+ fullName: 'fullName',
+ },
+ importedProject: null,
+ };
const findImportAllButton = () =>
wrapper
.findAll(GlButton)
.filter(w => w.props().variant === 'success')
.at(0);
+ const findImportAllModal = () => wrapper.find({ ref: 'importAllModal' });
const importAllFn = jest.fn();
+ const importAllModalShowFn = jest.fn();
const setPageFn = jest.fn();
+ const fetchReposFn = jest.fn();
function createComponent({
state: initialState,
@@ -46,7 +53,7 @@ describe('ImportProjectsTable', () => {
...customGetters,
},
actions: {
- fetchRepos: jest.fn(),
+ fetchRepos: fetchReposFn,
fetchJobs: jest.fn(),
fetchNamespaces: jest.fn(),
importAll: importAllFn,
@@ -66,6 +73,9 @@ describe('ImportProjectsTable', () => {
paginatable,
},
slots,
+ stubs: {
+ GlModal: { template: '<div>Modal!</div>', methods: { show: importAllModalShowFn } },
+ },
});
}
@@ -79,58 +89,54 @@ describe('ImportProjectsTable', () => {
it('renders a loading icon while repos are loading', () => {
createComponent({ state: { isLoadingRepos: true } });
- expect(wrapper.contains(GlLoadingIcon)).toBe(true);
+ expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
});
it('renders a loading icon while namespaces are loading', () => {
createComponent({ state: { isLoadingNamespaces: true } });
- expect(wrapper.contains(GlLoadingIcon)).toBe(true);
+ expect(wrapper.find(GlLoadingIcon).exists()).toBe(true);
});
- it('renders a table with imported projects and provider repos', () => {
+ it('renders a table with provider repos', () => {
+ const repositories = [
+ { importSource: { id: 1 }, importedProject: null },
+ { importSource: { id: 2 }, importedProject: { importStatus: STATUSES.FINISHED } },
+ { importSource: { id: 3, incompatible: true }, importedProject: {} },
+ ];
+
createComponent({
- state: {
- namespaces: [{ fullPath: 'path' }],
- repositories: [
- { importSource: { id: 1 }, importedProject: null, importStatus: STATUSES.NONE },
- { importSource: { id: 2 }, importedProject: {}, importStatus: STATUSES.FINISHED },
- {
- importSource: { id: 3, incompatible: true },
- importedProject: {},
- importStatus: STATUSES.NONE,
- },
- ],
- },
+ state: { namespaces: [{ fullPath: 'path' }], repositories },
});
- expect(wrapper.contains(GlLoadingIcon)).toBe(false);
- expect(wrapper.contains('table')).toBe(true);
+ expect(wrapper.find(GlLoadingIcon).exists()).toBe(false);
+ expect(wrapper.find('table').exists()).toBe(true);
expect(
wrapper
.findAll('th')
.filter(w => w.text() === `From ${providerTitle}`)
- .isEmpty(),
- ).toBe(false);
+ .exists(),
+ ).toBe(true);
- expect(wrapper.contains(ProviderRepoTableRow)).toBe(true);
- expect(wrapper.contains(ImportedProjectTableRow)).toBe(true);
- expect(wrapper.contains(IncompatibleRepoTableRow)).toBe(true);
+ expect(wrapper.findAll(ProviderRepoTableRow)).toHaveLength(repositories.length);
});
it.each`
- hasIncompatibleRepos | buttonText
- ${false} | ${'Import all repositories'}
- ${true} | ${'Import all compatible repositories'}
+ hasIncompatibleRepos | count | buttonText
+ ${false} | ${1} | ${'Import 1 repository'}
+ ${true} | ${1} | ${'Import 1 compatible repository'}
+ ${false} | ${5} | ${'Import 5 repositories'}
+ ${true} | ${5} | ${'Import 5 compatible repositories'}
`(
- 'import all button has "$buttonText" text when hasIncompatibleRepos is $hasIncompatibleRepos',
- ({ hasIncompatibleRepos, buttonText }) => {
+ 'import all button has "$buttonText" text when hasIncompatibleRepos is $hasIncompatibleRepos and repos count is $count',
+ ({ hasIncompatibleRepos, buttonText, count }) => {
createComponent({
state: {
providerRepos: [providerRepo],
},
getters: {
hasIncompatibleRepos: () => hasIncompatibleRepos,
+ importAllCount: () => count,
},
});
@@ -138,20 +144,28 @@ describe('ImportProjectsTable', () => {
},
);
- it('renders an empty state if there are no projects available', () => {
+ it('renders an empty state if there are no repositories available', () => {
createComponent({ state: { repositories: [] } });
- expect(wrapper.contains(ProviderRepoTableRow)).toBe(false);
- expect(wrapper.contains(ImportedProjectTableRow)).toBe(false);
+ expect(wrapper.find(ProviderRepoTableRow).exists()).toBe(false);
expect(wrapper.text()).toContain(`No ${providerTitle} repositories found`);
});
- it('sends importAll event when import button is clicked', async () => {
- createComponent({ state: { providerRepos: [providerRepo] } });
+ it('opens confirmation modal when import all button is clicked', async () => {
+ createComponent({ state: { repositories: [providerRepo] } });
findImportAllButton().vm.$emit('click');
await nextTick();
+ expect(importAllModalShowFn).toHaveBeenCalled();
+ });
+
+ it('triggers importAll action when modal is confirmed', async () => {
+ createComponent({ state: { providerRepos: [providerRepo] } });
+
+ findImportAllModal().vm.$emit('ok');
+ await nextTick();
+
expect(importAllFn).toHaveBeenCalled();
});
@@ -189,21 +203,29 @@ describe('ImportProjectsTable', () => {
});
});
- it('passes current page to page-query-param-sync component', () => {
- expect(wrapper.find(PageQueryParamSync).props().page).toBe(pageInfo.page);
+ it('does not call fetchRepos on mount', () => {
+ expect(fetchReposFn).not.toHaveBeenCalled();
+ });
+
+ it('renders intersection observer component', () => {
+ expect(wrapper.find(GlIntersectionObserver).exists()).toBe(true);
});
- it('dispatches setPage when page-query-param-sync emits popstate', () => {
- const NEW_PAGE = 2;
- wrapper.find(PageQueryParamSync).vm.$emit('popstate', NEW_PAGE);
+ it('calls fetchRepos when intersection observer appears', async () => {
+ wrapper.find(GlIntersectionObserver).vm.$emit('appear');
- const { calls } = setPageFn.mock;
+ await nextTick();
- expect(calls).toHaveLength(1);
- expect(calls[0][1]).toBe(NEW_PAGE);
+ expect(fetchReposFn).toHaveBeenCalled();
});
});
+ it('calls fetchRepos on mount', () => {
+ createComponent();
+
+ expect(fetchReposFn).toHaveBeenCalled();
+ });
+
it.each`
hasIncompatibleRepos | shouldRenderSlot | action
${false} | ${false} | ${'does not render'}
diff --git a/spec/frontend/import_projects/components/imported_project_table_row_spec.js b/spec/frontend/import_projects/components/imported_project_table_row_spec.js
deleted file mode 100644
index 8890c352826..00000000000
--- a/spec/frontend/import_projects/components/imported_project_table_row_spec.js
+++ /dev/null
@@ -1,44 +0,0 @@
-import { mount } from '@vue/test-utils';
-import ImportedProjectTableRow from '~/import_projects/components/imported_project_table_row.vue';
-import ImportStatus from '~/import_projects/components/import_status.vue';
-import { STATUSES } from '~/import_projects/constants';
-
-describe('ImportedProjectTableRow', () => {
- let wrapper;
- const project = {
- importSource: {
- fullName: 'fullName',
- providerLink: 'providerLink',
- },
- importedProject: {
- id: 1,
- fullPath: 'fullPath',
- importSource: 'importSource',
- },
- importStatus: STATUSES.FINISHED,
- };
-
- function mountComponent() {
- wrapper = mount(ImportedProjectTableRow, { propsData: { project } });
- }
-
- beforeEach(() => {
- mountComponent();
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('renders an imported project table row', () => {
- const providerLink = wrapper.find('[data-testid=providerLink]');
-
- expect(providerLink.attributes().href).toMatch(project.importSource.providerLink);
- expect(providerLink.text()).toMatch(project.importSource.fullName);
- expect(wrapper.find('[data-testid=fullPath]').text()).toMatch(project.importedProject.fullPath);
- expect(wrapper.find(ImportStatus).props().status).toBe(project.importStatus);
- expect(wrapper.find('[data-testid=goToProject').attributes().href).toMatch(
- project.importedProject.fullPath,
- );
- });
-});
diff --git a/spec/frontend/import_projects/components/page_query_param_sync_spec.js b/spec/frontend/import_projects/components/page_query_param_sync_spec.js
deleted file mode 100644
index be19ecca1ba..00000000000
--- a/spec/frontend/import_projects/components/page_query_param_sync_spec.js
+++ /dev/null
@@ -1,87 +0,0 @@
-import { shallowMount } from '@vue/test-utils';
-import { nextTick } from 'vue';
-import { TEST_HOST } from 'helpers/test_constants';
-
-import PageQueryParamSync from '~/import_projects/components/page_query_param_sync.vue';
-
-describe('PageQueryParamSync', () => {
- let originalPushState;
- let originalAddEventListener;
- let originalRemoveEventListener;
-
- const pushStateMock = jest.fn();
- const addEventListenerMock = jest.fn();
- const removeEventListenerMock = jest.fn();
-
- beforeAll(() => {
- window.location.search = '';
- originalPushState = window.pushState;
-
- window.history.pushState = pushStateMock;
-
- originalAddEventListener = window.addEventListener;
- window.addEventListener = addEventListenerMock;
-
- originalRemoveEventListener = window.removeEventListener;
- window.removeEventListener = removeEventListenerMock;
- });
-
- afterAll(() => {
- window.history.pushState = originalPushState;
- window.addEventListener = originalAddEventListener;
- window.removeEventListener = originalRemoveEventListener;
- });
-
- let wrapper;
- beforeEach(() => {
- wrapper = shallowMount(PageQueryParamSync, {
- propsData: { page: 3 },
- });
- });
-
- afterEach(() => {
- wrapper.destroy();
- });
-
- it('calls push state with page number when page is updated and differs from 1', async () => {
- wrapper.setProps({ page: 2 });
-
- await nextTick();
-
- const { calls } = pushStateMock.mock;
- expect(calls).toHaveLength(1);
- expect(calls[0][2]).toBe(`${TEST_HOST}/?page=2`);
- });
-
- it('calls push state without page number when page is updated and is 1', async () => {
- wrapper.setProps({ page: 1 });
-
- await nextTick();
-
- const { calls } = pushStateMock.mock;
- expect(calls).toHaveLength(1);
- expect(calls[0][2]).toBe(`${TEST_HOST}/`);
- });
-
- it('subscribes to popstate event on create', () => {
- expect(addEventListenerMock).toHaveBeenCalledWith('popstate', expect.any(Function));
- });
-
- it('unsubscribes from popstate event when destroyed', () => {
- const [, fn] = addEventListenerMock.mock.calls[0];
-
- wrapper.destroy();
-
- expect(removeEventListenerMock).toHaveBeenCalledWith('popstate', fn);
- });
-
- it('emits popstate event when popstate is triggered', async () => {
- const [, fn] = addEventListenerMock.mock.calls[0];
-
- delete window.location;
- window.location = new URL(`${TEST_HOST}/?page=5`);
- fn();
-
- expect(wrapper.emitted().popstate[0]).toStrictEqual([5]);
- });
-});
diff --git a/spec/frontend/import_projects/components/provider_repo_table_row_spec.js b/spec/frontend/import_projects/components/provider_repo_table_row_spec.js
index bd9cd07db78..03e30ef610e 100644
--- a/spec/frontend/import_projects/components/provider_repo_table_row_spec.js
+++ b/spec/frontend/import_projects/components/provider_repo_table_row_spec.js
@@ -1,6 +1,7 @@
import { nextTick } from 'vue';
import Vuex from 'vuex';
import { createLocalVue, shallowMount } from '@vue/test-utils';
+import { GlBadge } from '@gitlab/ui';
import ProviderRepoTableRow from '~/import_projects/components/provider_repo_table_row.vue';
import ImportStatus from '~/import_projects/components/import_status.vue';
import { STATUSES } from '~/import_projects/constants';
@@ -14,20 +15,6 @@ describe('ProviderRepoTableRow', () => {
targetNamespace: 'target',
newName: 'newName',
};
- const ciCdOnly = false;
- const repo = {
- importSource: {
- id: 'remote-1',
- fullName: 'fullName',
- providerLink: 'providerLink',
- },
- importedProject: {
- id: 1,
- fullPath: 'fullPath',
- importSource: 'importSource',
- },
- importStatus: STATUSES.FINISHED,
- };
const availableNamespaces = [
{ text: 'Groups', children: [{ id: 'test', text: 'test' }] },
@@ -46,55 +33,137 @@ describe('ProviderRepoTableRow', () => {
return store;
}
- const findImportButton = () =>
- wrapper
- .findAll('button')
- .filter(node => node.text() === 'Import')
- .at(0);
+ const findImportButton = () => {
+ const buttons = wrapper.findAll('button').filter(node => node.text() === 'Import');
+
+ return buttons.length ? buttons.at(0) : buttons;
+ };
- function mountComponent(initialState) {
+ function mountComponent(props) {
const localVue = createLocalVue();
localVue.use(Vuex);
- const store = initStore({ ciCdOnly, ...initialState });
+ const store = initStore();
wrapper = shallowMount(ProviderRepoTableRow, {
localVue,
store,
- propsData: { repo, availableNamespaces },
+ propsData: { availableNamespaces, ...props },
});
}
- beforeEach(() => {
- mountComponent();
- });
-
afterEach(() => {
wrapper.destroy();
+ wrapper = null;
});
- it('renders a provider repo table row', () => {
- const providerLink = wrapper.find('[data-testid=providerLink]');
+ describe('when rendering importable project', () => {
+ const repo = {
+ importSource: {
+ id: 'remote-1',
+ fullName: 'fullName',
+ providerLink: 'providerLink',
+ },
+ };
+
+ beforeEach(() => {
+ mountComponent({ repo });
+ });
+
+ it('renders project information', () => {
+ const providerLink = wrapper.find('[data-testid=providerLink]');
+
+ expect(providerLink.attributes().href).toMatch(repo.importSource.providerLink);
+ expect(providerLink.text()).toMatch(repo.importSource.fullName);
+ });
+
+ it('renders empty import status', () => {
+ expect(wrapper.find(ImportStatus).props().status).toBe(STATUSES.NONE);
+ });
+
+ it('renders a select2 namespace select', () => {
+ expect(wrapper.find(Select2Select).exists()).toBe(true);
+ expect(wrapper.find(Select2Select).props().options.data).toBe(availableNamespaces);
+ });
+
+ it('renders import button', () => {
+ expect(findImportButton().exists()).toBe(true);
+ });
+
+ it('imports repo when clicking import button', async () => {
+ findImportButton().trigger('click');
+
+ await nextTick();
+
+ const { calls } = fetchImport.mock;
- expect(providerLink.attributes().href).toMatch(repo.importSource.providerLink);
- expect(providerLink.text()).toMatch(repo.importSource.fullName);
- expect(wrapper.find(ImportStatus).props().status).toBe(repo.importStatus);
- expect(wrapper.contains('button')).toBe(true);
+ expect(calls).toHaveLength(1);
+ expect(calls[0][1]).toBe(repo.importSource.id);
+ });
});
- it('renders a select2 namespace select', () => {
- expect(wrapper.contains(Select2Select)).toBe(true);
- expect(wrapper.find(Select2Select).props().options.data).toBe(availableNamespaces);
+ describe('when rendering imported project', () => {
+ const repo = {
+ importSource: {
+ id: 'remote-1',
+ fullName: 'fullName',
+ providerLink: 'providerLink',
+ },
+ importedProject: {
+ id: 1,
+ fullPath: 'fullPath',
+ importSource: 'importSource',
+ importStatus: STATUSES.FINISHED,
+ },
+ };
+
+ beforeEach(() => {
+ mountComponent({ repo });
+ });
+
+ it('renders project information', () => {
+ const providerLink = wrapper.find('[data-testid=providerLink]');
+
+ expect(providerLink.attributes().href).toMatch(repo.importSource.providerLink);
+ expect(providerLink.text()).toMatch(repo.importSource.fullName);
+ });
+
+ it('renders proper import status', () => {
+ expect(wrapper.find(ImportStatus).props().status).toBe(repo.importedProject.importStatus);
+ });
+
+ it('does not renders a namespace select', () => {
+ expect(wrapper.find(Select2Select).exists()).toBe(false);
+ });
+
+ it('does not render import button', () => {
+ expect(findImportButton().exists()).toBe(false);
+ });
});
- it('imports repo when clicking import button', async () => {
- findImportButton().trigger('click');
+ describe('when rendering incompatible project', () => {
+ const repo = {
+ importSource: {
+ id: 'remote-1',
+ fullName: 'fullName',
+ providerLink: 'providerLink',
+ incompatible: true,
+ },
+ };
- await nextTick();
+ beforeEach(() => {
+ mountComponent({ repo });
+ });
+
+ it('renders project information', () => {
+ const providerLink = wrapper.find('[data-testid=providerLink]');
- const { calls } = fetchImport.mock;
+ expect(providerLink.attributes().href).toMatch(repo.importSource.providerLink);
+ expect(providerLink.text()).toMatch(repo.importSource.fullName);
+ });
- expect(calls).toHaveLength(1);
- expect(calls[0][1]).toBe(repo.importSource.id);
+ it('renders badge with error', () => {
+ expect(wrapper.find(GlBadge).text()).toBe('Incompatible project');
+ });
});
});
diff --git a/spec/frontend/import_projects/store/actions_spec.js b/spec/frontend/import_projects/store/actions_spec.js
index 45a59b3f6d6..6951f2bf04d 100644
--- a/spec/frontend/import_projects/store/actions_spec.js
+++ b/spec/frontend/import_projects/store/actions_spec.js
@@ -83,7 +83,7 @@ describe('import_projects store actions', () => {
afterEach(() => mock.restore());
- it('dispatches stopJobsPolling actions and commits REQUEST_REPOS, RECEIVE_REPOS_SUCCESS mutations on a successful request', () => {
+ it('commits SET_PAGE, REQUEST_REPOS, RECEIVE_REPOS_SUCCESS mutations on a successful request', () => {
mock.onGet(MOCK_ENDPOINT).reply(200, payload);
return testAction(
@@ -91,54 +91,65 @@ describe('import_projects store actions', () => {
null,
localState,
[
+ { type: SET_PAGE, payload: 1 },
{ type: REQUEST_REPOS },
{
type: RECEIVE_REPOS_SUCCESS,
payload: convertObjectPropsToCamelCase(payload, { deep: true }),
},
],
- [{ type: 'stopJobsPolling' }, { type: 'fetchJobs' }],
+ [],
);
});
- it('dispatches stopJobsPolling action and commits REQUEST_REPOS, RECEIVE_REPOS_ERROR mutations on an unsuccessful request', () => {
+ it('commits SET_PAGE, REQUEST_REPOS, RECEIVE_REPOS_ERROR and SET_PAGE again mutations on an unsuccessful request', () => {
mock.onGet(MOCK_ENDPOINT).reply(500);
return testAction(
fetchRepos,
null,
localState,
- [{ type: REQUEST_REPOS }, { type: RECEIVE_REPOS_ERROR }],
- [{ type: 'stopJobsPolling' }],
+ [
+ { type: SET_PAGE, payload: 1 },
+ { type: REQUEST_REPOS },
+ { type: SET_PAGE, payload: 0 },
+ { type: RECEIVE_REPOS_ERROR },
+ ],
+ [],
);
});
- describe('when pagination is enabled', () => {
- it('includes page in url query params', async () => {
- const { fetchRepos: fetchReposWithPagination } = actionsFactory({
- endpoints,
- hasPagination: true,
- });
+ it('includes page in url query params', async () => {
+ let requestedUrl;
+ mock.onGet().reply(config => {
+ requestedUrl = config.url;
+ return [200, payload];
+ });
- let requestedUrl;
- mock.onGet().reply(config => {
- requestedUrl = config.url;
- return [200, payload];
- });
+ const localStateWithPage = { ...localState, pageInfo: { page: 2 } };
- await testAction(
- fetchReposWithPagination,
- null,
- localState,
- expect.any(Array),
- expect.any(Array),
- );
+ await testAction(fetchRepos, null, localStateWithPage, expect.any(Array), expect.any(Array));
- expect(requestedUrl).toBe(`${MOCK_ENDPOINT}?page=${localState.pageInfo.page}`);
- });
+ expect(requestedUrl).toBe(`${MOCK_ENDPOINT}?page=${localStateWithPage.pageInfo.page + 1}`);
});
- describe('when filtered', () => {
+ it('correctly updates current page on an unsuccessful request', () => {
+ mock.onGet(MOCK_ENDPOINT).reply(500);
+ const CURRENT_PAGE = 5;
+
+ return testAction(
+ fetchRepos,
+ null,
+ { ...localState, pageInfo: { page: CURRENT_PAGE } },
+ expect.arrayContaining([
+ { type: SET_PAGE, payload: CURRENT_PAGE + 1 },
+ { type: SET_PAGE, payload: CURRENT_PAGE },
+ ]),
+ [],
+ );
+ });
+
+ describe('when /home/xanf/projects/gdk/gitlab/spec/frontend/import_projects/store/actions_spec.jsfiltered', () => {
it('fetches repos with filter applied', () => {
mock.onGet(`${TEST_HOST}/endpoint.json?filter=filter`).reply(200, payload);
@@ -147,13 +158,14 @@ describe('import_projects store actions', () => {
null,
{ ...localState, filter: 'filter' },
[
+ { type: SET_PAGE, payload: 1 },
{ type: REQUEST_REPOS },
{
type: RECEIVE_REPOS_SUCCESS,
payload: convertObjectPropsToCamelCase(payload, { deep: true }),
},
],
- [{ type: 'stopJobsPolling' }, { type: 'fetchJobs' }],
+ [],
);
});
});
diff --git a/spec/frontend/import_projects/store/getters_spec.js b/spec/frontend/import_projects/store/getters_spec.js
index 5c1ea25a684..1ce42e534ea 100644
--- a/spec/frontend/import_projects/store/getters_spec.js
+++ b/spec/frontend/import_projects/store/getters_spec.js
@@ -3,6 +3,7 @@ import {
isImportingAnyRepo,
hasIncompatibleRepos,
hasImportableRepos,
+ importAllCount,
getImportTarget,
} from '~/import_projects/store/getters';
import { STATUSES } from '~/import_projects/constants';
@@ -10,13 +11,12 @@ import state from '~/import_projects/store/state';
const IMPORTED_REPO = {
importSource: {},
- importedProject: { fullPath: 'some/path' },
+ importedProject: { fullPath: 'some/path', importStatus: STATUSES.FINISHED },
};
const IMPORTABLE_REPO = {
importSource: { id: 'some-id', sanitizedName: 'sanitized' },
importedProject: null,
- importStatus: STATUSES.NONE,
};
const INCOMPATIBLE_REPO = {
@@ -56,14 +56,20 @@ describe('import_projects store getters', () => {
${STATUSES.STARTED} | ${true}
${STATUSES.FINISHED} | ${false}
`(
- 'isImportingAnyRepo returns $value when repo with $importStatus status is available',
+ 'isImportingAnyRepo returns $value when project with $importStatus status is available',
({ importStatus, value }) => {
- localState.repositories = [{ importStatus }];
+ localState.repositories = [{ importedProject: { importStatus } }];
expect(isImportingAnyRepo(localState)).toBe(value);
},
);
+ it('isImportingAnyRepo returns false when project with no defined importStatus status is available', () => {
+ localState.repositories = [{ importSource: {} }];
+
+ expect(isImportingAnyRepo(localState)).toBe(false);
+ });
+
describe('hasIncompatibleRepos', () => {
it('returns true if there are any incompatible projects', () => {
localState.repositories = [IMPORTABLE_REPO, IMPORTED_REPO, INCOMPATIBLE_REPO];
@@ -92,6 +98,19 @@ describe('import_projects store getters', () => {
});
});
+ describe('importAllCount', () => {
+ it('returns count of available importable projects ', () => {
+ localState.repositories = [
+ IMPORTABLE_REPO,
+ IMPORTABLE_REPO,
+ IMPORTED_REPO,
+ INCOMPATIBLE_REPO,
+ ];
+
+ expect(importAllCount(localState)).toBe(2);
+ });
+ });
+
describe('getImportTarget', () => {
it('returns default value if no custom target available', () => {
localState.defaultTargetNamespace = 'default';
diff --git a/spec/frontend/import_projects/store/mutations_spec.js b/spec/frontend/import_projects/store/mutations_spec.js
index 3672ec9f2c0..5d78a7fa9e7 100644
--- a/spec/frontend/import_projects/store/mutations_spec.js
+++ b/spec/frontend/import_projects/store/mutations_spec.js
@@ -1,9 +1,11 @@
import * as types from '~/import_projects/store/mutation_types';
import mutations from '~/import_projects/store/mutations';
+import getInitialState from '~/import_projects/store/state';
import { STATUSES } from '~/import_projects/constants';
describe('import_projects store mutations', () => {
let state;
+
const SOURCE_PROJECT = {
id: 1,
full_name: 'full/name',
@@ -19,13 +21,23 @@ describe('import_projects store mutations', () => {
};
describe(`${types.SET_FILTER}`, () => {
- it('overwrites current filter value', () => {
- state = { filter: 'some-value' };
- const NEW_VALUE = 'new-value';
+ const NEW_VALUE = 'new-value';
+ beforeEach(() => {
+ state = {
+ filter: 'some-value',
+ repositories: ['some', ' repositories'],
+ pageInfo: { page: 1 },
+ };
mutations[types.SET_FILTER](state, NEW_VALUE);
+ });
- expect(state.filter).toBe(NEW_VALUE);
+ it('removes current repositories list', () => {
+ expect(state.repositories.length).toBe(0);
+ });
+
+ it('resets current page to 0', () => {
+ expect(state.pageInfo.page).toBe(0);
});
});
@@ -40,93 +52,104 @@ describe('import_projects store mutations', () => {
});
describe(`${types.RECEIVE_REPOS_SUCCESS}`, () => {
- describe('for imported projects', () => {
- const response = {
- importedProjects: [IMPORTED_PROJECT],
- providerRepos: [],
- };
+ describe('with legacy response format', () => {
+ describe('for imported projects', () => {
+ const response = {
+ importedProjects: [IMPORTED_PROJECT],
+ providerRepos: [],
+ };
- it('picks import status from response', () => {
- state = {};
+ it('recreates importSource from response', () => {
+ state = getInitialState();
- mutations[types.RECEIVE_REPOS_SUCCESS](state, response);
+ mutations[types.RECEIVE_REPOS_SUCCESS](state, response);
- expect(state.repositories[0].importStatus).toBe(IMPORTED_PROJECT.importStatus);
- });
+ expect(state.repositories[0].importSource).toStrictEqual(
+ expect.objectContaining({
+ fullName: IMPORTED_PROJECT.importSource,
+ sanitizedName: IMPORTED_PROJECT.name,
+ providerLink: IMPORTED_PROJECT.providerLink,
+ }),
+ );
+ });
- it('recreates importSource from response', () => {
- state = {};
+ it('passes project to importProject', () => {
+ state = getInitialState();
- mutations[types.RECEIVE_REPOS_SUCCESS](state, response);
+ mutations[types.RECEIVE_REPOS_SUCCESS](state, response);
- expect(state.repositories[0].importSource).toStrictEqual(
- expect.objectContaining({
- fullName: IMPORTED_PROJECT.importSource,
- sanitizedName: IMPORTED_PROJECT.name,
- providerLink: IMPORTED_PROJECT.providerLink,
- }),
- );
+ expect(IMPORTED_PROJECT).toStrictEqual(
+ expect.objectContaining(state.repositories[0].importedProject),
+ );
+ });
});
- it('passes project to importProject', () => {
- state = {};
+ describe('for importable projects', () => {
+ beforeEach(() => {
+ state = getInitialState();
- mutations[types.RECEIVE_REPOS_SUCCESS](state, response);
+ const response = {
+ importedProjects: [],
+ providerRepos: [SOURCE_PROJECT],
+ };
+ mutations[types.RECEIVE_REPOS_SUCCESS](state, response);
+ });
- expect(IMPORTED_PROJECT).toStrictEqual(
- expect.objectContaining(state.repositories[0].importedProject),
- );
+ it('sets importSource to project', () => {
+ expect(state.repositories[0].importSource).toBe(SOURCE_PROJECT);
+ });
});
- });
- describe('for importable projects', () => {
- beforeEach(() => {
- state = {};
+ describe('for incompatible projects', () => {
const response = {
importedProjects: [],
- providerRepos: [SOURCE_PROJECT],
+ providerRepos: [],
+ incompatibleRepos: [SOURCE_PROJECT],
};
- mutations[types.RECEIVE_REPOS_SUCCESS](state, response);
- });
- it('sets import status to none', () => {
- expect(state.repositories[0].importStatus).toBe(STATUSES.NONE);
- });
+ beforeEach(() => {
+ state = getInitialState();
+ mutations[types.RECEIVE_REPOS_SUCCESS](state, response);
+ });
+
+ it('sets incompatible flag', () => {
+ expect(state.repositories[0].importSource.incompatible).toBe(true);
+ });
- it('sets importSource to project', () => {
- expect(state.repositories[0].importSource).toBe(SOURCE_PROJECT);
+ it('sets importSource to project', () => {
+ expect(state.repositories[0].importSource).toStrictEqual(
+ expect.objectContaining(SOURCE_PROJECT),
+ );
+ });
});
- });
- describe('for incompatible projects', () => {
- const response = {
- importedProjects: [],
- providerRepos: [],
- incompatibleRepos: [SOURCE_PROJECT],
- };
+ it('sets repos loading flag to false', () => {
+ const response = {
+ importedProjects: [],
+ providerRepos: [],
+ };
+
+ state = getInitialState();
- beforeEach(() => {
- state = {};
mutations[types.RECEIVE_REPOS_SUCCESS](state, response);
- });
- it('sets incompatible flag', () => {
- expect(state.repositories[0].importSource.incompatible).toBe(true);
+ expect(state.isLoadingRepos).toBe(false);
});
+ });
- it('sets importSource to project', () => {
- expect(state.repositories[0].importSource).toStrictEqual(
- expect.objectContaining(SOURCE_PROJECT),
- );
- });
+ it('passes response as it is', () => {
+ const response = [];
+ state = getInitialState();
+
+ mutations[types.RECEIVE_REPOS_SUCCESS](state, response);
+
+ expect(state.repositories).toStrictEqual(response);
});
it('sets repos loading flag to false', () => {
- const response = {
- importedProjects: [],
- providerRepos: [],
- };
- state = {};
+ const response = [];
+
+ state = getInitialState();
mutations[types.RECEIVE_REPOS_SUCCESS](state, response);
@@ -136,7 +159,7 @@ describe('import_projects store mutations', () => {
describe(`${types.RECEIVE_REPOS_ERROR}`, () => {
it('sets repos loading flag to false', () => {
- state = {};
+ state = getInitialState();
mutations[types.RECEIVE_REPOS_ERROR](state);
@@ -154,7 +177,7 @@ describe('import_projects store mutations', () => {
});
it(`sets status to ${STATUSES.SCHEDULING}`, () => {
- expect(state.repositories[0].importStatus).toBe(STATUSES.SCHEDULING);
+ expect(state.repositories[0].importedProject.importStatus).toBe(STATUSES.SCHEDULING);
});
});
@@ -170,7 +193,9 @@ describe('import_projects store mutations', () => {
});
it('sets import status', () => {
- expect(state.repositories[0].importStatus).toBe(IMPORTED_PROJECT.importStatus);
+ expect(state.repositories[0].importedProject.importStatus).toBe(
+ IMPORTED_PROJECT.importStatus,
+ );
});
it('sets imported project', () => {
@@ -188,8 +213,8 @@ describe('import_projects store mutations', () => {
mutations[types.RECEIVE_IMPORT_ERROR](state, REPO_ID);
});
- it(`resets import status to ${STATUSES.NONE}`, () => {
- expect(state.repositories[0].importStatus).toBe(STATUSES.NONE);
+ it(`removes importedProject entry`, () => {
+ expect(state.repositories[0].importedProject).toBeNull();
});
});
@@ -203,7 +228,9 @@ describe('import_projects store mutations', () => {
mutations[types.RECEIVE_JOBS_SUCCESS](state, updatedProjects);
- expect(state.repositories[0].importStatus).toBe(updatedProjects[0].importStatus);
+ expect(state.repositories[0].importedProject.importStatus).toBe(
+ updatedProjects[0].importStatus,
+ );
});
});
@@ -280,17 +307,6 @@ describe('import_projects store mutations', () => {
});
});
- describe(`${types.SET_PAGE_INFO}`, () => {
- it('sets passed page info', () => {
- state = {};
- const pageInfo = { page: 1, total: 10 };
-
- mutations[types.SET_PAGE_INFO](state, pageInfo);
-
- expect(state.pageInfo).toBe(pageInfo);
- });
- });
-
describe(`${types.SET_PAGE}`, () => {
it('sets page number', () => {
const NEW_PAGE = 4;
diff --git a/spec/frontend/import_projects/utils_spec.js b/spec/frontend/import_projects/utils_spec.js
index 826b06d5a70..4e1e16a3184 100644
--- a/spec/frontend/import_projects/utils_spec.js
+++ b/spec/frontend/import_projects/utils_spec.js
@@ -1,7 +1,16 @@
-import { isProjectImportable } from '~/import_projects/utils';
+import { isProjectImportable, isIncompatible, getImportStatus } from '~/import_projects/utils';
import { STATUSES } from '~/import_projects/constants';
describe('import_projects utils', () => {
+ const COMPATIBLE_PROJECT = {
+ importSource: { incompatible: false },
+ };
+
+ const INCOMPATIBLE_PROJECT = {
+ importSource: { incompatible: true },
+ importedProject: null,
+ };
+
describe('isProjectImportable', () => {
it.each`
status | result
@@ -14,19 +23,43 @@ describe('import_projects utils', () => {
`('returns $result when project is compatible and status is $status', ({ status, result }) => {
expect(
isProjectImportable({
- importStatus: status,
- importSource: { incompatible: false },
+ ...COMPATIBLE_PROJECT,
+ importedProject: { importStatus: status },
}),
).toBe(result);
});
+ it('returns true if import status is not defined', () => {
+ expect(isProjectImportable({ importSource: {} })).toBe(true);
+ });
+
it('returns false if project is not compatible', () => {
+ expect(isProjectImportable(INCOMPATIBLE_PROJECT)).toBe(false);
+ });
+ });
+
+ describe('isIncompatible', () => {
+ it('returns true for incompatible project', () => {
+ expect(isIncompatible(INCOMPATIBLE_PROJECT)).toBe(true);
+ });
+
+ it('returns false for compatible project', () => {
+ expect(isIncompatible(COMPATIBLE_PROJECT)).toBe(false);
+ });
+ });
+
+ describe('getImportStatus', () => {
+ it('returns actual status when project status is provided', () => {
expect(
- isProjectImportable({
- importStatus: STATUSES.NONE,
- importSource: { incompatible: true },
+ getImportStatus({
+ ...COMPATIBLE_PROJECT,
+ importedProject: { importStatus: STATUSES.FINISHED },
}),
- ).toBe(false);
+ ).toBe(STATUSES.FINISHED);
+ });
+
+ it('returns NONE as status if import status is not provided', () => {
+ expect(getImportStatus(COMPATIBLE_PROJECT)).toBe(STATUSES.NONE);
});
});
});