Commit 5b21719b authored by Dave Pisek's avatar Dave Pisek

Refactor: pass error scan from parent

parent 61418b8a
......@@ -71,6 +71,20 @@ export default {
primaryButtonText: s__('SecurityReports|Learn more about setting up your dashboard'),
};
},
scansWithErrors() {
const getScans = (reportSummary) => reportSummary?.scans || [];
const hasErrors = (scan) => Boolean(scan.errors?.length);
return this.securityReportSummary
? Object.values(this.securityReportSummary)
// generate flat array of all scans
.flatMap(getScans)
.filter(hasErrors)
: [];
},
hasScansWithErrors() {
return this.scansWithErrors.length > 0;
},
},
created() {
this.setSourceBranch(this.pipeline.sourceBranch);
......@@ -87,7 +101,7 @@ export default {
<template>
<div>
<div v-if="securityReportSummary" class="gl-my-5">
<scan-errors-alert :security-report-summary="securityReportSummary" class="gl-mb-5" />
<scan-errors-alert v-if="hasScansWithErrors" :scans="scansWithErrors" class="gl-mb-5" />
<security-reports-summary :summary="securityReportSummary" />
</div>
<security-dashboard
......
<script>
import { GlAccordion, GlAccordionItem, GlAlert, GlButton, GlSprintf } from '@gitlab/ui';
import { sprintf, s__ } from '~/locale';
import { s__ } from '~/locale';
export default {
components: {
......@@ -12,34 +12,17 @@ export default {
},
inject: ['securityReportHelpPageLink'],
props: {
securityReportSummary: {
type: Object,
required: false,
default: () => ({}),
scans: {
type: Array,
required: true,
},
},
computed: {
scansWithErrors() {
const getScans = (reportSummary) => reportSummary?.scans || [];
const hasErrors = (scan) => Boolean(scan.errors?.length);
const addTitle = (scan) => ({
scansWithTitles() {
return this.scans.map((scan) => ({
...scan,
title: sprintf(s__('SecurityReports|%{errorName} (%{errorCount})'), {
errorName: scan.name,
errorCount: scan.errors.length,
}),
});
return this.securityReportSummary
? Object.values(this.securityReportSummary)
// generate flat array of all scans
.flatMap(getScans)
.filter(hasErrors)
.map(addTitle)
: [];
},
hasScansWithErrors() {
return this.scansWithErrors.length > 0;
title: `${scan.name} (${scan.errors.length})`,
}));
},
},
i18n: {
......@@ -52,7 +35,7 @@ export default {
</script>
<template>
<gl-alert v-if="hasScansWithErrors" variant="danger" :dismissible="false">
<gl-alert variant="danger" :dismissible="false">
<strong role="heading">
{{ $options.i18n.title }}
</strong>
......@@ -72,7 +55,7 @@ export default {
</p>
<gl-accordion :header-level="3">
<gl-accordion-item
v-for="{ name, errors, title } in scansWithErrors"
v-for="{ name, errors, title } in scansWithTitles"
:key="name"
:title="title"
>
......
......@@ -150,7 +150,44 @@ describe('Pipeline Security Dashboard component', () => {
});
});
describe('scan errors alert', () => {
describe('scans error alert', () => {
describe('with errors', () => {
const securityReportSummary = {
scanner_1: {
// this scan contains errors
scans: [
{ errors: ['scanner 1 - error 1', 'scanner 1 - error 2'], name: 'foo' },
{ errors: ['scanner 1 - error 3', 'scanner 1 - error 4'], name: 'bar' },
],
},
scanner_2: null,
scanner_3: {
// this scan contains errors
scans: [{ errors: ['scanner 3 - error 1', 'scanner 3 - error 2'], name: 'baz' }],
},
scanner_4: {
scans: [{ errors: [], name: 'quz' }],
},
};
const scansWithErrors = [
...securityReportSummary.scanner_1.scans,
...securityReportSummary.scanner_3.scans,
];
beforeEach(() => {
factory({
data: {
securityReportSummary,
},
});
});
it('shows an alert with information about each scan with errors', () => {
expect(findScanErrorsAlert().props('scans')).toEqual(scansWithErrors);
});
});
describe('without errors', () => {
const securityReportSummary = {
dast: {
scans: [
......@@ -170,12 +207,9 @@ describe('Pipeline Security Dashboard component', () => {
});
});
it('includes the alert', () => {
expect(findScanErrorsAlert().exists()).toBe(true);
it('does not show the alert', () => {
expect(findScanErrorsAlert().exists()).toBe(false);
});
it('passes the security report summary to the alert', () => {
expect(findScanErrorsAlert().props('securityReportSummary')).toBe(securityReportSummary);
});
});
......
......@@ -4,36 +4,22 @@ import PipelineScanErrorsAlert from 'ee/security_dashboard/components/pipeline/s
import { trimText } from 'helpers/text_helper';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
const TEST_SECURITY_REPORT_SUMMARY = {
scanner_1: {
// this scan contains errors
scans: [
{ errors: ['scanner 1 - error 1', 'scanner 1 - error 2'], name: 'foo' },
{ errors: ['scanner 1 - error 3', 'scanner 1 - error 4'], name: 'bar' },
],
},
scanner_2: null,
scanner_3: {
// this scan contains errors
scans: [{ errors: ['scanner 3 - error 1', 'scanner 3 - error 2'], name: 'baz' }],
},
scanner_4: {
scans: [{ errors: [], name: 'quz' }],
},
};
const TEST_HELP_PAGE_LINK = 'http://help.com';
const TEST_SCANS_WITH_ERRORS = [
...TEST_SECURITY_REPORT_SUMMARY.scanner_1.scans,
...TEST_SECURITY_REPORT_SUMMARY.scanner_3.scans,
{ errors: ['scanner 1 - error 1', 'scanner 1 - error 2'], name: 'foo' },
{ errors: ['scanner 1 - error 3', 'scanner 1 - error 4'], name: 'bar' },
{ errors: ['scanner 3 - error 1', 'scanner 3 - error 2'], name: 'baz' },
];
describe('ee/security_dashboard/components/pipeline_scan_errors_alert.vue', () => {
let wrapper;
const createWrapper = (options) =>
const createWrapper = () =>
extendedWrapper(
shallowMount(PipelineScanErrorsAlert, {
...options,
propsData: {
scans: TEST_SCANS_WITH_ERRORS,
},
provide: {
securityReportHelpPageLink: TEST_HELP_PAGE_LINK,
},
......@@ -55,25 +41,11 @@ describe('ee/security_dashboard/components/pipeline_scan_errors_alert.vue', () =
wrapper.destroy();
});
describe('without scanner errors', () => {
beforeEach(() => {
wrapper = createWrapper({ propsData: { securityReportSummary: {} } });
});
it('does not show error alert', () => {
expect(findAlert().exists()).toBe(false);
});
});
describe('with scanner errors', () => {
beforeEach(() => {
wrapper = createWrapper({
propsData: { securityReportSummary: TEST_SECURITY_REPORT_SUMMARY },
});
wrapper = createWrapper();
});
it('shows a non-dismissible error alert', () => {
expect(findAlert().exists()).toBe(true);
expect(findAlert().props()).toMatchObject({
variant: 'danger',
dismissible: false,
......@@ -91,7 +63,6 @@ describe('ee/security_dashboard/components/pipeline_scan_errors_alert.vue', () =
});
it('links to the security-report help page', () => {
expect(findHelpPageLink().exists()).toBe(true);
expect(findHelpPageLink().attributes('href')).toBe(TEST_HELP_PAGE_LINK);
});
......@@ -121,5 +92,4 @@ describe('ee/security_dashboard/components/pipeline_scan_errors_alert.vue', () =
});
});
});
});
});
......@@ -29078,9 +29078,6 @@ msgstr ""
msgid "SecurityOrchestration|Security policy project"
msgstr ""
msgid "SecurityReports|%{errorName} (%{errorCount})"
msgstr ""
msgid "SecurityReports|%{firstProject} and %{secondProject}"
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