Commit 6ee5d266 authored by Savas Vedova's avatar Savas Vedova

Merge branch '321775-move-project-dashboard-to-vulnerability-reports' into 'master'

Move project level vulnerabilities to vulnerability report component

See merge request gitlab-org/gitlab!59586
parents de948242 04752cbf
......@@ -6,13 +6,7 @@ export default {
components: {
GlEmptyState,
},
inject: ['emptyStateSvgPath', 'securityConfigurationPath'],
props: {
helpPath: {
type: String,
required: true,
},
},
inject: ['emptyStateSvgPath', 'securityConfigurationPath', 'securityDashboardHelpPath'],
i18n: {
title: s__('SecurityReports|Monitor vulnerabilities in your project'),
description: s__(
......@@ -32,6 +26,6 @@ export default {
:primary-button-text="$options.i18n.primaryButtonText"
:primary-button-link="securityConfigurationPath"
:secondary-button-text="$options.i18n.secondaryButtonText"
:secondary-button-link="helpPath"
:secondary-button-link="securityDashboardHelpPath"
/>
</template>
<script>
import Cookies from 'js-cookie';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import AutoFixUserCallout from './auto_fix_user_callout.vue';
import CsvExportButton from './csv_export_button.vue';
import ReportsNotConfigured from './empty_states/reports_not_configured.vue';
import Filters from './first_class_vulnerability_filters.vue';
import ProjectPipelineStatus from './project_pipeline_status.vue';
import ProjectVulnerabilitiesApp from './project_vulnerabilities.vue';
import SecurityDashboardLayout from './security_dashboard_layout.vue';
import SurveyRequestBanner from './survey_request_banner.vue';
import VulnerabilitiesCountList from './vulnerability_count_list.vue';
export default {
components: {
AutoFixUserCallout,
ProjectPipelineStatus,
ProjectVulnerabilitiesApp,
ReportsNotConfigured,
SecurityDashboardLayout,
VulnerabilitiesCountList,
CsvExportButton,
Filters,
SurveyRequestBanner,
},
mixins: [glFeatureFlagsMixin()],
inject: ['dashboardDocumentation', 'autoFixDocumentation', 'projectFullPath'],
props: {
securityDashboardHelpPath: {
type: String,
required: true,
},
pipeline: {
type: Object,
required: false,
default: () => ({}),
},
},
data() {
const shouldShowAutoFixUserCallout =
this.glFeatures.securityAutoFix && !Cookies.get('auto_fix_user_callout_dismissed');
return {
filters: null,
shouldShowAutoFixUserCallout,
};
},
methods: {
handleFilterChange(filters) {
this.filters = filters;
},
handleAutoFixUserCalloutClose() {
Cookies.set('auto_fix_user_callout_dismissed', 'true');
this.shouldShowAutoFixUserCallout = false;
},
},
};
</script>
<template>
<div>
<survey-request-banner class="gl-mt-5" />
<template v-if="pipeline.id">
<auto-fix-user-callout
v-if="shouldShowAutoFixUserCallout"
:help-page-path="autoFixDocumentation"
@close="handleAutoFixUserCalloutClose"
/>
<security-dashboard-layout>
<template #header>
<div class="gl-mt-6 gl-display-flex">
<h4 class="gl-flex-grow-1 gl-my-0">
{{ s__('SecurityReports|Vulnerability Report') }}
</h4>
<csv-export-button />
</div>
<project-pipeline-status :pipeline="pipeline" />
<vulnerabilities-count-list
class="gl-mt-6"
:full-path="projectFullPath"
:filters="filters"
/>
</template>
<template #sticky>
<filters @filterChange="handleFilterChange" />
</template>
<project-vulnerabilities-app
:dashboard-documentation="dashboardDocumentation"
:filters="filters"
/>
</security-dashboard-layout>
</template>
<reports-not-configured v-else :help-path="securityDashboardHelpPath" />
</div>
</template>
......@@ -40,10 +40,6 @@ export default {
required: false,
default: false,
},
helpPath: {
type: String,
required: true,
},
},
apollo: {
trendsByDay: {
......@@ -180,7 +176,7 @@ export default {
<template>
<security-charts-layout ref="layout">
<template v-if="shouldShowEmptyState" #empty-state>
<dashboard-not-configured :help-path="helpPath" />
<dashboard-not-configured />
</template>
<template v-else-if="shouldShowCharts" #default>
<gl-line-chart
......
<script>
import { GlLoadingIcon } from '@gitlab/ui';
import GroupSecurityVulnerabilities from 'ee/security_dashboard/components/first_class_group_security_dashboard_vulnerabilities.vue';
import InstanceSecurityVulnerabilities from 'ee/security_dashboard/components/first_class_instance_security_dashboard_vulnerabilities.vue';
import Cookies from 'js-cookie';
import Filters from 'ee/security_dashboard/components/first_class_vulnerability_filters.vue';
import SecurityDashboardLayout from 'ee/security_dashboard/components/security_dashboard_layout.vue';
import { DASHBOARD_TYPES } from 'ee/security_dashboard/store/constants';
import { s__ } from '~/locale';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
import vulnerableProjectsGroupQuery from '../graphql/queries/vulnerable_projects_group.query.graphql';
import vulnerableProjectsInstanceQuery from '../graphql/queries/vulnerable_projects_instance.query.graphql';
import AutoFixUserCallout from './auto_fix_user_callout.vue';
import CsvExportButton from './csv_export_button.vue';
import DashboardNotConfiguredGroup from './empty_states/group_dashboard_not_configured.vue';
import DashboardNotConfiguredInstance from './empty_states/instance_dashboard_not_configured.vue';
import DashboardNotConfiguredProject from './empty_states/reports_not_configured.vue';
import GroupSecurityVulnerabilities from './first_class_group_security_dashboard_vulnerabilities.vue';
import InstanceSecurityVulnerabilities from './first_class_instance_security_dashboard_vulnerabilities.vue';
import ProjectPipelineStatus from './project_pipeline_status.vue';
import ProjectSecurityVulnerabilities from './project_vulnerabilities.vue';
import SurveyRequestBanner from './survey_request_banner.vue';
import VulnerabilitiesCountList from './vulnerability_count_list.vue';
export default {
components: {
AutoFixUserCallout,
SecurityDashboardLayout,
GroupSecurityVulnerabilities,
InstanceSecurityVulnerabilities,
ProjectSecurityVulnerabilities,
Filters,
CsvExportButton,
SurveyRequestBanner,
DashboardNotConfiguredGroup,
DashboardNotConfiguredInstance,
DashboardNotConfiguredProject,
ProjectPipelineStatus,
GlLoadingIcon,
VulnerabilitiesCountList,
},
inject: ['groupFullPath', 'dashboardType'],
mixins: [glFeatureFlagsMixin()],
inject: [
'groupFullPath',
'projectFullPath',
'dashboardType',
'dashboardDocumentation',
'autoFixDocumentation',
'projectFullPath',
],
props: {
pipeline: {
type: Object,
required: false,
default: () => ({}),
},
},
queries: {
[DASHBOARD_TYPES.GROUP]: vulnerableProjectsGroupQuery,
[DASHBOARD_TYPES.INSTANCE]: vulnerableProjectsInstanceQuery,
......@@ -51,30 +76,49 @@ export default {
},
},
data() {
const shouldShowAutoFixUserCallout =
this.dashboardType === DASHBOARD_TYPES.PROJECT &&
this.glFeatures.securityAutoFix &&
!Cookies.get(this.$options.autoFixUserCalloutCookieName);
return {
filters: null,
projects: [],
shouldShowAutoFixUserCallout,
};
},
computed: {
projectsWereFetched() {
return !this.$apollo.queries.projects?.loading;
},
fullPath() {
return this.groupFullPath || this.projectFullPath;
},
isGroup() {
return this.dashboardType === DASHBOARD_TYPES.GROUP;
},
isInstance() {
return this.dashboardType === DASHBOARD_TYPES.INSTANCE;
},
hasNoProjects() {
return this.projects.length === 0 && this.projectsWereFetched;
isProject() {
return this.dashboardType === DASHBOARD_TYPES.PROJECT;
},
isDashboardConfigured() {
return this.isProject
? Boolean(this.pipeline?.id)
: this.projects.length > 0 && this.projectsWereFetched;
},
},
methods: {
handleFilterChange(filters) {
this.filters = filters;
},
handleAutoFixUserCalloutClose() {
Cookies.set(this.$options.autoFixUserCalloutCookieName, 'true');
this.shouldShowAutoFixUserCallout = false;
},
},
autoFixUserCalloutCookieName: 'auto_fix_user_callout_dismissed',
i18n: {
title: s__('SecurityReports|Vulnerability Report'),
},
......@@ -84,27 +128,37 @@ export default {
<template>
<div>
<gl-loading-icon v-if="!projectsWereFetched" size="lg" class="gl-mt-6" />
<template v-else-if="hasNoProjects">
<template v-else-if="!isDashboardConfigured">
<survey-request-banner class="gl-mt-5" />
<dashboard-not-configured-group v-if="isGroup" />
<dashboard-not-configured-instance v-else-if="isInstance" />
<dashboard-not-configured-project v-else-if="isProject" />
</template>
<template v-else>
<auto-fix-user-callout
v-if="shouldShowAutoFixUserCallout"
:help-page-path="autoFixDocumentation"
@close="handleAutoFixUserCalloutClose"
/>
<security-dashboard-layout>
<template #header>
<survey-request-banner class="gl-mt-5" />
<header class="gl-my-6 gl-display-flex gl-align-items-center">
<h2 class="gl-flex-grow-1 gl-my-0">
{{ $options.i18n.title }}
</h2>
<csv-export-button />
</header>
<project-pipeline-status v-if="isProject" class="gl-mb-6" :pipeline="pipeline" />
<vulnerabilities-count-list :full-path="fullPath" :filters="filters" />
</template>
<template #sticky>
<filters :projects="projects" @filterChange="handleFilterChange" />
</template>
<group-security-vulnerabilities v-if="isGroup" :filters="filters" />
<instance-security-vulnerabilities v-else-if="isInstance" :filters="filters" />
<project-security-vulnerabilities v-else-if="isProject" :filters="filters" />
</security-dashboard-layout>
</template>
<security-dashboard-layout v-else>
<template #header>
<survey-request-banner class="gl-mt-5" />
<header class="gl-my-6 gl-display-flex gl-align-items-center">
<h2 class="gl-flex-grow-1 gl-my-0">
{{ $options.i18n.title }}
</h2>
<csv-export-button />
</header>
<vulnerabilities-count-list :full-path="groupFullPath" :filters="filters" />
</template>
<template #sticky>
<filters :projects="projects" @filterChange="handleFilterChange" />
</template>
<group-security-vulnerabilities v-if="isGroup" :filters="filters" />
<instance-security-vulnerabilities v-if="isInstance" :filters="filters" />
</security-dashboard-layout>
</div>
</template>
......@@ -35,6 +35,7 @@ export default (el, dashboardType) => {
groupFullPath: el.dataset.groupFullPath,
securityConfigurationPath: el.dataset.securityConfigurationPath,
surveyRequestSvgPath: el.dataset.surveyRequestSvgPath,
securityDashboardHelpPath: el.dataset.securityDashboardHelpPath,
};
let component;
......@@ -49,7 +50,6 @@ export default (el, dashboardType) => {
component = ProjectSecurityCharts;
props.projectFullPath = el.dataset.projectFullPath;
props.hasVulnerabilities = parseBoolean(el.dataset.hasVulnerabilities);
props.helpPath = el.dataset.securityDashboardHelpPath;
}
const router = createRouter();
......
import Vue from 'vue';
import { DASHBOARD_TYPES } from 'ee/security_dashboard/store/constants';
import { parseBoolean } from '~/lib/utils/common_utils';
import FirstClassProjectSecurityDashboard from './components/first_class_project_security_dashboard.vue';
import UnavailableState from './components/unavailable_state.vue';
import VulnerabilityReport from './components/vulnerability_report.vue';
import apolloProvider from './graphql/provider';
......@@ -62,10 +61,15 @@ export default (el, dashboardType) => {
emptyStateSvgPath,
notEnabledScannersHelpPath,
noPipelineRunScannersHelpPath,
instanceDashboardSettingsPath,
securityDashboardHelpPath,
securityConfigurationPath,
surveyRequestSvgPath,
vulnerabilitiesExportEndpoint,
groupFullPath,
projectFullPath,
autoFixDocumentation,
autoFixMrsPath,
hasVulnerabilities: parseBoolean(hasVulnerabilities),
scanners: scanners ? JSON.parse(scanners) : [],
hasJiraVulnerabilitiesIntegrationEnabled: parseBoolean(
......@@ -74,16 +78,12 @@ export default (el, dashboardType) => {
};
const props = {
securityDashboardHelpPath,
projectAddEndpoint,
projectListEndpoint,
dashboardType,
};
let component;
if (dashboardType === DASHBOARD_TYPES.PROJECT) {
component = FirstClassProjectSecurityDashboard;
props.pipeline = {
createdAt: pipelineCreatedAt,
id: pipelineId,
......@@ -91,14 +91,6 @@ export default (el, dashboardType) => {
securityBuildsFailedCount: Number(pipelineSecurityBuildsFailedCount),
securityBuildsFailedPath: pipelineSecurityBuildsFailedPath,
};
provide.projectFullPath = projectFullPath;
provide.autoFixDocumentation = autoFixDocumentation;
provide.autoFixMrsPath = autoFixMrsPath;
} else if (dashboardType === DASHBOARD_TYPES.GROUP) {
component = VulnerabilityReport;
} else if (dashboardType === DASHBOARD_TYPES.INSTANCE) {
provide.instanceDashboardSettingsPath = instanceDashboardSettingsPath;
component = VulnerabilityReport;
}
const router = createRouter();
......@@ -111,7 +103,7 @@ export default (el, dashboardType) => {
apolloProvider,
provide,
render(createElement) {
return createElement(component, { props });
return createElement(VulnerabilityReport, { props });
},
});
};
......@@ -3,17 +3,17 @@ import ReportsNotConfigured from 'ee/security_dashboard/components/empty_states/
describe('reports not configured empty state', () => {
let wrapper;
const helpPath = '/help';
const emptyStateSvgPath = '/placeholder.svg';
const securityConfigurationPath = '/configuration';
const securityDashboardHelpPath = '/help';
const createComponent = () => {
wrapper = shallowMount(ReportsNotConfigured, {
provide: {
emptyStateSvgPath,
securityConfigurationPath,
securityDashboardHelpPath,
},
propsData: { helpPath },
});
};
......
import { GlBanner } from '@gitlab/ui';
import { within } from '@testing-library/dom';
import { shallowMount } from '@vue/test-utils';
import Cookies from 'js-cookie';
import AutoFixUserCallout from 'ee/security_dashboard/components/auto_fix_user_callout.vue';
import CsvExportButton from 'ee/security_dashboard/components/csv_export_button.vue';
import ReportsNotConfigured from 'ee/security_dashboard/components/empty_states/reports_not_configured.vue';
import FirstClassProjectSecurityDashboard from 'ee/security_dashboard/components/first_class_project_security_dashboard.vue';
import Filters from 'ee/security_dashboard/components/first_class_vulnerability_filters.vue';
import ProjectPipelineStatus from 'ee/security_dashboard/components/project_pipeline_status.vue';
import ProjectVulnerabilitiesApp from 'ee/security_dashboard/components/project_vulnerabilities.vue';
import SecurityDashboardLayout from 'ee/security_dashboard/components/security_dashboard_layout.vue';
import SurveyRequestBanner from 'ee/security_dashboard/components/survey_request_banner.vue';
import VulnerabilityCountList from 'ee/security_dashboard/components/vulnerability_count_list.vue';
const props = {
notEnabledScannersHelpPath: '/help/docs/',
noPipelineRunScannersHelpPath: '/new/pipeline',
pipeline: {
createdAt: '2020-10-06T20:08:07Z',
id: '214',
path: '/mixed-vulnerabilities/dependency-list-test-01/-/pipelines/214',
},
securityDashboardHelpPath: '/security/dashboard/help-path',
};
const provide = {
projectFullPath: '/group/project',
dashboardDocumentation: '/help/docs',
autoFixDocumentation: '/auto/fix/documentation',
emptyStateSvgPath: '/svgs/empty/svg',
glFeatures: {
securityAutoFix: true,
},
};
const filters = { foo: 'bar' };
describe('First class Project Security Dashboard component', () => {
let wrapper;
const findFilters = () => wrapper.findComponent(Filters);
const findProjectPipelineStatus = () => wrapper.findComponent(ProjectPipelineStatus);
const findVulnerabilities = () => wrapper.findComponent(ProjectVulnerabilitiesApp);
const findVulnerabilityCountList = () => wrapper.findComponent(VulnerabilityCountList);
const findUnconfiguredState = () => wrapper.findComponent(ReportsNotConfigured);
const findCsvExportButton = () => wrapper.findComponent(CsvExportButton);
const findAutoFixUserCallout = () => wrapper.findComponent(AutoFixUserCallout);
const findSurveyRequestBanner = () => wrapper.findComponent(SurveyRequestBanner);
const createComponent = (options) => {
wrapper = shallowMount(FirstClassProjectSecurityDashboard, {
propsData: {
...props,
...options.props,
},
provide,
stubs: { SecurityDashboardLayout, GlBanner },
...options,
});
};
afterEach(() => {
wrapper.destroy();
wrapper = null;
});
describe('on render when there are vulnerabilities', () => {
beforeEach(() => {
createComponent({
props: { hasVulnerabilities: true },
data: () => ({ filters }),
});
});
it('should render the header correctly', () => {
expect(
within(wrapper.element).getByRole('heading', { name: 'Vulnerability Report' }),
).not.toBe(null);
});
it('should render the vulnerabilities', () => {
expect(findVulnerabilities().exists()).toBe(true);
});
it('should pass down the properties correctly to the vulnerabilities', () => {
expect(findVulnerabilities().props()).toEqual({
projectFullPath: props.projectFullPath,
filters,
});
});
it('should pass down the properties correctly to the vulnerability count list', () => {
expect(findVulnerabilityCountList().props()).toEqual({
fullPath: provide.projectFullPath,
filters,
});
});
it('should render the filters component', () => {
expect(findFilters().exists()).toBe(true);
});
it('does not display the unconfigured state', () => {
expect(findUnconfiguredState().exists()).toBe(false);
});
it('should display the csv export button', () => {
expect(findCsvExportButton().props('vulnerabilitiesExportEndpoint')).toEqual(
props.vulnerabilitiesExportEndpoint,
);
});
it('should display the project pipeline status', () => {
expect(findProjectPipelineStatus()).toExist();
});
it('should show the survey request banner', () => {
expect(findSurveyRequestBanner().exists()).toBe(true);
});
});
describe('auto-fix user callout', () => {
describe('feature flag disabled', () => {
beforeEach(() => {
createComponent({
props: { hasVulnerabilities: true },
provide: {
...provide,
glFeatures: {
securityAutoFix: false,
},
},
});
});
it('does not show user callout', () => {
expect(findAutoFixUserCallout().exists()).toBe(false);
});
});
describe('cookie not set', () => {
beforeEach(() => {
jest.spyOn(Cookies, 'set');
createComponent({
props: { hasVulnerabilities: true },
});
});
it('shows user callout by default', () => {
expect(findAutoFixUserCallout().exists()).toBe(true);
});
it('when dismissed, hides the user callout and sets the cookie', async () => {
await findAutoFixUserCallout().vm.$emit('close');
expect(findAutoFixUserCallout().exists()).toBe(false);
expect(Cookies.set).toHaveBeenCalledWith('auto_fix_user_callout_dismissed', 'true');
});
});
describe('cookie set', () => {
beforeEach(() => {
jest.doMock('js-cookie', () => ({
get: jest.fn().mockReturnValue(true),
}));
createComponent({
props: { hasVulnerabilities: true },
});
});
it('does not show user callout', () => {
expect(findAutoFixUserCallout().exists()).toBe(false);
});
});
});
describe('with filter data', () => {
beforeEach(() => {
createComponent({
props: {
hasVulnerabilities: true,
},
data() {
return { filters };
},
});
});
it('should pass the filter data down to the vulnerabilities', () => {
expect(findVulnerabilities().props().filters).toEqual(filters);
});
});
describe('when there is no vulnerability', () => {
beforeEach(() => {
createComponent({
props: {
pipeline: { id: undefined },
},
});
});
it('displays the unconfigured state', () => {
expect(findUnconfiguredState().exists()).toBe(true);
});
it('shows the survey request banner', () => {
expect(findSurveyRequestBanner().exists()).toBe(true);
});
});
});
......@@ -137,7 +137,7 @@ describe('Project Security Charts component', () => {
});
it('should display the empty state', () => {
expect(findEmptyState().props()).toEqual({ helpPath });
expect(findEmptyState().exists()).toBe(true);
});
it('should not display the chart', () => {
......
import { GlLoadingIcon } from '@gitlab/ui';
import { shallowMount, createLocalVue } from '@vue/test-utils';
import Cookies from 'js-cookie';
import { nextTick } from 'vue';
import VueApollo from 'vue-apollo';
import AutoFixUserCallout from 'ee/security_dashboard/components/auto_fix_user_callout.vue';
import CsvExportButton from 'ee/security_dashboard/components/csv_export_button.vue';
import DashboardNotConfiguredGroup from 'ee/security_dashboard/components/empty_states/group_dashboard_not_configured.vue';
import DashboardNotConfiguredInstance from 'ee/security_dashboard/components/empty_states/instance_dashboard_not_configured.vue';
import DashboardNotConfiguredProject from 'ee/security_dashboard/components/empty_states/reports_not_configured.vue';
import GroupVulnerabilities from 'ee/security_dashboard/components/first_class_group_security_dashboard_vulnerabilities.vue';
import InstanceVulnerabilities from 'ee/security_dashboard/components/first_class_instance_security_dashboard_vulnerabilities.vue';
import Filters from 'ee/security_dashboard/components/first_class_vulnerability_filters.vue';
import ProjectPipelineStatus from 'ee/security_dashboard/components/project_pipeline_status.vue';
import ProjectVulnerabilities from 'ee/security_dashboard/components/project_vulnerabilities.vue';
import SecurityDashboardLayout from 'ee/security_dashboard/components/security_dashboard_layout.vue';
import SurveyRequestBanner from 'ee/security_dashboard/components/survey_request_banner.vue';
import VulnerabilitiesCountList from 'ee/security_dashboard/components/vulnerability_count_list.vue';
......@@ -24,12 +29,17 @@ describe('Vulnerability Report', () => {
const findSurveyRequestBanner = () => wrapper.findComponent(SurveyRequestBanner);
const findInstanceVulnerabilities = () => wrapper.findComponent(InstanceVulnerabilities);
const findGroupVulnerabilities = () => wrapper.findComponent(GroupVulnerabilities);
const findProjectVulnerabilities = () => wrapper.findComponent(ProjectVulnerabilities);
const findCsvExportButton = () => wrapper.findComponent(CsvExportButton);
const findGroupEmptyState = () => wrapper.findComponent(DashboardNotConfiguredGroup);
const findInstanceEmptyState = () => wrapper.findComponent(DashboardNotConfiguredInstance);
const findProjectEmptyState = () => wrapper.findComponent(DashboardNotConfiguredProject);
const findLoadingIcon = () => wrapper.findComponent(GlLoadingIcon);
const findFilters = () => wrapper.findComponent(Filters);
const findVulnerabilitiesCountList = () => wrapper.findComponent(VulnerabilitiesCountList);
const findProjectPipelineStatus = () => wrapper.findComponent(ProjectPipelineStatus);
const findAutoFixUserCallout = () => wrapper.findComponent(AutoFixUserCallout);
const findHeader = () => wrapper.find('h2');
const createWrapper = ({ data = {}, mocks, propsData, provide, apolloProvider }) => {
......@@ -45,7 +55,14 @@ describe('Vulnerability Report', () => {
data: () => data,
mocks,
propsData,
provide: { groupFullPath: undefined, ...provide },
provide: {
groupFullPath: undefined,
projectFullPath: undefined,
autoFixDocumentation: undefined,
dashboardDocumentation: 'path/to/documentation',
securityDashboardHelpPath: 'path/to/project/documentation',
...provide,
},
stubs: { SecurityDashboardLayout },
});
};
......@@ -119,6 +136,10 @@ describe('Vulnerability Report', () => {
it('shows the vulnerability count list and passes the filters prop', () => {
expect(findVulnerabilitiesCountList().props('filters')).toBe(filters);
});
it('does not show project pipeline status', () => {
expect(findProjectPipelineStatus().exists()).toBe(false);
});
});
describe('when initialized - group level', () => {
......@@ -168,6 +189,7 @@ describe('Vulnerability Report', () => {
it('only renders the empty state', () => {
expect(findGroupEmptyState().exists()).toBe(true);
expect(findInstanceEmptyState().exists()).toBe(false);
expect(findProjectEmptyState().exists()).toBe(false);
expect(findCsvExportButton().exists()).toBe(false);
expect(findFilters().exists()).toBe(false);
expect(findVulnerabilitiesCountList().exists()).toBe(false);
......@@ -201,4 +223,72 @@ describe('Vulnerability Report', () => {
expect(findSurveyRequestBanner().exists()).toBe(false);
});
});
describe('when initialized - project level', () => {
const createProjectWrapper = ({ securityAutoFix } = {}) =>
createWrapper({
provide: {
dashboardType: DASHBOARD_TYPES.PROJECT,
autoFixDocumentation: 'path/to/help-page',
glFeatures: {
securityAutoFix,
},
},
propsData: {
pipeline: {
id: '591',
},
},
apolloProvider: createApolloProvider(),
});
it('does not show user callout when feature flag is disabled', () => {
wrapper = createProjectWrapper({ securityAutoFix: false });
expect(findAutoFixUserCallout().exists()).toBe(false);
});
it('shows user callout when the cookie is not set and hides it when dismissed', async () => {
jest.spyOn(Cookies, 'set');
wrapper = createProjectWrapper({ securityAutoFix: true });
const autoFixUserCallOut = findAutoFixUserCallout();
expect(autoFixUserCallOut.exists()).toBe(true);
await autoFixUserCallOut.vm.$emit('close');
expect(autoFixUserCallOut.exists()).toBe(false);
expect(Cookies.set).toHaveBeenCalledWith(
wrapper.vm.$options.autoFixUserCalloutCookieName,
'true',
);
});
it('does not show user callout when the cookie is set', () => {
jest.doMock('js-cookie', () => ({ get: jest.fn().mockReturnValue(true) }));
wrapper = createProjectWrapper({ securityAutoFix: true });
expect(findAutoFixUserCallout().exists()).toBe(false);
});
it('shows the project pipeline status', () => {
wrapper = createProjectWrapper();
expect(findProjectPipelineStatus().exists()).toBe(true);
});
it('renders the vulnerabilities', () => {
wrapper = createProjectWrapper();
expect(findProjectVulnerabilities().exists()).toBe(true);
});
});
describe('when uninitialized - project level', () => {
beforeEach(() => {
wrapper = createWrapper({
provide: {
dashboardType: DASHBOARD_TYPES.PROJECT,
},
apolloProvider: createApolloProvider(),
});
});
it('renders empty project state', () => {
expect(findProjectEmptyState().exists()).toBe(true);
});
});
});
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