Commit ae4bed39 authored by Fatih Acet's avatar Fatih Acet

Merge branch '6079-dismissed-items-in-reports' into 'master'

Consider dismissed items in security reports summary

Closes #6079

See merge request gitlab-org/gitlab-ee!9275
parents c37bc72f be4969af
...@@ -273,7 +273,6 @@ export default { ...@@ -273,7 +273,6 @@ export default {
v-if="dependencyScanning.newIssues.length || dependencyScanning.resolvedIssues.length" v-if="dependencyScanning.newIssues.length || dependencyScanning.resolvedIssues.length"
:unresolved-issues="dependencyScanning.newIssues" :unresolved-issues="dependencyScanning.newIssues"
:resolved-issues="dependencyScanning.resolvedIssues" :resolved-issues="dependencyScanning.resolvedIssues"
:all-issues="dependencyScanning.allIssues"
:component="$options.componentNames.SastIssueBody" :component="$options.componentNames.SastIssueBody"
class="js-dss-issue-list report-block-group-list" class="js-dss-issue-list report-block-group-list"
/> />
......
import { s__, sprintf } from '~/locale'; import { s__, sprintf } from '~/locale';
import { groupedTextBuilder, statusIcon } from './utils'; import { countIssues, groupedTextBuilder, statusIcon } from './utils';
import { LOADING, ERROR, SUCCESS } from './constants'; import { LOADING, ERROR, SUCCESS } from './constants';
import messages from './messages'; import messages from './messages';
const groupedReportText = (report, name, errorMessage, loadingMessage) => { const groupedReportText = (report, reportType, errorMessage, loadingMessage) => {
const { paths } = report;
if (report.hasError) { if (report.hasError) {
return errorMessage; return errorMessage;
} }
...@@ -12,13 +14,11 @@ const groupedReportText = (report, name, errorMessage, loadingMessage) => { ...@@ -12,13 +14,11 @@ const groupedReportText = (report, name, errorMessage, loadingMessage) => {
return loadingMessage; return loadingMessage;
} }
return groupedTextBuilder( return groupedTextBuilder({
name, ...countIssues(report),
report.paths, reportType,
(report.newIssues || []).length, paths,
(report.resolvedIssues || []).length, });
(report.allIssues || []).length,
);
}; };
export const groupedSastText = ({ sast }) => export const groupedSastText = ({ sast }) =>
...@@ -43,6 +43,19 @@ export const groupedDependencyText = ({ dependencyScanning }) => ...@@ -43,6 +43,19 @@ export const groupedDependencyText = ({ dependencyScanning }) =>
messages.DEPENDENCY_SCANNING_IS_LOADING, messages.DEPENDENCY_SCANNING_IS_LOADING,
); );
export const summaryCounts = state =>
[state.sast, state.sastContainer, state.dast, state.dependencyScanning].reduce(
(acc, report) => {
const curr = countIssues(report);
acc.added += curr.added;
acc.dismissed += curr.dismissed;
acc.fixed += curr.fixed;
acc.existing += curr.existing;
return acc;
},
{ added: 0, dismissed: 0, fixed: 0, existing: 0 },
);
export const groupedSummaryText = (state, getters) => { export const groupedSummaryText = (state, getters) => {
const reportType = s__('ciReport|Security scanning'); const reportType = s__('ciReport|Security scanning');
...@@ -56,7 +69,7 @@ export const groupedSummaryText = (state, getters) => { ...@@ -56,7 +69,7 @@ export const groupedSummaryText = (state, getters) => {
return s__('ciReport|Security scanning failed loading any results'); return s__('ciReport|Security scanning failed loading any results');
} }
const { added, fixed, existing } = state.summaryCounts; const { added, fixed, existing, dismissed } = getters.summaryCounts;
let status = ''; let status = '';
...@@ -74,7 +87,7 @@ export const groupedSummaryText = (state, getters) => { ...@@ -74,7 +87,7 @@ export const groupedSummaryText = (state, getters) => {
*/ */
const paths = { head: true, base: !getters.noBaseInAllReports }; const paths = { head: true, base: !getters.noBaseInAllReports };
return groupedTextBuilder(reportType, paths, added, fixed, existing, status); return groupedTextBuilder({ reportType, paths, added, fixed, existing, dismissed, status });
}; };
export const summaryStatus = (state, getters) => { export const summaryStatus = (state, getters) => {
......
...@@ -81,17 +81,11 @@ export default { ...@@ -81,17 +81,11 @@ export default {
Vue.set(state.sast, 'resolvedIssues', resolvedIssues); Vue.set(state.sast, 'resolvedIssues', resolvedIssues);
Vue.set(state.sast, 'allIssues', allIssues); Vue.set(state.sast, 'allIssues', allIssues);
Vue.set(state.sast, 'isLoading', false); Vue.set(state.sast, 'isLoading', false);
state.summaryCounts.added += newIssues.length;
state.summaryCounts.fixed += resolvedIssues.length;
state.summaryCounts.existing += allIssues.length;
} else if (reports.head && !reports.base) { } else if (reports.head && !reports.base) {
const newIssues = parseSastIssues(reports.head, reports.enrichData, state.blobPath.head); const newIssues = parseSastIssues(reports.head, reports.enrichData, state.blobPath.head);
Vue.set(state.sast, 'newIssues', newIssues); Vue.set(state.sast, 'newIssues', newIssues);
Vue.set(state.sast, 'isLoading', false); Vue.set(state.sast, 'isLoading', false);
state.summaryCounts.added += newIssues.length;
} }
}, },
...@@ -134,9 +128,6 @@ export default { ...@@ -134,9 +128,6 @@ export default {
Vue.set(state.sastContainer, 'newIssues', newIssues); Vue.set(state.sastContainer, 'newIssues', newIssues);
Vue.set(state.sastContainer, 'resolvedIssues', resolvedIssues); Vue.set(state.sastContainer, 'resolvedIssues', resolvedIssues);
Vue.set(state.sastContainer, 'isLoading', false); Vue.set(state.sastContainer, 'isLoading', false);
state.summaryCounts.added += newIssues.length;
state.summaryCounts.fixed += resolvedIssues.length;
} else if (reports.head && !reports.base) { } else if (reports.head && !reports.base) {
const newIssues = getUnapprovedVulnerabilities( const newIssues = getUnapprovedVulnerabilities(
parseSastContainer(reports.head.vulnerabilities, reports.enrichData), parseSastContainer(reports.head.vulnerabilities, reports.enrichData),
...@@ -145,8 +136,6 @@ export default { ...@@ -145,8 +136,6 @@ export default {
Vue.set(state.sastContainer, 'newIssues', newIssues); Vue.set(state.sastContainer, 'newIssues', newIssues);
Vue.set(state.sastContainer, 'isLoading', false); Vue.set(state.sastContainer, 'isLoading', false);
state.summaryCounts.added += newIssues.length;
} }
}, },
...@@ -180,16 +169,11 @@ export default { ...@@ -180,16 +169,11 @@ export default {
Vue.set(state.dast, 'newIssues', newIssues); Vue.set(state.dast, 'newIssues', newIssues);
Vue.set(state.dast, 'resolvedIssues', resolvedIssues); Vue.set(state.dast, 'resolvedIssues', resolvedIssues);
Vue.set(state.dast, 'isLoading', false); Vue.set(state.dast, 'isLoading', false);
state.summaryCounts.added += newIssues.length;
state.summaryCounts.fixed += resolvedIssues.length;
} else if (reports.head && reports.head.site && !reports.base) { } else if (reports.head && reports.head.site && !reports.base) {
const newIssues = parseDastIssues(reports.head.site.alerts, reports.enrichData); const newIssues = parseDastIssues(reports.head.site.alerts, reports.enrichData);
Vue.set(state.dast, 'newIssues', newIssues); Vue.set(state.dast, 'newIssues', newIssues);
Vue.set(state.dast, 'isLoading', false); Vue.set(state.dast, 'isLoading', false);
state.summaryCounts.added += newIssues.length;
} }
}, },
...@@ -249,10 +233,6 @@ export default { ...@@ -249,10 +233,6 @@ export default {
Vue.set(state.dependencyScanning, 'resolvedIssues', resolvedIssues); Vue.set(state.dependencyScanning, 'resolvedIssues', resolvedIssues);
Vue.set(state.dependencyScanning, 'allIssues', allIssues); Vue.set(state.dependencyScanning, 'allIssues', allIssues);
Vue.set(state.dependencyScanning, 'isLoading', false); Vue.set(state.dependencyScanning, 'isLoading', false);
state.summaryCounts.added += newIssues.length;
state.summaryCounts.fixed += resolvedIssues.length;
state.summaryCounts.existing += allIssues.length;
} }
if (reports.head && !reports.base) { if (reports.head && !reports.base) {
...@@ -263,8 +243,6 @@ export default { ...@@ -263,8 +243,6 @@ export default {
); );
Vue.set(state.dependencyScanning, 'newIssues', newIssues); Vue.set(state.dependencyScanning, 'newIssues', newIssues);
Vue.set(state.dependencyScanning, 'isLoading', false); Vue.set(state.dependencyScanning, 'isLoading', false);
state.summaryCounts.added += newIssues.length;
} }
}, },
......
import { s__ } from '~/locale'; import { s__ } from '~/locale';
export default () => ({ export default () => ({
summaryCounts: {
added: 0,
fixed: 0,
existing: 0,
},
blobPath: { blobPath: {
head: null, head: null,
base: null, base: null,
......
...@@ -311,46 +311,86 @@ export const filterByKey = (firstArray = [], secondArray = [], key = '') => ...@@ -311,46 +311,86 @@ export const filterByKey = (firstArray = [], secondArray = [], key = '') =>
export const getUnapprovedVulnerabilities = (issues = [], unapproved = []) => export const getUnapprovedVulnerabilities = (issues = [], unapproved = []) =>
issues.filter(item => unapproved.find(el => el === item.vulnerability)); issues.filter(item => unapproved.find(el => el === item.vulnerability));
export const groupedTextBuilder = ( export const groupedTextBuilder = ({
reportType = '', reportType = '',
paths = {}, paths = {},
newIssues = 0, added = 0,
resolvedIssues = 0, fixed = 0,
allIssues = 0, existing = 0,
dismissed = 0,
status = '', status = '',
) => { }) => {
let baseString = ''; let baseString = '';
if (!paths.base) { if (!paths.base) {
if (newIssues > 0) { if (added && !dismissed) {
// added
baseString = n__( baseString = n__(
'ciReport|%{reportType} %{status} detected %{newCount} vulnerability for the source branch only', 'ciReport|%{reportType} %{status} detected %{newCount} vulnerability for the source branch only',
'ciReport|%{reportType} %{status} detected %{newCount} vulnerabilities for the source branch only', 'ciReport|%{reportType} %{status} detected %{newCount} vulnerabilities for the source branch only',
newIssues, added,
);
} else if (!added && dismissed) {
// dismissed
baseString = n__(
'ciReport|%{reportType} %{status} detected %{dismissedCount} dismissed vulnerability for the source branch only',
'ciReport|%{reportType} %{status} detected %{dismissedCount} dismissed vulnerabilities for the source branch only',
dismissed,
);
} else if (added && dismissed) {
// added & dismissed
baseString = s__(
'ciReport|%{reportType} %{status} detected %{newCount} new, and %{dismissedCount} dismissed vulnerabilities for the source branch only',
); );
} else { } else {
// no vulnerabilities
baseString = s__( baseString = s__(
'ciReport|%{reportType} %{status} detected no vulnerabilities for the source branch only', 'ciReport|%{reportType} %{status} detected no vulnerabilities for the source branch only',
); );
} }
} else if (paths.base && paths.head) { } else if (paths.head) {
if (newIssues > 0 && resolvedIssues > 0) { if (added && !fixed && !dismissed) {
baseString = s__( // added
'ciReport|%{reportType} %{status} detected %{newCount} new, and %{fixedCount} fixed vulnerabilities',
);
} else if (newIssues > 0 && resolvedIssues === 0) {
baseString = n__( baseString = n__(
'ciReport|%{reportType} %{status} detected %{newCount} new vulnerability', 'ciReport|%{reportType} %{status} detected %{newCount} new vulnerability',
'ciReport|%{reportType} %{status} detected %{newCount} new vulnerabilities', 'ciReport|%{reportType} %{status} detected %{newCount} new vulnerabilities',
newIssues, added,
); );
} else if (newIssues === 0 && resolvedIssues > 0) { } else if (!added && fixed && !dismissed) {
// fixed
baseString = n__( baseString = n__(
'ciReport|%{reportType} %{status} detected %{fixedCount} fixed vulnerability', 'ciReport|%{reportType} %{status} detected %{fixedCount} fixed vulnerability',
'ciReport|%{reportType} %{status} detected %{fixedCount} fixed vulnerabilities', 'ciReport|%{reportType} %{status} detected %{fixedCount} fixed vulnerabilities',
resolvedIssues, fixed,
);
} else if (!added && !fixed && dismissed) {
// dismissed
baseString = n__(
'ciReport|%{reportType} %{status} detected %{dismissedCount} dismissed vulnerability',
'ciReport|%{reportType} %{status} detected %{dismissedCount} dismissed vulnerabilities',
dismissed,
);
} else if (added && fixed && !dismissed) {
// added & fixed
baseString = s__(
'ciReport|%{reportType} %{status} detected %{newCount} new, and %{fixedCount} fixed vulnerabilities',
); );
} else if (allIssues > 0) { } else if (added && !fixed && dismissed) {
// added & dismissed
baseString = s__(
'ciReport|%{reportType} %{status} detected %{newCount} new, and %{dismissedCount} dismissed vulnerabilities',
);
} else if (!added && fixed && dismissed) {
// fixed & dismissed
baseString = s__(
'ciReport|%{reportType} %{status} detected %{fixedCount} fixed, and %{dismissedCount} dismissed vulnerabilities',
);
} else if (added && fixed && dismissed) {
// added & fixed & dismissed
baseString = s__(
'ciReport|%{reportType} %{status} detected %{newCount} new, %{fixedCount} fixed, and %{dismissedCount} dismissed vulnerabilities',
);
} else if (existing) {
baseString = s__('ciReport|%{reportType} %{status} detected no new vulnerabilities'); baseString = s__('ciReport|%{reportType} %{status} detected no new vulnerabilities');
} else { } else {
baseString = s__('ciReport|%{reportType} %{status} detected no vulnerabilities'); baseString = s__('ciReport|%{reportType} %{status} detected no vulnerabilities');
...@@ -364,8 +404,9 @@ export const groupedTextBuilder = ( ...@@ -364,8 +404,9 @@ export const groupedTextBuilder = (
return sprintf(baseString, { return sprintf(baseString, {
status, status,
reportType, reportType,
newCount: newIssues, newCount: added,
fixedCount: resolvedIssues, fixedCount: fixed,
dismissedCount: dismissed,
}); });
}; };
...@@ -380,3 +421,23 @@ export const statusIcon = (loading = false, failed = false, newIssues = 0, neutr ...@@ -380,3 +421,23 @@ export const statusIcon = (loading = false, failed = false, newIssues = 0, neutr
return 'success'; return 'success';
}; };
/**
* Counts issues. Simply returns the amount of existing and fixed Issues.
* New Issues are divided into dismissed and added.
*
* @param newIssues
* @param resolvedIssues
* @param allIssues
* @returns {{existing: number, added: number, dismissed: number, fixed: number}}
*/
export const countIssues = ({ newIssues = [], resolvedIssues = [], allIssues = [] } = {}) => {
const dismissed = newIssues.reduce((sum, issue) => (issue.isDismissed ? sum + 1 : sum), 0);
return {
added: newIssues.length - dismissed,
dismissed,
existing: allIssues.length,
fixed: resolvedIssues.length,
};
};
---
title: Consider dismissed items in security reports summary
merge_request: 9275
author:
type: changed
...@@ -13,8 +13,12 @@ import { ...@@ -13,8 +13,12 @@ import {
dastStatusIcon, dastStatusIcon,
dependencyScanningStatusIcon, dependencyScanningStatusIcon,
anyReportHasError, anyReportHasError,
summaryCounts,
} from 'ee/vue_shared/security_reports/store/getters'; } from 'ee/vue_shared/security_reports/store/getters';
const BASE_PATH = 'fake/base/path.json';
const HEAD_PATH = 'fake/head/path.json';
describe('Security reports getters', () => { describe('Security reports getters', () => {
function removeBreakLine(data) { function removeBreakLine(data) {
return data.replace(/\r?\n|\r/g, '').replace(/\s\s+/g, ' '); return data.replace(/\r?\n|\r/g, '').replace(/\s\s+/g, ' ');
...@@ -24,8 +28,8 @@ describe('Security reports getters', () => { ...@@ -24,8 +28,8 @@ describe('Security reports getters', () => {
describe('with no issues', () => { describe('with no issues', () => {
it('returns no issues text', () => { it('returns no issues text', () => {
const newState = state(); const newState = state();
newState.sast.paths.head = 'foo'; newState.sast.paths.head = HEAD_PATH;
newState.sast.paths.base = 'bar'; newState.sast.paths.base = BASE_PATH;
expect(groupedSastText(newState)).toEqual('SAST detected no vulnerabilities'); expect(groupedSastText(newState)).toEqual('SAST detected no vulnerabilities');
}); });
...@@ -34,8 +38,8 @@ describe('Security reports getters', () => { ...@@ -34,8 +38,8 @@ describe('Security reports getters', () => {
describe('with only `all` issues', () => { describe('with only `all` issues', () => {
it('returns no new issues text', () => { it('returns no new issues text', () => {
const newState = state(); const newState = state();
newState.sast.paths.head = 'foo'; newState.sast.paths.head = HEAD_PATH;
newState.sast.paths.base = 'bar'; newState.sast.paths.base = BASE_PATH;
newState.sast.allIssues = [{}]; newState.sast.allIssues = [{}];
expect(groupedSastText(newState)).toEqual('SAST detected no new vulnerabilities'); expect(groupedSastText(newState)).toEqual('SAST detected no new vulnerabilities');
...@@ -45,7 +49,7 @@ describe('Security reports getters', () => { ...@@ -45,7 +49,7 @@ describe('Security reports getters', () => {
describe('with new issues and without base', () => { describe('with new issues and without base', () => {
it('returns unable to compare text', () => { it('returns unable to compare text', () => {
const newState = state(); const newState = state();
newState.sast.paths.head = 'foo'; newState.sast.paths.head = HEAD_PATH;
newState.sast.newIssues = [{}]; newState.sast.newIssues = [{}];
expect(groupedSastText(newState)).toEqual( expect(groupedSastText(newState)).toEqual(
...@@ -58,19 +62,30 @@ describe('Security reports getters', () => { ...@@ -58,19 +62,30 @@ describe('Security reports getters', () => {
describe('with only new issues', () => { describe('with only new issues', () => {
it('returns new issues text', () => { it('returns new issues text', () => {
const newState = state(); const newState = state();
newState.sast.paths.head = 'foo'; newState.sast.paths.head = HEAD_PATH;
newState.sast.paths.base = 'bar'; newState.sast.paths.base = BASE_PATH;
newState.sast.newIssues = [{}]; newState.sast.newIssues = [{}];
expect(groupedSastText(newState)).toEqual('SAST detected 1 new vulnerability'); expect(groupedSastText(newState)).toEqual('SAST detected 1 new vulnerability');
}); });
}); });
describe('with only dismissed issues', () => {
it('returns dismissed issues text', () => {
const newState = state();
newState.sast.paths.head = HEAD_PATH;
newState.sast.paths.base = BASE_PATH;
newState.sast.newIssues = [{ isDismissed: true }];
expect(groupedSastText(newState)).toEqual('SAST detected 1 dismissed vulnerability');
});
});
describe('with new and resolved issues', () => { describe('with new and resolved issues', () => {
it('returns new and fixed issues text', () => { it('returns new and fixed issues text', () => {
const newState = state(); const newState = state();
newState.sast.paths.head = 'foo'; newState.sast.paths.head = HEAD_PATH;
newState.sast.paths.base = 'bar'; newState.sast.paths.base = BASE_PATH;
newState.sast.newIssues = [{}]; newState.sast.newIssues = [{}];
newState.sast.resolvedIssues = [{}]; newState.sast.resolvedIssues = [{}];
...@@ -83,8 +98,8 @@ describe('Security reports getters', () => { ...@@ -83,8 +98,8 @@ describe('Security reports getters', () => {
describe('with only resolved issues', () => { describe('with only resolved issues', () => {
it('returns fixed issues text', () => { it('returns fixed issues text', () => {
const newState = state(); const newState = state();
newState.sast.paths.head = 'foo'; newState.sast.paths.head = HEAD_PATH;
newState.sast.paths.base = 'bar'; newState.sast.paths.base = BASE_PATH;
newState.sast.resolvedIssues = [{}]; newState.sast.resolvedIssues = [{}];
expect(groupedSastText(newState)).toEqual('SAST detected 1 fixed vulnerability'); expect(groupedSastText(newState)).toEqual('SAST detected 1 fixed vulnerability');
...@@ -115,8 +130,8 @@ describe('Security reports getters', () => { ...@@ -115,8 +130,8 @@ describe('Security reports getters', () => {
describe('with no issues', () => { describe('with no issues', () => {
it('returns no issues text', () => { it('returns no issues text', () => {
const newState = state(); const newState = state();
newState.sastContainer.paths.head = 'foo'; newState.sastContainer.paths.head = HEAD_PATH;
newState.sastContainer.paths.base = 'foo'; newState.sastContainer.paths.base = BASE_PATH;
expect(groupedSastContainerText(newState)).toEqual( expect(groupedSastContainerText(newState)).toEqual(
'Container scanning detected no vulnerabilities', 'Container scanning detected no vulnerabilities',
...@@ -127,7 +142,7 @@ describe('Security reports getters', () => { ...@@ -127,7 +142,7 @@ describe('Security reports getters', () => {
describe('with new issues and without base', () => { describe('with new issues and without base', () => {
it('returns unable to compare text', () => { it('returns unable to compare text', () => {
const newState = state(); const newState = state();
newState.sastContainer.paths.head = 'foo'; newState.sastContainer.paths.head = HEAD_PATH;
newState.sastContainer.newIssues = [{}]; newState.sastContainer.newIssues = [{}];
expect(groupedSastContainerText(newState)).toEqual( expect(groupedSastContainerText(newState)).toEqual(
...@@ -140,8 +155,8 @@ describe('Security reports getters', () => { ...@@ -140,8 +155,8 @@ describe('Security reports getters', () => {
describe('with only new issues', () => { describe('with only new issues', () => {
it('returns new issues text', () => { it('returns new issues text', () => {
const newState = state(); const newState = state();
newState.sastContainer.paths.head = 'foo'; newState.sastContainer.paths.head = HEAD_PATH;
newState.sastContainer.paths.base = 'foo'; newState.sastContainer.paths.base = BASE_PATH;
newState.sastContainer.newIssues = [{}]; newState.sastContainer.newIssues = [{}];
expect(groupedSastContainerText(newState)).toEqual( expect(groupedSastContainerText(newState)).toEqual(
...@@ -150,11 +165,24 @@ describe('Security reports getters', () => { ...@@ -150,11 +165,24 @@ describe('Security reports getters', () => {
}); });
}); });
describe('with only dismissed issues', () => {
it('returns dismissed issues text', () => {
const newState = state();
newState.sastContainer.paths.head = HEAD_PATH;
newState.sastContainer.paths.base = BASE_PATH;
newState.sastContainer.newIssues = [{ isDismissed: true }];
expect(groupedSastContainerText(newState)).toEqual(
'Container scanning detected 1 dismissed vulnerability',
);
});
});
describe('with new and resolved issues', () => { describe('with new and resolved issues', () => {
it('returns new and fixed issues text', () => { it('returns new and fixed issues text', () => {
const newState = state(); const newState = state();
newState.sastContainer.paths.head = 'foo'; newState.sastContainer.paths.head = HEAD_PATH;
newState.sastContainer.paths.base = 'foo'; newState.sastContainer.paths.base = BASE_PATH;
newState.sastContainer.newIssues = [{}]; newState.sastContainer.newIssues = [{}];
newState.sastContainer.resolvedIssues = [{}]; newState.sastContainer.resolvedIssues = [{}];
...@@ -167,8 +195,8 @@ describe('Security reports getters', () => { ...@@ -167,8 +195,8 @@ describe('Security reports getters', () => {
describe('with only resolved issues', () => { describe('with only resolved issues', () => {
it('returns fixed issues text', () => { it('returns fixed issues text', () => {
const newState = state(); const newState = state();
newState.sastContainer.paths.head = 'foo'; newState.sastContainer.paths.head = HEAD_PATH;
newState.sastContainer.paths.base = 'foo'; newState.sastContainer.paths.base = BASE_PATH;
newState.sastContainer.resolvedIssues = [{}]; newState.sastContainer.resolvedIssues = [{}];
expect(groupedSastContainerText(newState)).toEqual( expect(groupedSastContainerText(newState)).toEqual(
...@@ -183,8 +211,8 @@ describe('Security reports getters', () => { ...@@ -183,8 +211,8 @@ describe('Security reports getters', () => {
describe('with no issues', () => { describe('with no issues', () => {
it('returns no issues text', () => { it('returns no issues text', () => {
const newState = state(); const newState = state();
newState.dast.paths.head = 'foo'; newState.dast.paths.head = HEAD_PATH;
newState.dast.paths.base = 'foo'; newState.dast.paths.base = BASE_PATH;
expect(groupedDastText(newState)).toEqual('DAST detected no vulnerabilities'); expect(groupedDastText(newState)).toEqual('DAST detected no vulnerabilities');
}); });
...@@ -193,7 +221,7 @@ describe('Security reports getters', () => { ...@@ -193,7 +221,7 @@ describe('Security reports getters', () => {
describe('with new issues and without base', () => { describe('with new issues and without base', () => {
it('returns unable to compare text', () => { it('returns unable to compare text', () => {
const newState = state(); const newState = state();
newState.dast.paths.head = 'foo'; newState.dast.paths.head = HEAD_PATH;
newState.dast.newIssues = [{}]; newState.dast.newIssues = [{}];
expect(groupedDastText(newState)).toEqual( expect(groupedDastText(newState)).toEqual(
...@@ -206,19 +234,30 @@ describe('Security reports getters', () => { ...@@ -206,19 +234,30 @@ describe('Security reports getters', () => {
describe('with only new issues', () => { describe('with only new issues', () => {
it('returns new issues text', () => { it('returns new issues text', () => {
const newState = state(); const newState = state();
newState.dast.paths.head = 'foo'; newState.dast.paths.head = HEAD_PATH;
newState.dast.paths.base = 'foo'; newState.dast.paths.base = BASE_PATH;
newState.dast.newIssues = [{}]; newState.dast.newIssues = [{}];
expect(groupedDastText(newState)).toEqual('DAST detected 1 new vulnerability'); expect(groupedDastText(newState)).toEqual('DAST detected 1 new vulnerability');
}); });
}); });
describe('with only dismissed issues', () => {
it('returns dismissed issues text', () => {
const newState = state();
newState.dast.paths.head = HEAD_PATH;
newState.dast.paths.base = BASE_PATH;
newState.dast.newIssues = [{ isDismissed: true }];
expect(groupedDastText(newState)).toEqual('DAST detected 1 dismissed vulnerability');
});
});
describe('with new and resolved issues', () => { describe('with new and resolved issues', () => {
it('returns new and fixed issues text', () => { it('returns new and fixed issues text', () => {
const newState = state(); const newState = state();
newState.dast.paths.head = 'foo'; newState.dast.paths.head = HEAD_PATH;
newState.dast.paths.base = 'foo'; newState.dast.paths.base = BASE_PATH;
newState.dast.newIssues = [{}]; newState.dast.newIssues = [{}];
newState.dast.resolvedIssues = [{}]; newState.dast.resolvedIssues = [{}];
...@@ -231,8 +270,8 @@ describe('Security reports getters', () => { ...@@ -231,8 +270,8 @@ describe('Security reports getters', () => {
describe('with only resolved issues', () => { describe('with only resolved issues', () => {
it('returns fixed issues text', () => { it('returns fixed issues text', () => {
const newState = state(); const newState = state();
newState.dast.paths.head = 'foo'; newState.dast.paths.head = HEAD_PATH;
newState.dast.paths.base = 'foo'; newState.dast.paths.base = BASE_PATH;
newState.dast.resolvedIssues = [{}]; newState.dast.resolvedIssues = [{}];
expect(groupedDastText(newState)).toEqual('DAST detected 1 fixed vulnerability'); expect(groupedDastText(newState)).toEqual('DAST detected 1 fixed vulnerability');
...@@ -245,8 +284,8 @@ describe('Security reports getters', () => { ...@@ -245,8 +284,8 @@ describe('Security reports getters', () => {
describe('with no issues', () => { describe('with no issues', () => {
it('returns no issues text', () => { it('returns no issues text', () => {
const newState = state(); const newState = state();
newState.dependencyScanning.paths.head = 'foo'; newState.dependencyScanning.paths.head = HEAD_PATH;
newState.dependencyScanning.paths.base = 'foo'; newState.dependencyScanning.paths.base = BASE_PATH;
expect(groupedDependencyText(newState)).toEqual( expect(groupedDependencyText(newState)).toEqual(
'Dependency scanning detected no vulnerabilities', 'Dependency scanning detected no vulnerabilities',
...@@ -257,7 +296,7 @@ describe('Security reports getters', () => { ...@@ -257,7 +296,7 @@ describe('Security reports getters', () => {
describe('with new issues and without base', () => { describe('with new issues and without base', () => {
it('returns unable to compare text', () => { it('returns unable to compare text', () => {
const newState = state(); const newState = state();
newState.dependencyScanning.paths.head = 'foo'; newState.dependencyScanning.paths.head = HEAD_PATH;
newState.dependencyScanning.newIssues = [{}]; newState.dependencyScanning.newIssues = [{}];
expect(groupedDependencyText(newState)).toEqual( expect(groupedDependencyText(newState)).toEqual(
...@@ -270,8 +309,8 @@ describe('Security reports getters', () => { ...@@ -270,8 +309,8 @@ describe('Security reports getters', () => {
describe('with only new issues', () => { describe('with only new issues', () => {
it('returns new issues text', () => { it('returns new issues text', () => {
const newState = state(); const newState = state();
newState.dependencyScanning.paths.head = 'foo'; newState.dependencyScanning.paths.head = HEAD_PATH;
newState.dependencyScanning.paths.base = 'foo'; newState.dependencyScanning.paths.base = BASE_PATH;
newState.dependencyScanning.newIssues = [{}]; newState.dependencyScanning.newIssues = [{}];
expect(groupedDependencyText(newState)).toEqual( expect(groupedDependencyText(newState)).toEqual(
...@@ -280,11 +319,24 @@ describe('Security reports getters', () => { ...@@ -280,11 +319,24 @@ describe('Security reports getters', () => {
}); });
}); });
describe('with only dismissed issues', () => {
it('returns dismissed issues text', () => {
const newState = state();
newState.dependencyScanning.paths.head = HEAD_PATH;
newState.dependencyScanning.paths.base = BASE_PATH;
newState.dependencyScanning.newIssues = [{ isDismissed: true }];
expect(groupedDependencyText(newState)).toEqual(
'Dependency scanning detected 1 dismissed vulnerability',
);
});
});
describe('with new and resolved issues', () => { describe('with new and resolved issues', () => {
it('returns new and fixed issues text', () => { it('returns new and fixed issues text', () => {
const newState = state(); const newState = state();
newState.dependencyScanning.paths.head = 'foo'; newState.dependencyScanning.paths.head = HEAD_PATH;
newState.dependencyScanning.paths.base = 'foo'; newState.dependencyScanning.paths.base = BASE_PATH;
newState.dependencyScanning.newIssues = [{}]; newState.dependencyScanning.newIssues = [{}];
newState.dependencyScanning.resolvedIssues = [{}]; newState.dependencyScanning.resolvedIssues = [{}];
...@@ -297,8 +349,8 @@ describe('Security reports getters', () => { ...@@ -297,8 +349,8 @@ describe('Security reports getters', () => {
describe('with only resolved issues', () => { describe('with only resolved issues', () => {
it('returns fixed issues text', () => { it('returns fixed issues text', () => {
const newState = state(); const newState = state();
newState.dependencyScanning.paths.head = 'foo'; newState.dependencyScanning.paths.head = HEAD_PATH;
newState.dependencyScanning.paths.base = 'foo'; newState.dependencyScanning.paths.base = BASE_PATH;
newState.dependencyScanning.resolvedIssues = [{}]; newState.dependencyScanning.resolvedIssues = [{}];
...@@ -310,6 +362,53 @@ describe('Security reports getters', () => { ...@@ -310,6 +362,53 @@ describe('Security reports getters', () => {
}); });
}); });
describe('summaryCounts', () => {
it('returns 0 count for empty state', () => {
const newState = state();
expect(summaryCounts(newState)).toEqual({
added: 0,
dismissed: 0,
existing: 0,
fixed: 0,
});
});
describe('combines all reports', () => {
it('of the same type', () => {
const newState = state();
newState.sast.resolvedIssues = [{}];
newState.sastContainer.resolvedIssues = [{}];
newState.dast.resolvedIssues = [{}];
newState.dependencyScanning.resolvedIssues = [{}];
expect(summaryCounts(newState)).toEqual({
added: 0,
dismissed: 0,
existing: 0,
fixed: 4,
});
});
it('of the different types', () => {
const newState = state();
newState.sast.allIssues = [{}];
newState.sastContainer.resolvedIssues = [{}];
newState.dast.newIssues = [{ isDismissed: true }];
newState.dependencyScanning.newIssues = [{ isDismissed: false }];
expect(summaryCounts(newState)).toEqual({
added: 1,
dismissed: 1,
existing: 1,
fixed: 1,
});
});
});
});
describe('groupedSummaryText', () => { describe('groupedSummaryText', () => {
it('returns failed text', () => { it('returns failed text', () => {
expect( expect(
...@@ -317,6 +416,7 @@ describe('Security reports getters', () => { ...@@ -317,6 +416,7 @@ describe('Security reports getters', () => {
allReportsHaveError: true, allReportsHaveError: true,
noBaseInAllReports: false, noBaseInAllReports: false,
areReportsLoading: false, areReportsLoading: false,
summaryCounts: {},
}), }),
).toEqual('Security scanning failed loading any results'); ).toEqual('Security scanning failed loading any results');
}); });
...@@ -327,6 +427,7 @@ describe('Security reports getters', () => { ...@@ -327,6 +427,7 @@ describe('Security reports getters', () => {
allReportsHaveError: false, allReportsHaveError: false,
noBaseInAllReports: true, noBaseInAllReports: true,
areReportsLoading: false, areReportsLoading: false,
summaryCounts: {},
}), }),
).toEqual('Security scanning detected no vulnerabilities for the source branch only'); ).toEqual('Security scanning detected no vulnerabilities for the source branch only');
}); });
...@@ -337,108 +438,116 @@ describe('Security reports getters', () => { ...@@ -337,108 +438,116 @@ describe('Security reports getters', () => {
allReportsHaveError: false, allReportsHaveError: false,
noBaseInAllReports: false, noBaseInAllReports: false,
areReportsLoading: true, areReportsLoading: true,
summaryCounts: {},
}), }),
).toContain('(is loading)'); ).toContain('(is loading)');
}); });
it('returns added and fixed text', () => { it('returns added and fixed text', () => {
const newState = state(); const newState = state();
newState.summaryCounts = {
added: 2,
fixed: 4,
existing: 5,
};
expect( expect(
groupedSummaryText(newState, { groupedSummaryText(newState, {
allReportsHaveError: false, allReportsHaveError: false,
noBaseInAllReports: false, noBaseInAllReports: false,
areReportsLoading: false, areReportsLoading: false,
summaryCounts: {
added: 2,
fixed: 4,
existing: 5,
},
}), }),
).toEqual('Security scanning detected 2 new, and 4 fixed vulnerabilities'); ).toEqual('Security scanning detected 2 new, and 4 fixed vulnerabilities');
}); });
it('returns added text', () => { it('returns added text', () => {
const newState = state(); const newState = state();
newState.summaryCounts = {
added: 2,
fixed: 0,
existing: 5,
};
expect( expect(
groupedSummaryText(newState, { groupedSummaryText(newState, {
allReportsHaveError: false, allReportsHaveError: false,
noBaseInAllReports: false, noBaseInAllReports: false,
areReportsLoading: false, areReportsLoading: false,
summaryCounts: {
added: 2,
existing: 5,
},
}), }),
).toEqual('Security scanning detected 2 new vulnerabilities'); ).toEqual('Security scanning detected 2 new vulnerabilities');
}); });
it('returns fixed text', () => { it('returns fixed text', () => {
const newState = state(); const newState = state();
newState.summaryCounts = {
added: 0,
fixed: 4,
existing: 5,
};
expect( expect(
groupedSummaryText(newState, { groupedSummaryText(newState, {
allReportsHaveError: false, allReportsHaveError: false,
noBaseInAllReports: false, noBaseInAllReports: false,
areReportsLoading: false, areReportsLoading: false,
summaryCounts: {
fixed: 4,
existing: 5,
},
}), }),
).toEqual('Security scanning detected 4 fixed vulnerabilities'); ).toEqual('Security scanning detected 4 fixed vulnerabilities');
}); });
it('returns dismissed text', () => {
const newState = state();
expect(
groupedSummaryText(newState, {
allReportsHaveError: false,
noBaseInAllReports: false,
areReportsLoading: false,
summaryCounts: {
dismissed: 4,
},
}),
).toEqual('Security scanning detected 4 dismissed vulnerabilities');
});
it('returns added and fixed while loading text', () => { it('returns added and fixed while loading text', () => {
const newState = state(); const newState = state();
newState.summaryCounts = {
added: 2,
fixed: 4,
existing: 5,
};
expect( expect(
groupedSummaryText(newState, { groupedSummaryText(newState, {
allReportsHaveError: false, allReportsHaveError: false,
noBaseInAllReports: false, noBaseInAllReports: false,
areReportsLoading: true, areReportsLoading: true,
summaryCounts: {
added: 2,
fixed: 4,
existing: 5,
},
}), }),
).toEqual('Security scanning (is loading) detected 2 new, and 4 fixed vulnerabilities'); ).toEqual('Security scanning (is loading) detected 2 new, and 4 fixed vulnerabilities');
}); });
it('returns no new text if there are existing ones', () => { it('returns no new text if there are existing ones', () => {
const newState = state(); const newState = state();
newState.summaryCounts = {
added: 0,
fixed: 0,
existing: 5,
};
expect( expect(
groupedSummaryText(newState, { groupedSummaryText(newState, {
allReportsHaveError: false, allReportsHaveError: false,
noBaseInAllReports: false, noBaseInAllReports: false,
areReportsLoading: false, areReportsLoading: false,
summaryCounts: {
existing: 5,
},
}), }),
).toEqual('Security scanning detected no new vulnerabilities'); ).toEqual('Security scanning detected no new vulnerabilities');
}); });
it('returns no text if there are existing ones', () => { it('returns no text if there are existing ones', () => {
const newState = state(); const newState = state();
newState.summaryCounts = {
added: 0,
fixed: 0,
existing: 0,
};
expect( expect(
groupedSummaryText(newState, { groupedSummaryText(newState, {
allReportsHaveError: false, allReportsHaveError: false,
noBaseInAllReports: false, noBaseInAllReports: false,
areReportsLoading: false, areReportsLoading: false,
summaryCounts: {},
}), }),
).toEqual('Security scanning detected no vulnerabilities'); ).toEqual('Security scanning detected no vulnerabilities');
}); });
...@@ -583,7 +692,7 @@ describe('Security reports getters', () => { ...@@ -583,7 +692,7 @@ describe('Security reports getters', () => {
it('returns false when any of the reports has base', () => { it('returns false when any of the reports has base', () => {
const newState = state(); const newState = state();
newState.sast.paths.base = 'foo'; newState.sast.paths.base = BASE_PATH;
expect(noBaseInAllReports(newState)).toEqual(false); expect(noBaseInAllReports(newState)).toEqual(false);
}); });
......
...@@ -124,7 +124,6 @@ describe('security reports mutations', () => { ...@@ -124,7 +124,6 @@ describe('security reports mutations', () => {
expect(stateCopy.sast.isLoading).toEqual(false); expect(stateCopy.sast.isLoading).toEqual(false);
expect(stateCopy.sast.newIssues).toEqual(parsedSastIssuesHead); expect(stateCopy.sast.newIssues).toEqual(parsedSastIssuesHead);
expect(stateCopy.sast.resolvedIssues).toEqual(parsedSastBaseStore); expect(stateCopy.sast.resolvedIssues).toEqual(parsedSastBaseStore);
expect(stateCopy.summaryCounts).toEqual({ added: 2, fixed: 1, existing: 1 });
}); });
}); });
...@@ -137,7 +136,6 @@ describe('security reports mutations', () => { ...@@ -137,7 +136,6 @@ describe('security reports mutations', () => {
expect(stateCopy.sast.isLoading).toEqual(false); expect(stateCopy.sast.isLoading).toEqual(false);
expect(stateCopy.sast.newIssues).toEqual(parsedSastIssuesStore); expect(stateCopy.sast.newIssues).toEqual(parsedSastIssuesStore);
expect(stateCopy.summaryCounts).toEqual({ added: 3, fixed: 0, existing: 0 });
}); });
}); });
}); });
...@@ -186,7 +184,6 @@ describe('security reports mutations', () => { ...@@ -186,7 +184,6 @@ describe('security reports mutations', () => {
expect(stateCopy.sastContainer.isLoading).toEqual(false); expect(stateCopy.sastContainer.isLoading).toEqual(false);
expect(stateCopy.sastContainer.newIssues).toEqual(dockerNewIssues); expect(stateCopy.sastContainer.newIssues).toEqual(dockerNewIssues);
expect(stateCopy.sastContainer.resolvedIssues).toEqual(parsedSastContainerBaseStore); expect(stateCopy.sastContainer.resolvedIssues).toEqual(parsedSastContainerBaseStore);
expect(stateCopy.summaryCounts).toEqual({ added: 1, fixed: 1, existing: 0 });
}); });
}); });
...@@ -198,7 +195,6 @@ describe('security reports mutations', () => { ...@@ -198,7 +195,6 @@ describe('security reports mutations', () => {
expect(stateCopy.sastContainer.isLoading).toEqual(false); expect(stateCopy.sastContainer.isLoading).toEqual(false);
expect(stateCopy.sastContainer.newIssues).toEqual(dockerOnlyHeadParsed); expect(stateCopy.sastContainer.newIssues).toEqual(dockerOnlyHeadParsed);
expect(stateCopy.summaryCounts).toEqual({ added: 2, fixed: 0, existing: 0 });
}); });
}); });
}); });
...@@ -248,7 +244,6 @@ describe('security reports mutations', () => { ...@@ -248,7 +244,6 @@ describe('security reports mutations', () => {
expect(stateCopy.dast.newIssues).toEqual(parsedDastNewIssues); expect(stateCopy.dast.newIssues).toEqual(parsedDastNewIssues);
expect(stateCopy.dast.resolvedIssues).toEqual([]); expect(stateCopy.dast.resolvedIssues).toEqual([]);
expect(stateCopy.summaryCounts).toEqual({ added: 1, fixed: 0, existing: 0 });
}); });
}); });
...@@ -260,7 +255,6 @@ describe('security reports mutations', () => { ...@@ -260,7 +255,6 @@ describe('security reports mutations', () => {
expect(stateCopy.dast.isLoading).toEqual(false); expect(stateCopy.dast.isLoading).toEqual(false);
expect(stateCopy.dast.newIssues).toEqual(parsedDast); expect(stateCopy.dast.newIssues).toEqual(parsedDast);
expect(stateCopy.summaryCounts).toEqual({ added: 2, fixed: 0, existing: 0 });
}); });
}); });
}); });
...@@ -313,8 +307,6 @@ describe('security reports mutations', () => { ...@@ -313,8 +307,6 @@ describe('security reports mutations', () => {
expect(stateCopy.dependencyScanning.resolvedIssues).toEqual( expect(stateCopy.dependencyScanning.resolvedIssues).toEqual(
parsedDependencyScanningBaseStore, parsedDependencyScanningBaseStore,
); );
expect(stateCopy.summaryCounts).toEqual({ added: 2, fixed: 1, existing: 1 });
}); });
}); });
...@@ -327,7 +319,6 @@ describe('security reports mutations', () => { ...@@ -327,7 +319,6 @@ describe('security reports mutations', () => {
expect(stateCopy.dependencyScanning.isLoading).toEqual(false); expect(stateCopy.dependencyScanning.isLoading).toEqual(false);
expect(stateCopy.dependencyScanning.newIssues).toEqual(parsedDependencyScanningIssuesStore); expect(stateCopy.dependencyScanning.newIssues).toEqual(parsedDependencyScanningIssuesStore);
expect(stateCopy.summaryCounts).toEqual({ added: 3, fixed: 0, existing: 0 });
}); });
}); });
}); });
...@@ -566,9 +557,9 @@ describe('security reports mutations', () => { ...@@ -566,9 +557,9 @@ describe('security reports mutations', () => {
}); });
it('updates issue in the resolved issues list', () => { it('updates issue in the resolved issues list', () => {
stateCopy.sast.newIssues = []; stateCopy.dependencyScanning.newIssues = [];
stateCopy.sast.resolvedIssues = parsedDependencyScanningIssuesHead; stateCopy.dependencyScanning.resolvedIssues = parsedDependencyScanningIssuesHead;
stateCopy.sast.allIssues = []; stateCopy.dependencyScanning.allIssues = [];
const updatedIssue = { const updatedIssue = {
...parsedDependencyScanningIssuesHead[0], ...parsedDependencyScanningIssuesHead[0],
foo: 'bar', foo: 'bar',
...@@ -576,7 +567,7 @@ describe('security reports mutations', () => { ...@@ -576,7 +567,7 @@ describe('security reports mutations', () => {
mutations[types.UPDATE_DEPENDENCY_SCANNING_ISSUE](stateCopy, updatedIssue); mutations[types.UPDATE_DEPENDENCY_SCANNING_ISSUE](stateCopy, updatedIssue);
expect(stateCopy.sast.resolvedIssues[0]).toEqual(updatedIssue); expect(stateCopy.dependencyScanning.resolvedIssues[0]).toEqual(updatedIssue);
}); });
it('updates issue in the all issues list', () => { it('updates issue in the all issues list', () => {
......
...@@ -10,6 +10,7 @@ import { ...@@ -10,6 +10,7 @@ import {
getUnapprovedVulnerabilities, getUnapprovedVulnerabilities,
groupedTextBuilder, groupedTextBuilder,
statusIcon, statusIcon,
countIssues,
} from 'ee/vue_shared/security_reports/store/utils'; } from 'ee/vue_shared/security_reports/store/utils';
import { import {
oldSastIssues, oldSastIssues,
...@@ -292,44 +293,56 @@ describe('security reports utils', () => { ...@@ -292,44 +293,56 @@ describe('security reports utils', () => {
}); });
describe('textBuilder', () => { describe('textBuilder', () => {
describe('with no issues', () => { describe('with only the head', () => {
it('should return no vulnerabiltities text', () => { const paths = { head: 'foo' };
expect(groupedTextBuilder('', { head: 'foo', base: 'bar' }, 0, 0, 0)).toEqual(
' detected no vulnerabilities', it('should return unable to compare text', () => {
expect(groupedTextBuilder({ paths, added: 1 })).toEqual(
' detected 1 vulnerability for the source branch only',
); );
}); });
});
describe('with only `all` issues', () => { it('should return unable to compare text with no vulnerability', () => {
it('should return no new vulnerabiltities text', () => { expect(groupedTextBuilder({ paths })).toEqual(
expect(groupedTextBuilder('', { head: 'foo', base: 'bar' }, 0, 0, 1)).toEqual( ' detected no vulnerabilities for the source branch only',
' detected no new vulnerabilities',
); );
}); });
});
describe('with new issues and without base', () => { it('should return dismissed text', () => {
it('should return unable to compare text', () => { expect(groupedTextBuilder({ paths, dismissed: 2 })).toEqual(
expect(groupedTextBuilder('', { head: 'foo' }, 1, 0, 0)).toEqual( ' detected 2 dismissed vulnerabilities for the source branch only',
' detected 1 vulnerability for the source branch only',
); );
}); });
it('should return unable to compare text with no vulnerability', () => { it('should return new and dismissed text', () => {
expect(groupedTextBuilder('', { head: 'foo' }, 0, 0, 0)).toEqual( expect(groupedTextBuilder({ paths, added: 1, dismissed: 2 })).toEqual(
' detected no vulnerabilities for the source branch only', ' detected 1 new, and 2 dismissed vulnerabilities for the source branch only',
); );
}); });
}); });
describe('with base and head', () => { describe('with base and head', () => {
const paths = { head: 'foo', base: 'foo' };
describe('with no issues', () => {
it('should return no vulnerabiltities text', () => {
expect(groupedTextBuilder({ paths })).toEqual(' detected no vulnerabilities');
});
});
describe('with only `all` issues', () => {
it('should return no new vulnerabiltities text', () => {
expect(groupedTextBuilder({ paths, existing: 1 })).toEqual(
' detected no new vulnerabilities',
);
});
});
describe('with only new issues', () => { describe('with only new issues', () => {
it('should return new issues text', () => { it('should return new issues text', () => {
expect(groupedTextBuilder('', { head: 'foo', base: 'foo' }, 1, 0, 0)).toEqual( expect(groupedTextBuilder({ paths, added: 1 })).toEqual(' detected 1 new vulnerability');
' detected 1 new vulnerability',
);
expect(groupedTextBuilder('', { head: 'foo', base: 'foo' }, 2, 0, 0)).toEqual( expect(groupedTextBuilder({ paths, added: 2 })).toEqual(
' detected 2 new vulnerabilities', ' detected 2 new vulnerabilities',
); );
}); });
...@@ -337,27 +350,53 @@ describe('security reports utils', () => { ...@@ -337,27 +350,53 @@ describe('security reports utils', () => {
describe('with new and resolved issues', () => { describe('with new and resolved issues', () => {
it('should return new and fixed issues text', () => { it('should return new and fixed issues text', () => {
expect( expect(groupedTextBuilder({ paths, added: 1, fixed: 1 }).replace(/\n+\s+/m, ' ')).toEqual(
groupedTextBuilder('', { head: 'foo', base: 'foo' }, 1, 1, 0).replace(/\n+\s+/m, ' '), ' detected 1 new, and 1 fixed vulnerabilities',
).toEqual(' detected 1 new, and 1 fixed vulnerabilities'); );
expect( expect(groupedTextBuilder({ paths, added: 2, fixed: 2 }).replace(/\n+\s+/m, ' ')).toEqual(
groupedTextBuilder('', { head: 'foo', base: 'foo' }, 2, 2, 0).replace(/\n+\s+/m, ' '), ' detected 2 new, and 2 fixed vulnerabilities',
).toEqual(' detected 2 new, and 2 fixed vulnerabilities'); );
}); });
}); });
describe('with only resolved issues', () => { describe('with only resolved issues', () => {
it('should return fixed issues text', () => { it('should return fixed issues text', () => {
expect(groupedTextBuilder('', { head: 'foo', base: 'foo' }, 0, 1, 0)).toEqual( expect(groupedTextBuilder({ paths, fixed: 1 })).toEqual(
' detected 1 fixed vulnerability', ' detected 1 fixed vulnerability',
); );
expect(groupedTextBuilder('', { head: 'foo', base: 'foo' }, 0, 2, 0)).toEqual( expect(groupedTextBuilder({ paths, fixed: 2 })).toEqual(
' detected 2 fixed vulnerabilities', ' detected 2 fixed vulnerabilities',
); );
}); });
}); });
describe('with dismissed issues', () => {
it('should return dismissed text', () => {
expect(groupedTextBuilder({ paths, dismissed: 2 })).toEqual(
' detected 2 dismissed vulnerabilities',
);
});
it('should return new and dismissed text', () => {
expect(groupedTextBuilder({ paths, added: 1, dismissed: 2 })).toEqual(
' detected 1 new, and 2 dismissed vulnerabilities',
);
});
it('should return fixed and dismissed text', () => {
expect(groupedTextBuilder({ paths, fixed: 1, dismissed: 2 })).toEqual(
' detected 1 fixed, and 2 dismissed vulnerabilities',
);
});
it('should return new, fixed and dismissed text', () => {
expect(groupedTextBuilder({ paths, fixed: 1, added: 1, dismissed: 2 })).toEqual(
' detected 1 new, 1 fixed, and 2 dismissed vulnerabilities',
);
});
});
}); });
}); });
...@@ -386,4 +425,67 @@ describe('security reports utils', () => { ...@@ -386,4 +425,67 @@ describe('security reports utils', () => {
}); });
}); });
}); });
describe('countIssues', () => {
const allIssues = [{}];
const resolvedIssues = [{}];
const dismissedIssues = [{ isDismissed: true }];
const addedIssues = [{ isDismissed: false }];
it('returns 0 for all counts if everything is empty', () => {
expect(countIssues()).toEqual({
added: 0,
dismissed: 0,
existing: 0,
fixed: 0,
});
});
it('counts `allIssues` as existing', () => {
expect(countIssues({ allIssues })).toEqual({
added: 0,
dismissed: 0,
existing: 1,
fixed: 0,
});
});
it('counts `resolvedIssues` as fixed', () => {
expect(countIssues({ resolvedIssues })).toEqual({
added: 0,
dismissed: 0,
existing: 0,
fixed: 1,
});
});
it('counts `newIssues` which are dismissed as dismissed', () => {
expect(countIssues({ newIssues: dismissedIssues })).toEqual({
added: 0,
dismissed: 1,
existing: 0,
fixed: 0,
});
});
it('counts `newIssues` which are not dismissed as added', () => {
expect(countIssues({ newIssues: addedIssues })).toEqual({
added: 1,
dismissed: 0,
existing: 0,
fixed: 0,
});
});
it('counts everything', () => {
expect(
countIssues({ newIssues: [...addedIssues, ...dismissedIssues], resolvedIssues, allIssues }),
).toEqual({
added: 1,
dismissed: 1,
existing: 1,
fixed: 1,
});
});
});
}); });
...@@ -11558,16 +11558,38 @@ msgstr "" ...@@ -11558,16 +11558,38 @@ msgstr ""
msgid "ciReport|%{remainingPackagesCount} more" msgid "ciReport|%{remainingPackagesCount} more"
msgstr "" msgstr ""
msgid "ciReport|%{reportType} %{status} detected %{dismissedCount} dismissed vulnerability"
msgid_plural "ciReport|%{reportType} %{status} detected %{dismissedCount} dismissed vulnerabilities"
msgstr[0] ""
msgstr[1] ""
msgid "ciReport|%{reportType} %{status} detected %{dismissedCount} dismissed vulnerability for the source branch only"
msgid_plural "ciReport|%{reportType} %{status} detected %{dismissedCount} dismissed vulnerabilities for the source branch only"
msgstr[0] ""
msgstr[1] ""
msgid "ciReport|%{reportType} %{status} detected %{fixedCount} fixed vulnerability" msgid "ciReport|%{reportType} %{status} detected %{fixedCount} fixed vulnerability"
msgid_plural "ciReport|%{reportType} %{status} detected %{fixedCount} fixed vulnerabilities" msgid_plural "ciReport|%{reportType} %{status} detected %{fixedCount} fixed vulnerabilities"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
msgid "ciReport|%{reportType} %{status} detected %{fixedCount} fixed, and %{dismissedCount} dismissed vulnerabilities"
msgstr ""
msgid "ciReport|%{reportType} %{status} detected %{newCount} new vulnerability" msgid "ciReport|%{reportType} %{status} detected %{newCount} new vulnerability"
msgid_plural "ciReport|%{reportType} %{status} detected %{newCount} new vulnerabilities" msgid_plural "ciReport|%{reportType} %{status} detected %{newCount} new vulnerabilities"
msgstr[0] "" msgstr[0] ""
msgstr[1] "" msgstr[1] ""
msgid "ciReport|%{reportType} %{status} detected %{newCount} new, %{fixedCount} fixed, and %{dismissedCount} dismissed vulnerabilities"
msgstr ""
msgid "ciReport|%{reportType} %{status} detected %{newCount} new, and %{dismissedCount} dismissed vulnerabilities"
msgstr ""
msgid "ciReport|%{reportType} %{status} detected %{newCount} new, and %{dismissedCount} dismissed vulnerabilities for the source branch only"
msgstr ""
msgid "ciReport|%{reportType} %{status} detected %{newCount} new, and %{fixedCount} fixed vulnerabilities" msgid "ciReport|%{reportType} %{status} detected %{newCount} new, and %{fixedCount} fixed vulnerabilities"
msgstr "" 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