Commit 2c5f9e76 authored by Mark Florian's avatar Mark Florian Committed by Phil Hughes

Split ManageFeature component by scanner type

This splits out scanner-specific management controls to separate
components, making it easier to add new ones/make scanner-specific
tweaks.

A very similar approach was taken in
https://gitlab.com/gitlab-org/gitlab/-/merge_requests/56555 for the
status of each feature/scanner.

Addresses https://gitlab.com/gitlab-org/gitlab/-/issues/323377.
parent 46d26300
......@@ -94,7 +94,7 @@ export default {
</template>
<template #cell(manage)="{ item }">
<manage-feature :feature="item" :auto-devops-enabled="autoDevopsEnabled" />
<manage-feature :feature="item" />
</template>
</gl-table>
</template>
<script>
import { GlButton } from '@gitlab/ui';
export default {
components: {
GlButton,
},
props: {
feature: {
type: Object,
required: true,
},
},
};
</script>
<template>
<gl-button :href="feature.configuration_path" data-testid="manage-button">{{
s__('SecurityConfiguration|Manage')
}}</gl-button>
</template>
<script>
import { GlButton } from '@gitlab/ui';
import { propsUnion } from '~/vue_shared/components/lib/utils/props_utils';
import { REPORT_TYPE_DAST_PROFILES } from '~/vue_shared/security_reports/constants';
import ManageDastProfiles from './manage_dast_profiles.vue';
import ManageGeneric from './manage_generic.vue';
const scannerComponentMap = {
[REPORT_TYPE_DAST_PROFILES]: ManageDastProfiles,
};
export default {
components: {
GlButton,
},
props: {
feature: {
type: Object,
required: true,
},
autoDevopsEnabled: {
type: Boolean,
required: true,
},
},
props: propsUnion([ManageGeneric, ...Object.values(scannerComponentMap)]),
computed: {
canConfigureFeature() {
return Boolean(this.feature.configuration_path);
},
canManageProfiles() {
return this.feature.type === 'dast_profiles';
manageComponent() {
return scannerComponentMap[this.feature.type] ?? ManageGeneric;
},
},
};
</script>
<template>
<gl-button
v-if="canManageProfiles"
:href="feature.configuration_path"
data-testid="manageButton"
>{{ s__('SecurityConfiguration|Manage') }}</gl-button
>
<gl-button
v-else-if="canConfigureFeature && feature.configured"
:href="feature.configuration_path"
data-testid="configureButton"
>{{ s__('SecurityConfiguration|Configure') }}</gl-button
>
<gl-button
v-else-if="canConfigureFeature"
variant="success"
category="primary"
:href="feature.configuration_path"
data-testid="enableButton"
:data-qa-selector="`${feature.type}_enable_button`"
>{{ s__('SecurityConfiguration|Enable') }}</gl-button
>
<component :is="manageComponent" v-bind="$props" />
</template>
<script>
import { GlButton } from '@gitlab/ui';
export default {
components: {
GlButton,
},
props: {
feature: {
type: Object,
required: true,
},
},
computed: {
canConfigure() {
return Boolean(this.feature.configuration_path && this.feature.configured);
},
canEnable() {
return Boolean(this.feature.configuration_path && !this.feature.configured);
},
},
};
</script>
<template>
<gl-button
v-if="canConfigure"
:href="feature.configuration_path"
data-testid="configure-button"
>{{ s__('SecurityConfiguration|Configure') }}</gl-button
>
<gl-button
v-else-if="canEnable"
variant="success"
category="primary"
:href="feature.configuration_path"
data-testid="enable-button"
:data-qa-selector="`${feature.type}_enable_button`"
>{{ s__('SecurityConfiguration|Enable') }}</gl-button
>
</template>
......@@ -26,7 +26,7 @@ RSpec.describe 'User sees Security Configuration table', :js do
within_sast_row do
expect(page).to have_text('SAST')
expect(page).to have_text('Not enabled')
expect(page).to have_css('[data-testid="enableButton"]')
expect(page).to have_css('[data-testid="enable-button"]')
end
end
end
......@@ -43,7 +43,7 @@ RSpec.describe 'User sees Security Configuration table', :js do
within_sast_row do
expect(page).to have_text('SAST')
expect(page).to have_text('Enabled')
expect(page).to have_css('[data-testid="configureButton"]')
expect(page).to have_css('[data-testid="configure-button"]')
end
end
end
......
......@@ -67,10 +67,7 @@ describe('ConfigurationTable component', () => {
gitlabCiHistoryPath: propsData.gitlabCiHistoryPath,
autoDevopsEnabled: propsData.autoDevopsEnabled,
});
expect(manage.find(ManageFeature).props()).toEqual({
feature,
autoDevopsEnabled: propsData.autoDevopsEnabled,
});
expect(manage.find(ManageFeature).props()).toEqual({ feature });
expect(description.find(GlLink).attributes('href')).toBe(feature.helpPath);
});
});
import { shallowMount } from '@vue/test-utils';
import ManageDastProfiles from 'ee/security_configuration/components/manage_dast_profiles.vue';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import { generateFeatures } from './helpers';
describe('ManageDastProfiles component', () => {
let wrapper;
const createComponent = (propsData) => {
wrapper = extendedWrapper(shallowMount(ManageDastProfiles, { propsData }));
};
const findButton = () => wrapper.findByTestId('manage-button');
afterEach(() => {
wrapper.destroy();
});
it('renders the DAST Profiles manage button', () => {
const [feature] = generateFeatures(1, { configuration_path: '/foo' });
createComponent({ feature });
const button = findButton();
expect(button.text()).toBe('Manage');
expect(button.attributes('href')).toBe(feature.configuration_path);
});
});
import { shallowMount } from '@vue/test-utils';
import { merge } from 'lodash';
import ManageDastProfiles from 'ee/security_configuration/components/manage_dast_profiles.vue';
import ManageFeature from 'ee/security_configuration/components/manage_feature.vue';
import ManageGeneric from 'ee/security_configuration/components/manage_generic.vue';
import { REPORT_TYPE_DAST_PROFILES } from '~/vue_shared/security_reports/constants';
import { generateFeatures } from './helpers';
const attrs = {
'data-qa-selector': 'foo',
};
describe('ManageFeature component', () => {
let wrapper;
let feature;
const createComponent = (options) => {
wrapper = shallowMount(
ManageFeature,
merge(
{
propsData: {
autoDevopsEnabled: false,
},
},
options,
),
);
wrapper = shallowMount(ManageFeature, options);
};
afterEach(() => {
wrapper.destroy();
});
const findTestId = (id) => wrapper.find(`[data-testid="${id}"]`);
describe.each`
configured | expectedTestId
${true} | ${'configureButton'}
${false} | ${'enableButton'}
`('given feature.configured is $configured', ({ configured, expectedTestId }) => {
describe('given a configuration path', () => {
describe('always', () => {
beforeEach(() => {
[feature] = generateFeatures(1, { configured, configuration_path: 'foo' });
createComponent({
propsData: { feature },
});
const [feature] = generateFeatures(1);
createComponent({ attrs, propsData: { feature } });
});
it('shows a button to configure the feature', () => {
const button = findTestId(expectedTestId);
expect(button.exists()).toBe(true);
expect(button.attributes('href')).toBe(feature.configuration_path);
});
it('passes through attributes to the expected component', () => {
expect(wrapper.attributes()).toMatchObject(attrs);
});
});
describe('given a feature with type "dast-profiles"', () => {
describe.each`
type | expectedComponent
${REPORT_TYPE_DAST_PROFILES} | ${ManageDastProfiles}
${'foo'} | ${ManageGeneric}
`('given a $type feature', ({ type, expectedComponent }) => {
let feature;
let component;
beforeEach(() => {
[feature] = generateFeatures(1, { type: 'dast_profiles', configuration_path: 'foo' });
[feature] = generateFeatures(1, { type });
createComponent({ propsData: { feature } });
createComponent({
propsData: { feature, autoDevopsEnabled: true },
component = wrapper.findComponent(expectedComponent);
});
it('renders expected component', () => {
expect(component.exists()).toBe(true);
});
it('shows the DAST Profiles manage button', () => {
const button = findTestId('manageButton');
expect(button.exists()).toBe(true);
expect(button.attributes('href')).toBe(feature.configuration_path);
it('passes through props to expected component', () => {
expect(component.props()).toEqual({ feature });
});
});
});
import { shallowMount } from '@vue/test-utils';
import ManageGeneric from 'ee/security_configuration/components/manage_generic.vue';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import { generateFeatures } from './helpers';
describe('ManageGeneric component', () => {
let wrapper;
let feature;
const createComponent = (propsData) => {
wrapper = extendedWrapper(shallowMount(ManageGeneric, { propsData }));
};
afterEach(() => {
wrapper.destroy();
});
describe.each`
configured | expectedTestId
${true} | ${'configure-button'}
${false} | ${'enable-button'}
`('given feature.configured is $configured', ({ configured, expectedTestId }) => {
describe('given a configuration path', () => {
beforeEach(() => {
[feature] = generateFeatures(1, { configured, configuration_path: 'foo' });
createComponent({ feature });
});
it('shows a button to configure the feature', () => {
const button = wrapper.findByTestId(expectedTestId);
expect(button.exists()).toBe(true);
expect(button.attributes('href')).toBe(feature.configuration_path);
});
});
});
describe('given a feature without a configuration path', () => {
beforeEach(() => {
[feature] = generateFeatures(1, { configuration_path: null });
createComponent({ feature });
});
it('renders nothing', () => {
expect(wrapper.html()).toBe('');
});
});
});
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