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 { ...@@ -94,7 +94,7 @@ export default {
</template> </template>
<template #cell(manage)="{ item }"> <template #cell(manage)="{ item }">
<manage-feature :feature="item" :auto-devops-enabled="autoDevopsEnabled" /> <manage-feature :feature="item" />
</template> </template>
</gl-table> </gl-table>
</template> </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> <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 { export default {
components: { props: propsUnion([ManageGeneric, ...Object.values(scannerComponentMap)]),
GlButton,
},
props: {
feature: {
type: Object,
required: true,
},
autoDevopsEnabled: {
type: Boolean,
required: true,
},
},
computed: { computed: {
canConfigureFeature() { manageComponent() {
return Boolean(this.feature.configuration_path); return scannerComponentMap[this.feature.type] ?? ManageGeneric;
},
canManageProfiles() {
return this.feature.type === 'dast_profiles';
}, },
}, },
}; };
</script> </script>
<template> <template>
<gl-button <component :is="manageComponent" v-bind="$props" />
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
>
</template> </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 ...@@ -26,7 +26,7 @@ RSpec.describe 'User sees Security Configuration table', :js do
within_sast_row do within_sast_row do
expect(page).to have_text('SAST') expect(page).to have_text('SAST')
expect(page).to have_text('Not enabled') 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 end
end end
...@@ -43,7 +43,7 @@ RSpec.describe 'User sees Security Configuration table', :js do ...@@ -43,7 +43,7 @@ RSpec.describe 'User sees Security Configuration table', :js do
within_sast_row do within_sast_row do
expect(page).to have_text('SAST') expect(page).to have_text('SAST')
expect(page).to have_text('Enabled') 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 end
end end
......
...@@ -67,10 +67,7 @@ describe('ConfigurationTable component', () => { ...@@ -67,10 +67,7 @@ describe('ConfigurationTable component', () => {
gitlabCiHistoryPath: propsData.gitlabCiHistoryPath, gitlabCiHistoryPath: propsData.gitlabCiHistoryPath,
autoDevopsEnabled: propsData.autoDevopsEnabled, autoDevopsEnabled: propsData.autoDevopsEnabled,
}); });
expect(manage.find(ManageFeature).props()).toEqual({ expect(manage.find(ManageFeature).props()).toEqual({ feature });
feature,
autoDevopsEnabled: propsData.autoDevopsEnabled,
});
expect(description.find(GlLink).attributes('href')).toBe(feature.helpPath); 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 { 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 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'; import { generateFeatures } from './helpers';
const attrs = {
'data-qa-selector': 'foo',
};
describe('ManageFeature component', () => { describe('ManageFeature component', () => {
let wrapper; let wrapper;
let feature;
const createComponent = (options) => { const createComponent = (options) => {
wrapper = shallowMount( wrapper = shallowMount(ManageFeature, options);
ManageFeature,
merge(
{
propsData: {
autoDevopsEnabled: false,
},
},
options,
),
);
}; };
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
}); });
const findTestId = (id) => wrapper.find(`[data-testid="${id}"]`); describe('always', () => {
describe.each`
configured | expectedTestId
${true} | ${'configureButton'}
${false} | ${'enableButton'}
`('given feature.configured is $configured', ({ configured, expectedTestId }) => {
describe('given a configuration path', () => {
beforeEach(() => { beforeEach(() => {
[feature] = generateFeatures(1, { configured, configuration_path: 'foo' }); const [feature] = generateFeatures(1);
createComponent({ attrs, propsData: { feature } });
createComponent({
propsData: { feature },
});
}); });
it('shows a button to configure the feature', () => { it('passes through attributes to the expected component', () => {
const button = findTestId(expectedTestId); expect(wrapper.attributes()).toMatchObject(attrs);
expect(button.exists()).toBe(true);
expect(button.attributes('href')).toBe(feature.configuration_path);
});
}); });
}); });
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(() => { beforeEach(() => {
[feature] = generateFeatures(1, { type: 'dast_profiles', configuration_path: 'foo' }); [feature] = generateFeatures(1, { type });
createComponent({ propsData: { feature } });
createComponent({ component = wrapper.findComponent(expectedComponent);
propsData: { feature, autoDevopsEnabled: true },
}); });
it('renders expected component', () => {
expect(component.exists()).toBe(true);
}); });
it('shows the DAST Profiles manage button', () => { it('passes through props to expected component', () => {
const button = findTestId('manageButton'); expect(component.props()).toEqual({ feature });
expect(button.exists()).toBe(true);
expect(button.attributes('href')).toBe(feature.configuration_path);
}); });
}); });
}); });
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