summaryrefslogtreecommitdiff
path: root/spec/frontend/security_configuration
diff options
context:
space:
mode:
authorGitLab Bot <gitlab-bot@gitlab.com>2021-12-20 13:37:47 +0000
committerGitLab Bot <gitlab-bot@gitlab.com>2021-12-20 13:37:47 +0000
commitaee0a117a889461ce8ced6fcf73207fe017f1d99 (patch)
tree891d9ef189227a8445d83f35c1b0fc99573f4380 /spec/frontend/security_configuration
parent8d46af3258650d305f53b819eabf7ab18d22f59e (diff)
downloadgitlab-ce-aee0a117a889461ce8ced6fcf73207fe017f1d99.tar.gz
Add latest changes from gitlab-org/gitlab@14-6-stable-eev14.6.0-rc42
Diffstat (limited to 'spec/frontend/security_configuration')
-rw-r--r--spec/frontend/security_configuration/components/app_spec.js55
-rw-r--r--spec/frontend/security_configuration/components/training_provider_list_spec.js88
-rw-r--r--spec/frontend/security_configuration/mock_data.js30
-rw-r--r--spec/frontend/security_configuration/utils_spec.js199
4 files changed, 270 insertions, 102 deletions
diff --git a/spec/frontend/security_configuration/components/app_spec.js b/spec/frontend/security_configuration/components/app_spec.js
index d4ee9e6e43d..0a2b18caf25 100644
--- a/spec/frontend/security_configuration/components/app_spec.js
+++ b/spec/frontend/security_configuration/components/app_spec.js
@@ -20,6 +20,7 @@ import {
AUTO_DEVOPS_ENABLED_ALERT_DISMISSED_STORAGE_KEY,
} from '~/security_configuration/components/constants';
import FeatureCard from '~/security_configuration/components/feature_card.vue';
+import TrainingProviderList from '~/security_configuration/components/training_provider_list.vue';
import UpgradeBanner from '~/security_configuration/components/upgrade_banner.vue';
import {
@@ -39,7 +40,11 @@ describe('App component', () => {
let wrapper;
let userCalloutDismissSpy;
- const createComponent = ({ shouldShowCallout = true, ...propsData }) => {
+ const createComponent = ({
+ shouldShowCallout = true,
+ secureVulnerabilityTraining = true,
+ ...propsData
+ }) => {
userCalloutDismissSpy = jest.fn();
wrapper = extendedWrapper(
@@ -50,6 +55,9 @@ describe('App component', () => {
autoDevopsHelpPagePath,
autoDevopsPath,
projectPath,
+ glFeatures: {
+ secureVulnerabilityTraining,
+ },
},
stubs: {
...stubChildren(SecurityConfigurationApp),
@@ -71,6 +79,7 @@ describe('App component', () => {
const findTabs = () => wrapper.findAllComponents(GlTab);
const findByTestId = (id) => wrapper.findByTestId(id);
const findFeatureCards = () => wrapper.findAllComponents(FeatureCard);
+ const findTrainingProviderList = () => wrapper.findComponent(TrainingProviderList);
const findManageViaMRErrorAlert = () => wrapper.findByTestId('manage-via-mr-error-alert');
const findLink = ({ href, text, container = wrapper }) => {
const selector = `a[href="${href}"]`;
@@ -138,20 +147,20 @@ describe('App component', () => {
expect(mainHeading.text()).toContain('Security Configuration');
});
- it('renders GlTab Component ', () => {
- expect(findTab().exists()).toBe(true);
- });
+ describe('tabs', () => {
+ const expectedTabs = ['security-testing', 'compliance-testing', 'vulnerability-management'];
- it('renders right amount of tabs with correct title ', () => {
- expect(findTabs()).toHaveLength(2);
- });
+ it('renders GlTab Component', () => {
+ expect(findTab().exists()).toBe(true);
+ });
- it('renders security-testing tab', () => {
- expect(findByTestId('security-testing-tab').exists()).toBe(true);
- });
+ it('renders correct amount of tabs', () => {
+ expect(findTabs()).toHaveLength(expectedTabs.length);
+ });
- it('renders compliance-testing tab', () => {
- expect(findByTestId('compliance-testing-tab').exists()).toBe(true);
+ it.each(expectedTabs)('renders the %s tab', (tabName) => {
+ expect(findByTestId(`${tabName}-tab`).exists()).toBe(true);
+ });
});
it('renders right amount of feature cards for given props with correct props', () => {
@@ -173,6 +182,10 @@ describe('App component', () => {
expect(findComplianceViewHistoryLink().exists()).toBe(false);
expect(findSecurityViewHistoryLink().exists()).toBe(false);
});
+
+ it('renders TrainingProviderList component', () => {
+ expect(findTrainingProviderList().exists()).toBe(true);
+ });
});
describe('Manage via MR Error Alert', () => {
@@ -418,4 +431,22 @@ describe('App component', () => {
expect(findSecurityViewHistoryLink().attributes('href')).toBe('test/historyPath');
});
});
+
+ describe('when secureVulnerabilityTraining feature flag is disabled', () => {
+ beforeEach(() => {
+ createComponent({
+ augmentedSecurityFeatures: securityFeaturesMock,
+ augmentedComplianceFeatures: complianceFeaturesMock,
+ secureVulnerabilityTraining: false,
+ });
+ });
+
+ it('renders correct amount of tabs', () => {
+ expect(findTabs()).toHaveLength(2);
+ });
+
+ it('does not render the vulnerability-management tab', () => {
+ expect(wrapper.findByTestId('vulnerability-management-tab').exists()).toBe(false);
+ });
+ });
});
diff --git a/spec/frontend/security_configuration/components/training_provider_list_spec.js b/spec/frontend/security_configuration/components/training_provider_list_spec.js
new file mode 100644
index 00000000000..60cc36a634c
--- /dev/null
+++ b/spec/frontend/security_configuration/components/training_provider_list_spec.js
@@ -0,0 +1,88 @@
+import { GlLink, GlToggle, GlCard, GlSkeletonLoader } from '@gitlab/ui';
+import { shallowMount } from '@vue/test-utils';
+import Vue from 'vue';
+import VueApollo from 'vue-apollo';
+import createMockApollo from 'helpers/mock_apollo_helper';
+import TrainingProviderList from '~/security_configuration/components/training_provider_list.vue';
+import waitForPromises from 'helpers/wait_for_promises';
+import { securityTrainingProviders, mockResolvers } from '../mock_data';
+
+Vue.use(VueApollo);
+
+describe('TrainingProviderList component', () => {
+ let wrapper;
+ let mockApollo;
+ let mockSecurityTrainingProvidersData;
+
+ const createComponent = () => {
+ mockApollo = createMockApollo([], mockResolvers);
+
+ wrapper = shallowMount(TrainingProviderList, {
+ apolloProvider: mockApollo,
+ });
+ };
+
+ const waitForQueryToBeLoaded = () => waitForPromises();
+
+ const findCards = () => wrapper.findAllComponents(GlCard);
+ const findLinks = () => wrapper.findAllComponents(GlLink);
+ const findToggles = () => wrapper.findAllComponents(GlToggle);
+ const findLoader = () => wrapper.findComponent(GlSkeletonLoader);
+
+ beforeEach(() => {
+ mockSecurityTrainingProvidersData = jest.fn();
+ mockSecurityTrainingProvidersData.mockResolvedValue(securityTrainingProviders);
+
+ createComponent();
+ });
+
+ afterEach(() => {
+ wrapper.destroy();
+ mockApollo = null;
+ });
+
+ describe('when loading', () => {
+ it('shows the loader', () => {
+ expect(findLoader().exists()).toBe(true);
+ });
+
+ it('does not show the cards', () => {
+ expect(findCards().exists()).toBe(false);
+ });
+ });
+
+ describe('basic structure', () => {
+ beforeEach(async () => {
+ await waitForQueryToBeLoaded();
+ });
+
+ it('renders correct amount of cards', () => {
+ expect(findCards()).toHaveLength(securityTrainingProviders.length);
+ });
+
+ securityTrainingProviders.forEach(({ name, description, url, isEnabled }, index) => {
+ it(`shows the name for card ${index}`, () => {
+ expect(findCards().at(index).text()).toContain(name);
+ });
+
+ it(`shows the description for card ${index}`, () => {
+ expect(findCards().at(index).text()).toContain(description);
+ });
+
+ it(`shows the learn more link for card ${index}`, () => {
+ expect(findLinks().at(index).attributes()).toEqual({
+ target: '_blank',
+ href: url,
+ });
+ });
+
+ it(`shows the toggle with the correct value for card ${index}`, () => {
+ expect(findToggles().at(index).props('value')).toEqual(isEnabled);
+ });
+
+ it('does not show loader when query is populated', () => {
+ expect(findLoader().exists()).toBe(false);
+ });
+ });
+ });
+});
diff --git a/spec/frontend/security_configuration/mock_data.js b/spec/frontend/security_configuration/mock_data.js
new file mode 100644
index 00000000000..cdb859c3800
--- /dev/null
+++ b/spec/frontend/security_configuration/mock_data.js
@@ -0,0 +1,30 @@
+export const securityTrainingProviders = [
+ {
+ id: 101,
+ name: 'Kontra',
+ description: 'Interactive developer security education.',
+ url: 'https://application.security/',
+ isEnabled: false,
+ },
+ {
+ id: 102,
+ name: 'SecureCodeWarrior',
+ description: 'Security training with guide and learning pathways.',
+ url: 'https://www.securecodewarrior.com/',
+ isEnabled: true,
+ },
+];
+
+export const securityTrainingProvidersResponse = {
+ data: {
+ securityTrainingProviders,
+ },
+};
+
+export const mockResolvers = {
+ Query: {
+ securityTrainingProviders() {
+ return securityTrainingProviders;
+ },
+ },
+};
diff --git a/spec/frontend/security_configuration/utils_spec.js b/spec/frontend/security_configuration/utils_spec.js
index eaed4532baa..241e69204d2 100644
--- a/spec/frontend/security_configuration/utils_spec.js
+++ b/spec/frontend/security_configuration/utils_spec.js
@@ -1,101 +1,120 @@
-import { augmentFeatures } from '~/security_configuration/utils';
-
-const mockSecurityFeatures = [
- {
- name: 'SAST',
- type: 'SAST',
- },
-];
-
-const mockComplianceFeatures = [
- {
- name: 'LICENSE_COMPLIANCE',
- type: 'LICENSE_COMPLIANCE',
- },
-];
-
-const mockFeaturesWithSecondary = [
- {
- name: 'DAST',
- type: 'DAST',
- secondary: {
- type: 'DAST PROFILES',
- name: 'DAST PROFILES',
+import { augmentFeatures, translateScannerNames } from '~/security_configuration/utils';
+import { SCANNER_NAMES_MAP } from '~/security_configuration/components/constants';
+
+describe('augmentFeatures', () => {
+ const mockSecurityFeatures = [
+ {
+ name: 'SAST',
+ type: 'SAST',
},
- },
-];
-
-const mockInvalidCustomFeature = [
- {
- foo: 'bar',
- },
-];
-
-const mockValidCustomFeature = [
- {
- name: 'SAST',
- type: 'SAST',
- customField: 'customvalue',
- },
-];
-
-const mockValidCustomFeatureSnakeCase = [
- {
- name: 'SAST',
- type: 'SAST',
- custom_field: 'customvalue',
- },
-];
-
-const expectedOutputDefault = {
- augmentedSecurityFeatures: mockSecurityFeatures,
- augmentedComplianceFeatures: mockComplianceFeatures,
-};
-
-const expectedOutputSecondary = {
- augmentedSecurityFeatures: mockSecurityFeatures,
- augmentedComplianceFeatures: mockFeaturesWithSecondary,
-};
-
-const expectedOutputCustomFeature = {
- augmentedSecurityFeatures: mockValidCustomFeature,
- augmentedComplianceFeatures: mockComplianceFeatures,
-};
-
-describe('returns an object with augmentedSecurityFeatures and augmentedComplianceFeatures when', () => {
- it('given an empty array', () => {
- expect(augmentFeatures(mockSecurityFeatures, mockComplianceFeatures, [])).toEqual(
- expectedOutputDefault,
- );
+ ];
+
+ const mockComplianceFeatures = [
+ {
+ name: 'LICENSE_COMPLIANCE',
+ type: 'LICENSE_COMPLIANCE',
+ },
+ ];
+
+ const mockFeaturesWithSecondary = [
+ {
+ name: 'DAST',
+ type: 'DAST',
+ secondary: {
+ type: 'DAST PROFILES',
+ name: 'DAST PROFILES',
+ },
+ },
+ ];
+
+ const mockInvalidCustomFeature = [
+ {
+ foo: 'bar',
+ },
+ ];
+
+ const mockValidCustomFeature = [
+ {
+ name: 'SAST',
+ type: 'SAST',
+ customField: 'customvalue',
+ },
+ ];
+
+ const mockValidCustomFeatureSnakeCase = [
+ {
+ name: 'SAST',
+ type: 'SAST',
+ custom_field: 'customvalue',
+ },
+ ];
+
+ const expectedOutputDefault = {
+ augmentedSecurityFeatures: mockSecurityFeatures,
+ augmentedComplianceFeatures: mockComplianceFeatures,
+ };
+
+ const expectedOutputSecondary = {
+ augmentedSecurityFeatures: mockSecurityFeatures,
+ augmentedComplianceFeatures: mockFeaturesWithSecondary,
+ };
+
+ const expectedOutputCustomFeature = {
+ augmentedSecurityFeatures: mockValidCustomFeature,
+ augmentedComplianceFeatures: mockComplianceFeatures,
+ };
+
+ describe('returns an object with augmentedSecurityFeatures and augmentedComplianceFeatures when', () => {
+ it('given an empty array', () => {
+ expect(augmentFeatures(mockSecurityFeatures, mockComplianceFeatures, [])).toEqual(
+ expectedOutputDefault,
+ );
+ });
+
+ it('given an invalid populated array', () => {
+ expect(
+ augmentFeatures(mockSecurityFeatures, mockComplianceFeatures, mockInvalidCustomFeature),
+ ).toEqual(expectedOutputDefault);
+ });
+
+ it('features have secondary key', () => {
+ expect(augmentFeatures(mockSecurityFeatures, mockFeaturesWithSecondary, [])).toEqual(
+ expectedOutputSecondary,
+ );
+ });
+
+ it('given a valid populated array', () => {
+ expect(
+ augmentFeatures(mockSecurityFeatures, mockComplianceFeatures, mockValidCustomFeature),
+ ).toEqual(expectedOutputCustomFeature);
+ });
});
- it('given an invalid populated array', () => {
- expect(
- augmentFeatures(mockSecurityFeatures, mockComplianceFeatures, mockInvalidCustomFeature),
- ).toEqual(expectedOutputDefault);
+ describe('returns an object with camelcased keys', () => {
+ it('given a customfeature in snakecase', () => {
+ expect(
+ augmentFeatures(
+ mockSecurityFeatures,
+ mockComplianceFeatures,
+ mockValidCustomFeatureSnakeCase,
+ ),
+ ).toEqual(expectedOutputCustomFeature);
+ });
});
+});
- it('features have secondary key', () => {
- expect(augmentFeatures(mockSecurityFeatures, mockFeaturesWithSecondary, [])).toEqual(
- expectedOutputSecondary,
- );
+describe('translateScannerNames', () => {
+ it.each(['', undefined, null, 1, 'UNKNOWN_SCANNER_KEY'])('returns %p as is', (key) => {
+ expect(translateScannerNames([key])).toEqual([key]);
});
- it('given a valid populated array', () => {
- expect(
- augmentFeatures(mockSecurityFeatures, mockComplianceFeatures, mockValidCustomFeature),
- ).toEqual(expectedOutputCustomFeature);
+ it('returns an empty array if no input is provided', () => {
+ expect(translateScannerNames([])).toEqual([]);
});
-});
-describe('returns an object with camelcased keys', () => {
- it('given a customfeature in snakecase', () => {
- expect(
- augmentFeatures(
- mockSecurityFeatures,
- mockComplianceFeatures,
- mockValidCustomFeatureSnakeCase,
- ),
- ).toEqual(expectedOutputCustomFeature);
+ it('returns translated scanner names', () => {
+ expect(translateScannerNames(Object.keys(SCANNER_NAMES_MAP))).toEqual(
+ Object.values(SCANNER_NAMES_MAP),
+ );
});
});