Commit 74021c8d authored by Mark Florian's avatar Mark Florian

Move security scan status strings to frontend

This moves the status strings from the Rails ConfigurationPresenter to
Vue components in the frontend.

This also updates the pinning tests in the previous commit. It's best to
ignore whitespace changes when viewing this commit, since there are some
indentation changes in the snapshots. For example:

    git show <this commit> --ignore-all-space

Addresses https://gitlab.com/gitlab-org/gitlab/-/issues/323375.
parent b38f54ed
/**
* Return the union of the given components' props options. Required props take
* precendence over non-required props of the same name.
*
* This makes two assumptions:
* - All given components define their props in verbose object format.
* - The components all agree on the `type` of a common prop.
*
* @param {object[]} components The components to derive the union from.
* @returns {object} The union of the props of the given components.
*/
export const propsUnion = (components) =>
components.reduce((acc, component) => {
Object.entries(component.props ?? {}).forEach(([propName, propOptions]) => {
if (process.env.NODE_ENV !== 'production') {
if (typeof propOptions !== 'object' || !('type' in propOptions)) {
throw new Error(
`Cannot create props union: expected verbose prop options for prop "${propName}"`,
);
}
if (propName in acc && acc[propName]?.type !== propOptions?.type) {
throw new Error(
`Cannot create props union: incompatible prop types for prop "${propName}"`,
);
}
}
if (!(propName in acc) || propOptions.required) {
acc[propName] = propOptions;
}
});
return acc;
}, {});
...@@ -88,6 +88,7 @@ export default { ...@@ -88,6 +88,7 @@ export default {
:feature="item" :feature="item"
:gitlab-ci-present="gitlabCiPresent" :gitlab-ci-present="gitlabCiPresent"
:gitlab-ci-history-path="gitlabCiHistoryPath" :gitlab-ci-history-path="gitlabCiHistoryPath"
:auto-devops-enabled="autoDevopsEnabled"
/> />
</template> </template>
......
<script> <script>
import { GlLink } from '@gitlab/ui'; import { propsUnion } from '~/vue_shared/components/lib/utils/props_utils';
import {
REPORT_TYPE_SAST,
REPORT_TYPE_DAST_PROFILES,
} from '~/vue_shared/security_reports/constants';
import StatusDastProfiles from './status_dast_profiles.vue';
import StatusGeneric from './status_generic.vue';
import StatusSast from './status_sast.vue';
const scannerComponentMap = {
[REPORT_TYPE_SAST]: StatusSast,
[REPORT_TYPE_DAST_PROFILES]: StatusDastProfiles,
};
export default { export default {
components: { inheritAttrs: false,
GlLink, props: propsUnion([StatusGeneric, ...Object.values(scannerComponentMap)]),
},
props: {
feature: {
type: Object,
required: true,
},
gitlabCiPresent: {
type: Boolean,
required: false,
default: false,
},
gitlabCiHistoryPath: {
type: String,
required: false,
default: '',
},
},
computed: { computed: {
canViewCiHistory() { statusComponent() {
const { type, configured } = this.feature; return scannerComponentMap[this.feature.type] ?? StatusGeneric;
return type === 'sast' && configured && this.gitlabCiPresent;
}, },
}, },
}; };
</script> </script>
<template> <template>
<div> <component :is="statusComponent" v-bind="$props" />
{{ feature.status }}
<template v-if="canViewCiHistory">
<br />
<gl-link :href="gitlabCiHistoryPath">{{ s__('SecurityConfiguration|View history') }}</gl-link>
</template>
</div>
</template> </template>
<script>
import { s__ } from '~/locale';
export default {
inheritAttrs: false,
i18n: {
availableForOnDemand: s__('SecurityConfiguration|Available for on-demand DAST'),
},
};
</script>
<template>
<div>{{ $options.i18n.availableForOnDemand }}</div>
</template>
<script>
import { s__ } from '~/locale';
export default {
inheritAttrs: false,
props: {
feature: {
type: Object,
required: true,
},
autoDevopsEnabled: {
type: Boolean,
required: true,
},
},
computed: {
status() {
if (this.feature.configured) {
return this.autoDevopsEnabled
? this.$options.i18n.enabledWithAutoDevOps
: this.$options.i18n.enabled;
}
return this.$options.i18n.notEnabled;
},
},
i18n: {
enabled: s__('SecurityConfiguration|Enabled'),
enabledWithAutoDevOps: s__('SecurityConfiguration|Enabled with Auto DevOps'),
notEnabled: s__('SecurityConfiguration|Not enabled'),
},
};
</script>
<template>
<div>{{ status }}</div>
</template>
<script>
import { GlLink } from '@gitlab/ui';
import StatusGeneric from './status_generic.vue';
export default {
components: {
GlLink,
StatusGeneric,
},
inheritAttrs: false,
props: {
feature: {
type: Object,
required: true,
},
autoDevopsEnabled: {
type: Boolean,
required: true,
},
gitlabCiPresent: {
type: Boolean,
required: false,
default: false,
},
gitlabCiHistoryPath: {
type: String,
required: false,
default: '',
},
},
computed: {
canViewCiHistory() {
return this.feature.configured && this.gitlabCiPresent;
},
},
};
</script>
<template>
<div>
<status-generic :feature="feature" :auto-devops-enabled="autoDevopsEnabled" />
<gl-link v-if="canViewCiHistory" :href="gitlabCiHistoryPath">{{
s__('SecurityConfiguration|View history')
}}</gl-link>
</div>
</template>
...@@ -58,14 +58,11 @@ module Projects ...@@ -58,14 +58,11 @@ module Projects
def features def features
scans = scan_types.map do |scan_type| scans = scan_types.map do |scan_type|
if scanner_enabled?(scan_type) scan(scan_type, configured: scanner_enabled?(scan_type))
scan(scan_type, configured: true, status: auto_devops_source? ? s_('SecurityConfiguration|Enabled with Auto DevOps') : s_('SecurityConfiguration|Enabled'))
else
scan(scan_type, configured: false, status: s_('SecurityConfiguration|Not enabled'))
end
end end
dast_profiles_insert(scans) # DAST On-demand scans is a static (non job) entry. Add it manually.
scans << scan(:dast_profiles, configured: true)
end end
def latest_pipeline_path def latest_pipeline_path
...@@ -74,23 +71,10 @@ module Projects ...@@ -74,23 +71,10 @@ module Projects
project_pipeline_path(self, latest_default_branch_pipeline) project_pipeline_path(self, latest_default_branch_pipeline)
end end
# DAST On-demand scans is a static (non job) entry. Add it manually following DAST def scan(type, configured: false)
# TODO: remove as part of https://gitlab.com/gitlab-org/gitlab/-/issues/323375
def dast_profiles_insert(scans)
index = scans.index { |scan| scan[:type] == :dast }
unless index.nil?
scans.insert(index + 1, scan(:dast_profiles, configured: true, status: s_('SecurityConfiguration|Available for on-demand DAST')))
end
scans
end
def scan(type, configured: false, status:)
{ {
type: type, type: type,
configured: configured, configured: configured,
status: status,
configuration_path: configuration_path(type) configuration_path: configuration_path(type)
} }
end end
......
...@@ -39,9 +39,9 @@ exports[`Security Configuration App given no enabled scanners matches the snapsh ...@@ -39,9 +39,9 @@ exports[`Security Configuration App given no enabled scanners matches the snapsh
<table <table
aria-busy="false" aria-busy="false"
aria-colcount="3" aria-colcount="3"
aria-describedby="__BVID__76__caption_" aria-describedby="__BVID__86__caption_"
class="table b-table gl-table b-table-stacked-md" class="table b-table gl-table b-table-stacked-md"
id="__BVID__76" id="__BVID__86"
role="table" role="table"
> >
<!----> <!---->
...@@ -129,9 +129,10 @@ exports[`Security Configuration App given no enabled scanners matches the snapsh ...@@ -129,9 +129,10 @@ exports[`Security Configuration App given no enabled scanners matches the snapsh
> >
<div> <div>
<div> <div>
<div>
Not enabled Not enabled
</div>
<!----> <!---->
</div> </div>
</div> </div>
...@@ -205,10 +206,7 @@ exports[`Security Configuration App given no enabled scanners matches the snapsh ...@@ -205,10 +206,7 @@ exports[`Security Configuration App given no enabled scanners matches the snapsh
> >
<div> <div>
<div> <div>
Not enabled
Not enabled
<!---->
</div> </div>
</div> </div>
</td> </td>
...@@ -267,10 +265,7 @@ exports[`Security Configuration App given no enabled scanners matches the snapsh ...@@ -267,10 +265,7 @@ exports[`Security Configuration App given no enabled scanners matches the snapsh
> >
<div> <div>
<div> <div>
Available for on-demand DAST
Available for on-demand DAST
<!---->
</div> </div>
</div> </div>
</td> </td>
...@@ -343,10 +338,7 @@ exports[`Security Configuration App given no enabled scanners matches the snapsh ...@@ -343,10 +338,7 @@ exports[`Security Configuration App given no enabled scanners matches the snapsh
> >
<div> <div>
<div> <div>
Not enabled
Not enabled
<!---->
</div> </div>
</div> </div>
</td> </td>
...@@ -405,10 +397,7 @@ exports[`Security Configuration App given no enabled scanners matches the snapsh ...@@ -405,10 +397,7 @@ exports[`Security Configuration App given no enabled scanners matches the snapsh
> >
<div> <div>
<div> <div>
Not enabled
Not enabled
<!---->
</div> </div>
</div> </div>
</td> </td>
...@@ -467,10 +456,7 @@ exports[`Security Configuration App given no enabled scanners matches the snapsh ...@@ -467,10 +456,7 @@ exports[`Security Configuration App given no enabled scanners matches the snapsh
> >
<div> <div>
<div> <div>
Not enabled
Not enabled
<!---->
</div> </div>
</div> </div>
</td> </td>
...@@ -529,10 +515,7 @@ exports[`Security Configuration App given no enabled scanners matches the snapsh ...@@ -529,10 +515,7 @@ exports[`Security Configuration App given no enabled scanners matches the snapsh
> >
<div> <div>
<div> <div>
Not enabled
Not enabled
<!---->
</div> </div>
</div> </div>
</td> </td>
...@@ -591,10 +574,7 @@ exports[`Security Configuration App given no enabled scanners matches the snapsh ...@@ -591,10 +574,7 @@ exports[`Security Configuration App given no enabled scanners matches the snapsh
> >
<div> <div>
<div> <div>
Not enabled
Not enabled
<!---->
</div> </div>
</div> </div>
</td> </td>
...@@ -653,10 +633,7 @@ exports[`Security Configuration App given no enabled scanners matches the snapsh ...@@ -653,10 +633,7 @@ exports[`Security Configuration App given no enabled scanners matches the snapsh
> >
<div> <div>
<div> <div>
Not enabled
Not enabled
<!---->
</div> </div>
</div> </div>
</td> </td>
...@@ -721,9 +698,9 @@ exports[`Security Configuration App given some enabled by ADO matches the snapsh ...@@ -721,9 +698,9 @@ exports[`Security Configuration App given some enabled by ADO matches the snapsh
<table <table
aria-busy="false" aria-busy="false"
aria-colcount="3" aria-colcount="3"
aria-describedby="__BVID__139__caption_" aria-describedby="__BVID__159__caption_"
class="table b-table gl-table b-table-stacked-md" class="table b-table gl-table b-table-stacked-md"
id="__BVID__139" id="__BVID__159"
role="table" role="table"
> >
<!----> <!---->
...@@ -811,9 +788,10 @@ exports[`Security Configuration App given some enabled by ADO matches the snapsh ...@@ -811,9 +788,10 @@ exports[`Security Configuration App given some enabled by ADO matches the snapsh
> >
<div> <div>
<div> <div>
<div>
Not enabled Not enabled
</div>
<!----> <!---->
</div> </div>
</div> </div>
...@@ -887,10 +865,7 @@ exports[`Security Configuration App given some enabled by ADO matches the snapsh ...@@ -887,10 +865,7 @@ exports[`Security Configuration App given some enabled by ADO matches the snapsh
> >
<div> <div>
<div> <div>
Not enabled
Not enabled
<!---->
</div> </div>
</div> </div>
</td> </td>
...@@ -949,10 +924,7 @@ exports[`Security Configuration App given some enabled by ADO matches the snapsh ...@@ -949,10 +924,7 @@ exports[`Security Configuration App given some enabled by ADO matches the snapsh
> >
<div> <div>
<div> <div>
Available for on-demand DAST
Available for on-demand DAST
<!---->
</div> </div>
</div> </div>
</td> </td>
...@@ -1025,10 +997,7 @@ exports[`Security Configuration App given some enabled by ADO matches the snapsh ...@@ -1025,10 +997,7 @@ exports[`Security Configuration App given some enabled by ADO matches the snapsh
> >
<div> <div>
<div> <div>
Not enabled
Not enabled
<!---->
</div> </div>
</div> </div>
</td> </td>
...@@ -1087,10 +1056,7 @@ exports[`Security Configuration App given some enabled by ADO matches the snapsh ...@@ -1087,10 +1056,7 @@ exports[`Security Configuration App given some enabled by ADO matches the snapsh
> >
<div> <div>
<div> <div>
Enabled with Auto DevOps
Enabled with Auto DevOps
<!---->
</div> </div>
</div> </div>
</td> </td>
...@@ -1149,10 +1115,7 @@ exports[`Security Configuration App given some enabled by ADO matches the snapsh ...@@ -1149,10 +1115,7 @@ exports[`Security Configuration App given some enabled by ADO matches the snapsh
> >
<div> <div>
<div> <div>
Enabled with Auto DevOps
Enabled with Auto DevOps
<!---->
</div> </div>
</div> </div>
</td> </td>
...@@ -1211,10 +1174,7 @@ exports[`Security Configuration App given some enabled by ADO matches the snapsh ...@@ -1211,10 +1174,7 @@ exports[`Security Configuration App given some enabled by ADO matches the snapsh
> >
<div> <div>
<div> <div>
Not enabled
Not enabled
<!---->
</div> </div>
</div> </div>
</td> </td>
...@@ -1273,10 +1233,7 @@ exports[`Security Configuration App given some enabled by ADO matches the snapsh ...@@ -1273,10 +1233,7 @@ exports[`Security Configuration App given some enabled by ADO matches the snapsh
> >
<div> <div>
<div> <div>
Not enabled
Not enabled
<!---->
</div> </div>
</div> </div>
</td> </td>
...@@ -1349,10 +1306,7 @@ exports[`Security Configuration App given some enabled by ADO matches the snapsh ...@@ -1349,10 +1306,7 @@ exports[`Security Configuration App given some enabled by ADO matches the snapsh
> >
<div> <div>
<div> <div>
Enabled with Auto DevOps
Enabled with Auto DevOps
<!---->
</div> </div>
</div> </div>
</td> </td>
...@@ -1507,10 +1461,9 @@ exports[`Security Configuration App given some enabled scanners (gitlab-ui) matc ...@@ -1507,10 +1461,9 @@ exports[`Security Configuration App given some enabled scanners (gitlab-ui) matc
> >
<div> <div>
<div> <div>
<div>
Enabled Enabled
</div>
<br />
<a <a
class="gl-link" class="gl-link"
...@@ -1590,10 +1543,7 @@ exports[`Security Configuration App given some enabled scanners (gitlab-ui) matc ...@@ -1590,10 +1543,7 @@ exports[`Security Configuration App given some enabled scanners (gitlab-ui) matc
> >
<div> <div>
<div> <div>
Not enabled
Not enabled
<!---->
</div> </div>
</div> </div>
</td> </td>
...@@ -1652,10 +1602,7 @@ exports[`Security Configuration App given some enabled scanners (gitlab-ui) matc ...@@ -1652,10 +1602,7 @@ exports[`Security Configuration App given some enabled scanners (gitlab-ui) matc
> >
<div> <div>
<div> <div>
Available for on-demand DAST
Available for on-demand DAST
<!---->
</div> </div>
</div> </div>
</td> </td>
...@@ -1728,10 +1675,7 @@ exports[`Security Configuration App given some enabled scanners (gitlab-ui) matc ...@@ -1728,10 +1675,7 @@ exports[`Security Configuration App given some enabled scanners (gitlab-ui) matc
> >
<div> <div>
<div> <div>
Enabled
Enabled
<!---->
</div> </div>
</div> </div>
</td> </td>
...@@ -1790,10 +1734,7 @@ exports[`Security Configuration App given some enabled scanners (gitlab-ui) matc ...@@ -1790,10 +1734,7 @@ exports[`Security Configuration App given some enabled scanners (gitlab-ui) matc
> >
<div> <div>
<div> <div>
Enabled
Enabled
<!---->
</div> </div>
</div> </div>
</td> </td>
...@@ -1852,10 +1793,7 @@ exports[`Security Configuration App given some enabled scanners (gitlab-ui) matc ...@@ -1852,10 +1793,7 @@ exports[`Security Configuration App given some enabled scanners (gitlab-ui) matc
> >
<div> <div>
<div> <div>
Enabled
Enabled
<!---->
</div> </div>
</div> </div>
</td> </td>
...@@ -1914,10 +1852,7 @@ exports[`Security Configuration App given some enabled scanners (gitlab-ui) matc ...@@ -1914,10 +1852,7 @@ exports[`Security Configuration App given some enabled scanners (gitlab-ui) matc
> >
<div> <div>
<div> <div>
Not enabled
Not enabled
<!---->
</div> </div>
</div> </div>
</td> </td>
...@@ -1976,10 +1911,7 @@ exports[`Security Configuration App given some enabled scanners (gitlab-ui) matc ...@@ -1976,10 +1911,7 @@ exports[`Security Configuration App given some enabled scanners (gitlab-ui) matc
> >
<div> <div>
<div> <div>
Not enabled
Not enabled
<!---->
</div> </div>
</div> </div>
</td> </td>
...@@ -2052,10 +1984,7 @@ exports[`Security Configuration App given some enabled scanners (gitlab-ui) matc ...@@ -2052,10 +1984,7 @@ exports[`Security Configuration App given some enabled scanners (gitlab-ui) matc
> >
<div> <div>
<div> <div>
Enabled
Enabled
<!---->
</div> </div>
</div> </div>
</td> </td>
......
...@@ -65,6 +65,7 @@ describe('ConfigurationTable component', () => { ...@@ -65,6 +65,7 @@ describe('ConfigurationTable component', () => {
feature, feature,
gitlabCiPresent: propsData.gitlabCiPresent, gitlabCiPresent: propsData.gitlabCiPresent,
gitlabCiHistoryPath: propsData.gitlabCiHistoryPath, gitlabCiHistoryPath: propsData.gitlabCiHistoryPath,
autoDevopsEnabled: propsData.autoDevopsEnabled,
}); });
expect(manage.find(ManageFeature).props()).toEqual({ expect(manage.find(ManageFeature).props()).toEqual({
feature, feature,
......
import { GlLink } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils'; import { shallowMount } from '@vue/test-utils';
import { pick } from 'lodash';
import FeatureStatus from 'ee/security_configuration/components/feature_status.vue'; import FeatureStatus from 'ee/security_configuration/components/feature_status.vue';
import StatusDastProfiles from 'ee/security_configuration/components/status_dast_profiles.vue';
import StatusGeneric from 'ee/security_configuration/components/status_generic.vue';
import StatusSast from 'ee/security_configuration/components/status_sast.vue';
import {
REPORT_TYPE_SAST,
REPORT_TYPE_DAST_PROFILES,
} from '~/vue_shared/security_reports/constants';
import { generateFeatures } from './helpers'; import { generateFeatures } from './helpers';
const gitlabCiHistoryPath = '/ci/history'; const props = {
gitlabCiPresent: true,
gitlabCiHistoryPath: '/ci-history',
autoDevopsEnabled: false,
};
const attrs = {
'data-foo': 'bar',
};
describe('FeatureStatus component', () => { describe('FeatureStatus component', () => {
let wrapper; let wrapper;
let feature;
const createComponent = (options) => { const createComponent = (options) => {
wrapper = shallowMount(FeatureStatus, options); wrapper = shallowMount(FeatureStatus, options);
...@@ -15,39 +29,37 @@ describe('FeatureStatus component', () => { ...@@ -15,39 +29,37 @@ describe('FeatureStatus component', () => {
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
feature = undefined;
}); });
const findHistoryLink = () => wrapper.find(GlLink);
describe.each` describe.each`
context | type | configured | gitlabCiPresent | shouldShowHistory type | expectedComponent
${'no CI with sast disabled'} | ${'sast'} | ${false} | ${false} | ${false} ${REPORT_TYPE_SAST} | ${StatusSast}
${'CI with sast disabled'} | ${'sast'} | ${false} | ${true} | ${false} ${REPORT_TYPE_DAST_PROFILES} | ${StatusDastProfiles}
${'no CI with sast enabled'} | ${'sast'} | ${true} | ${false} | ${false} ${'foo'} | ${StatusGeneric}
${'CI with foo enabled'} | ${'foo'} | ${true} | ${true} | ${false} `('given a $type feature', ({ type, expectedComponent }) => {
${'CI with sast enabled'} | ${'sast'} | ${true} | ${true} | ${true} let feature;
`('given $context', ({ type, configured, gitlabCiPresent, shouldShowHistory }) => { let component;
beforeEach(() => { beforeEach(() => {
[feature] = generateFeatures(1, { type, configured }); [feature] = generateFeatures(1, { type });
createComponent({ createComponent({
propsData: { feature, gitlabCiPresent, gitlabCiHistoryPath }, propsData: { feature, ...props },
attrs,
}); });
});
it('shows feature status text', () => { component = wrapper.findComponent(expectedComponent);
expect(wrapper.text()).toContain(feature.status);
}); });
it(`${shouldShowHistory ? 'shows' : 'does not show'} the history link`, () => { it('renders expected component', () => {
expect(findHistoryLink().exists()).toBe(shouldShowHistory); expect(component.exists()).toBe(true);
}); });
if (shouldShowHistory) { it('passes through props to expected component', () => {
it("sets the link's href correctly", () => { // Exclude props not defined on the expected component, since
expect(findHistoryLink().attributes('href')).toBe(gitlabCiHistoryPath); // @vue/test-utils won't include them in `Wrapper#props`.
}); const expectedProps = pick({ feature, ...props }, Object.keys(expectedComponent.props ?? {}));
} expect(component.props()).toEqual(expectedProps);
});
}); });
}); });
import { shallowMount } from '@vue/test-utils';
import StatusDastProfiles from 'ee/security_configuration/components/status_dast_profiles.vue';
describe('StatusDastProfiles component', () => {
let wrapper;
const createComponent = () => {
wrapper = shallowMount(StatusDastProfiles);
};
afterEach(() => {
wrapper.destroy();
});
it('renders the fixed DAST Profiles status', () => {
createComponent();
expect(wrapper.element).toMatchInlineSnapshot(`
<div>
Available for on-demand DAST
</div>
`);
});
});
import { shallowMount } from '@vue/test-utils';
import StatusGeneric from 'ee/security_configuration/components/status_generic.vue';
import { generateFeatures } from './helpers';
describe('StatusGeneric component', () => {
let wrapper;
const createComponent = (options) => {
wrapper = shallowMount(StatusGeneric, options);
};
afterEach(() => {
wrapper.destroy();
});
describe.each`
context | configured | autoDevopsEnabled | status
${'not configured'} | ${false} | ${false} | ${StatusGeneric.i18n.notEnabled}
${'not configured, but Auto DevOps is enabled'} | ${false} | ${true} | ${StatusGeneric.i18n.notEnabled}
${'configured'} | ${true} | ${false} | ${StatusGeneric.i18n.enabled}
${'configured with Auto DevOps'} | ${true} | ${true} | ${StatusGeneric.i18n.enabledWithAutoDevOps}
`('given the feature is $context', ({ configured, autoDevopsEnabled, status }) => {
let feature;
beforeEach(() => {
[feature] = generateFeatures(1, { configured });
createComponent({
propsData: { feature, autoDevopsEnabled },
});
});
it(`shows the status "${status}"`, () => {
expect(wrapper.text()).toBe(status);
});
});
});
import { GlLink } from '@gitlab/ui';
import { shallowMount } from '@vue/test-utils';
import StatusGeneric from 'ee/security_configuration/components/status_generic.vue';
import StatusSast from 'ee/security_configuration/components/status_sast.vue';
import { REPORT_TYPE_SAST } from '~/vue_shared/security_reports/constants';
import { generateFeatures } from './helpers';
const gitlabCiHistoryPath = '/ci/history';
const autoDevopsEnabled = true;
describe('StatusSast component', () => {
let wrapper;
const createComponent = (options) => {
wrapper = shallowMount(StatusSast, options);
};
afterEach(() => {
wrapper.destroy();
});
const findHistoryLink = () => wrapper.find(GlLink);
describe.each`
context | configured | gitlabCiPresent | shouldShowHistory
${'no CI with sast disabled'} | ${false} | ${false} | ${false}
${'CI with sast disabled'} | ${false} | ${true} | ${false}
${'no CI with sast enabled'} | ${true} | ${false} | ${false}
${'CI with sast enabled'} | ${true} | ${true} | ${true}
`('given $context', ({ configured, gitlabCiPresent, shouldShowHistory }) => {
let feature;
beforeEach(() => {
[feature] = generateFeatures(1, { type: REPORT_TYPE_SAST, configured });
createComponent({
propsData: { feature, gitlabCiPresent, gitlabCiHistoryPath, autoDevopsEnabled },
});
});
it('shows the generic status', () => {
const genericComponent = wrapper.findComponent(StatusGeneric);
expect(genericComponent.exists()).toBe(true);
expect(genericComponent.props()).toEqual({
feature,
autoDevopsEnabled,
});
});
it(`${shouldShowHistory ? 'shows' : 'does not show'} the history link`, () => {
expect(findHistoryLink().exists()).toBe(shouldShowHistory);
});
if (shouldShowHistory) {
it("sets the link's href correctly", () => {
expect(findHistoryLink().attributes('href')).toBe(gitlabCiHistoryPath);
});
}
});
});
...@@ -80,15 +80,15 @@ RSpec.describe Projects::Security::ConfigurationPresenter do ...@@ -80,15 +80,15 @@ RSpec.describe Projects::Security::ConfigurationPresenter do
it 'reports that all scanners are configured for which latest pipeline has builds' do it 'reports that all scanners are configured for which latest pipeline has builds' do
expect(Gitlab::Json.parse(subject[:features])).to contain_exactly( expect(Gitlab::Json.parse(subject[:features])).to contain_exactly(
security_scan(:dast, configured: true, auto_dev_ops_enabled: true), security_scan(:dast, configured: true),
security_scan(:dast_profiles, configured: true, auto_dev_ops_enabled: true), security_scan(:sast, configured: true),
security_scan(:sast, configured: true, auto_dev_ops_enabled: true), security_scan(:container_scanning, configured: false),
security_scan(:container_scanning, configured: false, auto_dev_ops_enabled: true), security_scan(:dependency_scanning, configured: false),
security_scan(:dependency_scanning, configured: false, auto_dev_ops_enabled: true), security_scan(:license_scanning, configured: false),
security_scan(:license_scanning, configured: false, auto_dev_ops_enabled: true), security_scan(:secret_detection, configured: true),
security_scan(:secret_detection, configured: true, auto_dev_ops_enabled: true), security_scan(:coverage_fuzzing, configured: false),
security_scan(:coverage_fuzzing, configured: false, auto_dev_ops_enabled: true), security_scan(:api_fuzzing, configured: false),
security_scan(:api_fuzzing, configured: false, auto_dev_ops_enabled: true) security_scan(:dast_profiles, configured: true)
) )
end end
end end
...@@ -105,14 +105,14 @@ RSpec.describe Projects::Security::ConfigurationPresenter do ...@@ -105,14 +105,14 @@ RSpec.describe Projects::Security::ConfigurationPresenter do
it 'reports all security jobs as unconfigured' do it 'reports all security jobs as unconfigured' do
expect(Gitlab::Json.parse(subject[:features])).to contain_exactly( expect(Gitlab::Json.parse(subject[:features])).to contain_exactly(
security_scan(:dast, configured: false), security_scan(:dast, configured: false),
security_scan(:dast_profiles, configured: true),
security_scan(:sast, configured: false), security_scan(:sast, configured: false),
security_scan(:container_scanning, configured: false), security_scan(:container_scanning, configured: false),
security_scan(:dependency_scanning, configured: false), security_scan(:dependency_scanning, configured: false),
security_scan(:license_scanning, configured: false), security_scan(:license_scanning, configured: false),
security_scan(:secret_detection, configured: false), security_scan(:secret_detection, configured: false),
security_scan(:coverage_fuzzing, configured: false), security_scan(:coverage_fuzzing, configured: false),
security_scan(:api_fuzzing, configured: false) security_scan(:api_fuzzing, configured: false),
security_scan(:dast_profiles, configured: true)
) )
end end
end end
...@@ -254,15 +254,12 @@ RSpec.describe Projects::Security::ConfigurationPresenter do ...@@ -254,15 +254,12 @@ RSpec.describe Projects::Security::ConfigurationPresenter do
end end
end end
def security_scan(type, configured:, auto_dev_ops_enabled: false) def security_scan(type, configured:)
configuration_path = configuration_path(type) configuration_path = configuration_path(type)
status_str = scan_status(type, configured, auto_dev_ops_enabled)
{ {
"type" => type.to_s, "type" => type.to_s,
"configured" => configured, "configured" => configured,
"status" => status_str,
"configuration_path" => configuration_path "configuration_path" => configuration_path
} }
end end
...@@ -274,16 +271,4 @@ RSpec.describe Projects::Security::ConfigurationPresenter do ...@@ -274,16 +271,4 @@ RSpec.describe Projects::Security::ConfigurationPresenter do
api_fuzzing: project_security_configuration_api_fuzzing_path(project) api_fuzzing: project_security_configuration_api_fuzzing_path(project)
}[type] }[type]
end end
def scan_status(type, configured, auto_dev_ops_enabled)
if type == :dast_profiles
"Available for on-demand DAST"
elsif configured && auto_dev_ops_enabled
"Enabled with Auto DevOps"
elsif configured
"Enabled"
else
"Not enabled"
end
end
end end
import { propsUnion } from '~/vue_shared/components/lib/utils/props_utils';
describe('propsUnion', () => {
const stringRequired = {
type: String,
required: true,
};
const stringOptional = {
type: String,
required: false,
};
const numberOptional = {
type: Number,
required: false,
};
const booleanRequired = {
type: Boolean,
required: true,
};
const FooComponent = {
props: { foo: stringRequired },
};
const BarComponent = {
props: { bar: numberOptional },
};
const FooBarComponent = {
props: {
foo: stringRequired,
bar: numberOptional,
},
};
const FooOptionalComponent = {
props: {
foo: stringOptional,
},
};
const QuxComponent = {
props: {
foo: booleanRequired,
qux: stringRequired,
},
};
it('returns an empty object given no components', () => {
expect(propsUnion([])).toEqual({});
});
it('merges non-overlapping props', () => {
expect(propsUnion([FooComponent, BarComponent])).toEqual({
...FooComponent.props,
...BarComponent.props,
});
});
it('merges overlapping props', () => {
expect(propsUnion([FooComponent, BarComponent, FooBarComponent])).toEqual({
...FooComponent.props,
...BarComponent.props,
...FooBarComponent.props,
});
});
it.each`
components
${[FooComponent, FooOptionalComponent]}
${[FooOptionalComponent, FooComponent]}
`('prefers required props over non-required props', ({ components }) => {
expect(propsUnion(components)).toEqual(FooComponent.props);
});
it('throws if given props with conflicting types', () => {
expect(() => propsUnion([FooComponent, QuxComponent])).toThrow(/incompatible prop types/);
});
it.each`
components
${[{ props: ['foo', 'bar'] }]}
${[{ props: { foo: String, bar: Number } }]}
${[{ props: { foo: {}, bar: {} } }]}
`('throw if given a non-verbose props object', ({ components }) => {
expect(() => propsUnion(components)).toThrow(/expected verbose prop/);
});
});
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