324 lines
11 KiB
JavaScript
324 lines
11 KiB
JavaScript
import Vue, { nextTick } from 'vue';
|
|
import VueApollo from 'vue-apollo';
|
|
import { GlTab, GlTabs, GlLink } from '@gitlab/ui';
|
|
import { useLocalStorageSpy } from 'helpers/local_storage_helper';
|
|
import { makeMockUserCalloutDismisser } from 'helpers/mock_user_callout_dismisser';
|
|
import stubChildren from 'helpers/stub_children';
|
|
import { mountExtended } 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 { 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 { securityFeaturesMock, provideMock } from '../mock_data';
|
|
|
|
const gitlabCiHistoryPath = 'test/historyPath';
|
|
const { vulnerabilityTrainingDocsPath, projectFullPath } = provideMock;
|
|
|
|
useLocalStorageSpy();
|
|
Vue.use(VueApollo);
|
|
|
|
describe('~/security_configuration/components/app', () => {
|
|
let wrapper;
|
|
let userCalloutDismissSpy;
|
|
|
|
const createComponent = ({ shouldShowCallout = true, ...propsData } = {}) => {
|
|
userCalloutDismissSpy = jest.fn();
|
|
|
|
wrapper = mountExtended(SecurityConfigurationApp, {
|
|
propsData: {
|
|
augmentedSecurityFeatures: securityFeaturesMock,
|
|
securityTrainingEnabled: true,
|
|
...propsData,
|
|
},
|
|
provide: provideMock,
|
|
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 findGlTabs = () => wrapper.findComponent(GlTabs);
|
|
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}"]`;
|
|
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 findAutoDevopsAlert = () => wrapper.findComponent(AutoDevopsAlert);
|
|
const findAutoDevopsEnabledAlert = () => wrapper.findComponent(AutoDevopsEnabledAlert);
|
|
const findVulnerabilityManagementTab = () => wrapper.findByTestId('vulnerability-management-tab');
|
|
|
|
describe('basic structure', () => {
|
|
beforeEach(() => {
|
|
createComponent();
|
|
});
|
|
|
|
it('renders main-heading with correct text', () => {
|
|
const mainHeading = findMainHeading();
|
|
expect(mainHeading.exists()).toBe(true);
|
|
expect(mainHeading.text()).toContain('Security configuration');
|
|
});
|
|
|
|
describe('tabs', () => {
|
|
const expectedTabs = ['security-testing', 'vulnerability-management'];
|
|
|
|
it('renders GlTab Component', () => {
|
|
expect(findTab().exists()).toBe(true);
|
|
});
|
|
|
|
it('passes the `sync-active-tab-with-query-params` prop', () => {
|
|
expect(findGlTabs().props('syncActiveTabWithQueryParams')).toBe(true);
|
|
});
|
|
|
|
it('lazy loads each tab', () => {
|
|
expect(findGlTabs().attributes('lazy')).not.toBe(undefined);
|
|
});
|
|
|
|
it('renders correct amount of tabs', () => {
|
|
expect(findTabs()).toHaveLength(expectedTabs.length);
|
|
});
|
|
|
|
it.each(expectedTabs)('renders the %s tab', (tabName) => {
|
|
expect(findByTestId(`${tabName}-tab`).exists()).toBe(true);
|
|
});
|
|
|
|
it.each(expectedTabs)('has the %s query-param-value', (tabName) => {
|
|
expect(findByTestId(`${tabName}-tab`).props('queryParamValue')).toBe(tabName);
|
|
});
|
|
});
|
|
|
|
it('renders right amount of feature cards for given props with correct props', () => {
|
|
const cards = findFeatureCards();
|
|
expect(cards).toHaveLength(1);
|
|
expect(cards.at(0).props()).toEqual({ feature: securityFeaturesMock[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(findSecurityViewHistoryLink().exists()).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('Manage via MR Error Alert', () => {
|
|
beforeEach(() => {
|
|
createComponent();
|
|
});
|
|
|
|
describe('on initial load', () => {
|
|
it('should not show Manage via MR Error Alert', () => {
|
|
expect(findManageViaMRErrorAlert().exists()).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('when error occurs', () => {
|
|
const errorMessage = 'There was a manage via MR error';
|
|
|
|
it('should show Alert with error Message', async () => {
|
|
expect(findManageViaMRErrorAlert().exists()).toBe(false);
|
|
findFeatureCards().at(0).vm.$emit('error', errorMessage);
|
|
|
|
await nextTick();
|
|
expect(findManageViaMRErrorAlert().exists()).toBe(true);
|
|
expect(findManageViaMRErrorAlert().text()).toBe(errorMessage);
|
|
});
|
|
|
|
it('should hide Alert when it is dismissed', async () => {
|
|
findFeatureCards().at(0).vm.$emit('error', errorMessage);
|
|
|
|
await nextTick();
|
|
expect(findManageViaMRErrorAlert().exists()).toBe(true);
|
|
|
|
findManageViaMRErrorAlert().vm.$emit('dismiss');
|
|
await nextTick();
|
|
expect(findManageViaMRErrorAlert().exists()).toBe(false);
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('Auto DevOps hint alert', () => {
|
|
describe('given the right props', () => {
|
|
beforeEach(() => {
|
|
createComponent({
|
|
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();
|
|
});
|
|
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} | ${[projectFullPath]} | ${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({
|
|
autoDevopsEnabled,
|
|
});
|
|
});
|
|
|
|
it(`${shouldRender ? 'renders' : 'does not render'}`, () => {
|
|
expect(findAutoDevopsEnabledAlert().exists()).toBe(shouldRender);
|
|
});
|
|
});
|
|
|
|
describe('dismissing', () => {
|
|
describe.each`
|
|
dismissedProjects | expectedWrittenValue
|
|
${null} | ${[projectFullPath]}
|
|
${[]} | ${[projectFullPath]}
|
|
${['foo/bar']} | ${['foo/bar', projectFullPath]}
|
|
${[projectFullPath]} | ${[projectFullPath]}
|
|
`(
|
|
'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,
|
|
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('when given latestPipelinePath props', () => {
|
|
beforeEach(() => {
|
|
createComponent({
|
|
latestPipelinePath: 'test/path',
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('given gitlabCiPresent & gitlabCiHistoryPath props', () => {
|
|
beforeEach(() => {
|
|
createComponent({
|
|
gitlabCiPresent: true,
|
|
gitlabCiHistoryPath,
|
|
});
|
|
});
|
|
|
|
it('should show configuration History Link', () => {
|
|
expect(findSecurityViewHistoryLink().exists()).toBe(true);
|
|
|
|
expect(findSecurityViewHistoryLink().attributes('href')).toBe('test/historyPath');
|
|
});
|
|
});
|
|
|
|
describe('Vulnerability management', () => {
|
|
const props = { securityTrainingEnabled: true };
|
|
|
|
beforeEach(() => {
|
|
createComponent({
|
|
...props,
|
|
});
|
|
});
|
|
|
|
it('shows the tab', () => {
|
|
expect(findVulnerabilityManagementTab().exists()).toBe(true);
|
|
});
|
|
|
|
it('renders TrainingProviderList component', () => {
|
|
expect(findTrainingProviderList().props()).toMatchObject(props);
|
|
});
|
|
|
|
it('renders security training description', () => {
|
|
expect(findVulnerabilityManagementTab().text()).toContain(i18n.securityTrainingDescription);
|
|
});
|
|
|
|
it('renders link to help docs', () => {
|
|
const trainingLink = findVulnerabilityManagementTab().findComponent(GlLink);
|
|
|
|
expect(trainingLink.text()).toBe('Learn more about vulnerability training');
|
|
expect(trainingLink.attributes('href')).toBe(vulnerabilityTrainingDocsPath);
|
|
});
|
|
});
|
|
});
|