Commit 8cb9f02e authored by Phil Hughes's avatar Phil Hughes

Merge branch '49614-dynamic-component-in-report-issue-ee' into 'master'

Use new extendable report_issues.vue (gitlab-ce!20843)

See merge request gitlab-org/gitlab-ee!6667
parents 6eca39f8 87482577
export const STATUS_FAILED = 'failed';
export const STATUS_SUCCESS = 'success';
export const STATUS_NEUTRAL = 'neutral';
export const components = {};
export const componentNames = {};
<script>
import Icon from '~/vue_shared/components/icon.vue';
import {
STATUS_FAILED,
STATUS_NEUTRAL,
STATUS_SUCCESS,
} from '~/vue_shared/components/reports/constants';
export default {
name: 'IssueStatusIcon',
components: {
Icon,
},
props: {
// failed || success
status: {
type: String,
required: true,
},
},
computed: {
iconName() {
if (this.isStatusFailed) {
return 'status_failed_borderless';
} else if (this.isStatusSuccess) {
return 'status_success_borderless';
}
return 'status_created_borderless';
},
isStatusFailed() {
return this.status === STATUS_FAILED;
},
isStatusSuccess() {
return this.status === STATUS_SUCCESS;
},
isStatusNeutral() {
return this.status === STATUS_NEUTRAL;
},
},
};
</script>
<template>
<div
:class="{
failed: isStatusFailed,
success: isStatusSuccess,
neutral: isStatusNeutral,
}"
class="report-block-list-icon"
>
<icon
:name="iconName"
:size="32"
/>
</div>
</template>
<script>
import IssuesBlock from '~/vue_shared/components/reports/report_issues.vue';
import {
STATUS_SUCCESS,
STATUS_FAILED,
STATUS_NEUTRAL,
} from '~/vue_shared/components/reports/constants';
import { componentNames } from 'ee/vue_shared/components/reports/issue_body';
import SastContainerInfo from 'ee/vue_shared/security_reports/components/sast_container_info.vue';
import { SAST_CONTAINER } from 'ee/vue_shared/security_reports/store/constants';
/**
* Renders block of issues
......@@ -13,7 +18,10 @@ export default {
IssuesBlock,
SastContainerInfo,
},
sastContainer: SAST_CONTAINER,
componentNames,
success: STATUS_SUCCESS,
failed: STATUS_FAILED,
neutral: STATUS_NEUTRAL,
props: {
unresolvedIssues: {
type: Array,
......@@ -35,9 +43,10 @@ export default {
required: false,
default: () => [],
},
type: {
component: {
type: String,
required: true,
required: false,
default: '',
},
},
data() {
......@@ -45,11 +54,6 @@ export default {
isFullReportVisible: false,
};
},
computed: {
unresolvedIssuesStatus() {
return this.type === 'license' ? 'neutral' : 'failed';
},
},
methods: {
openFullReport() {
this.isFullReportVisible = true;
......@@ -59,38 +63,37 @@ export default {
</script>
<template>
<div class="report-block-container">
<sast-container-info v-if="type === $options.sastContainer" />
<sast-container-info v-if="component === $options.componentNames.SastContainerIssueBody" />
<issues-block
v-if="unresolvedIssues.length"
:type="type"
:status="unresolvedIssuesStatus"
:component="component"
:issues="unresolvedIssues"
:status="$options.failed"
class="js-mr-code-new-issues"
/>
<issues-block
v-if="isFullReportVisible"
:type="type"
:component="component"
:issues="allIssues"
:status="$options.failed"
class="js-mr-code-all-issues"
status="failed"
/>
<issues-block
v-if="neutralIssues.length"
:type="type"
:component="component"
:issues="neutralIssues"
:status="$options.neutral"
class="js-mr-code-non-issues"
status="neutral"
/>
<issues-block
v-if="resolvedIssues.length"
:type="type"
:component="component"
:issues="resolvedIssues"
:status="$options.success"
class="js-mr-code-resolved-issues"
status="success"
/>
<button
......
<script>
import Icon from '~/vue_shared/components/icon.vue';
import PerformanceIssue from 'ee/vue_merge_request_widget/components/performance_issue_body.vue';
import CodequalityIssue from 'ee/vue_merge_request_widget/components/codequality_issue_body.vue';
import LicenseIssue from 'ee/vue_merge_request_widget/components/license_issue_body.vue';
import SastIssue from 'ee/vue_shared/security_reports/components/sast_issue_body.vue';
import SastContainerIssue from 'ee/vue_shared/security_reports/components/sast_container_issue_body.vue';
import DastIssue from 'ee/vue_shared/security_reports/components/dast_issue_body.vue';
import { SAST, DAST, SAST_CONTAINER } from 'ee/vue_shared/security_reports/store/constants';
import IssueStatusIcon from '~/vue_shared/components/reports/issue_status_icon.vue';
import { components, componentNames } from 'ee/vue_shared/components/reports/issue_body';
export default {
name: 'ReportIssues',
components: {
Icon,
SastIssue,
SastContainerIssue,
DastIssue,
PerformanceIssue,
CodequalityIssue,
LicenseIssue,
IssueStatusIcon,
...components,
},
props: {
issues: {
type: Array,
required: true,
},
// security || codequality || performance || docker || dast || license
type: {
component: {
type: String,
required: true,
required: false,
default: '',
validator: value => value === '' || Object.values(componentNames).includes(value),
},
// failed || success
status: {
......@@ -36,44 +25,6 @@ export default {
required: true,
},
},
computed: {
iconName() {
if (this.isStatusFailed) {
return 'status_failed_borderless';
} else if (this.isStatusSuccess) {
return 'status_success_borderless';
}
return 'status_created_borderless';
},
isStatusFailed() {
return this.status === 'failed';
},
isStatusSuccess() {
return this.status === 'success';
},
isStatusNeutral() {
return this.status === 'neutral';
},
isTypeCodequality() {
return this.type === 'codequality';
},
isTypePerformance() {
return this.type === 'performance';
},
isTypeLicense() {
return this.type === 'license';
},
isTypeSast() {
return this.type === SAST;
},
isTypeSastContainer() {
return this.type === SAST_CONTAINER;
},
isTypeDast() {
return this.type === DAST;
},
},
};
</script>
<template>
......@@ -85,60 +36,16 @@ export default {
:key="index"
class="report-block-list-issue"
>
<div
:class="{
failed: isStatusFailed,
success: isStatusSuccess,
neutral: isStatusNeutral,
}"
class="report-block-list-icon append-right-5"
>
<icon
v-if="isTypeLicense"
:size="24"
name="status_created_borderless"
css-classes="prepend-left-4"
/>
<icon
v-else
:name="iconName"
:size="32"
/>
</div>
<sast-issue
v-if="isTypeSast"
:issue="issue"
:status="status"
/>
<dast-issue
v-else-if="isTypeDast"
:issue="issue"
:issue-index="index"
:status="status"
/>
<sast-container-issue
v-else-if="isTypeSastContainer"
:issue="issue"
:status="status"
/>
<codequality-issue
v-else-if="isTypeCodequality"
:is-status-success="isStatusSuccess"
:issue="issue"
/>
<performance-issue
v-else-if="isTypePerformance"
:issue="issue"
<issue-status-icon
:status="issue.status || status"
class="append-right-5"
/>
<license-issue
v-else-if="isTypeLicense"
<component
v-if="component"
:is="component"
:issue="issue"
:status="issue.status || status"
/>
</li>
</ul>
......
......@@ -21,7 +21,7 @@ export default {
required: false,
default: false,
},
type: {
component: {
type: String,
required: false,
default: '',
......@@ -183,8 +183,9 @@ export default {
<issues-list
:unresolved-issues="unresolvedIssues"
:resolved-issues="resolvedIssues"
:neutral-issues="neutralIssues"
:all-issues="allIssues"
:type="type"
:component="component"
/>
</slot>
</div>
......
......@@ -4,6 +4,7 @@
* Fixed: [name] in [link]:[line]
*/
import ReportLink from '~/vue_shared/components/reports/report_link.vue';
import { STATUS_SUCCESS } from '~/vue_shared/components/reports/constants';
export default {
name: 'CodequalityIssueBody',
......@@ -11,10 +12,9 @@ export default {
components: {
ReportLink,
},
props: {
isStatusSuccess: {
type: Boolean,
status: {
type: String,
required: true,
},
issue: {
......@@ -22,6 +22,11 @@ export default {
required: true,
},
},
computed: {
isStatusSuccess() {
return this.status === STATUS_SUCCESS;
},
},
};
</script>
<template>
......
......@@ -2,6 +2,7 @@
import { s__, sprintf } from '~/locale';
export default {
name: 'LicenseIssueBody',
props: {
issue: {
type: Object,
......
......@@ -2,6 +2,7 @@
import ReportSection from '~/vue_shared/components/reports/report_section.vue';
import GroupedSecurityReportsApp from 'ee/vue_shared/security_reports/grouped_security_reports_app.vue';
import reportsMixin from 'ee/vue_shared/security_reports/mixins/reports_mixin';
import { componentNames } from 'ee/vue_shared/components/reports/issue_body';
import { n__, s__, __, sprintf } from '~/locale';
import CEWidgetOptions from '~/vue_merge_request_widget/mr_widget_options.vue';
......@@ -17,6 +18,7 @@ export default {
},
extends: CEWidgetOptions,
mixins: [reportsMixin],
componentNames,
data() {
return {
isLoadingCodequality: false,
......@@ -255,8 +257,8 @@ export default {
:unresolved-issues="mr.codeclimateMetrics.newIssues"
:resolved-issues="mr.codeclimateMetrics.resolvedIssues"
:has-issues="hasCodequalityIssues"
:component="$options.componentNames.CodequalityIssueBody"
class="js-codequality-widget mr-widget-border-top"
type="codequality"
/>
<report-section
v-if="shouldRenderPerformance"
......@@ -268,8 +270,8 @@ export default {
:resolved-issues="mr.performanceMetrics.improved"
:neutral-issues="mr.performanceMetrics.neutral"
:has-issues="hasPerformanceMetrics"
:component="$options.componentNames.PerformanceIssueBody"
class="js-performance-widget mr-widget-border-top"
type="performance"
/>
<grouped-security-reports-app
v-if="shouldRenderSecurityReport"
......@@ -299,10 +301,10 @@ export default {
:loading-text="translateText('license management').loading"
:error-text="translateText('license management').error"
:success-text="licenseReportText"
:unresolved-issues="mr.licenseReport"
:neutral-issues="mr.licenseReport"
:has-issues="hasLicenseReportIssues"
:component="$options.componentNames.LicenseIssueBody"
class="js-license-report-widget mr-widget-border-top"
type="license"
/>
<div class="mr-section-container">
<div class="mr-widget-section">
......
import {
components as componentsCE,
componentNames as componentNamesCE,
} from '~/vue_shared/components/reports/issue_body';
import PerformanceIssueBody from 'ee/vue_merge_request_widget/components/performance_issue_body.vue';
import CodequalityIssueBody from 'ee/vue_merge_request_widget/components/codequality_issue_body.vue';
import LicenseIssueBody from 'ee/vue_merge_request_widget/components/license_issue_body.vue';
import SastIssueBody from 'ee/vue_shared/security_reports/components/sast_issue_body.vue';
import SastContainerIssueBody from 'ee/vue_shared/security_reports/components/sast_container_issue_body.vue';
import DastIssueBody from 'ee/vue_shared/security_reports/components/dast_issue_body.vue';
export const components = {
...componentsCE,
PerformanceIssueBody,
CodequalityIssueBody,
LicenseIssueBody,
SastContainerIssueBody,
SastIssueBody,
DastIssueBody,
};
export const componentNames = {
...componentNamesCE,
PerformanceIssueBody: PerformanceIssueBody.name,
CodequalityIssueBody: CodequalityIssueBody.name,
LicenseIssueBody: LicenseIssueBody.name,
SastContainerIssueBody: SastContainerIssueBody.name,
SastIssueBody: SastIssueBody.name,
DastIssueBody: DastIssueBody.name,
};
......@@ -7,7 +7,7 @@
import ModalOpenName from '~/vue_shared/components/reports/modal_open_name.vue';
export default {
name: 'SastIssueBody',
name: 'DastIssueBody',
components: {
ModalOpenName,
},
......@@ -16,11 +16,6 @@ export default {
type: Object,
required: true,
},
issueIndex: {
type: Number,
required: true,
},
// failed || success
status: {
type: String,
......
......@@ -3,8 +3,8 @@ import { mapActions, mapState, mapGetters } from 'vuex';
import ReportSection from '~/vue_shared/components/reports/report_section.vue';
import SummaryRow from '~/vue_shared/components/reports/summary_row.vue';
import IssuesList from '~/vue_shared/components/reports/issues_list.vue';
import { componentNames } from 'ee/vue_shared/components/reports/issue_body';
import IssueModal from './components/modal.vue';
import { SAST, DAST, SAST_CONTAINER } from './store/constants';
import securityReportsMixin from './mixins/security_report_mixin';
import createStore from './store';
......@@ -111,9 +111,7 @@ export default {
required: true,
},
},
sast: SAST,
dast: DAST,
sastContainer: SAST_CONTAINER,
componentNames,
computed: {
...mapState(['sast', 'sastContainer', 'dast', 'dependencyScanning', 'summaryCounts']),
...mapGetters([
......@@ -229,7 +227,7 @@ export default {
:unresolved-issues="sast.newIssues"
:resolved-issues="sast.resolvedIssues"
:all-issues="sast.allIssues"
:type="$options.sast"
:component="$options.componentNames.SastIssueBody"
class="js-sast-issue-list report-block-group-list"
/>
</template>
......@@ -248,7 +246,7 @@ export default {
:unresolved-issues="dependencyScanning.newIssues"
:resolved-issues="dependencyScanning.resolvedIssues"
:all-issues="dependencyScanning.allIssues"
:type="$options.sast"
:component="$options.componentNames.SastIssueBody"
class="js-dss-issue-list report-block-group-list"
/>
</template>
......@@ -265,7 +263,7 @@ export default {
v-if="sastContainer.newIssues.length || sastContainer.resolvedIssues.length"
:unresolved-issues="sastContainer.newIssues"
:neutral-issues="sastContainer.resolvedIssues"
:type="$options.sastContainer"
:component="$options.componentNames.SastContainerIssueBody"
class="report-block-group-list"
/>
</template>
......@@ -282,7 +280,7 @@ export default {
v-if="dast.newIssues.length || dast.resolvedIssues.length"
:unresolved-issues="dast.newIssues"
:resolved-issues="dast.resolvedIssues"
:type="$options.dast"
:component="$options.componentNames.DastIssueBody"
class="report-block-group-list"
/>
</template>
......
......@@ -3,7 +3,7 @@ import { mapActions, mapState } from 'vuex';
import { s__, sprintf, n__ } from '~/locale';
import createFlash from '~/flash';
import ReportSection from '~/vue_shared/components/reports/report_section.vue';
import { SAST, DAST, SAST_CONTAINER } from './store/constants';
import { componentNames } from 'ee/vue_shared/components/reports/issue_body';
import IssueModal from './components/modal.vue';
import mixin from './mixins/security_report_mixin';
import reportsMixin from './mixins/reports_mixin';
......@@ -88,9 +88,7 @@ export default {
required: true,
},
},
sast: SAST,
dast: DAST,
sastContainer: SAST_CONTAINER,
componentNames,
computed: {
...mapState(['sast', 'dependencyScanning', 'sastContainer', 'dast']),
......@@ -216,7 +214,7 @@ export default {
<report-section
v-if="sastHeadPath"
:always-open="alwaysOpen"
:type="$options.sast"
:component="$options.componentNames.SastIssueBody"
:status="checkReportStatus(sast.isLoading, sast.hasError)"
:loading-text="translateText('SAST').loading"
:error-text="translateText('SAST').error"
......@@ -230,7 +228,7 @@ export default {
<report-section
v-if="dependencyScanningHeadPath"
:always-open="alwaysOpen"
:type="$options.sast"
:component="$options.componentNames.SastIssueBody"
:status="checkReportStatus(dependencyScanning.isLoading, dependencyScanning.hasError)"
:loading-text="translateText('Dependency scanning').loading"
:error-text="translateText('Dependency scanning').error"
......@@ -244,7 +242,7 @@ export default {
<report-section
v-if="sastContainerHeadPath"
:always-open="alwaysOpen"
:type="$options.sastContainer"
:component="$options.componentNames.SastContainerIssueBody"
:status="checkReportStatus(sastContainer.isLoading, sastContainer.hasError)"
:loading-text="translateText('Container scanning').loading"
:error-text="translateText('Container scanning').error"
......@@ -258,7 +256,7 @@ export default {
<report-section
v-if="dastHeadPath"
:always-open="alwaysOpen"
:type="$options.dast"
:component="$options.componentNames.DastIssueBody"
:status="checkReportStatus(dast.isLoading, dast.hasError)"
:loading-text="translateText('DAST').loading"
:error-text="translateText('DAST').error"
......
import Vue from 'vue';
import component from 'ee/vue_merge_request_widget/components/codequality_issue_body.vue';
import mountComponent from '../../helpers/vue_mount_component_helper';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import {
STATUS_FAILED,
STATUS_NEUTRAL,
STATUS_SUCCESS,
} from '~/vue_shared/components/reports/constants';
describe('sast issue body', () => {
describe('code quality issue body issue body', () => {
let vm;
const Component = Vue.extend(component);
......@@ -22,7 +27,7 @@ describe('sast issue body', () => {
it('renders fixed label', () => {
vm = mountComponent(Component, {
issue: codequalityIssue,
isStatusSuccess: true,
status: STATUS_SUCCESS,
});
expect(vm.$el.textContent.trim()).toContain('Fixed');
......@@ -33,7 +38,7 @@ describe('sast issue body', () => {
it('renders fixed label', () => {
vm = mountComponent(Component, {
issue: codequalityIssue,
isStatusSuccess: false,
status: STATUS_FAILED,
});
expect(vm.$el.textContent.trim()).not.toContain('Fixed');
......@@ -44,7 +49,7 @@ describe('sast issue body', () => {
it('renders name', () => {
vm = mountComponent(Component, {
issue: codequalityIssue,
isStatusSuccess: false,
status: STATUS_NEUTRAL,
});
expect(vm.$el.textContent.trim()).toContain(codequalityIssue.name);
......@@ -55,15 +60,11 @@ describe('sast issue body', () => {
it('renders name', () => {
vm = mountComponent(Component, {
issue: codequalityIssue,
isStatusSuccess: false,
status: STATUS_NEUTRAL,
});
expect(vm.$el.querySelector('a').getAttribute('href')).toEqual(
codequalityIssue.urlPath,
);
expect(vm.$el.querySelector('a').textContent.trim()).toEqual(
codequalityIssue.path,
);
expect(vm.$el.querySelector('a').getAttribute('href')).toEqual(codequalityIssue.urlPath);
expect(vm.$el.querySelector('a').textContent.trim()).toEqual(codequalityIssue.path);
});
});
});
import Vue from 'vue';
import component from 'ee/vue_merge_request_widget/components/performance_issue_body.vue';
import mountComponent from '../../helpers/vue_mount_component_helper';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
describe('performance issue body', () => {
let vm;
......
import Vue from 'vue';
import reportIssues from '~/vue_shared/components/reports/report_issues.vue';
import { STATUS_FAILED, STATUS_SUCCESS } from '~/vue_shared/components/reports/constants';
import { componentNames } from 'ee/vue_shared/components/reports/issue_body';
import store from 'ee/vue_shared/security_reports/store';
import mountComponent, { mountComponentWithStore } from 'spec/helpers/vue_mount_component_helper';
import {
codequalityParsedIssues,
} from 'spec/vue_mr_widget/mock_data';
import { codequalityParsedIssues } from 'spec/vue_mr_widget/mock_data';
import {
sastParsedIssues,
dockerReportParsed,
......@@ -28,8 +28,8 @@ describe('Report issues', () => {
beforeEach(() => {
vm = mountComponent(ReportIssues, {
issues: codequalityParsedIssues,
type: 'codequality',
status: 'success',
component: componentNames.CodequalityIssueBody,
status: STATUS_SUCCESS,
});
});
......@@ -49,8 +49,8 @@ describe('Report issues', () => {
beforeEach(() => {
vm = mountComponent(ReportIssues, {
issues: codequalityParsedIssues,
type: 'codequality',
status: 'failed',
component: componentNames.CodequalityIssueBody,
status: STATUS_FAILED,
});
});
......@@ -68,8 +68,8 @@ describe('Report issues', () => {
beforeEach(() => {
vm = mountComponent(ReportIssues, {
issues: sastParsedIssues,
type: 'SAST',
status: 'failed',
component: componentNames.SastIssueBody,
status: STATUS_FAILED,
});
});
......@@ -82,8 +82,8 @@ describe('Report issues', () => {
it('should render location', () => {
vm = mountComponent(ReportIssues, {
issues: sastParsedIssues,
type: 'SAST',
status: 'failed',
component: componentNames.SastIssueBody,
status: STATUS_FAILED,
});
expect(vm.$el.querySelector('.report-block-list li').textContent).toContain('in');
......@@ -97,8 +97,8 @@ describe('Report issues', () => {
issues: [{
title: 'foo',
}],
type: 'SAST',
status: 'failed',
component: componentNames.SastIssueBody,
status: STATUS_SUCCESS,
});
expect(vm.$el.querySelector('.report-block-list li').textContent).not.toContain('in');
......@@ -110,8 +110,8 @@ describe('Report issues', () => {
beforeEach(() => {
vm = mountComponent(ReportIssues, {
issues: dockerReportParsed.unapproved,
type: 'SAST_CONTAINER',
status: 'failed',
component: componentNames.SastContainerIssueBody,
status: STATUS_FAILED,
});
});
......@@ -142,8 +142,8 @@ describe('Report issues', () => {
vm = mountComponentWithStore(ReportIssues, { store,
props: {
issues: parsedDast,
type: 'DAST',
status: 'failed',
component: componentNames.DastIssueBody,
status: STATUS_FAILED,
},
});
});
......
// eslint-disable-next-line import/prefer-default-export
export const fullReport = {
status: 'SUCCESS',
successText: 'SAST improved on 1 security vulnerability and degraded on 1 security vulnerability',
errorText: 'Failed to load security report',
hasIssues: true,
loadingText: 'Loading security report',
resolvedIssues: [
{
cve: 'CVE-2016-9999',
file: 'Gemfile.lock',
message: 'Test Information Leak Vulnerability in Action View',
title: 'Test Information Leak Vulnerability in Action View',
path: 'Gemfile.lock',
solution:
'upgrade to >= 5.0.0.beta1.1, >= 4.2.5.1, ~> 4.2.5, >= 4.1.14.1, ~> 4.1.14, ~> 3.2.22.1',
tool: 'bundler_audit',
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/335P1DcLG00',
urlPath: '/Gemfile.lock',
},
],
unresolvedIssues: [
{
cve: 'CVE-2014-7829',
file: 'Gemfile.lock',
message: 'Arbitrary file existence disclosure in Action Pack',
title: 'Arbitrary file existence disclosure in Action Pack',
path: 'Gemfile.lock',
solution: 'upgrade to ~> 3.2.21, ~> 4.0.11.1, ~> 4.0.12, ~> 4.1.7.1, >= 4.1.8',
tool: 'bundler_audit',
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/rMTQy4oRCGk',
urlPath: '/Gemfile.lock',
},
],
allIssues: [
{
cve: 'CVE-2016-0752',
file: 'Gemfile.lock',
message: 'Possible Information Leak Vulnerability in Action View',
title: 'Possible Information Leak Vulnerability in Action View',
path: 'Gemfile.lock',
solution:
'upgrade to >= 5.0.0.beta1.1, >= 4.2.5.1, ~> 4.2.5, >= 4.1.14.1, ~> 4.1.14, ~> 3.2.22.1',
tool: 'bundler_audit',
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/335P1DcLG00',
urlPath: '/Gemfile.lock',
},
],
};
import Vue from 'vue';
import reportSection from '~/vue_shared/components/reports/report_section.vue';
import { componentNames } from 'ee/vue_shared/components/reports/issue_body';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { fullReport } from './report_section_mock_data';
describe('Report section', () => {
let vm;
const ReportSection = Vue.extend(reportSection);
afterEach(() => {
vm.$destroy();
});
describe('With full report', () => {
beforeEach(() => {
vm = mountComponent(ReportSection, {
component: componentNames.SastIssueBody,
...fullReport,
});
});
it('should render full report section', done => {
vm.$el.querySelector('button').click();
Vue.nextTick(() => {
expect(vm.$el.querySelector('.js-expand-full-list').textContent.trim()).toEqual(
'Show complete code vulnerabilities report',
);
done();
});
});
it('should expand full list when clicked and hide the show all button', done => {
vm.$el.querySelector('button').click();
Vue.nextTick(() => {
vm.$el.querySelector('.js-expand-full-list').click();
Vue.nextTick(() => {
expect(vm.$el.querySelector('.js-mr-code-all-issues').textContent.trim()).toContain(
'Possible Information Leak Vulnerability in Action View',
);
done();
});
});
});
});
});
......@@ -23,7 +23,7 @@ describe('Report section', () => {
describe('computed', () => {
beforeEach(() => {
vm = mountComponent(ReportSection, {
type: 'codequality',
component: '',
status: 'SUCCESS',
loadingText: 'Loading codeclimate report',
errorText: 'foo',
......@@ -89,7 +89,7 @@ describe('Report section', () => {
describe('when it is loading', () => {
it('should render loading indicator', () => {
vm = mountComponent(ReportSection, {
type: 'codequality',
component: '',
status: 'LOADING',
loadingText: 'Loading codeclimate report',
errorText: 'foo',
......@@ -103,7 +103,7 @@ describe('Report section', () => {
describe('with success status', () => {
beforeEach(() => {
vm = mountComponent(ReportSection, {
type: 'codequality',
component: '',
status: 'SUCCESS',
loadingText: 'Loading codeclimate report',
errorText: 'foo',
......@@ -161,7 +161,7 @@ describe('Report section', () => {
describe('with failed request', () => {
it('should render error indicator', () => {
vm = mountComponent(ReportSection, {
type: 'codequality',
component: '',
status: 'ERROR',
loadingText: 'Loading codeclimate report',
errorText: 'Failed to load codeclimate report',
......@@ -171,87 +171,4 @@ describe('Report section', () => {
expect(vm.$el.textContent.trim()).toEqual('Failed to load codeclimate report');
});
});
describe('With full report', () => {
beforeEach(() => {
vm = mountComponent(ReportSection, {
status: 'SUCCESS',
successText:
'SAST improved on 1 security vulnerability and degraded on 1 security vulnerability',
type: 'SAST',
errorText: 'Failed to load security report',
hasIssues: true,
loadingText: 'Loading security report',
resolvedIssues: [
{
cve: 'CVE-2016-9999',
file: 'Gemfile.lock',
message: 'Test Information Leak Vulnerability in Action View',
title: 'Test Information Leak Vulnerability in Action View',
path: 'Gemfile.lock',
solution:
'upgrade to >= 5.0.0.beta1.1, >= 4.2.5.1, ~> 4.2.5, >= 4.1.14.1, ~> 4.1.14, ~> 3.2.22.1',
tool: 'bundler_audit',
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/335P1DcLG00',
urlPath: '/Gemfile.lock',
},
],
unresolvedIssues: [
{
cve: 'CVE-2014-7829',
file: 'Gemfile.lock',
message: 'Arbitrary file existence disclosure in Action Pack',
title: 'Arbitrary file existence disclosure in Action Pack',
path: 'Gemfile.lock',
solution: 'upgrade to ~> 3.2.21, ~> 4.0.11.1, ~> 4.0.12, ~> 4.1.7.1, >= 4.1.8',
tool: 'bundler_audit',
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/rMTQy4oRCGk',
urlPath: '/Gemfile.lock',
},
],
allIssues: [
{
cve: 'CVE-2016-0752',
file: 'Gemfile.lock',
message: 'Possible Information Leak Vulnerability in Action View',
title: 'Possible Information Leak Vulnerability in Action View',
path: 'Gemfile.lock',
solution:
'upgrade to >= 5.0.0.beta1.1, >= 4.2.5.1, ~> 4.2.5, >= 4.1.14.1, ~> 4.1.14, ~> 3.2.22.1',
tool: 'bundler_audit',
url: 'https://groups.google.com/forum/#!topic/rubyonrails-security/335P1DcLG00',
urlPath: '/Gemfile.lock',
},
],
});
});
it('should render full report section', done => {
vm.$el.querySelector('button').click();
Vue.nextTick(() => {
expect(vm.$el.querySelector('.js-expand-full-list').textContent.trim()).toEqual(
'Show complete code vulnerabilities report',
);
done();
});
});
it('should expand full list when clicked and hide the show all button', done => {
vm.$el.querySelector('button').click();
Vue.nextTick(() => {
vm.$el.querySelector('.js-expand-full-list').click();
Vue.nextTick(() => {
expect(vm.$el.querySelector('.js-mr-code-all-issues').textContent.trim()).toContain(
'Possible Information Leak Vulnerability in Action View',
);
done();
});
});
});
});
});
import Vue from 'vue';
import component from 'ee/vue_shared/security_reports/components/sast_issue_body.vue';
import mountComponent from '../../../helpers/vue_mount_component_helper';
import mountComponent from 'spec/helpers/vue_mount_component_helper';
import { STATUS_FAILED } from '~/vue_shared/components/reports/constants';
describe('sast issue body', () => {
let vm;
......@@ -23,7 +24,7 @@ describe('sast issue body', () => {
confidence: 'Low',
};
const status = 'failed';
const status = STATUS_FAILED;
afterEach(() => {
vm.$destroy();
......
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