diff options
Diffstat (limited to 'spec/frontend/import_projects')
7 files changed, 0 insertions, 1394 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 deleted file mode 100644 index b65b388fd5f..00000000000 --- a/spec/frontend/import_projects/components/bitbucket_status_table_spec.js +++ /dev/null @@ -1,59 +0,0 @@ -import { nextTick } from 'vue'; -import { shallowMount } from '@vue/test-utils'; - -import { GlAlert } from '@gitlab/ui'; -import BitbucketStatusTable from '~/import_projects/components/bitbucket_status_table.vue'; -import ImportProjectsTable from '~/import_projects/components/import_projects_table.vue'; - -const ImportProjectsTableStub = { - name: 'ImportProjectsTable', - template: - '<div><slot name="incompatible-repos-warning"></slot><slot name="actions"></slot></div>', -}; - -describe('BitbucketStatusTable', () => { - let wrapper; - - afterEach(() => { - if (wrapper) { - wrapper.destroy(); - wrapper = null; - } - }); - - function createComponent(propsData, importProjectsTableStub = true, slots) { - wrapper = shallowMount(BitbucketStatusTable, { - propsData, - stubs: { - ImportProjectsTable: importProjectsTableStub, - }, - slots, - }); - } - - it('renders import table component', () => { - createComponent({ providerTitle: 'Test' }); - expect(wrapper.find(ImportProjectsTable).exists()).toBe(true); - }); - - it('passes alert in incompatible-repos-warning slot', () => { - createComponent({ providerTitle: 'Test' }, ImportProjectsTableStub); - expect(wrapper.find(GlAlert).exists()).toBe(true); - }); - - it('passes actions slot to import project table component', () => { - const actionsSlotContent = 'DEMO'; - createComponent({ providerTitle: 'Test' }, ImportProjectsTableStub, { - actions: actionsSlotContent, - }); - expect(wrapper.find(ImportProjectsTable).text()).toBe(actionsSlotContent); - }); - - it('dismisses alert when requested', async () => { - createComponent({ providerTitle: 'Test' }, ImportProjectsTableStub); - wrapper.find(GlAlert).vm.$emit('dismiss'); - await nextTick(); - - expect(wrapper.find(GlAlert).exists()).toBe(false); - }); -}); diff --git a/spec/frontend/import_projects/components/import_projects_table_spec.js b/spec/frontend/import_projects/components/import_projects_table_spec.js deleted file mode 100644 index 7322c7c1ae1..00000000000 --- a/spec/frontend/import_projects/components/import_projects_table_spec.js +++ /dev/null @@ -1,249 +0,0 @@ -import { nextTick } from 'vue'; -import Vuex from 'vuex'; -import { createLocalVue, shallowMount } from '@vue/test-utils'; -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 ProviderRepoTableRow from '~/import_projects/components/provider_repo_table_row.vue'; - -describe('ImportProjectsTable', () => { - let wrapper; - - const findFilterField = () => - wrapper.find('input[data-qa-selector="githubish_import_filter_field"]'); - - const providerTitle = 'THE PROVIDER'; - 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 fetchReposFn = jest.fn(); - - function createComponent({ - state: initialState, - getters: customGetters, - slots, - filterable, - paginatable, - } = {}) { - const localVue = createLocalVue(); - localVue.use(Vuex); - - const store = new Vuex.Store({ - state: { ...state(), ...initialState }, - getters: { - ...getters, - ...customGetters, - }, - actions: { - fetchRepos: fetchReposFn, - fetchJobs: jest.fn(), - fetchNamespaces: jest.fn(), - importAll: importAllFn, - stopJobsPolling: jest.fn(), - clearJobsEtagPoll: jest.fn(), - setFilter: jest.fn(), - }, - }); - - wrapper = shallowMount(ImportProjectsTable, { - localVue, - store, - propsData: { - providerTitle, - filterable, - paginatable, - }, - slots, - stubs: { - GlModal: { template: '<div>Modal!</div>', methods: { show: importAllModalShowFn } }, - }, - }); - } - - afterEach(() => { - if (wrapper) { - wrapper.destroy(); - wrapper = null; - } - }); - - it('renders a loading icon while repos are loading', () => { - createComponent({ state: { isLoadingRepos: true } }); - - expect(wrapper.find(GlLoadingIcon).exists()).toBe(true); - }); - - it('renders a loading icon while namespaces are loading', () => { - createComponent({ state: { isLoadingNamespaces: true } }); - - expect(wrapper.find(GlLoadingIcon).exists()).toBe(true); - }); - - 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 }, - }); - - expect(wrapper.find(GlLoadingIcon).exists()).toBe(false); - expect(wrapper.find('table').exists()).toBe(true); - expect( - wrapper - .findAll('th') - .filter(w => w.text() === `From ${providerTitle}`) - .exists(), - ).toBe(true); - - expect(wrapper.findAll(ProviderRepoTableRow)).toHaveLength(repositories.length); - }); - - it.each` - 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 and repos count is $count', - ({ hasIncompatibleRepos, buttonText, count }) => { - createComponent({ - state: { - providerRepos: [providerRepo], - }, - getters: { - hasIncompatibleRepos: () => hasIncompatibleRepos, - importAllCount: () => count, - }, - }); - - expect(findImportAllButton().text()).toBe(buttonText); - }, - ); - - it('renders an empty state if there are no repositories available', () => { - createComponent({ state: { repositories: [] } }); - - expect(wrapper.find(ProviderRepoTableRow).exists()).toBe(false); - expect(wrapper.text()).toContain(`No ${providerTitle} repositories found`); - }); - - 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(); - }); - - it('shows loading spinner when import is in progress', () => { - createComponent({ getters: { isImportingAnyRepo: () => true } }); - - expect(findImportAllButton().props().loading).toBe(true); - }); - - it('renders filtering input field by default', () => { - createComponent(); - - expect(findFilterField().exists()).toBe(true); - }); - - it('does not render filtering input field when filterable is false', () => { - createComponent({ filterable: false }); - - expect(findFilterField().exists()).toBe(false); - }); - - describe('when paginatable is set to true', () => { - const pageInfo = { page: 1 }; - - beforeEach(() => { - createComponent({ - state: { - namespaces: [{ fullPath: 'path' }], - pageInfo, - repositories: [ - { importSource: { id: 1 }, importedProject: null, importStatus: STATUSES.NONE }, - ], - }, - paginatable: true, - }); - }); - - it('does not call fetchRepos on mount', () => { - expect(fetchReposFn).not.toHaveBeenCalled(); - }); - - it('renders intersection observer component', () => { - expect(wrapper.find(GlIntersectionObserver).exists()).toBe(true); - }); - - it('calls fetchRepos when intersection observer appears', async () => { - wrapper.find(GlIntersectionObserver).vm.$emit('appear'); - - await nextTick(); - - expect(fetchReposFn).toHaveBeenCalled(); - }); - }); - - it('calls fetchRepos on mount', () => { - createComponent(); - - expect(fetchReposFn).toHaveBeenCalled(); - }); - - it.each` - hasIncompatibleRepos | shouldRenderSlot | action - ${false} | ${false} | ${'does not render'} - ${true} | ${true} | ${'render'} - `( - '$action incompatible-repos-warning slot if hasIncompatibleRepos is $hasIncompatibleRepos', - ({ hasIncompatibleRepos, shouldRenderSlot }) => { - const INCOMPATIBLE_TEXT = 'INCOMPATIBLE!'; - - createComponent({ - getters: { - hasIncompatibleRepos: () => hasIncompatibleRepos, - }, - - slots: { - 'incompatible-repos-warning': INCOMPATIBLE_TEXT, - }, - }); - - expect(wrapper.text().includes(INCOMPATIBLE_TEXT)).toBe(shouldRenderSlot); - }, - ); -}); 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 deleted file mode 100644 index 03e30ef610e..00000000000 --- a/spec/frontend/import_projects/components/provider_repo_table_row_spec.js +++ /dev/null @@ -1,169 +0,0 @@ -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'; -import Select2Select from '~/vue_shared/components/select2_select.vue'; - -describe('ProviderRepoTableRow', () => { - let wrapper; - const fetchImport = jest.fn(); - const setImportTarget = jest.fn(); - const fakeImportTarget = { - targetNamespace: 'target', - newName: 'newName', - }; - - const availableNamespaces = [ - { text: 'Groups', children: [{ id: 'test', text: 'test' }] }, - { text: 'Users', children: [{ id: 'root', text: 'root' }] }, - ]; - - function initStore(initialState) { - const store = new Vuex.Store({ - state: initialState, - getters: { - getImportTarget: () => () => fakeImportTarget, - }, - actions: { fetchImport, setImportTarget }, - }); - - return store; - } - - const findImportButton = () => { - const buttons = wrapper.findAll('button').filter(node => node.text() === 'Import'); - - return buttons.length ? buttons.at(0) : buttons; - }; - - function mountComponent(props) { - const localVue = createLocalVue(); - localVue.use(Vuex); - - const store = initStore(); - - wrapper = shallowMount(ProviderRepoTableRow, { - localVue, - store, - propsData: { availableNamespaces, ...props }, - }); - } - - afterEach(() => { - wrapper.destroy(); - wrapper = null; - }); - - 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(calls).toHaveLength(1); - expect(calls[0][1]).toBe(repo.importSource.id); - }); - }); - - 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); - }); - }); - - describe('when rendering incompatible project', () => { - const repo = { - importSource: { - id: 'remote-1', - fullName: 'fullName', - providerLink: 'providerLink', - incompatible: true, - }, - }; - - 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 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 deleted file mode 100644 index 06afb20c6a2..00000000000 --- a/spec/frontend/import_projects/store/actions_spec.js +++ /dev/null @@ -1,398 +0,0 @@ -import MockAdapter from 'axios-mock-adapter'; -import testAction from 'helpers/vuex_action_helper'; -import { TEST_HOST } from 'helpers/test_constants'; -import { deprecatedCreateFlash as createFlash } from '~/flash'; -import axios from '~/lib/utils/axios_utils'; -import { convertObjectPropsToCamelCase } from '~/lib/utils/common_utils'; -import { - REQUEST_REPOS, - RECEIVE_REPOS_SUCCESS, - RECEIVE_REPOS_ERROR, - REQUEST_IMPORT, - RECEIVE_IMPORT_SUCCESS, - RECEIVE_IMPORT_ERROR, - RECEIVE_JOBS_SUCCESS, - REQUEST_NAMESPACES, - RECEIVE_NAMESPACES_SUCCESS, - RECEIVE_NAMESPACES_ERROR, - SET_PAGE, - SET_FILTER, -} from '~/import_projects/store/mutation_types'; -import actionsFactory from '~/import_projects/store/actions'; -import { getImportTarget } from '~/import_projects/store/getters'; -import state from '~/import_projects/store/state'; -import { STATUSES } from '~/import_projects/constants'; - -jest.mock('~/flash'); - -const MOCK_ENDPOINT = `${TEST_HOST}/endpoint.json`; -const endpoints = { - reposPath: MOCK_ENDPOINT, - importPath: MOCK_ENDPOINT, - jobsPath: MOCK_ENDPOINT, - namespacesPath: MOCK_ENDPOINT, -}; - -const { - clearJobsEtagPoll, - stopJobsPolling, - importAll, - fetchRepos, - fetchImport, - fetchJobs, - fetchNamespaces, - setFilter, -} = actionsFactory({ - endpoints, -}); - -describe('import_projects store actions', () => { - let localState; - const importRepoId = 1; - const otherImportRepoId = 2; - const defaultTargetNamespace = 'default'; - const sanitizedName = 'sanitizedName'; - const defaultImportTarget = { newName: sanitizedName, targetNamespace: defaultTargetNamespace }; - - beforeEach(() => { - localState = { - ...state(), - defaultTargetNamespace, - repositories: [ - { importSource: { id: importRepoId, sanitizedName }, importStatus: STATUSES.NONE }, - { - importSource: { id: otherImportRepoId, sanitizedName: 's2' }, - importStatus: STATUSES.NONE, - }, - { - importSource: { id: 3, sanitizedName: 's3', incompatible: true }, - importStatus: STATUSES.NONE, - }, - ], - provider: 'provider', - }; - - localState.getImportTarget = getImportTarget(localState); - }); - - describe('fetchRepos', () => { - let mock; - const payload = { imported_projects: [{}], provider_repos: [{}] }; - - beforeEach(() => { - mock = new MockAdapter(axios); - }); - - afterEach(() => mock.restore()); - - it('commits SET_PAGE, REQUEST_REPOS, RECEIVE_REPOS_SUCCESS mutations on a successful request', () => { - mock.onGet(MOCK_ENDPOINT).reply(200, payload); - - return testAction( - fetchRepos, - null, - localState, - [ - { type: SET_PAGE, payload: 1 }, - { type: REQUEST_REPOS }, - { - type: RECEIVE_REPOS_SUCCESS, - payload: convertObjectPropsToCamelCase(payload, { deep: true }), - }, - ], - [], - ); - }); - - 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: SET_PAGE, payload: 1 }, - { type: REQUEST_REPOS }, - { type: SET_PAGE, payload: 0 }, - { type: RECEIVE_REPOS_ERROR }, - ], - [], - ); - }); - - it('includes page in url query params', async () => { - let requestedUrl; - mock.onGet().reply(config => { - requestedUrl = config.url; - return [200, payload]; - }); - - const localStateWithPage = { ...localState, pageInfo: { page: 2 } }; - - await testAction(fetchRepos, null, localStateWithPage, expect.any(Array), expect.any(Array)); - - expect(requestedUrl).toBe(`${MOCK_ENDPOINT}?page=${localStateWithPage.pageInfo.page + 1}`); - }); - - 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 rate limited', () => { - it('commits RECEIVE_REPOS_ERROR and shows rate limited error message', async () => { - mock.onGet(`${TEST_HOST}/endpoint.json?filter=filter`).reply(429); - - await testAction( - fetchRepos, - null, - { ...localState, filter: 'filter' }, - [ - { type: SET_PAGE, payload: 1 }, - { type: REQUEST_REPOS }, - { type: SET_PAGE, payload: 0 }, - { type: RECEIVE_REPOS_ERROR }, - ], - [], - ); - - expect(createFlash).toHaveBeenCalledWith('Provider rate limit exceeded. Try again later'); - }); - }); - - describe('when filtered', () => { - it('fetches repos with filter applied', () => { - mock.onGet(`${TEST_HOST}/endpoint.json?filter=filter`).reply(200, payload); - - return testAction( - fetchRepos, - null, - { ...localState, filter: 'filter' }, - [ - { type: SET_PAGE, payload: 1 }, - { type: REQUEST_REPOS }, - { - type: RECEIVE_REPOS_SUCCESS, - payload: convertObjectPropsToCamelCase(payload, { deep: true }), - }, - ], - [], - ); - }); - }); - }); - - describe('fetchImport', () => { - let mock; - - beforeEach(() => { - mock = new MockAdapter(axios); - }); - - afterEach(() => mock.restore()); - - it('commits REQUEST_IMPORT and REQUEST_IMPORT_SUCCESS mutations on a successful request', () => { - const importedProject = { name: 'imported/project' }; - mock.onPost(MOCK_ENDPOINT).reply(200, importedProject); - - return testAction( - fetchImport, - importRepoId, - localState, - [ - { - type: REQUEST_IMPORT, - payload: { repoId: importRepoId, importTarget: defaultImportTarget }, - }, - { - type: RECEIVE_IMPORT_SUCCESS, - payload: { - importedProject: convertObjectPropsToCamelCase(importedProject, { deep: true }), - repoId: importRepoId, - }, - }, - ], - [], - ); - }); - - it('commits REQUEST_IMPORT and RECEIVE_IMPORT_ERROR and shows generic error message on an unsuccessful request', async () => { - mock.onPost(MOCK_ENDPOINT).reply(500); - - await testAction( - fetchImport, - importRepoId, - localState, - [ - { - type: REQUEST_IMPORT, - payload: { repoId: importRepoId, importTarget: defaultImportTarget }, - }, - { type: RECEIVE_IMPORT_ERROR, payload: importRepoId }, - ], - [], - ); - - expect(createFlash).toHaveBeenCalledWith('Importing the project failed'); - }); - - it('commits REQUEST_IMPORT and RECEIVE_IMPORT_ERROR and shows detailed error message on an unsuccessful request with errors fields in response', async () => { - const ERROR_MESSAGE = 'dummy'; - mock.onPost(MOCK_ENDPOINT).reply(500, { errors: ERROR_MESSAGE }); - - await testAction( - fetchImport, - importRepoId, - localState, - [ - { - type: REQUEST_IMPORT, - payload: { repoId: importRepoId, importTarget: defaultImportTarget }, - }, - { type: RECEIVE_IMPORT_ERROR, payload: importRepoId }, - ], - [], - ); - - expect(createFlash).toHaveBeenCalledWith(`Importing the project failed: ${ERROR_MESSAGE}`); - }); - }); - - describe('fetchJobs', () => { - let mock; - const updatedProjects = [{ name: 'imported/project' }, { name: 'provider/repo' }]; - - beforeEach(() => { - mock = new MockAdapter(axios); - }); - - afterEach(() => { - stopJobsPolling(); - clearJobsEtagPoll(); - }); - - afterEach(() => mock.restore()); - - it('commits RECEIVE_JOBS_SUCCESS mutation on a successful request', async () => { - mock.onGet(MOCK_ENDPOINT).reply(200, updatedProjects); - - await testAction( - fetchJobs, - null, - localState, - [ - { - type: RECEIVE_JOBS_SUCCESS, - payload: convertObjectPropsToCamelCase(updatedProjects, { deep: true }), - }, - ], - [], - ); - }); - - describe('when filtered', () => { - beforeEach(() => { - localState.filter = 'filter'; - }); - - it('fetches realtime changes with filter applied', () => { - mock.onGet(`${TEST_HOST}/endpoint.json?filter=filter`).reply(200, updatedProjects); - - return testAction( - fetchJobs, - null, - localState, - [ - { - type: RECEIVE_JOBS_SUCCESS, - payload: convertObjectPropsToCamelCase(updatedProjects, { deep: true }), - }, - ], - [], - ); - }); - }); - }); - - describe('fetchNamespaces', () => { - let mock; - const namespaces = [{ full_name: 'test/ns1' }, { full_name: 'test_ns2' }]; - - beforeEach(() => { - mock = new MockAdapter(axios); - }); - - afterEach(() => mock.restore()); - - it('commits REQUEST_NAMESPACES and RECEIVE_NAMESPACES_SUCCESS on success', async () => { - mock.onGet(MOCK_ENDPOINT).reply(200, namespaces); - - await testAction( - fetchNamespaces, - null, - localState, - [ - { type: REQUEST_NAMESPACES }, - { - type: RECEIVE_NAMESPACES_SUCCESS, - payload: convertObjectPropsToCamelCase(namespaces, { deep: true }), - }, - ], - [], - ); - }); - - it('commits REQUEST_NAMESPACES and RECEIVE_NAMESPACES_ERROR and shows generic error message on an unsuccessful request', async () => { - mock.onGet(MOCK_ENDPOINT).reply(500); - - await testAction( - fetchNamespaces, - null, - localState, - [{ type: REQUEST_NAMESPACES }, { type: RECEIVE_NAMESPACES_ERROR }], - [], - ); - - expect(createFlash).toHaveBeenCalledWith('Requesting namespaces failed'); - }); - }); - - describe('importAll', () => { - it('dispatches multiple fetchImport actions', async () => { - await testAction( - importAll, - null, - localState, - [], - [ - { type: 'fetchImport', payload: importRepoId }, - { type: 'fetchImport', payload: otherImportRepoId }, - ], - ); - }); - }); - - describe('setFilter', () => { - it('dispatches sets the filter value and dispatches fetchRepos', async () => { - await testAction( - setFilter, - 'filteredRepo', - localState, - [{ type: SET_FILTER, payload: 'filteredRepo' }], - [{ type: 'fetchRepos' }], - ); - }); - }); -}); diff --git a/spec/frontend/import_projects/store/getters_spec.js b/spec/frontend/import_projects/store/getters_spec.js deleted file mode 100644 index 1ce42e534ea..00000000000 --- a/spec/frontend/import_projects/store/getters_spec.js +++ /dev/null @@ -1,135 +0,0 @@ -import { - isLoading, - isImportingAnyRepo, - hasIncompatibleRepos, - hasImportableRepos, - importAllCount, - getImportTarget, -} from '~/import_projects/store/getters'; -import { STATUSES } from '~/import_projects/constants'; -import state from '~/import_projects/store/state'; - -const IMPORTED_REPO = { - importSource: {}, - importedProject: { fullPath: 'some/path', importStatus: STATUSES.FINISHED }, -}; - -const IMPORTABLE_REPO = { - importSource: { id: 'some-id', sanitizedName: 'sanitized' }, - importedProject: null, -}; - -const INCOMPATIBLE_REPO = { - importSource: { incompatible: true }, -}; - -describe('import_projects store getters', () => { - let localState; - - beforeEach(() => { - localState = state(); - }); - - it.each` - isLoadingRepos | isLoadingNamespaces | isLoadingValue - ${false} | ${false} | ${false} - ${true} | ${false} | ${true} - ${false} | ${true} | ${true} - ${true} | ${true} | ${true} - `( - 'isLoading returns $isLoadingValue when isLoadingRepos is $isLoadingRepos and isLoadingNamespaces is $isLoadingNamespaces', - ({ isLoadingRepos, isLoadingNamespaces, isLoadingValue }) => { - Object.assign(localState, { - isLoadingRepos, - isLoadingNamespaces, - }); - - expect(isLoading(localState)).toBe(isLoadingValue); - }, - ); - - it.each` - importStatus | value - ${STATUSES.NONE} | ${false} - ${STATUSES.SCHEDULING} | ${true} - ${STATUSES.SCHEDULED} | ${true} - ${STATUSES.STARTED} | ${true} - ${STATUSES.FINISHED} | ${false} - `( - 'isImportingAnyRepo returns $value when project with $importStatus status is available', - ({ importStatus, value }) => { - 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]; - - expect(hasIncompatibleRepos(localState)).toBe(true); - }); - - it('returns false if there are no incompatible projects', () => { - localState.repositories = [IMPORTABLE_REPO, IMPORTED_REPO]; - - expect(hasIncompatibleRepos(localState)).toBe(false); - }); - }); - - describe('hasImportableRepos', () => { - it('returns true if there are any importable projects ', () => { - localState.repositories = [IMPORTABLE_REPO, IMPORTED_REPO, INCOMPATIBLE_REPO]; - - expect(hasImportableRepos(localState)).toBe(true); - }); - - it('returns false if there are no importable projects', () => { - localState.repositories = [IMPORTED_REPO, INCOMPATIBLE_REPO]; - - expect(hasImportableRepos(localState)).toBe(false); - }); - }); - - 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'; - localState.repositories = [IMPORTABLE_REPO]; - - expect(getImportTarget(localState)(IMPORTABLE_REPO.importSource.id)).toStrictEqual({ - newName: IMPORTABLE_REPO.importSource.sanitizedName, - targetNamespace: localState.defaultTargetNamespace, - }); - }); - - it('returns custom import target if available', () => { - const fakeTarget = { newName: 'something', targetNamespace: 'ns' }; - localState.repositories = [IMPORTABLE_REPO]; - localState.customImportTargets[IMPORTABLE_REPO.importSource.id] = fakeTarget; - - expect(getImportTarget(localState)(IMPORTABLE_REPO.importSource.id)).toStrictEqual( - fakeTarget, - ); - }); - }); -}); diff --git a/spec/frontend/import_projects/store/mutations_spec.js b/spec/frontend/import_projects/store/mutations_spec.js deleted file mode 100644 index 5d78a7fa9e7..00000000000 --- a/spec/frontend/import_projects/store/mutations_spec.js +++ /dev/null @@ -1,319 +0,0 @@ -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', - sanitized_name: 'name', - provider_link: 'https://demo.link/full/name', - }; - const IMPORTED_PROJECT = { - name: 'demo', - importSource: 'something', - providerLink: 'custom-link', - importStatus: 'status', - fullName: 'fullName', - }; - - describe(`${types.SET_FILTER}`, () => { - const NEW_VALUE = 'new-value'; - - beforeEach(() => { - state = { - filter: 'some-value', - repositories: ['some', ' repositories'], - pageInfo: { page: 1 }, - }; - mutations[types.SET_FILTER](state, 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); - }); - }); - - describe(`${types.REQUEST_REPOS}`, () => { - it('sets repos loading flag to true', () => { - state = {}; - - mutations[types.REQUEST_REPOS](state); - - expect(state.isLoadingRepos).toBe(true); - }); - }); - - describe(`${types.RECEIVE_REPOS_SUCCESS}`, () => { - describe('with legacy response format', () => { - describe('for imported projects', () => { - const response = { - importedProjects: [IMPORTED_PROJECT], - providerRepos: [], - }; - - it('recreates importSource from response', () => { - state = getInitialState(); - - 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, - }), - ); - }); - - it('passes project to importProject', () => { - state = getInitialState(); - - mutations[types.RECEIVE_REPOS_SUCCESS](state, response); - - expect(IMPORTED_PROJECT).toStrictEqual( - expect.objectContaining(state.repositories[0].importedProject), - ); - }); - }); - - describe('for importable projects', () => { - beforeEach(() => { - state = getInitialState(); - - const response = { - importedProjects: [], - providerRepos: [SOURCE_PROJECT], - }; - mutations[types.RECEIVE_REPOS_SUCCESS](state, response); - }); - - it('sets importSource to project', () => { - expect(state.repositories[0].importSource).toBe(SOURCE_PROJECT); - }); - }); - - describe('for incompatible projects', () => { - const response = { - importedProjects: [], - providerRepos: [], - incompatibleRepos: [SOURCE_PROJECT], - }; - - 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).toStrictEqual( - expect.objectContaining(SOURCE_PROJECT), - ); - }); - }); - - it('sets repos loading flag to false', () => { - const response = { - importedProjects: [], - providerRepos: [], - }; - - state = getInitialState(); - - mutations[types.RECEIVE_REPOS_SUCCESS](state, response); - - expect(state.isLoadingRepos).toBe(false); - }); - }); - - 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 = []; - - state = getInitialState(); - - mutations[types.RECEIVE_REPOS_SUCCESS](state, response); - - expect(state.isLoadingRepos).toBe(false); - }); - }); - - describe(`${types.RECEIVE_REPOS_ERROR}`, () => { - it('sets repos loading flag to false', () => { - state = getInitialState(); - - mutations[types.RECEIVE_REPOS_ERROR](state); - - expect(state.isLoadingRepos).toBe(false); - }); - }); - - describe(`${types.REQUEST_IMPORT}`, () => { - beforeEach(() => { - const REPO_ID = 1; - const importTarget = { targetNamespace: 'ns', newName: 'name ' }; - state = { repositories: [{ importSource: { id: REPO_ID } }] }; - - mutations[types.REQUEST_IMPORT](state, { repoId: REPO_ID, importTarget }); - }); - - it(`sets status to ${STATUSES.SCHEDULING}`, () => { - expect(state.repositories[0].importedProject.importStatus).toBe(STATUSES.SCHEDULING); - }); - }); - - describe(`${types.RECEIVE_IMPORT_SUCCESS}`, () => { - beforeEach(() => { - const REPO_ID = 1; - state = { repositories: [{ importSource: { id: REPO_ID } }] }; - - mutations[types.RECEIVE_IMPORT_SUCCESS](state, { - repoId: REPO_ID, - importedProject: IMPORTED_PROJECT, - }); - }); - - it('sets import status', () => { - expect(state.repositories[0].importedProject.importStatus).toBe( - IMPORTED_PROJECT.importStatus, - ); - }); - - it('sets imported project', () => { - expect(IMPORTED_PROJECT).toStrictEqual( - expect.objectContaining(state.repositories[0].importedProject), - ); - }); - }); - - describe(`${types.RECEIVE_IMPORT_ERROR}`, () => { - beforeEach(() => { - const REPO_ID = 1; - state = { repositories: [{ importSource: { id: REPO_ID } }] }; - - mutations[types.RECEIVE_IMPORT_ERROR](state, REPO_ID); - }); - - it(`removes importedProject entry`, () => { - expect(state.repositories[0].importedProject).toBeNull(); - }); - }); - - describe(`${types.RECEIVE_JOBS_SUCCESS}`, () => { - it('updates import status of existing project', () => { - const repoId = 1; - state = { - repositories: [{ importedProject: { id: repoId }, importStatus: STATUSES.STARTED }], - }; - const updatedProjects = [{ id: repoId, importStatus: STATUSES.FINISHED }]; - - mutations[types.RECEIVE_JOBS_SUCCESS](state, updatedProjects); - - expect(state.repositories[0].importedProject.importStatus).toBe( - updatedProjects[0].importStatus, - ); - }); - }); - - describe(`${types.REQUEST_NAMESPACES}`, () => { - it('sets namespaces loading flag to true', () => { - state = {}; - - mutations[types.REQUEST_NAMESPACES](state); - - expect(state.isLoadingNamespaces).toBe(true); - }); - }); - - describe(`${types.RECEIVE_NAMESPACES_SUCCESS}`, () => { - const response = [{ fullPath: 'some/path' }]; - - beforeEach(() => { - state = {}; - mutations[types.RECEIVE_NAMESPACES_SUCCESS](state, response); - }); - - it('stores namespaces to state', () => { - expect(state.namespaces).toStrictEqual(response); - }); - - it('sets namespaces loading flag to false', () => { - expect(state.isLoadingNamespaces).toBe(false); - }); - }); - - describe(`${types.RECEIVE_NAMESPACES_ERROR}`, () => { - it('sets namespaces loading flag to false', () => { - state = {}; - - mutations[types.RECEIVE_NAMESPACES_ERROR](state); - - expect(state.isLoadingNamespaces).toBe(false); - }); - }); - - describe(`${types.SET_IMPORT_TARGET}`, () => { - const PROJECT = { - id: 2, - sanitizedName: 'sanitizedName', - }; - - it('stores custom target if it differs from defaults', () => { - state = { customImportTargets: {}, repositories: [{ importSource: PROJECT }] }; - const importTarget = { targetNamespace: 'ns', newName: 'name ' }; - - mutations[types.SET_IMPORT_TARGET](state, { repoId: PROJECT.id, importTarget }); - expect(state.customImportTargets[PROJECT.id]).toBe(importTarget); - }); - - it('removes custom target if it is equal to defaults', () => { - const importTarget = { targetNamespace: 'ns', newName: 'name ' }; - state = { - defaultTargetNamespace: 'default', - customImportTargets: { - [PROJECT.id]: importTarget, - }, - repositories: [{ importSource: PROJECT }], - }; - - mutations[types.SET_IMPORT_TARGET](state, { - repoId: PROJECT.id, - importTarget: { - targetNamespace: state.defaultTargetNamespace, - newName: PROJECT.sanitizedName, - }, - }); - - expect(state.customImportTargets[SOURCE_PROJECT.id]).toBeUndefined(); - }); - }); - - describe(`${types.SET_PAGE}`, () => { - it('sets page number', () => { - const NEW_PAGE = 4; - state = { pageInfo: { page: 5 } }; - - mutations[types.SET_PAGE](state, NEW_PAGE); - expect(state.pageInfo.page).toBe(NEW_PAGE); - }); - }); -}); diff --git a/spec/frontend/import_projects/utils_spec.js b/spec/frontend/import_projects/utils_spec.js deleted file mode 100644 index 4e1e16a3184..00000000000 --- a/spec/frontend/import_projects/utils_spec.js +++ /dev/null @@ -1,65 +0,0 @@ -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 - ${STATUSES.FINISHED} | ${false} - ${STATUSES.FAILED} | ${false} - ${STATUSES.SCHEDULED} | ${false} - ${STATUSES.STARTED} | ${false} - ${STATUSES.NONE} | ${true} - ${STATUSES.SCHEDULING} | ${false} - `('returns $result when project is compatible and status is $status', ({ status, result }) => { - expect( - isProjectImportable({ - ...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( - getImportStatus({ - ...COMPATIBLE_PROJECT, - importedProject: { importStatus: STATUSES.FINISHED }, - }), - ).toBe(STATUSES.FINISHED); - }); - - it('returns NONE as status if import status is not provided', () => { - expect(getImportStatus(COMPATIBLE_PROJECT)).toBe(STATUSES.NONE); - }); - }); -}); |