diff options
Diffstat (limited to 'spec/frontend/security_configuration/components/app_spec.js')
-rw-r--r-- | spec/frontend/security_configuration/components/app_spec.js | 382 |
1 files changed, 382 insertions, 0 deletions
diff --git a/spec/frontend/security_configuration/components/app_spec.js b/spec/frontend/security_configuration/components/app_spec.js new file mode 100644 index 00000000000..f27f45f2b26 --- /dev/null +++ b/spec/frontend/security_configuration/components/app_spec.js @@ -0,0 +1,382 @@ +import { GlTab } from '@gitlab/ui'; +import { mount } from '@vue/test-utils'; +import { useLocalStorageSpy } from 'helpers/local_storage_helper'; +import { makeMockUserCalloutDismisser } from 'helpers/mock_user_callout_dismisser'; +import stubChildren from 'helpers/stub_children'; +import { extendedWrapper } from 'helpers/vue_test_utils_helper'; +import SecurityConfigurationApp, { i18n } from '~/security_configuration/components/app.vue'; +import AutoDevopsAlert from '~/security_configuration/components/auto_dev_ops_alert.vue'; +import AutoDevopsEnabledAlert from '~/security_configuration/components/auto_dev_ops_enabled_alert.vue'; +import { + SAST_NAME, + SAST_SHORT_NAME, + SAST_DESCRIPTION, + SAST_HELP_PATH, + SAST_CONFIG_HELP_PATH, + LICENSE_COMPLIANCE_NAME, + LICENSE_COMPLIANCE_DESCRIPTION, + LICENSE_COMPLIANCE_HELP_PATH, + AUTO_DEVOPS_ENABLED_ALERT_DISMISSED_STORAGE_KEY, +} from '~/security_configuration/components/constants'; +import FeatureCard from '~/security_configuration/components/feature_card.vue'; + +import UpgradeBanner from '~/security_configuration/components/upgrade_banner.vue'; +import { + REPORT_TYPE_LICENSE_COMPLIANCE, + REPORT_TYPE_SAST, +} from '~/vue_shared/security_reports/constants'; + +const upgradePath = '/upgrade'; +const autoDevopsHelpPagePath = '/autoDevopsHelpPagePath'; +const autoDevopsPath = '/autoDevopsPath'; +const gitlabCiHistoryPath = 'test/historyPath'; +const projectPath = 'namespace/project'; + +useLocalStorageSpy(); + +describe('App component', () => { + let wrapper; + let userCalloutDismissSpy; + + const createComponent = ({ shouldShowCallout = true, ...propsData }) => { + userCalloutDismissSpy = jest.fn(); + + wrapper = extendedWrapper( + mount(SecurityConfigurationApp, { + propsData, + provide: { + upgradePath, + autoDevopsHelpPagePath, + autoDevopsPath, + projectPath, + }, + stubs: { + ...stubChildren(SecurityConfigurationApp), + GlLink: false, + GlSprintf: false, + LocalStorageSync: false, + SectionLayout: false, + UserCalloutDismisser: makeMockUserCalloutDismisser({ + dismiss: userCalloutDismissSpy, + shouldShowCallout, + }), + }, + }), + ); + }; + + const findMainHeading = () => wrapper.find('h1'); + const findTab = () => wrapper.findComponent(GlTab); + const findTabs = () => wrapper.findAllComponents(GlTab); + const findByTestId = (id) => wrapper.findByTestId(id); + const findFeatureCards = () => wrapper.findAllComponents(FeatureCard); + const findLink = ({ href, text, container = wrapper }) => { + const selector = `a[href="${href}"]`; + const link = container.find(selector); + + if (link.exists() && link.text() === text) { + return link; + } + + return wrapper.find(`${selector} does not exist`); + }; + const findSecurityViewHistoryLink = () => + findLink({ + href: gitlabCiHistoryPath, + text: i18n.configurationHistory, + container: findByTestId('security-testing-tab'), + }); + const findComplianceViewHistoryLink = () => + findLink({ + href: gitlabCiHistoryPath, + text: i18n.configurationHistory, + container: findByTestId('compliance-testing-tab'), + }); + const findUpgradeBanner = () => wrapper.findComponent(UpgradeBanner); + const findAutoDevopsAlert = () => wrapper.findComponent(AutoDevopsAlert); + const findAutoDevopsEnabledAlert = () => wrapper.findComponent(AutoDevopsEnabledAlert); + + const securityFeaturesMock = [ + { + name: SAST_NAME, + shortName: SAST_SHORT_NAME, + description: SAST_DESCRIPTION, + helpPath: SAST_HELP_PATH, + configurationHelpPath: SAST_CONFIG_HELP_PATH, + type: REPORT_TYPE_SAST, + available: true, + }, + ]; + + const complianceFeaturesMock = [ + { + name: LICENSE_COMPLIANCE_NAME, + description: LICENSE_COMPLIANCE_DESCRIPTION, + helpPath: LICENSE_COMPLIANCE_HELP_PATH, + type: REPORT_TYPE_LICENSE_COMPLIANCE, + configurationHelpPath: LICENSE_COMPLIANCE_HELP_PATH, + }, + ]; + + afterEach(() => { + wrapper.destroy(); + }); + + describe('basic structure', () => { + beforeEach(() => { + createComponent({ + augmentedSecurityFeatures: securityFeaturesMock, + augmentedComplianceFeatures: complianceFeaturesMock, + }); + }); + + it('renders main-heading with correct text', () => { + const mainHeading = findMainHeading(); + expect(mainHeading).toExist(); + expect(mainHeading.text()).toContain('Security Configuration'); + }); + + it('renders GlTab Component ', () => { + expect(findTab()).toExist(); + }); + + it('renders right amount of tabs with correct title ', () => { + expect(findTabs()).toHaveLength(2); + }); + + it('renders security-testing tab', () => { + expect(findByTestId('security-testing-tab').exists()).toBe(true); + }); + + it('renders compliance-testing tab', () => { + expect(findByTestId('compliance-testing-tab').exists()).toBe(true); + }); + + it('renders right amount of feature cards for given props with correct props', () => { + const cards = findFeatureCards(); + expect(cards).toHaveLength(2); + expect(cards.at(0).props()).toEqual({ feature: securityFeaturesMock[0] }); + expect(cards.at(1).props()).toEqual({ feature: complianceFeaturesMock[0] }); + }); + + it('renders a basic description', () => { + expect(wrapper.text()).toContain(i18n.description); + }); + + it('should not show latest pipeline link when latestPipelinePath is not defined', () => { + expect(findByTestId('latest-pipeline-info').exists()).toBe(false); + }); + + it('should not show configuration History Link when gitlabCiPresent & gitlabCiHistoryPath are not defined', () => { + expect(findComplianceViewHistoryLink().exists()).toBe(false); + expect(findSecurityViewHistoryLink().exists()).toBe(false); + }); + }); + + describe('Auto DevOps hint alert', () => { + describe('given the right props', () => { + beforeEach(() => { + createComponent({ + augmentedSecurityFeatures: securityFeaturesMock, + augmentedComplianceFeatures: complianceFeaturesMock, + autoDevopsEnabled: false, + gitlabCiPresent: false, + canEnableAutoDevops: true, + }); + }); + + it('should show AutoDevopsAlert', () => { + expect(findAutoDevopsAlert().exists()).toBe(true); + }); + + it('calls the dismiss callback when closing the AutoDevopsAlert', () => { + expect(userCalloutDismissSpy).not.toHaveBeenCalled(); + + findAutoDevopsAlert().vm.$emit('dismiss'); + + expect(userCalloutDismissSpy).toHaveBeenCalledTimes(1); + }); + }); + + describe('given the wrong props', () => { + beforeEach(() => { + createComponent({ + augmentedSecurityFeatures: securityFeaturesMock, + augmentedComplianceFeatures: complianceFeaturesMock, + }); + }); + it('should not show AutoDevopsAlert', () => { + expect(findAutoDevopsAlert().exists()).toBe(false); + }); + }); + }); + + describe('Auto DevOps enabled alert', () => { + describe.each` + context | autoDevopsEnabled | localStorageValue | shouldRender + ${'enabled'} | ${true} | ${null} | ${true} + ${'enabled, alert dismissed on other project'} | ${true} | ${['foo/bar']} | ${true} + ${'enabled, alert dismissed on this project'} | ${true} | ${[projectPath]} | ${false} + ${'not enabled'} | ${false} | ${null} | ${false} + `('given Auto DevOps is $context', ({ autoDevopsEnabled, localStorageValue, shouldRender }) => { + beforeEach(() => { + if (localStorageValue !== null) { + window.localStorage.setItem( + AUTO_DEVOPS_ENABLED_ALERT_DISMISSED_STORAGE_KEY, + JSON.stringify(localStorageValue), + ); + } + + createComponent({ + augmentedSecurityFeatures: securityFeaturesMock, + augmentedComplianceFeatures: complianceFeaturesMock, + autoDevopsEnabled, + }); + }); + + it(shouldRender ? 'renders' : 'does not render', () => { + expect(findAutoDevopsEnabledAlert().exists()).toBe(shouldRender); + }); + }); + + describe('dismissing', () => { + describe.each` + dismissedProjects | expectedWrittenValue + ${null} | ${[projectPath]} + ${[]} | ${[projectPath]} + ${['foo/bar']} | ${['foo/bar', projectPath]} + ${[projectPath]} | ${[projectPath]} + `( + 'given dismissed projects $dismissedProjects', + ({ dismissedProjects, expectedWrittenValue }) => { + beforeEach(() => { + if (dismissedProjects !== null) { + window.localStorage.setItem( + AUTO_DEVOPS_ENABLED_ALERT_DISMISSED_STORAGE_KEY, + JSON.stringify(dismissedProjects), + ); + } + + createComponent({ + augmentedSecurityFeatures: securityFeaturesMock, + augmentedComplianceFeatures: complianceFeaturesMock, + autoDevopsEnabled: true, + }); + + findAutoDevopsEnabledAlert().vm.$emit('dismiss'); + }); + + it('adds current project to localStorage value', () => { + expect(window.localStorage.setItem).toHaveBeenLastCalledWith( + AUTO_DEVOPS_ENABLED_ALERT_DISMISSED_STORAGE_KEY, + JSON.stringify(expectedWrittenValue), + ); + }); + + it('hides the alert', () => { + expect(findAutoDevopsEnabledAlert().exists()).toBe(false); + }); + }, + ); + }); + }); + + describe('upgrade banner', () => { + const makeAvailable = (available) => (feature) => ({ ...feature, available }); + + describe('given at least one unavailable feature', () => { + beforeEach(() => { + createComponent({ + augmentedSecurityFeatures: securityFeaturesMock, + augmentedComplianceFeatures: complianceFeaturesMock.map(makeAvailable(false)), + }); + }); + + it('renders the banner', () => { + expect(findUpgradeBanner().exists()).toBe(true); + }); + + it('calls the dismiss callback when closing the banner', () => { + expect(userCalloutDismissSpy).not.toHaveBeenCalled(); + + findUpgradeBanner().vm.$emit('close'); + + expect(userCalloutDismissSpy).toHaveBeenCalledTimes(1); + }); + }); + + describe('given at least one unavailable feature, but banner is already dismissed', () => { + beforeEach(() => { + createComponent({ + augmentedSecurityFeatures: securityFeaturesMock, + augmentedComplianceFeatures: complianceFeaturesMock.map(makeAvailable(false)), + shouldShowCallout: false, + }); + }); + + it('does not render the banner', () => { + expect(findUpgradeBanner().exists()).toBe(false); + }); + }); + + describe('given all features are available', () => { + beforeEach(() => { + createComponent({ + augmentedSecurityFeatures: securityFeaturesMock.map(makeAvailable(true)), + augmentedComplianceFeatures: complianceFeaturesMock.map(makeAvailable(true)), + }); + }); + + it('does not render the banner', () => { + expect(findUpgradeBanner().exists()).toBe(false); + }); + }); + }); + + describe('when given latestPipelinePath props', () => { + beforeEach(() => { + createComponent({ + augmentedSecurityFeatures: securityFeaturesMock, + augmentedComplianceFeatures: complianceFeaturesMock, + latestPipelinePath: 'test/path', + }); + }); + + it('should show latest pipeline info on the security tab with correct link when latestPipelinePath is defined', () => { + const latestPipelineInfoSecurity = findByTestId('latest-pipeline-info-security'); + + expect(latestPipelineInfoSecurity.text()).toMatchInterpolatedText( + i18n.latestPipelineDescription, + ); + expect(latestPipelineInfoSecurity.find('a').attributes('href')).toBe('test/path'); + }); + + it('should show latest pipeline info on the compliance tab with correct link when latestPipelinePath is defined', () => { + const latestPipelineInfoCompliance = findByTestId('latest-pipeline-info-compliance'); + + expect(latestPipelineInfoCompliance.text()).toMatchInterpolatedText( + i18n.latestPipelineDescription, + ); + expect(latestPipelineInfoCompliance.find('a').attributes('href')).toBe('test/path'); + }); + }); + + describe('given gitlabCiPresent & gitlabCiHistoryPath props', () => { + beforeEach(() => { + createComponent({ + augmentedSecurityFeatures: securityFeaturesMock, + augmentedComplianceFeatures: complianceFeaturesMock, + gitlabCiPresent: true, + gitlabCiHistoryPath, + }); + }); + + it('should show configuration History Link', () => { + expect(findComplianceViewHistoryLink().exists()).toBe(true); + expect(findSecurityViewHistoryLink().exists()).toBe(true); + + expect(findComplianceViewHistoryLink().attributes('href')).toBe('test/historyPath'); + expect(findSecurityViewHistoryLink().attributes('href')).toBe('test/historyPath'); + }); + }); +}); |