Commit 50d2a85b authored by Savas Vedova's avatar Savas Vedova

Merge branch 'make-vulnerability-training-reusable' into 'master'

Refactor vulnerability training to be reusable

See merge request gitlab-org/gitlab!80308
parents 5b46af3b 7efe7715
...@@ -3,7 +3,10 @@ import { GlLink, GlSprintf, GlSafeHtmlDirective } from '@gitlab/ui'; ...@@ -3,7 +3,10 @@ import { GlLink, GlSprintf, GlSafeHtmlDirective } from '@gitlab/ui';
import { bodyWithFallBack } from 'ee/vue_shared/security_reports/components/helpers'; import { bodyWithFallBack } from 'ee/vue_shared/security_reports/components/helpers';
import SeverityBadge from 'ee/vue_shared/security_reports/components/severity_badge.vue'; import SeverityBadge from 'ee/vue_shared/security_reports/components/severity_badge.vue';
import convertReportType from 'ee/vue_shared/security_reports/store/utils/convert_report_type'; import convertReportType from 'ee/vue_shared/security_reports/store/utils/convert_report_type';
import { SUPPORTING_MESSAGE_TYPES } from 'ee/vulnerabilities/constants'; import {
SUPPORTING_MESSAGE_TYPES,
VULNERABILITY_TRAINING_HEADING,
} from 'ee/vulnerabilities/constants';
import { s__, __ } from '~/locale'; import { s__, __ } from '~/locale';
import CodeBlock from '~/vue_shared/components/code_block.vue'; import CodeBlock from '~/vue_shared/components/code_block.vue';
import DetailItem from './detail_item.vue'; import DetailItem from './detail_item.vue';
...@@ -183,6 +186,7 @@ export default { ...@@ -183,6 +186,7 @@ export default {
'Vulnerability|Actual received response is the one received when this fault was detected', 'Vulnerability|Actual received response is the one received when this fault was detected',
), ),
}, },
VULNERABILITY_TRAINING_HEADING,
}; };
</script> </script>
...@@ -376,6 +380,10 @@ export default { ...@@ -376,6 +380,10 @@ export default {
</ul> </ul>
</template> </template>
<vulnerability-training :identifiers="vulnerability.identifiers" /> <vulnerability-training :identifiers="vulnerability.identifiers">
<template #header>
<h3>{{ $options.VULNERABILITY_TRAINING_HEADING.title }}</h3>
</template>
</vulnerability-training>
</div> </div>
</template> </template>
...@@ -8,7 +8,6 @@ import axios from '~/lib/utils/axios_utils'; ...@@ -8,7 +8,6 @@ import axios from '~/lib/utils/axios_utils';
import { SUPPORTED_IDENTIFIER_TYPES } from '../constants'; import { SUPPORTED_IDENTIFIER_TYPES } from '../constants';
export const i18n = { export const i18n = {
trainingTitle: s__('Vulnerability|Training'),
trainingDescription: s__( trainingDescription: s__(
'Vulnerability|Learn more about this vulnerability and the best way to resolve it.', 'Vulnerability|Learn more about this vulnerability and the best way to resolve it.',
), ),
...@@ -118,7 +117,7 @@ export default { ...@@ -118,7 +117,7 @@ export default {
<template> <template>
<div v-if="showVulnerabilityTraining"> <div v-if="showVulnerabilityTraining">
<h3>{{ $options.i18n.trainingTitle }}</h3> <slot name="header"></slot>
<p class="gl-text-gray-600!" data-testid="description"> <p class="gl-text-gray-600!" data-testid="description">
{{ $options.i18n.trainingDescription }} {{ $options.i18n.trainingDescription }}
</p> </p>
......
...@@ -89,3 +89,7 @@ export const SUPPORTING_MESSAGE_TYPES = { ...@@ -89,3 +89,7 @@ export const SUPPORTING_MESSAGE_TYPES = {
export const SUPPORTED_IDENTIFIER_TYPES = { export const SUPPORTED_IDENTIFIER_TYPES = {
cwe: 'cwe', cwe: 'cwe',
}; };
export const VULNERABILITY_TRAINING_HEADING = {
title: s__('Vulnerability|Training'),
};
...@@ -3,7 +3,10 @@ import { getAllByRole, getByTestId } from '@testing-library/dom'; ...@@ -3,7 +3,10 @@ import { getAllByRole, getByTestId } from '@testing-library/dom';
import { mount, shallowMount } from '@vue/test-utils'; import { mount, shallowMount } from '@vue/test-utils';
import SeverityBadge from 'ee/vue_shared/security_reports/components/severity_badge.vue'; import SeverityBadge from 'ee/vue_shared/security_reports/components/severity_badge.vue';
import VulnerabilityDetails from 'ee/vulnerabilities/components/vulnerability_details.vue'; import VulnerabilityDetails from 'ee/vulnerabilities/components/vulnerability_details.vue';
import { SUPPORTING_MESSAGE_TYPES } from 'ee/vulnerabilities/constants'; import {
SUPPORTING_MESSAGE_TYPES,
VULNERABILITY_TRAINING_HEADING,
} from 'ee/vulnerabilities/constants';
import VulnerabilityTraining from 'ee/vulnerabilities/components/vulnerability_training.vue'; import VulnerabilityTraining from 'ee/vulnerabilities/components/vulnerability_training.vue';
describe('Vulnerability Details', () => { describe('Vulnerability Details', () => {
...@@ -18,7 +21,7 @@ describe('Vulnerability Details', () => { ...@@ -18,7 +21,7 @@ describe('Vulnerability Details', () => {
identifiers: [], identifiers: [],
}; };
const createWrapper = (vulnerabilityOverrides, { mountFn = mount } = {}) => { const createWrapper = (vulnerabilityOverrides, { mountFn = mount, options = {} } = {}) => {
const propsData = { const propsData = {
vulnerability: { ...vulnerability, ...vulnerabilityOverrides }, vulnerability: { ...vulnerability, ...vulnerabilityOverrides },
}; };
...@@ -27,13 +30,16 @@ describe('Vulnerability Details', () => { ...@@ -27,13 +30,16 @@ describe('Vulnerability Details', () => {
provide: { provide: {
projectFullPath: 'namespace/project', projectFullPath: 'namespace/project',
}, },
...options,
}); });
}; };
const createShallowWrapper = (...args) => createWrapper(...args, { mountFn: shallowMount }); const createShallowWrapper = (vulnerabilityOverrides, options = {}) =>
createWrapper(vulnerabilityOverrides, { mountFn: shallowMount, options });
const getById = (id) => wrapper.find(`[data-testid="${id}"]`); const getById = (id) => wrapper.find(`[data-testid="${id}"]`);
const getAllById = (id) => wrapper.findAll(`[data-testid="${id}"]`); const getAllById = (id) => wrapper.findAll(`[data-testid="${id}"]`);
const getText = (id) => getById(id).text(); const getText = (id) => getById(id).text();
const findVulnerabilityTraining = () => wrapper.findComponent(VulnerabilityTraining);
afterEach(() => { afterEach(() => {
wrapper.destroy(); wrapper.destroy();
...@@ -197,11 +203,34 @@ describe('Vulnerability Details', () => { ...@@ -197,11 +203,34 @@ describe('Vulnerability Details', () => {
assetsData.forEach(checkIdentifier); assetsData.forEach(checkIdentifier);
}); });
it('renders the vulnerabilityTraining component', () => { describe('VulnerabilityTraining', () => {
const identifiers = [{ externalType: 'cwe' }, { externalType: 'cve' }]; const identifiers = [{ externalType: 'cwe' }, { externalType: 'cve' }];
createShallowWrapper({ identifiers });
expect(wrapper.findComponent(VulnerabilityTraining).props()).toMatchObject({ it('renders component', () => {
identifiers, createShallowWrapper({
identifiers,
});
expect(findVulnerabilityTraining().props()).toMatchObject({
identifiers,
});
});
it('renders title text', () => {
createShallowWrapper(
{
identifiers,
},
{
stubs: {
VulnerabilityTraining: {
template: '<div><slot name="header"></slot></div>',
},
},
},
);
expect(wrapper.text()).toContain(VULNERABILITY_TRAINING_HEADING.title);
}); });
}); });
......
...@@ -39,12 +39,13 @@ describe('VulnerabilityTraining component', () => { ...@@ -39,12 +39,13 @@ describe('VulnerabilityTraining component', () => {
]); ]);
}; };
const createComponent = (props = {}, { secureVulnerabilityTraining = true } = {}) => { const createComponent = (props = {}, { slots = {}, secureVulnerabilityTraining = true } = {}) => {
wrapper = shallowMountExtended(VulnerabilityTraining, { wrapper = shallowMountExtended(VulnerabilityTraining, {
propsData: { propsData: {
...defaultProps, ...defaultProps,
...props, ...props,
}, },
slots,
apolloProvider, apolloProvider,
provide: { provide: {
projectFullPath: 'namespace/project', projectFullPath: 'namespace/project',
...@@ -71,7 +72,6 @@ describe('VulnerabilityTraining component', () => { ...@@ -71,7 +72,6 @@ describe('VulnerabilityTraining component', () => {
const mockTrainingSuccess = async () => const mockTrainingSuccess = async () =>
mock.onGet(mockProvider.path).reply(httpStatus.OK, { url: mockSuccessTrainingUrl }); mock.onGet(mockProvider.path).reply(httpStatus.OK, { url: mockSuccessTrainingUrl });
const waitForQueryToBeLoaded = () => waitForPromises(); const waitForQueryToBeLoaded = () => waitForPromises();
const findTitle = () => wrapper.findByRole('heading', i18n.trainingTitle);
const findDescription = () => wrapper.findByTestId('description'); const findDescription = () => wrapper.findByTestId('description');
const findUnavailableMessage = () => wrapper.findByTestId('unavailable-message'); const findUnavailableMessage = () => wrapper.findByTestId('unavailable-message');
const findTrainingItemName = () => wrapper.findByText(mockProvider.name); const findTrainingItemName = () => wrapper.findByText(mockProvider.name);
...@@ -84,12 +84,6 @@ describe('VulnerabilityTraining component', () => { ...@@ -84,12 +84,6 @@ describe('VulnerabilityTraining component', () => {
}); });
describe('basic structure', () => { describe('basic structure', () => {
it('displays the title', async () => {
createComponent();
await waitForQueryToBeLoaded();
expect(findTitle().text()).toBe(i18n.trainingTitle);
});
it('displays the description', async () => { it('displays the description', async () => {
createComponent(); createComponent();
await waitForQueryToBeLoaded(); await waitForQueryToBeLoaded();
...@@ -107,6 +101,15 @@ describe('VulnerabilityTraining component', () => { ...@@ -107,6 +101,15 @@ describe('VulnerabilityTraining component', () => {
}); });
}); });
describe('with title slot', () => {
it('renders slot content', async () => {
const mockSlotText = 'some title';
createComponent({}, { slots: { header: mockSlotText } });
await waitForQueryToBeLoaded();
expect(wrapper.text()).toContain(mockSlotText);
});
});
describe('training availability message', () => { describe('training availability message', () => {
it('displays the message', async () => { it('displays the message', async () => {
createComponent({ createComponent({
......
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