Commit d90a33f4 authored by Alexander Turinske's avatar Alexander Turinske

Refactor security_dashboard store tests to be Jest

- moving Karma tests to Jest
parent 8d1fe49b
......@@ -441,11 +441,11 @@ export const receiveUndoDismissError = ({ commit }, { flashError }) => {
};
export const downloadPatch = ({ state }) => {
/*
/*
This action doesn't actually mutate the Vuex state and is a dirty
workaround to modifying the dom. We do this because gl-split-button
relies on a old version of vue-bootstrap and it doesn't allow us to
set a href for a file download.
workaround to modifying the dom. We do this because gl-split-button
relies on a old version of vue-bootstrap and it doesn't allow us to
set a href for a file download.
https://gitlab.com/gitlab-org/gitlab-ui/issues/188#note_165808493
*/
......
import testAction from 'spec/helpers/vuex_action_helper';
import testAction from 'helpers/vuex_action_helper';
import createState from 'ee/security_dashboard/store/modules/filters/state';
import * as types from 'ee/security_dashboard/store/modules/filters/mutation_types';
import module, * as actions from 'ee/security_dashboard/store/modules/filters/actions';
import * as actions from 'ee/security_dashboard/store/modules/filters/actions';
import { ALL } from 'ee/security_dashboard/store/modules/filters/constants';
import Tracking from '~/tracking';
import { getParameterValues } from '~/lib/utils/url_utility';
jest.mock('~/lib/utils/url_utility', () => ({
getParameterValues: jest.fn().mockReturnValue([]),
}));
describe('filters actions', () => {
beforeEach(() => {
spyOn(Tracking, 'event');
jest.spyOn(Tracking, 'event').mockImplementation(() => {});
});
describe('setFilter', () => {
......@@ -85,7 +90,7 @@ describe('filters actions', () => {
},
{
type: types.SET_FILTER,
payload: jasmine.objectContaining({
payload: expect.objectContaining({
filterId: 'project_id',
optionId: ALL,
}),
......@@ -164,7 +169,8 @@ describe('filters actions', () => {
},
].forEach(testCase => {
it(testCase.description, done => {
spyOnDependency(module, 'getParameterValues').and.returnValue(testCase.returnValue);
const mockValue = testCase.returnValue;
getParameterValues.mockImplementation(() => mockValue);
const state = createState();
testAction(
actions.setHideDismissedToggleInitialState,
......
import MockAdapter from 'axios-mock-adapter';
import testAction from 'spec/helpers/vuex_action_helper';
import testAction from 'helpers/vuex_action_helper';
import { TEST_HOST } from 'spec/test_constants';
import createState from 'ee/security_dashboard/store/modules/projects/state';
......
import MockAdapter from 'axios-mock-adapter';
import testAction from 'helpers/vuex_action_helper';
import createState from 'ee/security_dashboard/store/modules/unscanned_projects/state';
import { TEST_HOST } from 'spec/test_constants';
import { DAYS } from 'ee/security_dashboard/store/modules/vulnerabilities/constants';
import initialState from 'ee/security_dashboard/store/modules/vulnerabilities/state';
import * as types from 'ee/security_dashboard/store/modules/vulnerabilities/mutation_types';
import * as actions from 'ee/security_dashboard/store/modules/vulnerabilities/actions';
import axios from '~/lib/utils/axios_utils';
import toast from '~/vue_shared/plugins/global_toast';
import mockDataVulnerabilities from './data/mock_data_vulnerabilities';
import mockDataVulnerabilitiesCount from './data/mock_data_vulnerabilities_count.json';
import mockDataVulnerabilitiesHistory from './data/mock_data_vulnerabilities_history.json';
const sourceBranch = 'feature-branch-1';
jest.mock('~/vue_shared/plugins/global_toast');
jest.mock('jquery', () => () => ({
modal: jest.fn(),
}));
describe('vulnerabilities count actions', () => {
const data = mockDataVulnerabilitiesCount;
const params = { filters: { type: ['sast'] } };
const filteredData = mockDataVulnerabilitiesCount.sast;
let state;
beforeEach(() => {
state = initialState();
});
describe('setPipelineId', () => {
const pipelineId = 123;
it('should commit the correct mutation', done => {
testAction(
actions.setPipelineId,
pipelineId,
state,
[
{
type: types.SET_PIPELINE_ID,
payload: pipelineId,
},
],
[],
done,
);
});
});
describe('setSourceBranch', () => {
it('should commit the correct mutation', done => {
testAction(
actions.setSourceBranch,
sourceBranch,
state,
[
{
type: types.SET_SOURCE_BRANCH,
payload: sourceBranch,
},
],
[],
done,
);
});
});
describe('setVulnerabilitiesCountEndpoint', () => {
it('should commit the correct mutuation', done => {
const endpoint = 'fakepath.json';
testAction(
actions.setVulnerabilitiesCountEndpoint,
endpoint,
state,
[
{
type: types.SET_VULNERABILITIES_COUNT_ENDPOINT,
payload: endpoint,
},
],
[],
done,
);
});
});
describe('fetchVulnerabilitiesCount', () => {
let mock;
beforeEach(() => {
state.vulnerabilitiesCountEndpoint = `${TEST_HOST}/vulnerabilities_count.json`;
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
describe('on success', () => {
beforeEach(() => {
mock
.onGet(state.vulnerabilitiesCountEndpoint, { params })
.replyOnce(200, filteredData)
.onGet(state.vulnerabilitiesCountEndpoint)
.replyOnce(200, data);
});
it('should dispatch the request and success actions', done => {
testAction(
actions.fetchVulnerabilitiesCount,
{},
state,
[],
[
{ type: 'requestVulnerabilitiesCount' },
{
type: 'receiveVulnerabilitiesCountSuccess',
payload: { data },
},
],
done,
);
});
it('should send the passed filters to the endpoint', done => {
testAction(
actions.fetchVulnerabilitiesCount,
params,
state,
[],
[
{ type: 'requestVulnerabilitiesCount' },
{
type: 'receiveVulnerabilitiesCountSuccess',
payload: { data: filteredData },
},
],
done,
);
});
});
describe('on error', () => {
beforeEach(() => {
mock.onGet(state.vulnerabilitiesCountEndpoint).replyOnce(404, {});
});
it('should dispatch the request and error actions', done => {
testAction(
actions.fetchVulnerabilitiesCount,
{},
state,
[],
[{ type: 'requestVulnerabilitiesCount' }, { type: 'receiveVulnerabilitiesCountError' }],
done,
);
});
});
describe('with an empty endpoint', () => {
beforeEach(() => {
state.vulnerabilitiesCountEndpoint = '';
});
it('should not do anything', done => {
testAction(actions.fetchVulnerabilitiesCount, {}, state, [], [], done);
});
});
});
describe('requestVulnerabilitiesCount', () => {
it('should commit the request mutation', done => {
testAction(
actions.requestVulnerabilitiesCount,
{},
state,
[{ type: types.REQUEST_VULNERABILITIES_COUNT }],
[],
done,
);
});
});
describe('receiveVulnerabilitiesCountSuccess', () => {
it('should commit the success mutation', done => {
testAction(
actions.receiveVulnerabilitiesCountSuccess,
{ data },
state,
[{ type: types.RECEIVE_VULNERABILITIES_COUNT_SUCCESS, payload: data }],
[],
done,
);
});
});
describe('receiveVulnerabilitiesCountError', () => {
it('should commit the error mutation', done => {
testAction(
actions.receiveVulnerabilitiesCountError,
{},
state,
[{ type: types.RECEIVE_VULNERABILITIES_COUNT_ERROR }],
[],
done,
);
});
});
});
describe('vulnerabilities actions', () => {
const data = mockDataVulnerabilities;
const params = { filters: { severity: ['critical'] } };
const filteredData = mockDataVulnerabilities.filter(vuln => vuln.severity === 'critical');
const pageInfo = {
page: 1,
nextPage: 2,
previousPage: 1,
perPage: 20,
total: 100,
totalPages: 5,
};
const headers = {
'X-Next-Page': pageInfo.nextPage,
'X-Page': pageInfo.page,
'X-Per-Page': pageInfo.perPage,
'X-Prev-Page': pageInfo.previousPage,
'X-Total': pageInfo.total,
'X-Total-Pages': pageInfo.totalPages,
};
let state;
beforeEach(() => {
state = initialState();
});
describe('fetchVulnerabilities', () => {
let mock;
beforeEach(() => {
state.vulnerabilitiesEndpoint = `${TEST_HOST}/vulnerabilities.json`;
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
describe('on success', () => {
beforeEach(() => {
mock
.onGet(state.vulnerabilitiesEndpoint, { params })
.replyOnce(200, filteredData, headers)
.onGet(state.vulnerabilitiesEndpoint)
.replyOnce(200, data, headers);
});
it('should dispatch the request and success actions', done => {
testAction(
actions.fetchVulnerabilities,
{},
state,
[],
[
{ type: 'requestVulnerabilities' },
{
type: 'receiveVulnerabilitiesSuccess',
payload: { data, headers },
},
],
done,
);
});
it('should pass through the filters', done => {
testAction(
actions.fetchVulnerabilities,
params,
state,
[],
[
{ type: 'requestVulnerabilities' },
{
type: 'receiveVulnerabilitiesSuccess',
payload: { data: filteredData, headers },
},
],
done,
);
});
});
describe('on error', () => {
const errorCode = 404;
beforeEach(() => {
mock.onGet(state.vulnerabilitiesEndpoint).replyOnce(errorCode, {});
});
it('should dispatch the request and error actions', done => {
testAction(
actions.fetchVulnerabilities,
{},
state,
[],
[
{ type: 'requestVulnerabilities' },
{ type: 'receiveVulnerabilitiesError', payload: errorCode },
],
done,
);
});
});
describe('with an empty endpoint', () => {
beforeEach(() => {
state.vulnerabilitiesEndpoint = '';
});
it('should not do anything', done => {
testAction(actions.fetchVulnerabilities, {}, state, [], [], done);
});
});
});
describe('receiveVulnerabilitiesSuccess', () => {
it('should commit the success mutation', done => {
testAction(
actions.receiveVulnerabilitiesSuccess,
{ headers, data },
state,
[
{
type: types.RECEIVE_VULNERABILITIES_SUCCESS,
payload: { pageInfo, vulnerabilities: data },
},
],
[],
done,
);
});
});
describe('receiveVulnerabilitiesError', () => {
it('should commit the error mutation', done => {
const errorCode = 403;
testAction(
actions.receiveVulnerabilitiesError,
errorCode,
state,
[{ type: types.RECEIVE_VULNERABILITIES_ERROR, payload: errorCode }],
[],
done,
);
});
});
describe('requestVulnerabilities', () => {
it('should commit the request mutation', done => {
testAction(
actions.requestVulnerabilities,
{},
state,
[{ type: types.REQUEST_VULNERABILITIES }],
[],
done,
);
});
});
describe('setVulnerabilitiesEndpoint', () => {
it('should commit the correct mutuation', done => {
const endpoint = 'fakepath.json';
testAction(
actions.setVulnerabilitiesEndpoint,
endpoint,
state,
[
{
type: types.SET_VULNERABILITIES_ENDPOINT,
payload: endpoint,
},
],
[],
done,
);
});
});
describe('setVulnerabilitiesPage', () => {
it('should commit the correct mutuation', done => {
const page = 3;
testAction(
actions.setVulnerabilitiesPage,
page,
state,
[
{
type: types.SET_VULNERABILITIES_PAGE,
payload: page,
},
],
[],
done,
);
});
});
});
describe('openModal', () => {
let state;
beforeEach(() => {
state = initialState();
});
it('should commit the SET_MODAL_DATA mutation', done => {
const vulnerability = mockDataVulnerabilities[0];
testAction(
actions.openModal,
{ vulnerability },
state,
[
{
type: types.SET_MODAL_DATA,
payload: { vulnerability },
},
],
[],
done,
);
});
});
describe('downloadPatch', () => {
it('creates a download link and clicks on it to download the file', () => {
jest.spyOn(document, 'createElement');
jest.spyOn(document.body, 'appendChild');
jest.spyOn(document.body, 'removeChild');
actions.downloadPatch({
state: {
modal: {
vulnerability: {
remediations: [
{
diff: 'abcdef',
},
],
},
},
},
});
expect(document.createElement).toHaveBeenCalledTimes(1);
expect(document.body.appendChild).toHaveBeenCalledTimes(1);
expect(document.body.removeChild).toHaveBeenCalledTimes(1);
});
});
describe('issue creation', () => {
let state;
beforeEach(() => {
state = initialState();
});
describe('createIssue', () => {
const vulnerability = mockDataVulnerabilities[0];
const data = { issue_url: 'fakepath.html' };
let mock;
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
describe('on success', () => {
beforeEach(() => {
mock
.onPost(vulnerability.create_vulnerability_feedback_issue_path)
.replyOnce(200, { data });
});
it('should dispatch the request and success actions', done => {
testAction(
actions.createIssue,
{ vulnerability },
{},
[],
[
{ type: 'requestCreateIssue' },
{
type: 'receiveCreateIssueSuccess',
payload: { data },
},
],
done,
);
});
});
describe('on error', () => {
beforeEach(() => {
mock.onPost(vulnerability.create_vulnerability_feedback_issue_path).replyOnce(404, {});
});
it('should dispatch the request and error actions', done => {
const flashError = false;
testAction(
actions.createIssue,
{ vulnerability, flashError },
{},
[],
[
{ type: 'requestCreateIssue' },
{ type: 'receiveCreateIssueError', payload: { flashError } },
],
done,
);
});
});
});
describe('receiveCreateIssueSuccess', () => {
it('should commit the success mutation', done => {
const data = mockDataVulnerabilities[0];
testAction(
actions.receiveCreateIssueSuccess,
{ data },
state,
[
{
type: types.RECEIVE_CREATE_ISSUE_SUCCESS,
payload: { data },
},
],
[],
done,
);
});
});
describe('receiveCreateIssueError', () => {
it('should commit the error mutation', done => {
testAction(
actions.receiveCreateIssueError,
{},
state,
[{ type: types.RECEIVE_CREATE_ISSUE_ERROR }],
[],
done,
);
});
});
describe('requestCreateIssue', () => {
it('should commit the request mutation', done => {
testAction(
actions.requestCreateIssue,
{},
state,
[{ type: types.REQUEST_CREATE_ISSUE }],
[],
done,
);
});
});
});
describe('merge request creation', () => {
let state;
beforeEach(() => {
state = initialState();
});
describe('createMergeRequest', () => {
const vulnerability = mockDataVulnerabilities[0];
const data = { merge_request_path: 'fakepath.html' };
let mock;
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
describe('on success', () => {
beforeEach(() => {
mock
.onPost(vulnerability.vulnerability_feedback_merge_request_path)
.replyOnce(200, { data });
});
it('should dispatch the request and success actions', done => {
testAction(
actions.createMergeRequest,
{ vulnerability },
{},
[],
[
{ type: 'requestCreateMergeRequest' },
{
type: 'receiveCreateMergeRequestSuccess',
payload: { data },
},
],
done,
);
});
});
describe('on error', () => {
beforeEach(() => {
mock.onPost(vulnerability.vulnerability_feedback_merge_request_path).replyOnce(404, {});
});
it('should dispatch the request and error actions', done => {
const flashError = false;
testAction(
actions.createMergeRequest,
{ vulnerability, flashError },
{},
[],
[
{ type: 'requestCreateMergeRequest' },
{ type: 'receiveCreateMergeRequestError', payload: { flashError } },
],
done,
);
});
});
});
describe('receiveCreateMergeRequestSuccess', () => {
it('should commit the success mutation', done => {
const data = mockDataVulnerabilities[0];
testAction(
actions.receiveCreateMergeRequestSuccess,
{ data },
state,
[
{
type: types.RECEIVE_CREATE_MERGE_REQUEST_SUCCESS,
payload: { data },
},
],
[],
done,
);
});
});
describe('receiveCreateMergeRequestError', () => {
it('should commit the error mutation', done => {
testAction(
actions.receiveCreateMergeRequestError,
{},
state,
[{ type: types.RECEIVE_CREATE_MERGE_REQUEST_ERROR }],
[],
done,
);
});
});
describe('requestCreateMergeRequest', () => {
it('should commit the request mutation', done => {
testAction(
actions.requestCreateMergeRequest,
{},
state,
[{ type: types.REQUEST_CREATE_MERGE_REQUEST }],
[],
done,
);
});
});
});
describe('vulnerability dismissal', () => {
let state;
beforeEach(() => {
state = initialState();
});
describe('dismissVulnerability', () => {
const vulnerability = mockDataVulnerabilities[0];
const data = { vulnerability };
const comment =
'How many times have I told you we need locking mechanisms on the vehicle doors!';
let mock;
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
describe('on success', () => {
beforeEach(() => {
mock
.onPost(vulnerability.create_vulnerability_feedback_dismissal_path)
.replyOnce(200, data);
});
it('should dispatch the request and success actions', done => {
testAction(
actions.dismissVulnerability,
{ vulnerability, comment },
{},
[],
[
{ type: 'requestDismissVulnerability' },
{ type: 'closeDismissalCommentBox' },
{
type: 'receiveDismissVulnerabilitySuccess',
payload: { data, vulnerability },
},
],
done,
);
});
it('should show the dismissal toast message', done => {
const checkToastMessage = () => {
expect(toast).toHaveBeenCalledTimes(1);
done();
};
testAction(
actions.dismissVulnerability,
{ vulnerability, comment },
{},
[],
[
{ type: 'requestDismissVulnerability' },
{ type: 'closeDismissalCommentBox' },
{
type: 'receiveDismissVulnerabilitySuccess',
payload: { data, vulnerability },
},
],
checkToastMessage,
);
});
});
describe('on error', () => {
beforeEach(() => {
mock.onPost(vulnerability.create_vulnerability_feedback_dismissal_path).replyOnce(404, {});
});
it('should dispatch the request and error actions', done => {
const flashError = false;
testAction(
actions.dismissVulnerability,
{ vulnerability, flashError },
{},
[],
[
{ type: 'requestDismissVulnerability' },
{ type: 'receiveDismissVulnerabilityError', payload: { flashError } },
],
done,
);
});
});
describe('with dismissed vulnerabilities hidden', () => {
beforeEach(() => {
state = {
...initialState(),
filters: {
hideDismissed: true,
},
};
mock
.onPost(vulnerability.create_vulnerability_feedback_dismissal_path)
.replyOnce(200, data);
});
it('should show the dismissal toast message and refresh vulnerabilities', done => {
const checkToastMessage = () => {
const [message, options] = toast.mock.calls[0];
expect(toast).toHaveBeenCalledTimes(1);
expect(message).toContain('Turn off the hide dismissed toggle to view');
expect(Object.keys(options.action).length).toBe(2);
done();
};
testAction(
actions.dismissVulnerability,
{ vulnerability, comment },
state,
[],
[
{ type: 'requestDismissVulnerability' },
{ type: 'closeDismissalCommentBox' },
{
type: 'receiveDismissVulnerabilitySuccess',
payload: { data, vulnerability },
},
{ type: 'fetchVulnerabilities', payload: { page: 1 } },
],
checkToastMessage,
);
});
it('should load the previous page if there is no more vulnerabiliy on the current one and page > 1', () => {
state.vulnerabilities = [mockDataVulnerabilities[0]];
state.pageInfo.page = 3;
testAction(
actions.dismissVulnerability,
{ vulnerability, comment },
state,
[],
[
{ type: 'requestDismissVulnerability' },
{ type: 'closeDismissalCommentBox' },
{
type: 'receiveDismissVulnerabilitySuccess',
payload: { data, vulnerability },
},
{ type: 'fetchVulnerabilities', payload: { page: 2 } },
],
);
});
});
});
describe('receiveDismissVulnerabilitySuccess', () => {
it('should commit the success mutation', done => {
const data = mockDataVulnerabilities[0];
testAction(
actions.receiveDismissVulnerabilitySuccess,
{ data },
state,
[
{
type: types.RECEIVE_DISMISS_VULNERABILITY_SUCCESS,
payload: { data },
},
],
[],
done,
);
});
});
describe('receiveDismissVulnerabilityError', () => {
it('should commit the error mutation', done => {
testAction(
actions.receiveDismissVulnerabilityError,
{},
state,
[{ type: types.RECEIVE_DISMISS_VULNERABILITY_ERROR }],
[],
done,
);
});
});
describe('EE Vulnerabilities actions', () => {
const mockEndpoint = 'mock-list-endpoint';
const mockResponse = [{ key_foo: 'valueFoo' }];
describe('requestDismissVulnerability', () => {
it('should commit the request mutation', done => {
testAction(
actions.requestDismissVulnerability,
{},
state,
[{ type: types.REQUEST_DISMISS_VULNERABILITY }],
[],
done,
);
});
});
});
let mockAxios;
describe('add vulnerability dismissal comment', () => {
let state;
let vulnerability;
beforeEach(() => {
mockAxios = new MockAdapter(axios);
state = createState();
vulnerability = {
create_vulnerability_feedback_issue_path: mockEndpoint,
report_type: 'issue',
project_fingerprint: 'some-fingerprint',
};
state = initialState();
});
afterEach(() => {
mockAxios.restore();
describe('addDismissalComment', () => {
const vulnerability = mockDataVulnerabilities[2];
const data = { vulnerability };
const url = `${vulnerability.create_vulnerability_feedback_dismissal_path}/${vulnerability.dismissal_feedback.id}`;
const comment = 'Well, we’re back in the car again.';
let mock;
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
describe('on success', () => {
beforeEach(() => {
mock.onPatch(url).replyOnce(200, data);
});
it('should dispatch the request and success actions', done => {
const checkPassedData = () => {
const { project_id, id } = vulnerability.dismissal_feedback;
const expected = JSON.stringify({ project_id, id, comment });
expect(mock.history.patch[0].data).toBe(expected);
expect(toast).toHaveBeenCalledTimes(1);
done();
};
testAction(
actions.addDismissalComment,
{ vulnerability, comment },
{},
[],
[
{ type: 'requestAddDismissalComment' },
{ type: 'closeDismissalCommentBox' },
{ type: 'receiveAddDismissalCommentSuccess', payload: { data, vulnerability } },
],
checkPassedData,
);
});
it('should show the add dismissal toast message', done => {
const checkPassedData = () => {
const { project_id, id } = vulnerability.dismissal_feedback;
const expected = JSON.stringify({ project_id, id, comment });
expect(mock.history.patch[0].data).toBe(expected);
expect(toast).toHaveBeenCalledTimes(1);
done();
};
testAction(
actions.addDismissalComment,
{ vulnerability, comment },
{},
[],
[
{ type: 'requestAddDismissalComment' },
{ type: 'closeDismissalCommentBox' },
{ type: 'receiveAddDismissalCommentSuccess', payload: { data, vulnerability } },
],
checkPassedData,
);
});
});
describe('on error', () => {
beforeEach(() => {
mock.onPatch(url).replyOnce(404);
});
it('should dispatch the request and error actions', done => {
testAction(
actions.addDismissalComment,
{ vulnerability, comment },
{},
[],
[{ type: 'requestAddDismissalComment' }, { type: 'receiveAddDismissalCommentError' }],
done,
);
});
});
describe('receiveAddDismissalCommentSuccess', () => {
it('should commit the success mutation', done => {
testAction(
actions.receiveAddDismissalCommentSuccess,
{ data },
state,
[{ type: types.RECEIVE_ADD_DISMISSAL_COMMENT_SUCCESS, payload: { data } }],
[],
done,
);
});
});
describe('receiveAddDismissalCommentError', () => {
it('should commit the error mutation', done => {
testAction(
actions.receiveAddDismissalCommentError,
{},
state,
[{ type: types.RECEIVE_ADD_DISMISSAL_COMMENT_ERROR }],
[],
done,
);
});
});
describe('requestAddDismissalComment', () => {
it('should commit the request mutation', done => {
testAction(
actions.requestAddDismissalComment,
{},
state,
[{ type: types.REQUEST_ADD_DISMISSAL_COMMENT }],
[],
done,
);
});
});
});
describe('createIssue', () => {
it('calls the createIssue endpoint and receives a success response', done => {
mockAxios.onPost(mockEndpoint).replyOnce(200, mockResponse);
const spy = jest.spyOn(axios, 'post');
describe('deleteDismissalComment', () => {
const vulnerability = mockDataVulnerabilities[2];
const data = { vulnerability };
const url = `${vulnerability.create_vulnerability_feedback_dismissal_path}/${vulnerability.dismissal_feedback.id}`;
const comment = '';
let mock;
return testAction(
actions.createIssue,
{
vulnerability,
},
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
describe('on success', () => {
beforeEach(() => {
mock.onPatch(url).replyOnce(200, data);
});
it('should dispatch the request and success actions', done => {
const checkPassedData = () => {
const { project_id } = vulnerability.dismissal_feedback;
const expected = JSON.stringify({ project_id, comment });
expect(mock.history.patch[0].data).toBe(expected);
done();
};
testAction(
actions.deleteDismissalComment,
{ vulnerability },
{},
[],
[
{ type: 'requestDeleteDismissalComment' },
{ type: 'closeDismissalCommentBox' },
{
type: 'receiveDeleteDismissalCommentSuccess',
payload: { data, id: vulnerability.id },
},
],
checkPassedData,
);
});
it('should show the delete dismissal comment toast message', done => {
const checkPassedData = () => {
const { project_id } = vulnerability.dismissal_feedback;
const expected = JSON.stringify({ project_id, comment });
expect(mock.history.patch[0].data).toBe(expected);
expect(toast).toHaveBeenCalledTimes(1);
done();
};
testAction(
actions.deleteDismissalComment,
{ vulnerability },
{},
[],
[
{ type: 'requestDeleteDismissalComment' },
{ type: 'closeDismissalCommentBox' },
{
type: 'receiveDeleteDismissalCommentSuccess',
payload: { data, id: vulnerability.id },
},
],
checkPassedData,
);
});
});
describe('on error', () => {
beforeEach(() => {
mock.onPatch(url).replyOnce(404);
});
it('should dispatch the request and error actions', done => {
testAction(
actions.deleteDismissalComment,
{ vulnerability },
{},
[],
[
{ type: 'requestDeleteDismissalComment' },
{ type: 'receiveDeleteDismissalCommentError' },
],
done,
);
});
});
describe('receiveDeleteDismissalCommentSuccess', () => {
it('should commit the success mutation', done => {
testAction(
actions.receiveDeleteDismissalCommentSuccess,
{ data },
state,
[{ type: types.RECEIVE_DELETE_DISMISSAL_COMMENT_SUCCESS, payload: { data } }],
[],
done,
);
});
});
describe('receiveDeleteDismissalCommentError', () => {
it('should commit the error mutation', done => {
testAction(
actions.receiveDeleteDismissalCommentError,
{},
state,
[{ type: types.RECEIVE_DELETE_DISMISSAL_COMMENT_ERROR }],
[],
done,
);
});
});
describe('requestDeleteDismissalComment', () => {
it('should commit the request mutation', done => {
testAction(
actions.requestDeleteDismissalComment,
{},
state,
[{ type: types.REQUEST_DELETE_DISMISSAL_COMMENT }],
[],
done,
);
});
});
});
});
describe('dismiss multiple vulnerabilities', () => {
let state;
let selectedVulnerabilities;
beforeEach(() => {
state = initialState();
state.vulnerabilities = mockDataVulnerabilities;
selectedVulnerabilities = {
[state.vulnerabilities[0].id]: true,
[state.vulnerabilities[1].id]: true,
};
state.selectedVulnerabilities = selectedVulnerabilities;
});
describe('dismissSelectedVulnerabilities', () => {
let mock;
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
it('should fire the dismissSelected mutations when all is well', done => {
mock
.onPost(state.vulnerabilities[0].create_vulnerability_feedback_dismissal_path)
.replyOnce(200)
.onPost(state.vulnerabilities[1].create_vulnerability_feedback_dismissal_path)
.replyOnce(200);
testAction(
actions.dismissSelectedVulnerabilities,
{},
state,
[],
[
{ type: 'requestCreateIssue' },
{ type: 'receiveCreateIssueSuccess', payload: mockResponse },
{ type: 'requestDismissSelectedVulnerabilities' },
{
type: 'receiveDismissSelectedVulnerabilitiesSuccess',
},
],
() => {
expect(spy).toHaveBeenCalledWith(mockEndpoint, {
vulnerability_feedback: {
category: 'issue',
feedback_type: 'issue',
project_fingerprint: 'some-fingerprint',
vulnerability_data: {
category: 'issue',
create_vulnerability_feedback_issue_path: mockEndpoint,
project_fingerprint: 'some-fingerprint',
report_type: 'issue',
},
},
});
expect(mock.history.post).toHaveLength(2);
expect(mock.history.post[0].url).toEqual(
state.vulnerabilities[0].create_vulnerability_feedback_dismissal_path,
);
done();
},
);
});
it('handles an API error by dispatching "receiveCreateIssueError"', done => {
mockAxios.onPost(mockEndpoint).replyOnce(500);
it('should trigger the error state when something goes wrong', done => {
mock
.onPost(state.vulnerabilities[0].create_vulnerability_feedback_dismissal_path)
.replyOnce(200)
.onPost(state.vulnerabilities[1].create_vulnerability_feedback_dismissal_path)
.replyOnce(500);
testAction(
actions.dismissSelectedVulnerabilities,
{},
state,
[],
[
{ type: 'requestDismissSelectedVulnerabilities' },
{ type: 'receiveDismissSelectedVulnerabilitiesError', payload: { flashError: true } },
],
done,
);
});
describe('receiveDismissSelectedVulnerabilitiesSuccess', () => {
it(`should commit ${types.RECEIVE_DISMISS_SELECTED_VULNERABILITIES_SUCCESS}`, done => {
testAction(
actions.receiveDismissSelectedVulnerabilitiesSuccess,
{ selectedVulnerabilities },
state,
[{ type: types.RECEIVE_DISMISS_SELECTED_VULNERABILITIES_SUCCESS }],
[],
done,
);
});
});
describe('receiveDismissSelectedVulnerabilitiesError', () => {
it(`should commit ${types.RECEIVE_DISMISS_SELECTED_VULNERABILITIES_ERROR}`, done => {
testAction(
actions.receiveDismissSelectedVulnerabilitiesError,
{},
state,
[{ type: types.RECEIVE_DISMISS_SELECTED_VULNERABILITIES_ERROR }],
[],
done,
);
});
});
});
});
describe('selecting vulnerabilities', () => {
let state;
beforeEach(() => {
state = initialState();
});
describe('selectVulnerability', () => {
it(`selectVulnerability should commit ${types.SELECT_VULNERABILITY}`, done => {
const id = 1234;
testAction(
actions.selectVulnerability,
{ id },
state,
[{ type: types.SELECT_VULNERABILITY, payload: id }],
[],
done,
);
});
});
describe('deselectVulnerability', () => {
it(`should commit ${types.DESELECT_VULNERABILITY}`, done => {
const id = 1234;
testAction(
actions.deselectVulnerability,
{ id },
state,
[{ type: types.DESELECT_VULNERABILITY, payload: id }],
[],
done,
);
});
});
describe('selectAllVulnerabilities', () => {
it(`should commit ${types.SELECT_ALL_VULNERABILITIES}`, done => {
testAction(
actions.selectAllVulnerabilities,
{},
state,
[{ type: types.SELECT_ALL_VULNERABILITIES }],
[],
done,
);
});
});
describe('deselectAllVulnerabilities', () => {
it(`should commit ${types.DESELECT_ALL_VULNERABILITIES}`, done => {
testAction(
actions.deselectAllVulnerabilities,
{},
state,
[{ type: types.DESELECT_ALL_VULNERABILITIES }],
[],
done,
);
});
});
});
describe('showDismissalDeleteButtons', () => {
let state;
beforeEach(() => {
state = initialState();
});
it('commits show dismissal delete buttons', done => {
testAction(
actions.showDismissalDeleteButtons,
null,
state,
[
{
type: types.SHOW_DISMISSAL_DELETE_BUTTONS,
},
],
[],
done,
);
});
});
describe('hideDismissalDeleteButtons', () => {
let state;
beforeEach(() => {
state = initialState();
});
return testAction(
actions.createIssue,
it('commits hide dismissal delete buttons', done => {
testAction(
actions.hideDismissalDeleteButtons,
null,
state,
[
{
vulnerability,
type: types.HIDE_DISMISSAL_DELETE_BUTTONS,
},
],
[],
done,
);
});
});
describe('revert vulnerability dismissal', () => {
describe('undoDismiss', () => {
const vulnerability = mockDataVulnerabilities[2];
const url = vulnerability.dismissal_feedback.destroy_vulnerability_feedback_dismissal_path;
let mock;
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
describe('on success', () => {
beforeEach(() => {
mock.onDelete(url).replyOnce(200, {});
});
it('should dispatch the request and success actions', done => {
testAction(
actions.undoDismiss,
{ vulnerability },
{},
[],
[
{ type: 'requestUndoDismiss' },
{ type: 'receiveUndoDismissSuccess', payload: { vulnerability } },
],
done,
);
});
});
describe('on error', () => {
beforeEach(() => {
mock.onDelete(url).replyOnce(404, {});
});
it('should dispatch the request and error actions', done => {
const flashError = false;
testAction(
actions.undoDismiss,
{ vulnerability, flashError },
{},
[],
[
{ type: 'requestUndoDismiss' },
{ type: 'receiveUndoDismissError', payload: { flashError } },
],
done,
);
});
});
});
describe('receiveUndoDismissSuccess', () => {
it('should commit the success mutation', done => {
const state = initialState;
const data = mockDataVulnerabilities[0];
testAction(
actions.receiveUndoDismissSuccess,
{ data },
state,
[
{
type: types.RECEIVE_REVERT_DISMISSAL_SUCCESS,
payload: { data },
},
],
[],
done,
);
});
});
describe('receiveUndoDismissError', () => {
it('should commit the error mutation', done => {
const state = initialState;
testAction(
actions.receiveUndoDismissError,
{},
state,
[{ type: types.RECEIVE_REVERT_DISMISSAL_ERROR }],
[],
done,
);
});
});
describe('requestUndoDismiss', () => {
it('should commit the request mutation', done => {
const state = initialState;
testAction(
actions.requestUndoDismiss,
{},
state,
[{ type: types.REQUEST_REVERT_DISMISSAL }],
[],
done,
);
});
});
});
describe('vulnerabilities history actions', () => {
const data = mockDataVulnerabilitiesHistory;
const params = { filters: { severity: ['critical'] } };
const filteredData = mockDataVulnerabilitiesHistory.critical;
let state;
beforeEach(() => {
state = initialState();
});
describe('setVulnerabilitiesHistoryEndpoint', () => {
it('should commit the correct mutuation', done => {
const endpoint = 'fakepath.json';
testAction(
actions.setVulnerabilitiesHistoryEndpoint,
endpoint,
state,
[
{
type: types.SET_VULNERABILITIES_HISTORY_ENDPOINT,
payload: endpoint,
},
],
[],
done,
);
});
});
describe('setVulnerabilitiesHistoryDayRange', () => {
it('should commit the number of past days to show', done => {
const days = DAYS.THIRTY;
testAction(
actions.setVulnerabilitiesHistoryDayRange,
days,
state,
[
{ type: 'requestCreateIssue' },
{ type: 'receiveCreateIssueError', payload: { flashError: undefined } },
{
type: types.SET_VULNERABILITIES_HISTORY_DAY_RANGE,
payload: days,
},
],
[],
done,
);
});
});
describe('fetchVulnerabilitiesHistory', () => {
let mock;
beforeEach(() => {
state.vulnerabilitiesHistoryEndpoint = `${TEST_HOST}/vulnerabilitIES_HISTORY.json`;
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
describe('on success', () => {
beforeEach(() => {
mock
.onGet(state.vulnerabilitiesHistoryEndpoint, { params })
.replyOnce(200, filteredData)
.onGet(state.vulnerabilitiesHistoryEndpoint)
.replyOnce(200, data);
});
it('should dispatch the request and success actions', done => {
testAction(
actions.fetchVulnerabilitiesHistory,
{},
state,
[],
[
{ type: 'requestVulnerabilitiesHistory' },
{
type: 'receiveVulnerabilitiesHistorySuccess',
payload: { data },
},
],
done,
);
});
it('return the filtered results', done => {
testAction(
actions.fetchVulnerabilitiesHistory,
params,
state,
[],
[
{ type: 'requestVulnerabilitiesHistory' },
{
type: 'receiveVulnerabilitiesHistorySuccess',
payload: { data: filteredData },
},
],
done,
);
});
});
describe('on error', () => {
beforeEach(() => {
mock.onGet(state.vulnerabilitiesHistoryEndpoint).replyOnce(404, {});
});
it('should dispatch the request and error actions', done => {
testAction(
actions.fetchVulnerabilitiesHistory,
{},
state,
[],
[
{ type: 'requestVulnerabilitiesHistory' },
{ type: 'receiveVulnerabilitiesHistoryError' },
],
done,
);
});
});
describe('with an empty endpoint', () => {
beforeEach(() => {
state.vulnerabilitiesHistoryEndpoint = '';
});
it('should not do anything', done => {
testAction(actions.fetchVulnerabilitiesHistory, {}, state, [], [], done);
});
});
});
describe('requestVulnerabilitiesHistory', () => {
it('should commit the request mutation', done => {
testAction(
actions.requestVulnerabilitiesHistory,
{},
state,
[{ type: types.REQUEST_VULNERABILITIES_HISTORY }],
[],
done,
);
});
});
describe('receiveVulnerabilitiesHistorySuccess', () => {
it('should commit the success mutation', done => {
testAction(
actions.receiveVulnerabilitiesHistorySuccess,
{ data },
state,
[{ type: types.RECEIVE_VULNERABILITIES_HISTORY_SUCCESS, payload: data }],
[],
done,
);
});
});
describe('receiveVulnerabilitiesHistoryError', () => {
it('should commit the error mutation', done => {
testAction(
actions.receiveVulnerabilitiesHistoryError,
{},
state,
[{ type: types.RECEIVE_VULNERABILITIES_HISTORY_ERROR }],
[],
done,
);
});
});
describe('openDismissalCommentBox', () => {
it('should commit the open comment mutation with a default payload', done => {
testAction(
actions.openDismissalCommentBox,
undefined,
state,
[{ type: types.OPEN_DISMISSAL_COMMENT_BOX }],
[],
done,
);
});
});
describe('closeDismissalCommentBox', () => {
it('should commit the close comment mutation', done => {
testAction(
actions.closeDismissalCommentBox,
{},
state,
[{ type: types.CLOSE_DISMISSAL_COMMENT_BOX }],
[],
done,
);
});
......
import createState from 'ee/security_dashboard/store/modules/vulnerabilities/state';
import { DAYS } from 'ee/security_dashboard/store/modules/vulnerabilities/constants';
import * as getters from 'ee/security_dashboard/store/modules/vulnerabilities/getters';
import mockHistoryData from '../vulnerabilities/data/mock_data_vulnerabilities_history.json';
import mockHistoryData from './data/mock_data_vulnerabilities_history.json';
describe('vulnerabilities module getters', () => {
describe('dashboardError', () => {
......@@ -65,16 +65,26 @@ describe('vulnerabilities module getters', () => {
getters.getVulnerabilityHistoryByName(state)(name);
return { getVulnerabilityHistoryByName };
};
const realDate = Date;
beforeEach(() => {
state = createState();
state.vulnerabilitiesHistory = mockHistoryData;
jasmine.clock().install();
jasmine.clock().mockDate(new Date(2019, 1, 2));
jest.useFakeTimers();
const currentDate = new Date(2019, 1, 2);
global.Date = class extends Date {
constructor(date) {
if (date) {
// eslint-disable-next-line constructor-super
return super(date);
}
return currentDate;
}
};
});
afterEach(function() {
jasmine.clock().uninstall();
afterEach(() => {
global.Date = realDate;
});
it('should filter the data to the last 30 days and days we have data for', () => {
......
......@@ -19,7 +19,7 @@ describe('mediator', () => {
beforeEach(() => {
store = createStore();
spyOn(store, 'dispatch');
jest.spyOn(store, 'dispatch').mockImplementation(() => {});
});
it('triggers fetching vulnerabilities after one filter changes', () => {
......
import Vue from 'vue';
import MockAdapter from 'axios-mock-adapter';
import testAction from 'spec/helpers/vuex_action_helper';
import { TEST_HOST } from 'spec/test_constants';
import { DAYS } from 'ee/security_dashboard/store/modules/vulnerabilities/constants';
import initialState from 'ee/security_dashboard/store/modules/vulnerabilities/state';
import * as types from 'ee/security_dashboard/store/modules/vulnerabilities/mutation_types';
import * as actions from 'ee/security_dashboard/store/modules/vulnerabilities/actions';
import axios from '~/lib/utils/axios_utils';
import mockDataVulnerabilities from './data/mock_data_vulnerabilities';
import mockDataVulnerabilitiesCount from './data/mock_data_vulnerabilities_count.json';
import mockDataVulnerabilitiesHistory from './data/mock_data_vulnerabilities_history.json';
const sourceBranch = 'feature-branch-1';
describe('vulnerabilities count actions', () => {
const data = mockDataVulnerabilitiesCount;
const params = { filters: { type: ['sast'] } };
const filteredData = mockDataVulnerabilitiesCount.sast;
let state;
beforeEach(() => {
state = initialState();
});
describe('setPipelineId', () => {
const pipelineId = 123;
it('should commit the correct mutation', done => {
testAction(
actions.setPipelineId,
pipelineId,
state,
[
{
type: types.SET_PIPELINE_ID,
payload: pipelineId,
},
],
[],
done,
);
});
});
describe('setSourceBranch', () => {
it('should commit the correct mutation', done => {
testAction(
actions.setSourceBranch,
sourceBranch,
state,
[
{
type: types.SET_SOURCE_BRANCH,
payload: sourceBranch,
},
],
[],
done,
);
});
});
describe('setVulnerabilitiesCountEndpoint', () => {
it('should commit the correct mutuation', done => {
const endpoint = 'fakepath.json';
testAction(
actions.setVulnerabilitiesCountEndpoint,
endpoint,
state,
[
{
type: types.SET_VULNERABILITIES_COUNT_ENDPOINT,
payload: endpoint,
},
],
[],
done,
);
});
});
describe('fetchVulnerabilitiesCount', () => {
let mock;
beforeEach(() => {
state.vulnerabilitiesCountEndpoint = `${TEST_HOST}/vulnerabilities_count.json`;
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
describe('on success', () => {
beforeEach(() => {
mock
.onGet(state.vulnerabilitiesCountEndpoint, { params })
.replyOnce(200, filteredData)
.onGet(state.vulnerabilitiesCountEndpoint)
.replyOnce(200, data);
});
it('should dispatch the request and success actions', done => {
testAction(
actions.fetchVulnerabilitiesCount,
{},
state,
[],
[
{ type: 'requestVulnerabilitiesCount' },
{
type: 'receiveVulnerabilitiesCountSuccess',
payload: { data },
},
],
done,
);
});
it('should send the passed filters to the endpoint', done => {
testAction(
actions.fetchVulnerabilitiesCount,
params,
state,
[],
[
{ type: 'requestVulnerabilitiesCount' },
{
type: 'receiveVulnerabilitiesCountSuccess',
payload: { data: filteredData },
},
],
done,
);
});
});
describe('on error', () => {
beforeEach(() => {
mock.onGet(state.vulnerabilitiesCountEndpoint).replyOnce(404, {});
});
it('should dispatch the request and error actions', done => {
testAction(
actions.fetchVulnerabilitiesCount,
{},
state,
[],
[{ type: 'requestVulnerabilitiesCount' }, { type: 'receiveVulnerabilitiesCountError' }],
done,
);
});
});
describe('with an empty endpoint', () => {
beforeEach(() => {
state.vulnerabilitiesCountEndpoint = '';
});
it('should not do anything', done => {
testAction(actions.fetchVulnerabilitiesCount, {}, state, [], [], done);
});
});
});
describe('requestVulnerabilitiesCount', () => {
it('should commit the request mutation', done => {
testAction(
actions.requestVulnerabilitiesCount,
{},
state,
[{ type: types.REQUEST_VULNERABILITIES_COUNT }],
[],
done,
);
});
});
describe('receiveVulnerabilitiesCountSuccess', () => {
it('should commit the success mutation', done => {
testAction(
actions.receiveVulnerabilitiesCountSuccess,
{ data },
state,
[{ type: types.RECEIVE_VULNERABILITIES_COUNT_SUCCESS, payload: data }],
[],
done,
);
});
});
describe('receiveVulnerabilitiesCountError', () => {
it('should commit the error mutation', done => {
testAction(
actions.receiveVulnerabilitiesCountError,
{},
state,
[{ type: types.RECEIVE_VULNERABILITIES_COUNT_ERROR }],
[],
done,
);
});
});
});
describe('vulnerabilities actions', () => {
const data = mockDataVulnerabilities;
const params = { filters: { severity: ['critical'] } };
const filteredData = mockDataVulnerabilities.filter(vuln => vuln.severity === 'critical');
const pageInfo = {
page: 1,
nextPage: 2,
previousPage: 1,
perPage: 20,
total: 100,
totalPages: 5,
};
const headers = {
'X-Next-Page': pageInfo.nextPage,
'X-Page': pageInfo.page,
'X-Per-Page': pageInfo.perPage,
'X-Prev-Page': pageInfo.previousPage,
'X-Total': pageInfo.total,
'X-Total-Pages': pageInfo.totalPages,
};
let state;
beforeEach(() => {
state = initialState();
});
describe('fetchVulnerabilities', () => {
let mock;
beforeEach(() => {
state.vulnerabilitiesEndpoint = `${TEST_HOST}/vulnerabilities.json`;
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
describe('on success', () => {
beforeEach(() => {
mock
.onGet(state.vulnerabilitiesEndpoint, { params })
.replyOnce(200, filteredData, headers)
.onGet(state.vulnerabilitiesEndpoint)
.replyOnce(200, data, headers);
});
it('should dispatch the request and success actions', done => {
testAction(
actions.fetchVulnerabilities,
{},
state,
[],
[
{ type: 'requestVulnerabilities' },
{
type: 'receiveVulnerabilitiesSuccess',
payload: { data, headers },
},
],
done,
);
});
it('should pass through the filters', done => {
testAction(
actions.fetchVulnerabilities,
params,
state,
[],
[
{ type: 'requestVulnerabilities' },
{
type: 'receiveVulnerabilitiesSuccess',
payload: { data: filteredData, headers },
},
],
done,
);
});
});
describe('on error', () => {
const errorCode = 404;
beforeEach(() => {
mock.onGet(state.vulnerabilitiesEndpoint).replyOnce(errorCode, {});
});
it('should dispatch the request and error actions', done => {
testAction(
actions.fetchVulnerabilities,
{},
state,
[],
[
{ type: 'requestVulnerabilities' },
{ type: 'receiveVulnerabilitiesError', payload: errorCode },
],
done,
);
});
});
describe('with an empty endpoint', () => {
beforeEach(() => {
state.vulnerabilitiesEndpoint = '';
});
it('should not do anything', done => {
testAction(actions.fetchVulnerabilities, {}, state, [], [], done);
});
});
});
describe('receiveVulnerabilitiesSuccess', () => {
it('should commit the success mutation', done => {
testAction(
actions.receiveVulnerabilitiesSuccess,
{ headers, data },
state,
[
{
type: types.RECEIVE_VULNERABILITIES_SUCCESS,
payload: { pageInfo, vulnerabilities: data },
},
],
[],
done,
);
});
});
describe('receiveVulnerabilitiesError', () => {
it('should commit the error mutation', done => {
const errorCode = 403;
testAction(
actions.receiveVulnerabilitiesError,
errorCode,
state,
[{ type: types.RECEIVE_VULNERABILITIES_ERROR, payload: errorCode }],
[],
done,
);
});
});
describe('requestVulnerabilities', () => {
it('should commit the request mutation', done => {
testAction(
actions.requestVulnerabilities,
{},
state,
[{ type: types.REQUEST_VULNERABILITIES }],
[],
done,
);
});
});
describe('setVulnerabilitiesEndpoint', () => {
it('should commit the correct mutuation', done => {
const endpoint = 'fakepath.json';
testAction(
actions.setVulnerabilitiesEndpoint,
endpoint,
state,
[
{
type: types.SET_VULNERABILITIES_ENDPOINT,
payload: endpoint,
},
],
[],
done,
);
});
});
describe('setVulnerabilitiesPage', () => {
it('should commit the correct mutuation', done => {
const page = 3;
testAction(
actions.setVulnerabilitiesPage,
page,
state,
[
{
type: types.SET_VULNERABILITIES_PAGE,
payload: page,
},
],
[],
done,
);
});
});
});
describe('openModal', () => {
let state;
beforeEach(() => {
state = initialState();
});
it('should commit the SET_MODAL_DATA mutation', done => {
const vulnerability = mockDataVulnerabilities[0];
testAction(
actions.openModal,
{ vulnerability },
state,
[
{
type: types.SET_MODAL_DATA,
payload: { vulnerability },
},
],
[],
done,
);
});
});
describe('downloadPatch', () => {
it('creates a download link and clicks on it to download the file', () => {
spyOn(document, 'createElement').and.callThrough();
spyOn(document.body, 'appendChild').and.callThrough();
spyOn(document.body, 'removeChild').and.callThrough();
actions.downloadPatch({
state: {
modal: {
vulnerability: {
remediations: [
{
diff: 'abcdef',
},
],
},
},
},
});
expect(document.createElement).toHaveBeenCalledTimes(1);
expect(document.body.appendChild).toHaveBeenCalledTimes(1);
expect(document.body.removeChild).toHaveBeenCalledTimes(1);
});
});
describe('issue creation', () => {
let state;
beforeEach(() => {
state = initialState();
});
describe('createIssue', () => {
const vulnerability = mockDataVulnerabilities[0];
const data = { issue_url: 'fakepath.html' };
let mock;
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
describe('on success', () => {
beforeEach(() => {
mock
.onPost(vulnerability.create_vulnerability_feedback_issue_path)
.replyOnce(200, { data });
});
it('should dispatch the request and success actions', done => {
testAction(
actions.createIssue,
{ vulnerability },
{},
[],
[
{ type: 'requestCreateIssue' },
{
type: 'receiveCreateIssueSuccess',
payload: { data },
},
],
done,
);
});
});
describe('on error', () => {
beforeEach(() => {
mock.onPost(vulnerability.create_vulnerability_feedback_issue_path).replyOnce(404, {});
});
it('should dispatch the request and error actions', done => {
const flashError = false;
testAction(
actions.createIssue,
{ vulnerability, flashError },
{},
[],
[
{ type: 'requestCreateIssue' },
{ type: 'receiveCreateIssueError', payload: { flashError } },
],
done,
);
});
});
});
describe('receiveCreateIssueSuccess', () => {
it('should commit the success mutation', done => {
const data = mockDataVulnerabilities[0];
testAction(
actions.receiveCreateIssueSuccess,
{ data },
state,
[
{
type: types.RECEIVE_CREATE_ISSUE_SUCCESS,
payload: { data },
},
],
[],
done,
);
});
});
describe('receiveCreateIssueError', () => {
it('should commit the error mutation', done => {
testAction(
actions.receiveCreateIssueError,
{},
state,
[{ type: types.RECEIVE_CREATE_ISSUE_ERROR }],
[],
done,
);
});
});
describe('requestCreateIssue', () => {
it('should commit the request mutation', done => {
testAction(
actions.requestCreateIssue,
{},
state,
[{ type: types.REQUEST_CREATE_ISSUE }],
[],
done,
);
});
});
});
describe('merge request creation', () => {
let state;
beforeEach(() => {
state = initialState();
});
describe('createMergeRequest', () => {
const vulnerability = mockDataVulnerabilities[0];
const data = { merge_request_path: 'fakepath.html' };
let mock;
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
describe('on success', () => {
beforeEach(() => {
mock
.onPost(vulnerability.vulnerability_feedback_merge_request_path)
.replyOnce(200, { data });
});
it('should dispatch the request and success actions', done => {
testAction(
actions.createMergeRequest,
{ vulnerability },
{},
[],
[
{ type: 'requestCreateMergeRequest' },
{
type: 'receiveCreateMergeRequestSuccess',
payload: { data },
},
],
done,
);
});
});
describe('on error', () => {
beforeEach(() => {
mock.onPost(vulnerability.vulnerability_feedback_merge_request_path).replyOnce(404, {});
});
it('should dispatch the request and error actions', done => {
const flashError = false;
testAction(
actions.createMergeRequest,
{ vulnerability, flashError },
{},
[],
[
{ type: 'requestCreateMergeRequest' },
{ type: 'receiveCreateMergeRequestError', payload: { flashError } },
],
done,
);
});
});
});
describe('receiveCreateMergeRequestSuccess', () => {
it('should commit the success mutation', done => {
const data = mockDataVulnerabilities[0];
testAction(
actions.receiveCreateMergeRequestSuccess,
{ data },
state,
[
{
type: types.RECEIVE_CREATE_MERGE_REQUEST_SUCCESS,
payload: { data },
},
],
[],
done,
);
});
});
describe('receiveCreateMergeRequestError', () => {
it('should commit the error mutation', done => {
testAction(
actions.receiveCreateMergeRequestError,
{},
state,
[{ type: types.RECEIVE_CREATE_MERGE_REQUEST_ERROR }],
[],
done,
);
});
});
describe('requestCreateMergeRequest', () => {
it('should commit the request mutation', done => {
testAction(
actions.requestCreateMergeRequest,
{},
state,
[{ type: types.REQUEST_CREATE_MERGE_REQUEST }],
[],
done,
);
});
});
});
describe('vulnerability dismissal', () => {
let state;
beforeEach(() => {
state = initialState();
});
describe('dismissVulnerability', () => {
const vulnerability = mockDataVulnerabilities[0];
const data = { vulnerability };
const comment =
'How many times have I told you we need locking mechanisms on the vehicle doors!';
let mock;
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
describe('on success', () => {
beforeEach(() => {
mock
.onPost(vulnerability.create_vulnerability_feedback_dismissal_path)
.replyOnce(200, data);
});
it('should dispatch the request and success actions', done => {
testAction(
actions.dismissVulnerability,
{ vulnerability, comment },
{},
[],
[
{ type: 'requestDismissVulnerability' },
{ type: 'closeDismissalCommentBox' },
{
type: 'receiveDismissVulnerabilitySuccess',
payload: { data, vulnerability },
},
],
done,
);
});
it('should show the dismissal toast message', done => {
spyOn(Vue.toasted, 'show').and.callThrough();
const checkToastMessage = () => {
expect(Vue.toasted.show).toHaveBeenCalledTimes(1);
done();
};
testAction(
actions.dismissVulnerability,
{ vulnerability, comment },
{},
[],
[
{ type: 'requestDismissVulnerability' },
{ type: 'closeDismissalCommentBox' },
{
type: 'receiveDismissVulnerabilitySuccess',
payload: { data, vulnerability },
},
],
checkToastMessage,
);
});
});
describe('on error', () => {
beforeEach(() => {
mock.onPost(vulnerability.create_vulnerability_feedback_dismissal_path).replyOnce(404, {});
});
it('should dispatch the request and error actions', done => {
const flashError = false;
testAction(
actions.dismissVulnerability,
{ vulnerability, flashError },
{},
[],
[
{ type: 'requestDismissVulnerability' },
{ type: 'receiveDismissVulnerabilityError', payload: { flashError } },
],
done,
);
});
});
describe('with dismissed vulnerabilities hidden', () => {
beforeEach(() => {
state = {
...initialState(),
filters: {
hideDismissed: true,
},
};
mock
.onPost(vulnerability.create_vulnerability_feedback_dismissal_path)
.replyOnce(200, data);
});
it('should show the dismissal toast message and refresh vulnerabilities', done => {
spyOn(Vue.toasted, 'show').and.callThrough();
const checkToastMessage = () => {
const [message, options] = Vue.toasted.show.calls.argsFor(0);
expect(Vue.toasted.show).toHaveBeenCalledTimes(1);
expect(message).toContain('Turn off the hide dismissed toggle to view');
expect(options.action.length).toBe(2);
done();
};
testAction(
actions.dismissVulnerability,
{ vulnerability, comment },
state,
[],
[
{ type: 'requestDismissVulnerability' },
{ type: 'closeDismissalCommentBox' },
{
type: 'receiveDismissVulnerabilitySuccess',
payload: { data, vulnerability },
},
{ type: 'fetchVulnerabilities', payload: { page: 1 } },
],
checkToastMessage,
);
});
it('should load the previous page if there is no more vulnerabiliy on the current one and page > 1', () => {
state.vulnerabilities = [mockDataVulnerabilities[0]];
state.pageInfo.page = 3;
testAction(
actions.dismissVulnerability,
{ vulnerability, comment },
state,
[],
[
{ type: 'requestDismissVulnerability' },
{ type: 'closeDismissalCommentBox' },
{
type: 'receiveDismissVulnerabilitySuccess',
payload: { data, vulnerability },
},
{ type: 'fetchVulnerabilities', payload: { page: 2 } },
],
);
});
});
});
describe('receiveDismissVulnerabilitySuccess', () => {
it('should commit the success mutation', done => {
const data = mockDataVulnerabilities[0];
testAction(
actions.receiveDismissVulnerabilitySuccess,
{ data },
state,
[
{
type: types.RECEIVE_DISMISS_VULNERABILITY_SUCCESS,
payload: { data },
},
],
[],
done,
);
});
});
describe('receiveDismissVulnerabilityError', () => {
it('should commit the error mutation', done => {
testAction(
actions.receiveDismissVulnerabilityError,
{},
state,
[{ type: types.RECEIVE_DISMISS_VULNERABILITY_ERROR }],
[],
done,
);
});
});
describe('requestDismissVulnerability', () => {
it('should commit the request mutation', done => {
testAction(
actions.requestDismissVulnerability,
{},
state,
[{ type: types.REQUEST_DISMISS_VULNERABILITY }],
[],
done,
);
});
});
});
describe('add vulnerability dismissal comment', () => {
let state;
beforeEach(() => {
state = initialState();
});
describe('addDismissalComment', () => {
const vulnerability = mockDataVulnerabilities[2];
const data = { vulnerability };
const url = `${vulnerability.create_vulnerability_feedback_dismissal_path}/${vulnerability.dismissal_feedback.id}`;
const comment = 'Well, we’re back in the car again.';
let mock;
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
describe('on success', () => {
beforeEach(() => {
mock.onPatch(url).replyOnce(200, data);
});
it('should dispatch the request and success actions', done => {
const checkPassedData = () => {
const { project_id, id } = vulnerability.dismissal_feedback;
const expected = JSON.stringify({ project_id, id, comment });
expect(mock.history.patch[0].data).toBe(expected);
done();
};
testAction(
actions.addDismissalComment,
{ vulnerability, comment },
{},
[],
[
{ type: 'requestAddDismissalComment' },
{ type: 'closeDismissalCommentBox' },
{ type: 'receiveAddDismissalCommentSuccess', payload: { data, vulnerability } },
],
checkPassedData,
);
});
it('should show the add dismissal toast message', done => {
spyOn(Vue.toasted, 'show').and.callThrough();
const checkPassedData = () => {
const { project_id, id } = vulnerability.dismissal_feedback;
const expected = JSON.stringify({ project_id, id, comment });
expect(mock.history.patch[0].data).toBe(expected);
expect(Vue.toasted.show).toHaveBeenCalledTimes(1);
done();
};
testAction(
actions.addDismissalComment,
{ vulnerability, comment },
{},
[],
[
{ type: 'requestAddDismissalComment' },
{ type: 'closeDismissalCommentBox' },
{ type: 'receiveAddDismissalCommentSuccess', payload: { data, vulnerability } },
],
checkPassedData,
);
});
});
describe('on error', () => {
beforeEach(() => {
mock.onPatch(url).replyOnce(404);
});
it('should dispatch the request and error actions', done => {
testAction(
actions.addDismissalComment,
{ vulnerability, comment },
{},
[],
[{ type: 'requestAddDismissalComment' }, { type: 'receiveAddDismissalCommentError' }],
done,
);
});
});
describe('receiveAddDismissalCommentSuccess', () => {
it('should commit the success mutation', done => {
testAction(
actions.receiveAddDismissalCommentSuccess,
{ data },
state,
[{ type: types.RECEIVE_ADD_DISMISSAL_COMMENT_SUCCESS, payload: { data } }],
[],
done,
);
});
});
describe('receiveAddDismissalCommentError', () => {
it('should commit the error mutation', done => {
testAction(
actions.receiveAddDismissalCommentError,
{},
state,
[{ type: types.RECEIVE_ADD_DISMISSAL_COMMENT_ERROR }],
[],
done,
);
});
});
describe('requestAddDismissalComment', () => {
it('should commit the request mutation', done => {
testAction(
actions.requestAddDismissalComment,
{},
state,
[{ type: types.REQUEST_ADD_DISMISSAL_COMMENT }],
[],
done,
);
});
});
});
describe('deleteDismissalComment', () => {
const vulnerability = mockDataVulnerabilities[2];
const data = { vulnerability };
const url = `${vulnerability.create_vulnerability_feedback_dismissal_path}/${vulnerability.dismissal_feedback.id}`;
const comment = '';
let mock;
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
describe('on success', () => {
beforeEach(() => {
mock.onPatch(url).replyOnce(200, data);
});
it('should dispatch the request and success actions', done => {
const checkPassedData = () => {
const { project_id } = vulnerability.dismissal_feedback;
const expected = JSON.stringify({ project_id, comment });
expect(mock.history.patch[0].data).toBe(expected);
done();
};
testAction(
actions.deleteDismissalComment,
{ vulnerability },
{},
[],
[
{ type: 'requestDeleteDismissalComment' },
{ type: 'closeDismissalCommentBox' },
{
type: 'receiveDeleteDismissalCommentSuccess',
payload: { data, id: vulnerability.id },
},
],
checkPassedData,
);
});
it('should show the delete dismissal comment toast message', done => {
spyOn(Vue.toasted, 'show').and.callThrough();
const checkPassedData = () => {
const { project_id } = vulnerability.dismissal_feedback;
const expected = JSON.stringify({ project_id, comment });
expect(mock.history.patch[0].data).toBe(expected);
expect(Vue.toasted.show).toHaveBeenCalledTimes(1);
done();
};
testAction(
actions.deleteDismissalComment,
{ vulnerability },
{},
[],
[
{ type: 'requestDeleteDismissalComment' },
{ type: 'closeDismissalCommentBox' },
{
type: 'receiveDeleteDismissalCommentSuccess',
payload: { data, id: vulnerability.id },
},
],
checkPassedData,
);
});
});
describe('on error', () => {
beforeEach(() => {
mock.onPatch(url).replyOnce(404);
});
it('should dispatch the request and error actions', done => {
testAction(
actions.deleteDismissalComment,
{ vulnerability },
{},
[],
[
{ type: 'requestDeleteDismissalComment' },
{ type: 'receiveDeleteDismissalCommentError' },
],
done,
);
});
});
describe('receiveDeleteDismissalCommentSuccess', () => {
it('should commit the success mutation', done => {
testAction(
actions.receiveDeleteDismissalCommentSuccess,
{ data },
state,
[{ type: types.RECEIVE_DELETE_DISMISSAL_COMMENT_SUCCESS, payload: { data } }],
[],
done,
);
});
});
describe('receiveDeleteDismissalCommentError', () => {
it('should commit the error mutation', done => {
testAction(
actions.receiveDeleteDismissalCommentError,
{},
state,
[{ type: types.RECEIVE_DELETE_DISMISSAL_COMMENT_ERROR }],
[],
done,
);
});
});
describe('requestDeleteDismissalComment', () => {
it('should commit the request mutation', done => {
testAction(
actions.requestDeleteDismissalComment,
{},
state,
[{ type: types.REQUEST_DELETE_DISMISSAL_COMMENT }],
[],
done,
);
});
});
});
});
describe('dismiss multiple vulnerabilities', () => {
let state;
let selectedVulnerabilities;
beforeEach(() => {
state = initialState();
state.vulnerabilities = mockDataVulnerabilities;
selectedVulnerabilities = {
[state.vulnerabilities[0].id]: true,
[state.vulnerabilities[1].id]: true,
};
state.selectedVulnerabilities = selectedVulnerabilities;
});
describe('dismissSelectedVulnerabilities', () => {
let mock;
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
it('should fire the dismissSelected mutations when all is well', done => {
mock
.onPost(state.vulnerabilities[0].create_vulnerability_feedback_dismissal_path)
.replyOnce(200)
.onPost(state.vulnerabilities[1].create_vulnerability_feedback_dismissal_path)
.replyOnce(200);
testAction(
actions.dismissSelectedVulnerabilities,
{},
state,
[],
[
{ type: 'requestDismissSelectedVulnerabilities' },
{
type: 'receiveDismissSelectedVulnerabilitiesSuccess',
},
],
() => {
expect(mock.history.post).toHaveLength(2);
expect(mock.history.post[0].url).toEqual(
state.vulnerabilities[0].create_vulnerability_feedback_dismissal_path,
);
done();
},
);
});
it('should trigger the error state when something goes wrong', done => {
mock
.onPost(state.vulnerabilities[0].create_vulnerability_feedback_dismissal_path)
.replyOnce(200)
.onPost(state.vulnerabilities[1].create_vulnerability_feedback_dismissal_path)
.replyOnce(500);
testAction(
actions.dismissSelectedVulnerabilities,
{},
state,
[],
[
{ type: 'requestDismissSelectedVulnerabilities' },
{ type: 'receiveDismissSelectedVulnerabilitiesError', payload: { flashError: true } },
],
done,
);
});
describe('receiveDismissSelectedVulnerabilitiesSuccess', () => {
it(`should commit ${types.RECEIVE_DISMISS_SELECTED_VULNERABILITIES_SUCCESS}`, done => {
testAction(
actions.receiveDismissSelectedVulnerabilitiesSuccess,
{ selectedVulnerabilities },
state,
[{ type: types.RECEIVE_DISMISS_SELECTED_VULNERABILITIES_SUCCESS }],
[],
done,
);
});
});
describe('receiveDismissSelectedVulnerabilitiesError', () => {
it(`should commit ${types.RECEIVE_DISMISS_SELECTED_VULNERABILITIES_ERROR}`, done => {
testAction(
actions.receiveDismissSelectedVulnerabilitiesError,
{},
state,
[{ type: types.RECEIVE_DISMISS_SELECTED_VULNERABILITIES_ERROR }],
[],
done,
);
});
});
});
});
describe('selecting vulnerabilities', () => {
let state;
beforeEach(() => {
state = initialState();
});
describe('selectVulnerability', () => {
it(`selectVulnerability should commit ${types.SELECT_VULNERABILITY}`, done => {
const id = 1234;
testAction(
actions.selectVulnerability,
{ id },
state,
[{ type: types.SELECT_VULNERABILITY, payload: id }],
[],
done,
);
});
});
describe('deselectVulnerability', () => {
it(`should commit ${types.DESELECT_VULNERABILITY}`, done => {
const id = 1234;
testAction(
actions.deselectVulnerability,
{ id },
state,
[{ type: types.DESELECT_VULNERABILITY, payload: id }],
[],
done,
);
});
});
describe('selectAllVulnerabilities', () => {
it(`should commit ${types.SELECT_ALL_VULNERABILITIES}`, done => {
testAction(
actions.selectAllVulnerabilities,
{},
state,
[{ type: types.SELECT_ALL_VULNERABILITIES }],
[],
done,
);
});
});
describe('deselectAllVulnerabilities', () => {
it(`should commit ${types.DESELECT_ALL_VULNERABILITIES}`, done => {
testAction(
actions.deselectAllVulnerabilities,
{},
state,
[{ type: types.DESELECT_ALL_VULNERABILITIES }],
[],
done,
);
});
});
});
describe('showDismissalDeleteButtons', () => {
let state;
beforeEach(() => {
state = initialState();
});
it('commits show dismissal delete buttons', done => {
testAction(
actions.showDismissalDeleteButtons,
null,
state,
[
{
type: types.SHOW_DISMISSAL_DELETE_BUTTONS,
},
],
[],
done,
);
});
});
describe('hideDismissalDeleteButtons', () => {
let state;
beforeEach(() => {
state = initialState();
});
it('commits hide dismissal delete buttons', done => {
testAction(
actions.hideDismissalDeleteButtons,
null,
state,
[
{
type: types.HIDE_DISMISSAL_DELETE_BUTTONS,
},
],
[],
done,
);
});
});
describe('revert vulnerability dismissal', () => {
describe('undoDismiss', () => {
const vulnerability = mockDataVulnerabilities[2];
const url = vulnerability.dismissal_feedback.destroy_vulnerability_feedback_dismissal_path;
let mock;
beforeEach(() => {
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
describe('on success', () => {
beforeEach(() => {
mock.onDelete(url).replyOnce(200, {});
});
it('should dispatch the request and success actions', done => {
testAction(
actions.undoDismiss,
{ vulnerability },
{},
[],
[
{ type: 'requestUndoDismiss' },
{ type: 'receiveUndoDismissSuccess', payload: { vulnerability } },
],
done,
);
});
});
describe('on error', () => {
beforeEach(() => {
mock.onDelete(url).replyOnce(404, {});
});
it('should dispatch the request and error actions', done => {
const flashError = false;
testAction(
actions.undoDismiss,
{ vulnerability, flashError },
{},
[],
[
{ type: 'requestUndoDismiss' },
{ type: 'receiveUndoDismissError', payload: { flashError } },
],
done,
);
});
});
});
describe('receiveUndoDismissSuccess', () => {
it('should commit the success mutation', done => {
const state = initialState;
const data = mockDataVulnerabilities[0];
testAction(
actions.receiveUndoDismissSuccess,
{ data },
state,
[
{
type: types.RECEIVE_REVERT_DISMISSAL_SUCCESS,
payload: { data },
},
],
[],
done,
);
});
});
describe('receiveUndoDismissError', () => {
it('should commit the error mutation', done => {
const state = initialState;
testAction(
actions.receiveUndoDismissError,
{},
state,
[{ type: types.RECEIVE_REVERT_DISMISSAL_ERROR }],
[],
done,
);
});
});
describe('requestUndoDismiss', () => {
it('should commit the request mutation', done => {
const state = initialState;
testAction(
actions.requestUndoDismiss,
{},
state,
[{ type: types.REQUEST_REVERT_DISMISSAL }],
[],
done,
);
});
});
});
describe('vulnerabilities history actions', () => {
const data = mockDataVulnerabilitiesHistory;
const params = { filters: { severity: ['critical'] } };
const filteredData = mockDataVulnerabilitiesHistory.critical;
let state;
beforeEach(() => {
state = initialState();
});
describe('setVulnerabilitiesHistoryEndpoint', () => {
it('should commit the correct mutuation', done => {
const endpoint = 'fakepath.json';
testAction(
actions.setVulnerabilitiesHistoryEndpoint,
endpoint,
state,
[
{
type: types.SET_VULNERABILITIES_HISTORY_ENDPOINT,
payload: endpoint,
},
],
[],
done,
);
});
});
describe('setVulnerabilitiesHistoryDayRange', () => {
it('should commit the number of past days to show', done => {
const days = DAYS.THIRTY;
testAction(
actions.setVulnerabilitiesHistoryDayRange,
days,
state,
[
{
type: types.SET_VULNERABILITIES_HISTORY_DAY_RANGE,
payload: days,
},
],
[],
done,
);
});
});
describe('fetchVulnerabilitiesHistory', () => {
let mock;
beforeEach(() => {
state.vulnerabilitiesHistoryEndpoint = `${TEST_HOST}/vulnerabilitIES_HISTORY.json`;
mock = new MockAdapter(axios);
});
afterEach(() => {
mock.restore();
});
describe('on success', () => {
beforeEach(() => {
mock
.onGet(state.vulnerabilitiesHistoryEndpoint, { params })
.replyOnce(200, filteredData)
.onGet(state.vulnerabilitiesHistoryEndpoint)
.replyOnce(200, data);
});
it('should dispatch the request and success actions', done => {
testAction(
actions.fetchVulnerabilitiesHistory,
{},
state,
[],
[
{ type: 'requestVulnerabilitiesHistory' },
{
type: 'receiveVulnerabilitiesHistorySuccess',
payload: { data },
},
],
done,
);
});
it('return the filtered results', done => {
testAction(
actions.fetchVulnerabilitiesHistory,
params,
state,
[],
[
{ type: 'requestVulnerabilitiesHistory' },
{
type: 'receiveVulnerabilitiesHistorySuccess',
payload: { data: filteredData },
},
],
done,
);
});
});
describe('on error', () => {
beforeEach(() => {
mock.onGet(state.vulnerabilitiesHistoryEndpoint).replyOnce(404, {});
});
it('should dispatch the request and error actions', done => {
testAction(
actions.fetchVulnerabilitiesHistory,
{},
state,
[],
[
{ type: 'requestVulnerabilitiesHistory' },
{ type: 'receiveVulnerabilitiesHistoryError' },
],
done,
);
});
});
describe('with an empty endpoint', () => {
beforeEach(() => {
state.vulnerabilitiesHistoryEndpoint = '';
});
it('should not do anything', done => {
testAction(actions.fetchVulnerabilitiesHistory, {}, state, [], [], done);
});
});
});
describe('requestVulnerabilitiesHistory', () => {
it('should commit the request mutation', done => {
testAction(
actions.requestVulnerabilitiesHistory,
{},
state,
[{ type: types.REQUEST_VULNERABILITIES_HISTORY }],
[],
done,
);
});
});
describe('receiveVulnerabilitiesHistorySuccess', () => {
it('should commit the success mutation', done => {
testAction(
actions.receiveVulnerabilitiesHistorySuccess,
{ data },
state,
[{ type: types.RECEIVE_VULNERABILITIES_HISTORY_SUCCESS, payload: data }],
[],
done,
);
});
});
describe('receiveVulnerabilitiesHistoryError', () => {
it('should commit the error mutation', done => {
testAction(
actions.receiveVulnerabilitiesHistoryError,
{},
state,
[{ type: types.RECEIVE_VULNERABILITIES_HISTORY_ERROR }],
[],
done,
);
});
});
describe('openDismissalCommentBox', () => {
it('should commit the open comment mutation with a default payload', done => {
testAction(
actions.openDismissalCommentBox,
undefined,
state,
[{ type: types.OPEN_DISMISSAL_COMMENT_BOX }],
[],
done,
);
});
});
describe('closeDismissalCommentBox', () => {
it('should commit the close comment mutation', done => {
testAction(
actions.closeDismissalCommentBox,
{},
state,
[{ type: types.CLOSE_DISMISSAL_COMMENT_BOX }],
[],
done,
);
});
});
});
export {
default,
} from '../../../../../frontend/security_dashboard/store/modules/vulnerabilities/data/mock_data_vulnerabilities';
{
"critical": 2,
"high": 4,
"low": 7,
"medium": 8,
"unknown": 0
}
\ No newline at end of file
{
"low": {
"2018-10-1": 87,
"2018-10-2": 88,
"2018-10-3": 90,
"2018-10-4": 89,
"2018-10-5": 89,
"2018-10-6": 80,
"2018-10-7": 85,
"2018-10-8": 67,
"2018-10-9": 84,
"2018-10-10": 72,
"2018-10-11": 67,
"2018-10-12": 86,
"2018-10-13": 70,
"2018-10-14": 68,
"2018-10-15": 61,
"2018-10-16": 74,
"2018-10-17": 67,
"2018-10-18": 78,
"2018-10-19": 65,
"2018-10-20": 72,
"2018-10-21": 78,
"2018-10-22": 81,
"2018-10-23": 62,
"2018-10-24": 86,
"2018-10-25": 79,
"2018-10-26": 86,
"2018-10-27": 78,
"2018-10-28": 75,
"2018-10-29": 67,
"2018-10-30": 87,
"2018-10-31": 86,
"2018-11-1": 75,
"2018-11-2": 81,
"2018-11-3": 88,
"2018-11-4": 82,
"2018-11-5": 76,
"2018-11-6": 76,
"2018-11-7": 68,
"2018-11-8": 86,
"2018-11-9": 70,
"2018-11-10": 74,
"2018-11-11": 60,
"2018-11-12": 61,
"2018-11-13": 73,
"2018-11-14": 90,
"2018-11-15": 69,
"2018-11-16": 78,
"2018-11-17": 81,
"2018-11-18": 60,
"2018-11-19": 86,
"2018-11-20": 72,
"2018-11-21": 73,
"2018-11-22": 60,
"2018-11-23": 88,
"2018-11-24": 70,
"2018-11-25": 60,
"2018-11-26": 72,
"2018-11-27": 71,
"2018-11-28": 77,
"2018-11-29": 77,
"2018-11-30": 70,
"2018-12-1": 69,
"2018-12-2": 80,
"2018-12-3": 73,
"2018-12-4": 71,
"2018-12-5": 84,
"2018-12-6": 82,
"2018-12-7": 68,
"2018-12-8": 66,
"2018-12-9": 76,
"2018-12-10": 81,
"2018-12-11": 61,
"2018-12-12": 78,
"2018-12-13": 85,
"2018-12-14": 74,
"2018-12-15": 65,
"2018-12-16": 90,
"2018-12-17": 87,
"2018-12-18": 83,
"2018-12-19": 72,
"2018-12-20": 79,
"2018-12-21": 83,
"2018-12-22": 70,
"2018-12-23": 75,
"2018-12-24": 77,
"2018-12-25": 68,
"2018-12-26": 86,
"2018-12-27": 76,
"2018-12-28": 86,
"2018-12-29": 89,
"2018-12-30": 73,
"2018-12-31": 70
},
"medium": {
"2018-10-1": 73,
"2018-10-2": 76,
"2018-10-3": 101,
"2018-10-4": 84,
"2018-10-5": 90,
"2018-10-6": 97,
"2018-10-7": 77,
"2018-10-8": 81,
"2018-10-9": 98,
"2018-10-10": 83,
"2018-10-11": 82,
"2018-10-12": 70,
"2018-10-13": 99,
"2018-10-14": 83,
"2018-10-15": 81,
"2018-10-16": 80,
"2018-10-17": 82,
"2018-10-18": 89,
"2018-10-19": 89,
"2018-10-20": 71,
"2018-10-21": 73,
"2018-10-22": 74,
"2018-10-23": 83,
"2018-10-24": 91,
"2018-10-25": 85,
"2018-10-26": 90,
"2018-10-27": 77,
"2018-10-28": 102,
"2018-10-29": 75,
"2018-10-30": 78,
"2018-10-31": 70,
"2018-11-1": 90,
"2018-11-2": 96,
"2018-11-3": 98,
"2018-11-4": 88,
"2018-11-5": 79,
"2018-11-6": 91,
"2018-11-7": 101,
"2018-11-8": 75,
"2018-11-9": 75,
"2018-11-10": 84,
"2018-11-11": 70,
"2018-11-12": 89,
"2018-11-13": 104,
"2018-11-14": 90,
"2018-11-15": 81,
"2018-11-16": 102,
"2018-11-17": 86,
"2018-11-18": 80,
"2018-11-19": 71,
"2018-11-20": 72,
"2018-11-21": 103,
"2018-11-22": 89,
"2018-11-23": 83,
"2018-11-24": 79,
"2018-11-25": 87,
"2018-11-26": 79,
"2018-11-27": 104,
"2018-11-28": 70,
"2018-11-29": 103,
"2018-11-30": 86,
"2018-12-1": 86,
"2018-12-2": 77,
"2018-12-3": 96,
"2018-12-4": 95,
"2018-12-5": 74,
"2018-12-6": 99,
"2018-12-7": 101,
"2018-12-8": 78,
"2018-12-9": 83,
"2018-12-10": 76,
"2018-12-11": 77,
"2018-12-12": 105,
"2018-12-13": 81,
"2018-12-14": 82,
"2018-12-15": 90,
"2018-12-16": 88,
"2018-12-17": 78,
"2018-12-18": 82,
"2018-12-19": 83,
"2018-12-20": 105,
"2018-12-21": 70,
"2018-12-22": 85,
"2018-12-23": 91,
"2018-12-24": 89,
"2018-12-25": 83,
"2018-12-26": 73,
"2018-12-27": 91,
"2018-12-28": 77,
"2018-12-29": 101,
"2018-12-30": 83,
"2018-12-31": 94
},
"high": {
"2018-10-1": 43,
"2018-10-2": 42,
"2018-10-3": 42,
"2018-10-4": 49,
"2018-10-5": 44,
"2018-10-6": 59,
"2018-10-7": 49,
"2018-10-8": 53,
"2018-10-9": 44,
"2018-10-10": 51,
"2018-10-11": 43,
"2018-10-12": 53,
"2018-10-13": 52,
"2018-10-14": 43,
"2018-10-15": 60,
"2018-10-16": 53,
"2018-10-17": 57,
"2018-10-18": 42,
"2018-10-19": 46,
"2018-10-20": 43,
"2018-10-21": 43,
"2018-10-22": 41,
"2018-10-23": 47,
"2018-10-24": 44,
"2018-10-25": 43,
"2018-10-26": 60,
"2018-10-27": 43,
"2018-10-28": 59,
"2018-10-29": 55,
"2018-10-30": 45,
"2018-10-31": 51,
"2018-11-1": 55,
"2018-11-2": 50,
"2018-11-3": 43,
"2018-11-4": 41,
"2018-11-5": 51,
"2018-11-6": 49,
"2018-11-7": 49,
"2018-11-8": 60,
"2018-11-9": 60,
"2018-11-10": 43,
"2018-11-11": 57,
"2018-11-12": 42,
"2018-11-13": 59,
"2018-11-14": 41,
"2018-11-15": 53,
"2018-11-16": 53,
"2018-11-17": 43,
"2018-11-18": 53,
"2018-11-19": 48,
"2018-11-20": 56,
"2018-11-21": 51,
"2018-11-22": 42,
"2018-11-23": 60,
"2018-11-24": 50,
"2018-11-25": 49,
"2018-11-26": 47,
"2018-11-27": 46,
"2018-11-28": 40,
"2018-11-29": 41,
"2018-11-30": 57,
"2018-12-1": 57,
"2018-12-2": 45,
"2018-12-3": 52,
"2018-12-4": 46,
"2018-12-5": 56,
"2018-12-6": 48,
"2018-12-7": 58,
"2018-12-8": 59,
"2018-12-9": 47,
"2018-12-10": 58,
"2018-12-11": 50,
"2018-12-12": 45,
"2018-12-13": 59,
"2018-12-14": 40,
"2018-12-15": 40,
"2018-12-16": 48,
"2018-12-17": 44,
"2018-12-18": 54,
"2018-12-19": 44,
"2018-12-20": 57,
"2018-12-21": 54,
"2018-12-22": 44,
"2018-12-23": 59,
"2018-12-24": 41,
"2018-12-25": 52,
"2018-12-26": 52,
"2018-12-27": 50,
"2018-12-28": 49,
"2018-12-29": 45,
"2018-12-30": 44,
"2018-12-31": 60
},
"critical": {
"2018-10-1": 54,
"2018-10-2": 67,
"2018-10-3": 62,
"2018-10-4": 63,
"2018-10-5": 51,
"2018-10-6": 56,
"2018-10-7": 66,
"2018-10-8": 69,
"2018-10-9": 58,
"2018-10-10": 61,
"2018-10-11": 69,
"2018-10-12": 73,
"2018-10-13": 68,
"2018-10-14": 64,
"2018-10-15": 69,
"2018-10-16": 63,
"2018-10-17": 72,
"2018-10-18": 71,
"2018-10-19": 56,
"2018-10-20": 71,
"2018-10-21": 59,
"2018-10-22": 55,
"2018-10-23": 51,
"2018-10-24": 74,
"2018-10-25": 68,
"2018-10-26": 74,
"2018-10-27": 53,
"2018-10-28": 73,
"2018-10-29": 54,
"2018-10-30": 53,
"2018-10-31": 53,
"2018-11-1": 68,
"2018-11-2": 71,
"2018-11-3": 57,
"2018-11-4": 59,
"2018-11-5": 58,
"2018-11-6": 67,
"2018-11-7": 56,
"2018-11-8": 74,
"2018-11-9": 54,
"2018-11-10": 67,
"2018-11-11": 61,
"2018-11-12": 73,
"2018-11-13": 58,
"2018-11-14": 56,
"2018-11-15": 55,
"2018-11-16": 72,
"2018-11-17": 53,
"2018-11-18": 68,
"2018-11-19": 52,
"2018-11-20": 64,
"2018-11-21": 72,
"2018-11-22": 50,
"2018-11-23": 59,
"2018-11-24": 56,
"2018-11-25": 74,
"2018-11-26": 71,
"2018-11-27": 66,
"2018-11-28": 55,
"2018-11-29": 51,
"2018-11-30": 63,
"2018-12-1": 54,
"2018-12-2": 63,
"2018-12-3": 64,
"2018-12-4": 51,
"2018-12-5": 66,
"2018-12-6": 61,
"2018-12-7": 62,
"2018-12-8": 59,
"2018-12-9": 69,
"2018-12-10": 73,
"2018-12-11": 67,
"2018-12-12": 58,
"2018-12-13": 69,
"2018-12-14": 71,
"2018-12-15": 69,
"2018-12-16": 72,
"2018-12-17": 73,
"2018-12-18": 59,
"2018-12-19": 60,
"2018-12-20": 52,
"2018-12-21": 71,
"2018-12-22": 56,
"2018-12-23": 61,
"2018-12-24": 61,
"2018-12-25": 72,
"2018-12-26": 66,
"2018-12-27": 67,
"2018-12-28": 72,
"2018-12-29": 58,
"2018-12-30": 68,
"2018-12-31": 54,
"2019-1-1": 139,
"2019-1-2": 137,
"2019-1-3": 142,
"2019-1-4": 137,
"2019-1-5": 134,
"2019-1-6": 133,
"2019-1-7": 137,
"2019-1-8": 140,
"2019-1-9": 130,
"2019-1-10": 132,
"2019-1-11": 134,
"2019-1-12": 143,
"2019-1-13": 130,
"2019-1-14": 133,
"2019-1-15": 137,
"2019-1-16": 141,
"2019-1-17": 139,
"2019-1-18": 145,
"2019-1-19": 141,
"2019-1-20": 137,
"2019-1-21": 139,
"2019-1-22": 131,
"2019-1-23": 134,
"2019-1-24": 144,
"2019-1-25": 140,
"2019-1-26": 145,
"2019-1-27": 138,
"2019-1-28": 136,
"2019-1-29": 144,
"2019-1-30": 131,
"2019-1-31": 142
},
"unknown": {
"2018-10-1": 39,
"2018-10-2": 44,
"2018-10-3": 35,
"2018-10-4": 34,
"2018-10-5": 38,
"2018-10-6": 34,
"2018-10-7": 34,
"2018-10-8": 43,
"2018-10-9": 41,
"2018-10-10": 45,
"2018-10-11": 41,
"2018-10-12": 37,
"2018-10-13": 34,
"2018-10-14": 41,
"2018-10-15": 45,
"2018-10-16": 33,
"2018-10-17": 40,
"2018-10-18": 31,
"2018-10-19": 42,
"2018-10-20": 33,
"2018-10-21": 44,
"2018-10-22": 33,
"2018-10-23": 35,
"2018-10-24": 37,
"2018-10-25": 43,
"2018-10-26": 33,
"2018-10-27": 43,
"2018-10-28": 39,
"2018-10-29": 37,
"2018-10-30": 36,
"2018-10-31": 37,
"2018-11-1": 42,
"2018-11-2": 41,
"2018-11-3": 36,
"2018-11-4": 31,
"2018-11-5": 41,
"2018-11-6": 37,
"2018-11-7": 42,
"2018-11-8": 42,
"2018-11-9": 45,
"2018-11-10": 34,
"2018-11-11": 30,
"2018-11-12": 40,
"2018-11-13": 39,
"2018-11-14": 44,
"2018-11-15": 36,
"2018-11-16": 35,
"2018-11-17": 30,
"2018-11-18": 31,
"2018-11-19": 34,
"2018-11-20": 31,
"2018-11-21": 36,
"2018-11-22": 37,
"2018-11-23": 41,
"2018-11-24": 38,
"2018-11-25": 42,
"2018-11-26": 41,
"2018-11-27": 36,
"2018-11-28": 32,
"2018-11-29": 43,
"2018-11-30": 36,
"2018-12-1": 44,
"2018-12-2": 34,
"2018-12-3": 42,
"2018-12-4": 32,
"2018-12-5": 44,
"2018-12-6": 31,
"2018-12-7": 39,
"2018-12-8": 37,
"2018-12-9": 33,
"2018-12-10": 37,
"2018-12-11": 38,
"2018-12-12": 35,
"2018-12-13": 34,
"2018-12-14": 40,
"2018-12-15": 35,
"2018-12-16": 42,
"2018-12-17": 44,
"2018-12-18": 40,
"2018-12-19": 40,
"2018-12-20": 30,
"2018-12-21": 44,
"2018-12-22": 32,
"2018-12-23": 39,
"2018-12-24": 37,
"2018-12-25": 35,
"2018-12-26": 39,
"2018-12-27": 38,
"2018-12-28": 44,
"2018-12-29": 42,
"2018-12-30": 37,
"2018-12-31": 35
},
"all": {
"2018-10-1": 143,
"2018-10-2": 130,
"2018-10-3": 139,
"2018-10-4": 134,
"2018-10-5": 138,
"2018-10-6": 131,
"2018-10-7": 137,
"2018-10-8": 144,
"2018-10-9": 140,
"2018-10-10": 134,
"2018-10-11": 142,
"2018-10-12": 132,
"2018-10-13": 136,
"2018-10-14": 141,
"2018-10-15": 134,
"2018-10-16": 139,
"2018-10-17": 141,
"2018-10-18": 134,
"2018-10-19": 131,
"2018-10-20": 141,
"2018-10-21": 139,
"2018-10-22": 145,
"2018-10-23": 142,
"2018-10-24": 143,
"2018-10-25": 143,
"2018-10-26": 135,
"2018-10-27": 136,
"2018-10-28": 143,
"2018-10-29": 142,
"2018-10-30": 131,
"2018-10-31": 141,
"2018-11-1": 134,
"2018-11-2": 134,
"2018-11-3": 130,
"2018-11-4": 137,
"2018-11-5": 145,
"2018-11-6": 137,
"2018-11-7": 135,
"2018-11-8": 145,
"2018-11-9": 132,
"2018-11-10": 134,
"2018-11-11": 139,
"2018-11-12": 139,
"2018-11-13": 130,
"2018-11-14": 137,
"2018-11-15": 136,
"2018-11-16": 145,
"2018-11-17": 130,
"2018-11-18": 143,
"2018-11-19": 134,
"2018-11-20": 145,
"2018-11-21": 137,
"2018-11-22": 140,
"2018-11-23": 138,
"2018-11-24": 132,
"2018-11-25": 143,
"2018-11-26": 131,
"2018-11-27": 130,
"2018-11-28": 144,
"2018-11-29": 139,
"2018-11-30": 143,
"2018-12-1": 139,
"2018-12-2": 137,
"2018-12-3": 142,
"2018-12-4": 137,
"2018-12-5": 134,
"2018-12-6": 133,
"2018-12-7": 137,
"2018-12-8": 140,
"2018-12-9": 130,
"2018-12-10": 132,
"2018-12-11": 134,
"2018-12-12": 143,
"2018-12-13": 130,
"2018-12-14": 133,
"2018-12-15": 137,
"2018-12-16": 141,
"2018-12-17": 139,
"2018-12-18": 145,
"2018-12-19": 141,
"2018-12-20": 137,
"2018-12-21": 139,
"2018-12-22": 131,
"2018-12-23": 134,
"2018-12-24": 144,
"2018-12-25": 140,
"2018-12-26": 145,
"2018-12-27": 138,
"2018-12-28": 136,
"2018-12-29": 144,
"2018-12-30": 131,
"2018-12-31": 142,
"2019-1-1": 139,
"2019-1-2": 137,
"2019-1-3": 142,
"2019-1-4": 137,
"2019-1-5": 134,
"2019-1-6": 133,
"2019-1-7": 137,
"2019-1-8": 140,
"2019-1-9": 130,
"2019-1-10": 132,
"2019-1-11": 134,
"2019-1-12": 143,
"2019-1-13": 130,
"2019-1-14": 133,
"2019-1-15": 137,
"2019-1-16": 141,
"2019-1-17": 139,
"2019-1-18": 145,
"2019-1-19": 141,
"2019-1-20": 137,
"2019-1-21": 139,
"2019-1-22": 131,
"2019-1-23": 134,
"2019-1-24": 144,
"2019-1-25": 140,
"2019-1-26": 145,
"2019-1-27": 138,
"2019-1-28": 136,
"2019-1-29": 144,
"2019-1-30": 131,
"2019-1-31": 142
}
}
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