debian-mirror-gitlab/spec/frontend/import_projects/store/actions_spec.js
2021-01-29 00:20:46 +05:30

399 lines
11 KiB
JavaScript

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' }],
);
});
});
});