Commit 56987a07 authored by Kushal Pandya's avatar Kushal Pandya

Merge branch '6953-instance-lvl-security-dashboard-project-selector-store-module' into 'master'

Add projectSelector store module to security dashboards

See merge request gitlab-org/gitlab!17918
parents f3ddb255 133cedea
import Api from '~/api';
import axios from '~/lib/utils/axios_utils';
import createFlash from '~/flash';
import { __, s__, sprintf } from '~/locale';
import * as types from './mutation_types';
const API_MINIMUM_QUERY_LENGTH = 3;
export const toggleSelectedProject = ({ commit, state }, project) => {
const isProject = ({ id }) => id === project.id;
if (state.selectedProjects.some(isProject)) {
commit(types.DESELECT_PROJECT, project);
} else {
commit(types.SELECT_PROJECT, project);
}
};
export const clearSearchResults = ({ commit }) => {
commit(types.CLEAR_SEARCH_RESULTS);
};
export const setSearchQuery = ({ commit }, query) => {
commit(types.SET_SEARCH_QUERY, query);
};
export const setProjectEndpoints = ({ commit }, endpoints) => {
commit(types.SET_PROJECT_ENDPOINTS, endpoints);
};
export const addProjects = ({ state, dispatch }) => {
dispatch('requestAddProjects');
return axios
.post(state.projectEndpoints.add, {
project_ids: state.selectedProjects.map(p => p.id),
})
.then(response => dispatch('receiveAddProjectsSuccess', response.data))
.catch(() => dispatch('receiveAddProjectsError'));
};
export const requestAddProjects = ({ commit }) => {
commit(types.REQUEST_ADD_PROJECTS);
};
export const receiveAddProjectsSuccess = ({ commit, dispatch, state }, data) => {
const { added, invalid } = data;
commit(types.RECEIVE_ADD_PROJECTS_SUCCESS);
if (invalid.length) {
const [firstProject, secondProject, ...rest] = state.selectedProjects
.filter(project => invalid.includes(project.id))
.map(project => project.name);
const translationValues = {
firstProject,
secondProject,
rest: rest.join(', '),
};
let invalidProjects;
if (rest.length > 0) {
invalidProjects = sprintf(
s__('SecurityDashboard|%{firstProject}, %{secondProject}, and %{rest}'),
translationValues,
);
} else if (secondProject) {
invalidProjects = sprintf(
s__('SecurityDashboard|%{firstProject} and %{secondProject}'),
translationValues,
);
} else {
invalidProjects = firstProject;
}
createFlash(
sprintf(s__('SecurityDashboard|Unable to add %{invalidProjects}'), {
invalidProjects,
}),
);
}
if (added.length) {
dispatch('fetchProjects');
}
};
export const receiveAddProjectsError = ({ commit }) => {
commit(types.RECEIVE_ADD_PROJECTS_ERROR);
createFlash(__('Something went wrong, unable to add projects to dashboard'));
};
export const fetchProjects = ({ state, dispatch }) => {
dispatch('requestProjects');
return axios
.get(state.projectEndpoints.list)
.then(({ data }) => {
dispatch('receiveProjectsSuccess', data);
})
.catch(() => dispatch('receiveProjectsError'));
};
export const requestProjects = ({ commit }) => {
commit(types.REQUEST_PROJECTS);
};
export const receiveProjectsSuccess = ({ commit }, { projects }) => {
commit(types.RECEIVE_PROJECTS_SUCCESS, projects);
};
export const receiveProjectsError = ({ commit }) => {
commit(types.RECEIVE_PROJECTS_ERROR);
createFlash(__('Something went wrong, unable to get projects'));
};
export const removeProject = ({ dispatch }, removePath) => {
dispatch('requestRemoveProject');
return axios
.delete(removePath)
.then(() => {
dispatch('receiveRemoveProjectSuccess');
})
.catch(() => dispatch('receiveRemoveProjectError'));
};
export const requestRemoveProject = ({ commit }) => {
commit(types.REQUEST_REMOVE_PROJECT);
};
export const receiveRemoveProjectSuccess = ({ commit, dispatch }) => {
commit(types.RECEIVE_REMOVE_PROJECT_SUCCESS);
dispatch('fetchProjects');
};
export const receiveRemoveProjectError = ({ commit }) => {
commit(types.RECEIVE_REMOVE_PROJECT_ERROR);
createFlash(__('Something went wrong, unable to remove project'));
};
export const fetchSearchResults = ({ state, dispatch }) => {
const { searchQuery } = state;
dispatch('requestSearchResults');
if (!searchQuery || searchQuery.length < API_MINIMUM_QUERY_LENGTH) {
return dispatch('setMinimumQueryMessage');
}
return Api.projects(searchQuery, {})
.then(results => dispatch('receiveSearchResultsSuccess', results))
.catch(() => dispatch('receiveSearchResultsError'));
};
export const requestSearchResults = ({ commit }) => {
commit(types.REQUEST_SEARCH_RESULTS);
};
export const receiveSearchResultsSuccess = ({ commit }, results) => {
commit(types.RECEIVE_SEARCH_RESULTS_SUCCESS, results);
};
export const receiveSearchResultsError = ({ commit }) => {
commit(types.RECEIVE_SEARCH_RESULTS_ERROR);
};
export const setMinimumQueryMessage = ({ commit }) => {
commit(types.SET_MINIMUM_QUERY_MESSAGE);
};
// prevent babel-plugin-rewire from generating an invalid default during karma tests
export default () => {};
import state from './state';
import mutations from './mutations';
import * as actions from './actions';
export default () => ({
namespaced: true,
state,
mutations,
actions,
});
export const SET_PROJECT_ENDPOINTS = 'SET_PROJECT_ENDPOINTS';
export const SET_SEARCH_QUERY = 'SET_SEARCH_QUERY';
export const SELECT_PROJECT = 'SELECT_PROJECT';
export const DESELECT_PROJECT = 'DESELECT_PROJECT';
export const REQUEST_ADD_PROJECTS = 'REQUEST_ADD_PROJECTS';
export const RECEIVE_ADD_PROJECTS_SUCCESS = 'RECEIVE_ADD_PROJECTS_SUCCESS';
export const RECEIVE_ADD_PROJECTS_ERROR = 'RECEIVE_ADD_PROJECTS_ERROR';
export const REQUEST_REMOVE_PROJECT = 'REQUEST_REMOVE_PROJECT';
export const RECEIVE_REMOVE_PROJECT_SUCCESS = 'RECEIVE_REMOVE_PROJECT_SUCCESS';
export const RECEIVE_REMOVE_PROJECT_ERROR = 'RECEIVE_REMOVE_PROJECT_ERROR';
export const REQUEST_PROJECTS = 'REQUEST_PROJECTS';
export const RECEIVE_PROJECTS_SUCCESS = 'RECEIVE_PROJECTS_SUCCESS';
export const RECEIVE_PROJECTS_ERROR = 'RECEIVE_PROJECTS_ERROR';
export const CLEAR_SEARCH_RESULTS = 'CLEAR_SEARCH_RESULTS';
export const REQUEST_SEARCH_RESULTS = 'REQUEST_SEARCH_RESULTS';
export const RECEIVE_SEARCH_RESULTS_SUCCESS = 'RECEIVE_SEARCH_RESULTS_SUCCESS';
export const RECEIVE_SEARCH_RESULTS_ERROR = 'RECEIVE_SEARCH_RESULTS_ERROR';
export const SET_MINIMUM_QUERY_MESSAGE = 'SET_MINIMUM_QUERY_MESSAGE';
import * as types from './mutation_types';
export default {
[types.SET_PROJECT_ENDPOINTS](state, endpoints) {
state.projectEndpoints.add = endpoints.add;
state.projectEndpoints.list = endpoints.list;
},
[types.SET_SEARCH_QUERY](state, query) {
state.searchQuery = query;
},
[types.SELECT_PROJECT](state, project) {
if (!state.selectedProjects.some(p => p.id === project.id)) {
state.selectedProjects.push(project);
}
},
[types.DESELECT_PROJECT](state, project) {
state.selectedProjects = state.selectedProjects.filter(p => p.id !== project.id);
},
[types.REQUEST_ADD_PROJECTS](state) {
state.isAddingProjects = true;
},
[types.RECEIVE_ADD_PROJECTS_SUCCESS](state) {
state.isAddingProjects = false;
},
[types.RECEIVE_ADD_PROJECTS_ERROR](state) {
state.isAddingProjects = false;
},
[types.REQUEST_REMOVE_PROJECT](state) {
state.isRemovingProject = true;
},
[types.RECEIVE_REMOVE_PROJECT_SUCCESS](state) {
state.isRemovingProject = false;
},
[types.RECEIVE_REMOVE_PROJECT_ERROR](state) {
state.isRemovingProject = false;
},
[types.REQUEST_PROJECTS](state) {
state.isLoadingProjects = true;
},
[types.RECEIVE_PROJECTS_SUCCESS](state, projects) {
state.projects = projects;
state.isLoadingProjects = false;
},
[types.RECEIVE_PROJECTS_ERROR](state) {
state.projects = [];
state.isLoadingProjects = false;
},
[types.CLEAR_SEARCH_RESULTS](state) {
state.projectSearchResults = [];
state.selectedProjects = [];
},
[types.REQUEST_SEARCH_RESULTS](state) {
state.messages.minimumQuery = false;
state.searchCount += 1;
},
[types.RECEIVE_SEARCH_RESULTS_SUCCESS](state, results) {
state.projectSearchResults = results;
state.messages.noResults = state.projectSearchResults.length === 0;
state.messages.searchError = false;
state.messages.minimumQuery = false;
state.searchCount = Math.max(0, state.searchCount - 1);
},
[types.RECEIVE_SEARCH_RESULTS_ERROR](state) {
state.projectSearchResults = [];
state.messages.noResults = false;
state.messages.searchError = true;
state.messages.minimumQuery = false;
state.searchCount = Math.max(0, state.searchCount - 1);
},
[types.SET_MINIMUM_QUERY_MESSAGE](state) {
state.projectSearchResults = [];
state.messages.noResults = false;
state.messages.searchError = false;
state.messages.minimumQuery = true;
state.searchCount = Math.max(0, state.searchCount - 1);
},
};
export default () => ({
inputValue: '',
isLoadingProjects: false,
isAddingProjects: false,
isRemovingProject: false,
projectEndpoints: {
list: null,
add: null,
},
searchQuery: '',
projects: [],
projectSearchResults: [],
selectedProjects: [],
messages: {
noResults: false,
searchError: false,
minimumQuery: false,
},
searchCount: 0,
});
import MockAdapter from 'axios-mock-adapter';
import axios from '~/lib/utils/axios_utils';
import testAction from 'helpers/vuex_action_helper';
import Api from '~/api';
import createFlash from '~/flash';
import createState from 'ee/security_dashboard/store/modules/project_selector/state';
import * as types from 'ee/security_dashboard/store/modules/project_selector/mutation_types';
import * as actions from 'ee/security_dashboard/store/modules/project_selector/actions';
jest.mock('~/api');
jest.mock('~/flash');
describe('projectSelector actions', () => {
const getMockProjects = n => [...Array(n).keys()].map(i => ({ id: i, name: `project-${i}` }));
const mockAddEndpoint = 'mock-add_endpoint';
const mockListEndpoint = 'mock-list_endpoint';
const mockResponse = { data: 'mock-data' };
let mockAxios;
let mockDispatchContext;
let state;
beforeEach(() => {
mockAxios = new MockAdapter(axios);
mockDispatchContext = { dispatch: () => {}, commit: () => {}, state };
state = createState();
});
afterEach(() => {
jest.clearAllMocks();
mockAxios.restore();
});
describe('toggleSelectedProject', () => {
it('adds a project to selectedProjects if it does not already exist in the list', done => {
const payload = getMockProjects(1);
testAction(
actions.toggleSelectedProject,
payload,
state,
[
{
type: types.SELECT_PROJECT,
payload,
},
],
[],
done,
);
});
it('removes a project from selectedProjects if it already exist in the list', () => {
const payload = getMockProjects(1)[0];
state.selectedProjects = getMockProjects(1);
return testAction(
actions.toggleSelectedProject,
payload,
state,
[
{
type: types.DESELECT_PROJECT,
payload,
},
],
[],
);
});
});
describe('addProjects', () => {
it('posts selected project ids to project add endpoint', () => {
state.projectEndpoints.add = mockAddEndpoint;
mockAxios.onPost(mockAddEndpoint).replyOnce(200, mockResponse);
return testAction(
actions.addProjects,
null,
state,
[],
[
{
type: 'requestAddProjects',
},
{
type: 'receiveAddProjectsSuccess',
payload: mockResponse,
},
],
);
});
it('calls addProjects error handler on error', () => {
mockAxios.onPost(mockAddEndpoint).replyOnce(500);
return testAction(
actions.addProjects,
null,
state,
[],
[{ type: 'requestAddProjects' }, { type: 'receiveAddProjectsError' }],
);
});
});
describe('requestAddProjects', () => {
it('commits the REQUEST_ADD_PROJECTS mutation', () =>
testAction(
actions.requestAddProjects,
null,
state,
[
{
type: types.REQUEST_ADD_PROJECTS,
},
],
[],
));
});
describe('receiveAddProjectsSuccess', () => {
beforeEach(() => {
state.selectedProjects = getMockProjects(3);
});
it('fetches projects when new projects are added to the dashboard', () => {
const addedProject = state.selectedProjects[0];
const payload = {
added: [addedProject.id],
invalid: [],
duplicate: [],
};
return testAction(
actions.receiveAddProjectsSuccess,
payload,
state,
[{ type: types.RECEIVE_ADD_PROJECTS_SUCCESS }],
[
{
type: 'fetchProjects',
},
],
);
});
it('displays an error when user tries to add one invalid project to dashboard', () => {
const invalidProject = state.selectedProjects[0];
const payload = {
added: [],
invalid: [invalidProject.id],
};
return testAction(
actions.receiveAddProjectsSuccess,
payload,
state,
[{ type: types.RECEIVE_ADD_PROJECTS_SUCCESS }],
[],
).then(() => {
expect(createFlash).toHaveBeenCalledWith(`Unable to add ${invalidProject.name}`);
});
});
it('displays an error when user tries to add two invalid projects to dashboard', () => {
const invalidProject1 = state.selectedProjects[0];
const invalidProject2 = state.selectedProjects[1];
const payload = {
added: [],
invalid: [invalidProject1.id, invalidProject2.id],
};
return testAction(
actions.receiveAddProjectsSuccess,
payload,
state,
[{ type: types.RECEIVE_ADD_PROJECTS_SUCCESS }],
[],
).then(() => {
expect(createFlash).toHaveBeenCalledWith(
`Unable to add ${invalidProject1.name} and ${invalidProject2.name}`,
);
});
});
it('displays an error when user tries to add more than two invalid projects to dashboard', () => {
const invalidProject1 = state.selectedProjects[0];
const invalidProject2 = state.selectedProjects[1];
const invalidProject3 = state.selectedProjects[2];
const payload = {
added: [],
invalid: [invalidProject1.id, invalidProject2.id, invalidProject3.id],
};
return testAction(
actions.receiveAddProjectsSuccess,
payload,
state,
[{ type: types.RECEIVE_ADD_PROJECTS_SUCCESS }],
[],
).then(() => {
expect(createFlash).toHaveBeenCalledWith(
`Unable to add ${invalidProject1.name}, ${invalidProject2.name}, and ${invalidProject3.name}`,
);
});
});
});
describe('receiveAddProjectsError', () => {
it('commits RECEIVE_ADD_PROJECTS_ERROR', () =>
testAction(
actions.receiveAddProjectsError,
null,
state,
[
{
type: types.RECEIVE_ADD_PROJECTS_ERROR,
},
],
[],
));
it('shows error message', () => {
actions.receiveAddProjectsError(mockDispatchContext);
expect(createFlash).toHaveBeenCalledTimes(1);
expect(createFlash).toHaveBeenCalledWith(
'Something went wrong, unable to add projects to dashboard',
);
});
});
describe('clearSearchResults', () => {
it('clears all project search results', () =>
testAction(
actions.clearSearchResults,
null,
state,
[
{
type: types.CLEAR_SEARCH_RESULTS,
},
],
[],
));
});
describe('fetchProjects', () => {
it('calls project list endpoint', () => {
state.projectEndpoints.list = mockListEndpoint;
mockAxios.onGet(mockListEndpoint).replyOnce(200, mockResponse);
return testAction(
actions.fetchProjects,
null,
state,
[],
[{ type: 'requestProjects' }, { type: 'receiveProjectsSuccess', payload: mockResponse }],
);
});
it('handles response errors', () => {
state.projectEndpoints.list = mockListEndpoint;
mockAxios.onGet(mockListEndpoint).replyOnce(500);
return testAction(
actions.fetchProjects,
null,
state,
[],
[{ type: 'requestProjects' }, { type: 'receiveProjectsError' }],
);
});
});
describe('requestProjects', () => {
it('toggles project loading state', () =>
testAction(actions.requestProjects, null, state, [{ type: types.REQUEST_PROJECTS }], []));
});
describe('receiveProjectsSuccess', () => {
it('sets projects from data on success', () => {
const payload = {
projects: [{ id: 0, name: 'mock-name1' }],
};
return testAction(
actions.receiveProjectsSuccess,
payload,
state,
[
{
type: types.RECEIVE_PROJECTS_SUCCESS,
payload: payload.projects,
},
],
[],
);
});
});
describe('receiveProjectsError', () => {
it('clears projects and alerts user of error', () =>
testAction(
actions.receiveProjectsError,
null,
state,
[
{
type: types.RECEIVE_PROJECTS_ERROR,
},
],
[],
).then(() => {
expect(createFlash).toHaveBeenCalledWith('Something went wrong, unable to get projects');
}));
});
describe('removeProject', () => {
const mockRemovePath = 'mock-removePath';
it('calls project removal path and fetches projects on success', () => {
mockAxios.onDelete(mockRemovePath).replyOnce(200);
return testAction(
actions.removeProject,
mockRemovePath,
null,
[],
[{ type: 'requestRemoveProject' }, { type: 'receiveRemoveProjectSuccess' }],
);
});
it('passes off handling of project removal errors', () => {
mockAxios.onDelete(mockRemovePath).replyOnce(500);
return testAction(
actions.removeProject,
mockRemovePath,
null,
[],
[{ type: 'requestRemoveProject' }, { type: 'receiveRemoveProjectError' }],
);
});
});
describe('requestRemoveProject', () => {
it('commits REQUEST_REMOVE_PROJECT mutation', () =>
testAction(
actions.requestRemoveProject,
null,
state,
[
{
type: types.REQUEST_REMOVE_PROJECT,
},
],
[],
));
});
describe('receiveRemoveProjectSuccess', () => {
it('commits RECEIVE_REMOVE_PROJECT_SUCCESS mutation and dispatches fetchProjects', () =>
testAction(
actions.receiveRemoveProjectSuccess,
null,
state,
[
{
type: types.RECEIVE_REMOVE_PROJECT_SUCCESS,
},
],
[{ type: 'fetchProjects' }],
));
});
describe('receiveRemoveProjectError', () => {
it('commits REQUEST_REMOVE_PROJECT mutation', () =>
testAction(
actions.receiveRemoveProjectError,
null,
state,
[
{
type: types.RECEIVE_REMOVE_PROJECT_ERROR,
},
],
[],
));
it('displays project removal error', () => {
actions.receiveRemoveProjectError(mockDispatchContext);
expect(createFlash).toHaveBeenCalledTimes(1);
expect(createFlash).toHaveBeenCalledWith('Something went wrong, unable to remove project');
});
});
describe('fetchSearchResults', () => {
it.each([null, undefined, false, NaN, 0, ''])(
'dispatches setMinimumQueryMessage if the search query is falsy',
searchQuery => {
state.searchQuery = searchQuery;
return testAction(
actions.fetchSearchResults,
null,
state,
[],
[
{
type: 'requestSearchResults',
},
{
type: 'setMinimumQueryMessage',
},
],
);
},
);
it.each(['a', 'aa'])(
'dispatches setMinimumQueryMessage if the search query was not long enough',
shortSearchQuery => {
state.searchQuery = shortSearchQuery;
return testAction(
actions.fetchSearchResults,
null,
state,
[],
[
{
type: 'requestSearchResults',
},
{
type: 'setMinimumQueryMessage',
},
],
);
},
);
it('dispatches the correct actions when the query is valid', () => {
const mockProjects = [{ id: 0, name: 'mock-name1' }];
Api.projects.mockResolvedValueOnce(mockProjects);
state.searchQuery = 'mock-query';
return testAction(
actions.fetchSearchResults,
null,
state,
[],
[
{
type: 'requestSearchResults',
},
{
type: 'receiveSearchResultsSuccess',
payload: mockProjects,
},
],
);
});
});
describe('requestSearchResults', () => {
it('commits the REQUEST_SEARCH_RESULTS mutation', () =>
testAction(
actions.requestSearchResults,
null,
state,
[
{
type: types.REQUEST_SEARCH_RESULTS,
},
],
[],
));
});
describe('receiveSearchResultsSuccess', () => {
it('commits the RECEIVE_SEARCH_RESULTS_SUCCESS mutation', () => {
const mockProjects = [{ id: 0, name: 'mock-project1' }];
return testAction(
actions.receiveSearchResultsSuccess,
mockProjects,
state,
[
{
type: types.RECEIVE_SEARCH_RESULTS_SUCCESS,
payload: mockProjects,
},
],
[],
);
});
});
describe('receiveSearchResultsError', () => {
it('commits the RECEIVE_SEARCH_RESULTS_ERROR mutation', () =>
testAction(
actions.receiveSearchResultsError,
['error'],
state,
[
{
type: types.RECEIVE_SEARCH_RESULTS_ERROR,
},
],
[],
));
});
describe('setProjectEndpoints', () => {
it('commits project list and add endpoints', () => {
const payload = {
add: 'add',
list: 'list',
};
return testAction(
actions.setProjectEndpoints,
payload,
state,
[
{
type: types.SET_PROJECT_ENDPOINTS,
payload,
},
],
[],
);
});
});
describe('setMinimumQueryMessage', () => {
it('commits the SET_MINIMUM_QUERY_MESSAGE mutation', () =>
testAction(
actions.setMinimumQueryMessage,
null,
state,
[
{
type: types.SET_MINIMUM_QUERY_MESSAGE,
},
],
[],
));
});
});
import createState from 'ee/security_dashboard/store/modules/project_selector/state';
import mutations from 'ee/security_dashboard/store/modules/project_selector/mutations';
import * as types from 'ee/security_dashboard/store/modules/project_selector/mutation_types';
describe('projectsSelector mutations', () => {
let state;
beforeEach(() => {
state = createState();
});
describe('SET_PROJECT_ENDPOINTS', () => {
it('sets "projectEndpoints.list" and "projectEndpoints.add"', () => {
const payload = { list: 'list', add: 'add' };
state.projectEndpoints = {};
mutations[types.SET_PROJECT_ENDPOINTS](state, payload);
expect(state.projectEndpoints.list).toBe(payload.list);
expect(state.projectEndpoints.add).toBe(payload.add);
});
});
describe('SET_SEARCH_QUERY', () => {
it('sets "searchQuery" to be the given payload', () => {
const payload = 'searchQuery';
state.searchQuery = '';
mutations[types.SET_SEARCH_QUERY](state, payload);
expect(state.searchQuery).toBe(payload);
});
});
describe('SELECT_PROJECT', () => {
it('adds the given project to "selectedProjects"', () => {
const payload = {};
state.selectedProjects = [];
mutations[types.SELECT_PROJECT](state, payload);
expect(state.selectedProjects[0]).toBe(payload);
});
it('prevents projects from being added to "selectedProjects" twice', () => {
const payload1 = { id: 1 };
const payload2 = { id: 2 };
mutations[types.SELECT_PROJECT](state, payload1);
mutations[types.SELECT_PROJECT](state, payload1);
expect(state.selectedProjects).toHaveLength(1);
mutations[types.SELECT_PROJECT](state, payload2);
expect(state.selectedProjects).toHaveLength(2);
});
});
describe('DESELECT_PROJECT', () => {
it('removes the project with the given id from "selectedProjects"', () => {
state.selectedProjects = [{ id: 1 }, { id: 2 }];
const payload = { id: 1 };
mutations[types.DESELECT_PROJECT](state, payload);
expect(state.selectedProjects).toHaveLength(1);
expect(state.selectedProjects[0].id).toBe(2);
});
});
describe('REQUEST_ADD_PROJECTS', () => {
it('sets "isAddingProjects" to be true', () => {
state.isAddingProjects = false;
mutations[types.REQUEST_ADD_PROJECTS](state);
expect(state.isAddingProjects).toBe(true);
});
});
describe('RECEIVE_ADD_PROJECTS_SUCCESS', () => {
it('sets "isAddingProjects" to be true', () => {
state.isAddingProjects = true;
mutations[types.RECEIVE_ADD_PROJECTS_SUCCESS](state);
expect(state.isAddingProjects).toBe(false);
});
});
describe('RECEIVE_ADD_PROJECTS_ERROR', () => {
it('sets "isAddingProjects" to be true', () => {
state.isAddingProjects = true;
mutations[types.RECEIVE_ADD_PROJECTS_ERROR](state);
expect(state.isAddingProjects).toBe(false);
});
});
describe('REQUEST_REMOVE_PROJECT', () => {
it('sets "isRemovingProjects" to be true', () => {
state.isRemovingProject = false;
mutations[types.REQUEST_REMOVE_PROJECT](state);
expect(state.isRemovingProject).toBe(true);
});
});
describe('RECEIVE_REMOVE_PROJECT_SUCCESS', () => {
it('sets "isRemovingProjects" to be true', () => {
state.isRemovingProject = true;
mutations[types.RECEIVE_REMOVE_PROJECT_SUCCESS](state);
expect(state.isRemovingProject).toBe(false);
});
});
describe('RECEIVE_REMOVE_PROJECT_ERROR', () => {
it('sets "isRemovingProjects" to be true', () => {
state.isRemovingProject = true;
mutations[types.RECEIVE_REMOVE_PROJECT_ERROR](state);
expect(state.isRemovingProject).toBe(false);
});
});
describe('REQUEST_PROJECTS', () => {
it('sets "isLoadingProjects" to be true', () => {
state.isLoadingProjects = false;
mutations[types.REQUEST_PROJECTS](state);
expect(state.isLoadingProjects).toBe(true);
});
});
describe('RECEIVE_PROJECTS_SUCCESS', () => {
it('sets "projects" to be the payload', () => {
const payload = [];
state.projects = [];
mutations[types.RECEIVE_PROJECTS_SUCCESS](state, payload);
expect(state.projects).toBe(payload);
});
it('sets "isLoadingProjects" to be false', () => {
state.isLoadingProjects = true;
mutations[types.RECEIVE_PROJECTS_SUCCESS](state, []);
expect(state.isLoadingProjects).toBe(false);
});
});
describe('RECEIVE_PROJECTS_ERROR', () => {
it('sets "projects" to be an empty array', () => {
state.projects = [];
mutations[types.RECEIVE_PROJECTS_ERROR](state);
expect(state.projects).toEqual([]);
});
it('sets "isLoadingProjects" to be false', () => {
state.isLoadingProjects = true;
mutations[types.RECEIVE_PROJECTS_ERROR](state);
expect(state.isLoadingProjects).toBe(false);
});
});
describe('CLEAR_SEARCH_RESULTS', () => {
it('sets "projectSearchResults" to be an empty array', () => {
state.projectSearchResults = [''];
mutations[types.CLEAR_SEARCH_RESULTS](state);
expect(state.projectSearchResults).toHaveLength(0);
});
it('sets "selectedProjects" to be an empty array', () => {
state.selectedProjects = [''];
mutations[types.CLEAR_SEARCH_RESULTS](state);
expect(state.selectedProjects).toHaveLength(0);
});
});
describe('REQUEST_SEARCH_RESULTS', () => {
it('sets "messages.minimumQuery" to be false', () => {
state.messages.minimumQuery = true;
mutations[types.REQUEST_SEARCH_RESULTS](state);
expect(state.messages.minimumQuery).toBe(false);
});
it('increments "searchCount" by one', () => {
state.searchCount = 0;
mutations[types.REQUEST_SEARCH_RESULTS](state);
expect(state.searchCount).toBe(1);
});
});
describe('RECEIVE_SEARCH_RESULTS_SUCCESS', () => {
it('sets "projectSearchResults" to be the payload', () => {
const payload = [];
mutations[types.RECEIVE_SEARCH_RESULTS_SUCCESS](state, payload);
expect(state.projectSearchResults).toBe(payload);
});
it('sets "messages.noResults" to be false if the payload is not empty', () => {
state.messages.noResults = true;
mutations[types.RECEIVE_SEARCH_RESULTS_SUCCESS](state, ['']);
expect(state.messages.noResults).toBe(false);
});
it('sets "messages.searchError" to be false', () => {
state.messages.searchError = true;
mutations[types.RECEIVE_SEARCH_RESULTS_SUCCESS](state, ['']);
expect(state.messages.searchError).toBe(false);
});
it('sets "messages.minimumQuery" to be false', () => {
state.messages.minimumQuery = true;
mutations[types.RECEIVE_SEARCH_RESULTS_SUCCESS](state, ['']);
expect(state.messages.minimumQuery).toBe(false);
});
it('decrements "searchCount" by one', () => {
state.searchCount = 1;
mutations[types.RECEIVE_SEARCH_RESULTS_SUCCESS](state, ['']);
expect(state.searchCount).toBe(0);
});
it('does not decrement "searchCount" into negative', () => {
state.searchCount = 0;
mutations[types.RECEIVE_SEARCH_RESULTS_SUCCESS](state, ['']);
expect(state.searchCount).toBe(0);
});
});
describe('RECEIVE_SEARCH_RESULTS_ERROR', () => {
it('sets "projectSearchResult" to be empty', () => {
state.projectSearchResults = [''];
mutations[types.RECEIVE_SEARCH_RESULTS_ERROR](state);
expect(state.projectSearchResults).toHaveLength(0);
});
it('sets "messages.noResults" to be false', () => {
state.messages.noResults = true;
mutations[types.RECEIVE_SEARCH_RESULTS_ERROR](state);
expect(state.messages.noResults).toBe(false);
});
it('sets "messages.searchError" to be true', () => {
state.messages.searchError = false;
mutations[types.RECEIVE_SEARCH_RESULTS_ERROR](state);
expect(state.messages.searchError).toBe(true);
});
it('sets "messages.minimumQuery" to be false', () => {
state.messages.minimumQuery = true;
mutations[types.RECEIVE_SEARCH_RESULTS_ERROR](state);
expect(state.messages.minimumQuery).toBe(false);
});
it('decrements "searchCount" by one', () => {
state.searchCount = 1;
mutations[types.RECEIVE_SEARCH_RESULTS_ERROR](state);
expect(state.searchCount).toBe(0);
});
it('does not decrement "searchCount" into negative', () => {
state.searchCount = 0;
mutations[types.RECEIVE_SEARCH_RESULTS_ERROR](state);
expect(state.searchCount).toBe(0);
});
});
describe('SET_MINIMUM_QUERY_MESSAGE', () => {
it('sets "projectSearchResult" to be an empty array', () => {
state.projectSearchResults = [''];
mutations[types.SET_MINIMUM_QUERY_MESSAGE](state);
expect(state.projectSearchResults).toHaveLength(0);
});
it('sets "messages.noResults" to be false', () => {
state.messages.noResults = true;
mutations[types.SET_MINIMUM_QUERY_MESSAGE](state);
expect(state.messages.noResults).toBe(false);
});
it('sets "messages.searchError" to be false', () => {
state.messages.searchError = true;
mutations[types.SET_MINIMUM_QUERY_MESSAGE](state);
expect(state.messages.searchError).toBe(false);
});
it('sets "messages.minimumQuery" to true', () => {
state.messages.minimumQuery = false;
mutations[types.SET_MINIMUM_QUERY_MESSAGE](state);
expect(state.messages.minimumQuery).toBe(true);
});
it('does not decrement "searchCount" into negative', () => {
state.searchCount = 0;
mutations[types.RECEIVE_SEARCH_RESULTS_ERROR](state);
expect(state.searchCount).toBe(0);
});
});
});
import createState from 'ee/security_dashboard/store/modules/project_selector/state';
describe('projectsSelector default state', () => {
const state = createState();
it('has "inputValue" set to be an empty string', () => {
expect(state.inputValue).toBe('');
});
it('has "isLoadingProjects" set to be false', () => {
expect(state.isLoadingProjects).toBe(false);
});
it('has "isAddingProjects" set to be false', () => {
expect(state.isAddingProjects).toBe(false);
});
it('has "isRemovingProject" set to be false', () => {
expect(state.isRemovingProject).toBe(false);
});
it('has all "projectEndpoints" set to be null', () => {
expect(state.projectEndpoints.list).toBe(null);
expect(state.projectEndpoints.add).toBe(null);
});
it('has "searchQuery" set to an empty string', () => {
expect(state.searchQuery).toBe('');
});
it('has "projects" set to be an empty array', () => {
expect(state.projects).toEqual([]);
});
it('has "projectSearchResults" set to be an empty array', () => {
expect(state.projectSearchResults).toEqual([]);
});
it('has "selectedProjects" set to be an empty array', () => {
expect(state.selectedProjects).toEqual([]);
});
it('has all "messages" set to be false', () => {
expect(state.messages.noResults).toBe(false);
expect(state.messages.searchError).toBe(false);
expect(state.messages.minimumQuery).toBe(false);
});
it('has "searchCount" set to be 0', () => {
expect(state.searchCount).toBe(0);
});
});
......@@ -14039,6 +14039,12 @@ msgstr ""
msgid "SecurityDashboard| The security dashboard displays the latest security report. Use it to find and fix vulnerabilities."
msgstr ""
msgid "SecurityDashboard|%{firstProject} and %{secondProject}"
msgstr ""
msgid "SecurityDashboard|%{firstProject}, %{secondProject}, and %{rest}"
msgstr ""
msgid "SecurityDashboard|Confidence"
msgstr ""
......@@ -14060,6 +14066,9 @@ msgstr ""
msgid "SecurityDashboard|Severity"
msgstr ""
msgid "SecurityDashboard|Unable to add %{invalidProjects}"
msgstr ""
msgid "See metrics"
msgstr ""
......@@ -14785,6 +14794,9 @@ msgstr ""
msgid "Something went wrong, unable to add %{project} to dashboard"
msgstr ""
msgid "Something went wrong, unable to add projects to dashboard"
msgstr ""
msgid "Something went wrong, unable to get projects"
msgstr ""
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment