Commit 993a83a6 authored by Kushal Pandya's avatar Kushal Pandya

Merge branch 'djadmin-dast-profiles-refactor' into 'master'

Refactor DAST Profiles List components

See merge request gitlab-org/gitlab!48670
parents ed5ba395 d926063f
...@@ -4,7 +4,6 @@ import { camelCase, kebabCase } from 'lodash'; ...@@ -4,7 +4,6 @@ import { camelCase, kebabCase } from 'lodash';
import * as Sentry from '~/sentry/wrapper'; import * as Sentry from '~/sentry/wrapper';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
import { getLocationHash } from '~/lib/utils/url_utility'; import { getLocationHash } from '~/lib/utils/url_utility';
import ProfilesList from './dast_profiles_list.vue';
import * as cacheUtils from '../graphql/cache_utils'; import * as cacheUtils from '../graphql/cache_utils';
import { getProfileSettings } from '../settings/profiles'; import { getProfileSettings } from '../settings/profiles';
...@@ -14,7 +13,6 @@ export default { ...@@ -14,7 +13,6 @@ export default {
GlDropdownItem, GlDropdownItem,
GlTab, GlTab,
GlTabs, GlTabs,
ProfilesList,
}, },
props: { props: {
createNewProfilePaths: { createNewProfilePaths: {
...@@ -249,10 +247,11 @@ export default { ...@@ -249,10 +247,11 @@ export default {
<gl-tabs v-model="tabIndex"> <gl-tabs v-model="tabIndex">
<gl-tab v-for="(settings, profileType) in profileSettings" :key="profileType"> <gl-tab v-for="(settings, profileType) in profileSettings" :key="profileType">
<template #title> <template #title>
<span>{{ settings.i18n.tabName }}</span> <span>{{ settings.i18n.name }}</span>
</template> </template>
<profiles-list <component
:is="profileSettings[profileType].component"
:data-testid="`${profileType}List`" :data-testid="`${profileType}List`"
:error-message="profileTypes[profileType].errorMessage" :error-message="profileTypes[profileType].errorMessage"
:error-details="profileTypes[profileType].errorDetails" :error-details="profileTypes[profileType].errorDetails"
...@@ -260,6 +259,7 @@ export default { ...@@ -260,6 +259,7 @@ export default {
:is-loading="isLoadingProfiles(profileType)" :is-loading="isLoadingProfiles(profileType)"
:profiles-per-page="$options.profilesPerPage" :profiles-per-page="$options.profilesPerPage"
:profiles="profileTypes[profileType].profiles" :profiles="profileTypes[profileType].profiles"
:table-label="settings.i18n.name"
:fields="settings.tableFields" :fields="settings.tableFields"
:full-path="projectFullPath" :full-path="projectFullPath"
@load-more-profiles="fetchMoreProfiles(profileType)" @load-more-profiles="fetchMoreProfiles(profileType)"
......
...@@ -3,40 +3,32 @@ import { uniqueId } from 'lodash'; ...@@ -3,40 +3,32 @@ import { uniqueId } from 'lodash';
import { import {
GlAlert, GlAlert,
GlButton, GlButton,
GlIcon,
GlModal, GlModal,
GlSkeletonLoader, GlSkeletonLoader,
GlTable, GlTable,
GlTooltipDirective, GlTooltipDirective,
} from '@gitlab/ui'; } from '@gitlab/ui';
import DastSiteValidationModal from 'ee/security_configuration/dast_site_validation/components/dast_site_validation_modal.vue';
import {
DAST_SITE_VALIDATION_STATUS,
DAST_SITE_VALIDATION_STATUS_PROPS,
} from 'ee/security_configuration/dast_site_validation/constants';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
const { PENDING, FAILED } = DAST_SITE_VALIDATION_STATUS;
export default { export default {
components: { components: {
GlAlert, GlAlert,
GlButton, GlButton,
GlIcon,
GlModal, GlModal,
GlSkeletonLoader, GlSkeletonLoader,
GlTable, GlTable,
DastSiteValidationModal,
}, },
directives: { directives: {
GlTooltip: GlTooltipDirective, GlTooltip: GlTooltipDirective,
}, },
mixins: [glFeatureFlagsMixin()],
props: { props: {
profiles: { profiles: {
type: Array, type: Array,
required: true, required: true,
}, },
tableLabel: {
type: String,
required: true,
},
fields: { fields: {
type: Array, type: Array,
required: true, required: true,
...@@ -73,10 +65,8 @@ export default { ...@@ -73,10 +65,8 @@ export default {
data() { data() {
return { return {
toBeDeletedProfileId: null, toBeDeletedProfileId: null,
validatingProfile: null,
}; };
}, },
statuses: DAST_SITE_VALIDATION_STATUS_PROPS,
computed: { computed: {
hasError() { hasError() {
return this.errorMessage !== ''; return this.errorMessage !== '';
...@@ -115,24 +105,6 @@ export default { ...@@ -115,24 +105,6 @@ export default {
handleCancel() { handleCancel() {
this.toBeDeletedProfileId = null; this.toBeDeletedProfileId = null;
}, },
shouldShowValidationBtn(status) {
return (
this.glFeatures.securityOnDemandScansSiteValidation &&
(status === PENDING || status === FAILED)
);
},
shouldShowValidationStatus(status) {
return this.glFeatures.securityOnDemandScansSiteValidation && status !== PENDING;
},
showValidationModal() {
this.$refs['dast-site-validation-modal'].show();
},
setValidatingProfile(profile) {
this.validatingProfile = profile;
this.$nextTick(() => {
this.showValidationModal();
});
},
}, },
}; };
</script> </script>
...@@ -140,7 +112,7 @@ export default { ...@@ -140,7 +112,7 @@ export default {
<section> <section>
<div v-if="shouldShowTable"> <div v-if="shouldShowTable">
<gl-table <gl-table
:aria-label="s__('DastProfiles|Site Profiles')" :aria-label="tableLabel"
:busy="isLoadingInitialProfiles" :busy="isLoadingInitialProfiles"
:fields="tableFields" :fields="tableFields"
:items="profiles" :items="profiles"
...@@ -166,30 +138,13 @@ export default { ...@@ -166,30 +138,13 @@ export default {
<strong>{{ value }}</strong> <strong>{{ value }}</strong>
</template> </template>
<template #cell(validationStatus)="{ value }"> <template v-for="slotName in Object.keys($scopedSlots)" #[slotName]="slotScope">
<template v-if="shouldShowValidationStatus(value)"> <slot :name="slotName" v-bind="slotScope"></slot>
<span :class="$options.statuses[value].cssClass">
{{ $options.statuses[value].label }}
</span>
<gl-icon
v-gl-tooltip
name="question-o"
class="gl-vertical-align-text-bottom gl-text-gray-300 gl-ml-2"
:title="$options.statuses[value].tooltipText"
/>
</template>
</template> </template>
<template #cell(actions)="{ item }"> <template #cell(actions)="{ item }">
<div class="gl-text-right"> <div class="gl-text-right">
<gl-button <slot name="actions" :profile="item"></slot>
v-if="shouldShowValidationBtn(item.validationStatus)"
variant="info"
category="secondary"
size="small"
@click="setValidatingProfile(item)"
>{{ s__('DastSiteValidation|Validate target site') }}</gl-button
>
<gl-button v-if="item.editPath" :href="item.editPath" class="gl-mx-5" size="small">{{ <gl-button v-if="item.editPath" :href="item.editPath" class="gl-mx-5" size="small">{{
__('Edit') __('Edit')
...@@ -248,11 +203,6 @@ export default { ...@@ -248,11 +203,6 @@ export default {
@cancel="handleCancel" @cancel="handleCancel"
/> />
<dast-site-validation-modal <slot></slot>
v-if="validatingProfile"
ref="dast-site-validation-modal"
:full-path="fullPath"
:target-url="validatingProfile.targetUrl"
/>
</section> </section>
</template> </template>
<script>
import ProfilesList from './dast_profiles_list.vue';
export default {
components: {
ProfilesList,
},
};
</script>
<template>
<profiles-list v-bind="$attrs" v-on="$listeners" />
</template>
<script>
import { GlButton, GlIcon, GlTooltipDirective } from '@gitlab/ui';
import {
DAST_SITE_VALIDATION_STATUS,
DAST_SITE_VALIDATION_STATUS_PROPS,
} from 'ee/security_configuration/dast_site_validation/constants';
import DastSiteValidationModal from 'ee/security_configuration/dast_site_validation/components/dast_site_validation_modal.vue';
import ProfilesList from './dast_profiles_list.vue';
import glFeatureFlagsMixin from '~/vue_shared/mixins/gl_feature_flags_mixin';
const { PENDING, FAILED } = DAST_SITE_VALIDATION_STATUS;
export default {
components: {
GlButton,
GlIcon,
DastSiteValidationModal,
ProfilesList,
},
directives: {
GlTooltip: GlTooltipDirective,
},
mixins: [glFeatureFlagsMixin()],
props: {
fullPath: {
type: String,
required: true,
},
},
data() {
return {
validatingProfile: null,
};
},
statuses: DAST_SITE_VALIDATION_STATUS_PROPS,
methods: {
shouldShowValidationBtn(status) {
return (
this.glFeatures.securityOnDemandScansSiteValidation &&
(status === PENDING || status === FAILED)
);
},
shouldShowValidationStatus(status) {
return this.glFeatures.securityOnDemandScansSiteValidation && status !== PENDING;
},
showValidationModal() {
this.$refs['dast-site-validation-modal'].show();
},
setValidatingProfile(profile) {
this.validatingProfile = profile;
this.$nextTick(() => {
this.showValidationModal();
});
},
},
};
</script>
<template>
<profiles-list :full-path="fullPath" v-bind="$attrs" v-on="$listeners">
<template #cell(validationStatus)="{ value }">
<template v-if="shouldShowValidationStatus(value)">
<span :class="$options.statuses[value].cssClass">
{{ $options.statuses[value].label }}
</span>
<gl-icon
v-gl-tooltip
name="question-o"
class="gl-vertical-align-text-bottom gl-text-gray-300 gl-ml-2"
:title="$options.statuses[value].tooltipText"
/>
</template>
</template>
<template #actions="{ profile }">
<gl-button
v-if="shouldShowValidationBtn(profile.validationStatus)"
variant="info"
category="secondary"
size="small"
@click="setValidatingProfile(profile)"
>{{ s__('DastSiteValidation|Validate target site') }}</gl-button
>
</template>
<dast-site-validation-modal
v-if="validatingProfile"
ref="dast-site-validation-modal"
:full-path="fullPath"
:target-url="validatingProfile.targetUrl"
/>
</profiles-list>
</template>
...@@ -3,6 +3,8 @@ import dastSiteProfilesDelete from 'ee/security_configuration/dast_profiles/grap ...@@ -3,6 +3,8 @@ import dastSiteProfilesDelete from 'ee/security_configuration/dast_profiles/grap
import dastScannerProfilesQuery from 'ee/security_configuration/dast_profiles/graphql/dast_scanner_profiles.query.graphql'; import dastScannerProfilesQuery from 'ee/security_configuration/dast_profiles/graphql/dast_scanner_profiles.query.graphql';
import dastScannerProfilesDelete from 'ee/security_configuration/dast_profiles/graphql/dast_scanner_profiles_delete.mutation.graphql'; import dastScannerProfilesDelete from 'ee/security_configuration/dast_profiles/graphql/dast_scanner_profiles_delete.mutation.graphql';
import { dastProfilesDeleteResponse } from 'ee/security_configuration/dast_profiles/graphql/cache_utils'; import { dastProfilesDeleteResponse } from 'ee/security_configuration/dast_profiles/graphql/cache_utils';
import DastSiteProfileList from 'ee/security_configuration/dast_profiles/components/dast_site_profiles_list.vue';
import DastScannerProfileList from 'ee/security_configuration/dast_profiles/components/dast_scanner_profiles_list.vue';
import { s__ } from '~/locale'; import { s__ } from '~/locale';
export const getProfileSettings = ({ createNewProfilePaths }) => ({ export const getProfileSettings = ({ createNewProfilePaths }) => ({
...@@ -19,10 +21,11 @@ export const getProfileSettings = ({ createNewProfilePaths }) => ({ ...@@ -19,10 +21,11 @@ export const getProfileSettings = ({ createNewProfilePaths }) => ({
}), }),
}, },
}, },
component: DastSiteProfileList,
tableFields: ['profileName', 'targetUrl', 'validationStatus'], tableFields: ['profileName', 'targetUrl', 'validationStatus'],
i18n: { i18n: {
createNewLinkText: s__('DastProfiles|Site Profile'), createNewLinkText: s__('DastProfiles|Site Profile'),
tabName: s__('DastProfiles|Site Profiles'), name: s__('DastProfiles|Site Profiles'),
errorMessages: { errorMessages: {
fetchNetworkError: s__( fetchNetworkError: s__(
'DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later.', 'DastProfiles|Could not fetch site profiles. Please refresh the page, or try again later.',
...@@ -47,10 +50,11 @@ export const getProfileSettings = ({ createNewProfilePaths }) => ({ ...@@ -47,10 +50,11 @@ export const getProfileSettings = ({ createNewProfilePaths }) => ({
}), }),
}, },
}, },
component: DastScannerProfileList,
tableFields: ['profileName'], tableFields: ['profileName'],
i18n: { i18n: {
createNewLinkText: s__('DastProfiles|Scanner Profile'), createNewLinkText: s__('DastProfiles|Scanner Profile'),
tabName: s__('DastProfiles|Scanner Profiles'), name: s__('DastProfiles|Scanner Profiles'),
errorMessages: { errorMessages: {
fetchNetworkError: s__( fetchNetworkError: s__(
'DastProfiles|Could not fetch scanner profiles. Please refresh the page, or try again later.', 'DastProfiles|Could not fetch scanner profiles. Please refresh the page, or try again later.',
......
...@@ -14,6 +14,7 @@ describe('EE - DastProfilesList', () => { ...@@ -14,6 +14,7 @@ describe('EE - DastProfilesList', () => {
const createComponentFactory = (mountFn = shallowMount) => (options = {}) => { const createComponentFactory = (mountFn = shallowMount) => (options = {}) => {
const defaultProps = { const defaultProps = {
profiles: [], profiles: [],
tableLabel: 'Profiles Table',
fields: ['profileName', 'targetUrl', 'validationStatus'], fields: ['profileName', 'targetUrl', 'validationStatus'],
hasMorePages: false, hasMorePages: false,
profilesPerPage: 10, profilesPerPage: 10,
...@@ -27,9 +28,6 @@ describe('EE - DastProfilesList', () => { ...@@ -27,9 +28,6 @@ describe('EE - DastProfilesList', () => {
merge( merge(
{}, {},
{ {
provide: {
glFeatures: { securityOnDemandScansSiteValidation: true },
},
propsData: defaultProps, propsData: defaultProps,
}, },
options, options,
...@@ -46,7 +44,7 @@ describe('EE - DastProfilesList', () => { ...@@ -46,7 +44,7 @@ describe('EE - DastProfilesList', () => {
const createFullComponent = createComponentFactory(mount); const createFullComponent = createComponentFactory(mount);
const withinComponent = () => within(wrapper.element); const withinComponent = () => within(wrapper.element);
const getTable = () => withinComponent().getByRole('table', { name: /site profiles/i }); const getTable = () => withinComponent().getByRole('table', { name: /profiles table/i });
const getAllRowGroups = () => within(getTable()).getAllByRole('rowgroup'); const getAllRowGroups = () => within(getTable()).getAllByRole('rowgroup');
const getTableBody = () => { const getTableBody = () => {
// first item is the table head // first item is the table head
...@@ -140,53 +138,23 @@ describe('EE - DastProfilesList', () => { ...@@ -140,53 +138,23 @@ describe('EE - DastProfilesList', () => {
expect(editLink).not.toBe(null); expect(editLink).not.toBe(null);
expect(editLink.getAttribute('href')).toBe(profile.editPath); expect(editLink.getAttribute('href')).toBe(profile.editPath);
}); });
});
describe('with site validation enabled', () => { describe('profile list with scoped slots', () => {
describe.each` beforeEach(() => {
status | statusEnum | label | hasValidateButton createFullComponent({
${'pending'} | ${'PENDING_VALIDATION'} | ${''} | ${true} propsData: { profiles },
${'in-progress'} | ${'INPROGRESS_VALIDATION'} | ${'Validating...'} | ${false} scopedSlots: {
${'passed'} | ${'PASSED_VALIDATION'} | ${'Validated'} | ${false} 'cell(profileName)': '<b>{{props.item.profileName}}</b>',
${'failed'} | ${'FAILED_VALIDATION'} | ${'Validation failed'} | ${true} actions: '<button>hello</button>',
`('profile with validation $status', ({ statusEnum, label, hasValidateButton }) => { },
const profile = profiles.find(({ validationStatus }) => validationStatus === statusEnum);
it(`should show correct label`, () => {
const validationStatusCell = getTableRowForProfile(profile).cells[2];
expect(validationStatusCell.innerText).toContain(label);
});
it(`should ${hasValidateButton ? '' : 'not '}render validate button`, () => {
const actionsCell = getTableRowForProfile(profile).cells[3];
const validateButton = within(actionsCell).queryByRole('button', {
name: /validate/i,
});
if (hasValidateButton) {
expect(validateButton).not.toBeNull();
} else {
expect(validateButton).toBeNull();
}
});
}); });
}); });
it.each(profiles)('renders list item %# correctly', profile => {
const [profileCell, , , actionsCell] = getTableRowForProfile(profile).cells;
describe('without site validation enabled', () => { expect(profileCell.innerHTML).toContain(`<b>${profile.profileName}</b>`);
beforeEach(() => { expect(within(actionsCell).getByRole('button', { name: /hello/i })).not.toBe(null);
createFullComponent({
provide: {
glFeatures: { securityOnDemandScansSiteValidation: false },
},
propsData: { profiles },
});
});
it.each(profiles)('profile %# should not have validate button and status', profile => {
const [, , validationStatusCell, actionsCell] = getTableRowForProfile(profile).cells;
expect(within(actionsCell).queryByRole('button', { name: /validate/i })).toBe(null);
expect(validationStatusCell.innerText).toBe('');
});
}); });
}); });
......
...@@ -171,37 +171,23 @@ describe('EE - DastProfiles', () => { ...@@ -171,37 +171,23 @@ describe('EE - DastProfiles', () => {
createComponent(); createComponent();
}); });
it('passes down the correct default props', () => { it('passes down the loading state when loading is true', () => {
expect(getProfilesComponent(profileType).props()).toEqual({ createComponent({ mocks: { $apollo: { queries: { [profileType]: { loading: true } } } } });
errorMessage: '',
errorDetails: [],
hasMoreProfilesToLoad: false,
isLoading: false,
profilesPerPage: expect.any(Number),
profiles: [],
fields: expect.any(Array),
fullPath: '/namespace/project',
});
});
it.each([true, false])('passes down the loading state when loading is "%s"', loading => {
createComponent({ mocks: { $apollo: { queries: { [profileType]: { loading } } } } });
expect(getProfilesComponent(profileType).props('isLoading')).toBe(loading); expect(getProfilesComponent(profileType).attributes('is-loading')).toBe('true');
}); });
it.each` it.each`
givenData | propName | expectedPropValue givenData | propName | expectedPropValue
${{ profileTypes: { [profileType]: { errorMessage: 'foo' } } }} | ${'errorMessage'} | ${'foo'} ${{ profileTypes: { [profileType]: { errorMessage: 'foo' } } }} | ${'error-message'} | ${'foo'}
${{ profileTypes: { [profileType]: { errorDetails: ['foo'] } } }} | ${'errorDetails'} | ${['foo']} ${{ profileTypes: { [profileType]: { errorDetails: ['foo'] } } }} | ${'error-details'} | ${'foo'}
${{ profileTypes: { [profileType]: { pageInfo: { hasNextPage: true } } } }} | ${'hasMoreProfilesToLoad'} | ${true} ${{ profileTypes: { [profileType]: { pageInfo: { hasNextPage: true } } } }} | ${'has-more-profiles-to-load'} | ${'true'}
${{ profileTypes: { [profileType]: { profiles: [{ foo: 'bar' }] } } }} | ${'profiles'} | ${[{ foo: 'bar' }]}
`('passes down $propName correctly', async ({ givenData, propName, expectedPropValue }) => { `('passes down $propName correctly', async ({ givenData, propName, expectedPropValue }) => {
wrapper.setData(givenData); wrapper.setData(givenData);
await wrapper.vm.$nextTick(); await wrapper.vm.$nextTick();
expect(getProfilesComponent(profileType).props(propName)).toEqual(expectedPropValue); expect(getProfilesComponent(profileType).attributes(propName)).toEqual(expectedPropValue);
}); });
it('fetches more results when "@load-more-profiles" is emitted', () => { it('fetches more results when "@load-more-profiles" is emitted', () => {
......
import { mount, shallowMount } from '@vue/test-utils';
import { merge } from 'lodash';
import Component from 'ee/security_configuration/dast_profiles/components/dast_scanner_profiles_list.vue';
import ProfilesList from 'ee/security_configuration/dast_profiles/components/dast_profiles_list.vue';
import { scannerProfiles } from './mock_data';
describe('EE - DastScannerProfileList', () => {
let wrapper;
const defaultProps = {
profiles: [],
tableLabel: 'Scanner profiles',
fields: ['profileName'],
profilesPerPage: 10,
errorMessage: '',
errorDetails: [],
fullPath: '/namespace/project',
hasMoreProfilesToLoad: false,
isLoading: false,
};
const wrapperFactory = (mountFn = shallowMount) => (options = {}) => {
wrapper = mountFn(
Component,
merge(
{
propsData: defaultProps,
},
options,
),
);
};
const createComponent = wrapperFactory();
const createFullComponent = wrapperFactory(mount);
const findProfileList = () => wrapper.find(ProfilesList);
afterEach(() => {
wrapper.destroy();
});
it('renders profile list properly', () => {
createComponent({
propsData: { profiles: scannerProfiles },
});
expect(findProfileList()).toExist();
});
it('passes down the props properly', () => {
createFullComponent();
expect(findProfileList().props()).toEqual(defaultProps);
});
it('sets listeners on profile list component', () => {
const inputHandler = jest.fn();
createComponent({
listeners: {
input: inputHandler,
},
});
findProfileList().vm.$emit('input');
expect(inputHandler).toHaveBeenCalled();
});
});
import { mount, shallowMount } from '@vue/test-utils';
import { within } from '@testing-library/dom';
import { merge } from 'lodash';
import Component from 'ee/security_configuration/dast_profiles/components/dast_site_profiles_list.vue';
import ProfilesList from 'ee/security_configuration/dast_profiles/components/dast_profiles_list.vue';
import { siteProfiles } from './mock_data';
describe('EE - DastSiteProfileList', () => {
let wrapper;
const defaultProps = {
profiles: [],
tableLabel: 'Site profiles',
fields: ['profileName', 'targetUrl', 'validationStatus'],
profilesPerPage: 10,
errorMessage: '',
errorDetails: [],
fullPath: '/namespace/project',
hasMoreProfilesToLoad: false,
isLoading: false,
};
const wrapperFactory = (mountFn = shallowMount) => (options = {}) => {
wrapper = mountFn(
Component,
merge(
{
propsData: defaultProps,
provide: {
glFeatures: { securityOnDemandScansSiteValidation: true },
},
},
options,
),
);
};
const createComponent = wrapperFactory();
const createFullComponent = wrapperFactory(mount);
const withinComponent = () => within(wrapper.element);
const getTable = () => withinComponent().getByRole('table', { name: /profiles/i });
const getAllRowGroups = () => within(getTable()).getAllByRole('rowgroup');
const getTableBody = () => {
// first item is the table head
const [, tableBody] = getAllRowGroups();
return tableBody;
};
const getAllTableRows = () => within(getTableBody()).getAllByRole('row');
const getTableRowForProfile = profile => getAllTableRows()[siteProfiles.indexOf(profile)];
const findProfileList = () => wrapper.find(ProfilesList);
afterEach(() => {
wrapper.destroy();
});
it('renders profile list properly', () => {
createComponent({
propsData: { profiles: siteProfiles },
});
expect(findProfileList()).toExist();
});
it('passes down the props properly', () => {
createFullComponent();
expect(findProfileList().props()).toEqual(defaultProps);
});
it('sets listeners on profile list component', () => {
const inputHandler = jest.fn();
createComponent({
listeners: {
input: inputHandler,
},
});
findProfileList().vm.$emit('input');
expect(inputHandler).toHaveBeenCalled();
});
describe('with site validation enabled', () => {
beforeEach(() => {
createFullComponent({ propsData: { siteProfiles } });
});
describe.each`
status | statusEnum | label | hasValidateButton
${'pending'} | ${'PENDING_VALIDATION'} | ${''} | ${true}
${'in-progress'} | ${'INPROGRESS_VALIDATION'} | ${'Validating...'} | ${false}
${'passed'} | ${'PASSED_VALIDATION'} | ${'Validated'} | ${false}
${'failed'} | ${'FAILED_VALIDATION'} | ${'Validation failed'} | ${true}
`('profile with validation $status', ({ statusEnum, label, hasValidateButton }) => {
const profile = siteProfiles.find(({ validationStatus }) => validationStatus === statusEnum);
it(`should show correct label`, () => {
const validationStatusCell = getTableRowForProfile(profile).cells[2];
expect(validationStatusCell.innerText).toContain(label);
});
it(`should ${hasValidateButton ? '' : 'not '}render validate button`, () => {
const actionsCell = getTableRowForProfile(profile).cells[3];
const validateButton = within(actionsCell).queryByRole('button', {
name: /validate/i,
});
if (hasValidateButton) {
expect(validateButton).not.toBeNull();
} else {
expect(validateButton).toBeNull();
}
});
});
});
describe('without site validation enabled', () => {
beforeEach(() => {
createFullComponent({
provide: {
glFeatures: { securityOnDemandScansSiteValidation: false },
},
propsData: { siteProfiles },
});
});
it.each(siteProfiles)('profile %# should not have validate button and status', profile => {
const [, , validationStatusCell, actionsCell] = getTableRowForProfile(profile).cells;
expect(within(actionsCell).queryByRole('button', { name: /validate/i })).toBe(null);
expect(validationStatusCell.innerText).toBe('');
});
});
});
...@@ -28,3 +28,24 @@ export const siteProfiles = [ ...@@ -28,3 +28,24 @@ export const siteProfiles = [
validationStatus: 'FAILED_VALIDATION', validationStatus: 'FAILED_VALIDATION',
}, },
]; ];
export const scannerProfiles = [
{
id: 'gid://gitlab/DastScannerProfile/1',
profileName: 'Scanner profile #1',
spiderTimeout: 5,
targetTimeout: 10,
scanType: 'PASSIVE',
useAjaxSpider: false,
showDebugMessages: false,
},
{
id: 'gid://gitlab/DastScannerProfile/2',
profileName: 'Scanner profile #2',
spiderTimeout: 20,
targetTimeout: 150,
scanType: 'ACTIVE',
useAjaxSpider: true,
showDebugMessages: 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