Commit 703a148c authored by Paul Gascou-Vaillancourt's avatar Paul Gascou-Vaillancourt Committed by Enrique Alcántara

Automatically select DAST profile

When there is only a single profile available in an on-demand scan's
profile selector, it is automatically selected to save the user some
clicks and to prevent potential confusion.
parent 0733c8bf
...@@ -30,7 +30,7 @@ import ProfileSelectorSummaryCell from './profile_selector/summary_cell.vue'; ...@@ -30,7 +30,7 @@ import ProfileSelectorSummaryCell from './profile_selector/summary_cell.vue';
import ScannerProfileSelector from './profile_selector/scanner_profile_selector.vue'; import ScannerProfileSelector from './profile_selector/scanner_profile_selector.vue';
import SiteProfileSelector from './profile_selector/site_profile_selector.vue'; import SiteProfileSelector from './profile_selector/site_profile_selector.vue';
const createProfilesApolloOptions = (name, { fetchQuery, fetchError }) => ({ const createProfilesApolloOptions = (name, field, { fetchQuery, fetchError }) => ({
query: fetchQuery, query: fetchQuery,
variables() { variables() {
return { return {
...@@ -39,6 +39,9 @@ const createProfilesApolloOptions = (name, { fetchQuery, fetchError }) => ({ ...@@ -39,6 +39,9 @@ const createProfilesApolloOptions = (name, { fetchQuery, fetchError }) => ({
}, },
update(data) { update(data) {
const edges = data?.project?.[name]?.edges ?? []; const edges = data?.project?.[name]?.edges ?? [];
if (edges.length === 1) {
this[field] = edges[0].node.id;
}
return edges.map(({ node }) => node); return edges.map(({ node }) => node);
}, },
error(e) { error(e) {
...@@ -66,8 +69,16 @@ export default { ...@@ -66,8 +69,16 @@ export default {
}, },
mixins: [glFeatureFlagsMixin()], mixins: [glFeatureFlagsMixin()],
apollo: { apollo: {
scannerProfiles: createProfilesApolloOptions('scannerProfiles', SCANNER_PROFILES_QUERY), scannerProfiles: createProfilesApolloOptions(
siteProfiles: createProfilesApolloOptions('siteProfiles', SITE_PROFILES_QUERY), 'scannerProfiles',
'selectedScannerProfileId',
SCANNER_PROFILES_QUERY,
),
siteProfiles: createProfilesApolloOptions(
'siteProfiles',
'selectedSiteProfileId',
SITE_PROFILES_QUERY,
),
}, },
props: { props: {
helpPagePath: { helpPagePath: {
...@@ -104,8 +115,8 @@ export default { ...@@ -104,8 +115,8 @@ export default {
return { return {
scannerProfiles: [], scannerProfiles: [],
siteProfiles: [], siteProfiles: [],
selectedScannerProfile: null, selectedScannerProfileId: null,
selectedSiteProfile: null, selectedSiteProfileId: null,
loading: false, loading: false,
errorType: null, errorType: null,
errors: [], errors: [],
...@@ -113,6 +124,16 @@ export default { ...@@ -113,6 +124,16 @@ export default {
}; };
}, },
computed: { computed: {
selectedScannerProfile() {
return this.selectedScannerProfileId
? this.scannerProfiles.find(({ id }) => id === this.selectedScannerProfileId)
: null;
},
selectedSiteProfile() {
return this.selectedSiteProfileId
? this.siteProfiles.find(({ id }) => id === this.selectedSiteProfileId)
: null;
},
errorMessage() { errorMessage() {
return ERROR_MESSAGES[this.errorType] || null; return ERROR_MESSAGES[this.errorType] || null;
}, },
...@@ -238,37 +259,37 @@ export default { ...@@ -238,37 +259,37 @@ export default {
</template> </template>
<template v-else-if="!failedToLoadProfiles"> <template v-else-if="!failedToLoadProfiles">
<scanner-profile-selector <scanner-profile-selector
v-model="selectedScannerProfile" v-model="selectedScannerProfileId"
class="gl-mb-5" class="gl-mb-5"
:profiles="scannerProfiles" :profiles="scannerProfiles"
> >
<template #summary="{ profile }"> <template v-if="selectedScannerProfile" #summary>
<div class="row"> <div class="row">
<profile-selector-summary-cell <profile-selector-summary-cell
:class="{ 'gl-text-red-500': hasProfilesConflict }" :class="{ 'gl-text-red-500': hasProfilesConflict }"
:label="s__('DastProfiles|Scan mode')" :label="s__('DastProfiles|Scan mode')"
:value="$options.SCAN_TYPE_LABEL[profile.scanType]" :value="$options.SCAN_TYPE_LABEL[selectedScannerProfile.scanType]"
/> />
</div> </div>
<div class="row"> <div class="row">
<profile-selector-summary-cell <profile-selector-summary-cell
:label="s__('DastProfiles|Spider timeout')" :label="s__('DastProfiles|Spider timeout')"
:value="n__('%d minute', '%d minutes', profile.spiderTimeout)" :value="n__('%d minute', '%d minutes', selectedScannerProfile.spiderTimeout)"
/> />
<profile-selector-summary-cell <profile-selector-summary-cell
:label="s__('DastProfiles|Target timeout')" :label="s__('DastProfiles|Target timeout')"
:value="n__('%d second', '%d seconds', profile.targetTimeout)" :value="n__('%d second', '%d seconds', selectedScannerProfile.targetTimeout)"
/> />
</div> </div>
<div class="row"> <div class="row">
<profile-selector-summary-cell <profile-selector-summary-cell
:label="s__('DastProfiles|AJAX spider')" :label="s__('DastProfiles|AJAX spider')"
:value="profile.useAjaxSpider ? __('On') : __('Off')" :value="selectedScannerProfile.useAjaxSpider ? __('On') : __('Off')"
/> />
<profile-selector-summary-cell <profile-selector-summary-cell
:label="s__('DastProfiles|Debug messages')" :label="s__('DastProfiles|Debug messages')"
:value=" :value="
profile.showDebugMessages selectedScannerProfile.showDebugMessages
? s__('DastProfiles|Show debug messages') ? s__('DastProfiles|Show debug messages')
: s__('DastProfiles|Hide debug messages') : s__('DastProfiles|Hide debug messages')
" "
...@@ -276,13 +297,17 @@ export default { ...@@ -276,13 +297,17 @@ export default {
</div> </div>
</template> </template>
</scanner-profile-selector> </scanner-profile-selector>
<site-profile-selector v-model="selectedSiteProfile" class="gl-mb-5" :profiles="siteProfiles"> <site-profile-selector
<template #summary="{ profile }"> v-model="selectedSiteProfileId"
class="gl-mb-5"
:profiles="siteProfiles"
>
<template v-if="selectedSiteProfile" #summary>
<div class="row"> <div class="row">
<profile-selector-summary-cell <profile-selector-summary-cell
:class="{ 'gl-text-red-500': hasProfilesConflict }" :class="{ 'gl-text-red-500': hasProfilesConflict }"
:label="s__('DastProfiles|Target URL')" :label="s__('DastProfiles|Target URL')"
:value="profile.targetUrl" :value="selectedSiteProfile.targetUrl"
/> />
</div> </div>
</template> </template>
......
...@@ -25,14 +25,14 @@ export default { ...@@ -25,14 +25,14 @@ export default {
default: () => [], default: () => [],
}, },
value: { value: {
type: Object, type: String,
required: false, required: false,
default: null, default: null,
}, },
}, },
methods: { computed: {
isChecked({ id }) { selectedProfile() {
return this.value?.id === id; return this.value ? this.profiles.find(({ id }) => this.value === id) : null;
}, },
}, },
}; };
...@@ -67,7 +67,9 @@ export default { ...@@ -67,7 +67,9 @@ export default {
</template> </template>
<gl-dropdown <gl-dropdown
:text=" :text="
value ? value.dropdownLabel : s__('OnDemandScans|Select one of the existing profiles') selectedProfile
? selectedProfile.dropdownLabel
: s__('OnDemandScans|Select one of the existing profiles')
" "
class="mw-460" class="mw-460"
data-testid="profiles-dropdown" data-testid="profiles-dropdown"
...@@ -75,9 +77,9 @@ export default { ...@@ -75,9 +77,9 @@ export default {
<gl-dropdown-item <gl-dropdown-item
v-for="profile in profiles" v-for="profile in profiles"
:key="profile.id" :key="profile.id"
:is-checked="isChecked(profile)" :is-checked="value === profile.id"
is-check-item is-check-item
@click="$emit('input', profile)" @click="$emit('input', profile.id)"
> >
{{ profile.profileName }} {{ profile.profileName }}
</gl-dropdown-item> </gl-dropdown-item>
...@@ -87,7 +89,7 @@ export default { ...@@ -87,7 +89,7 @@ export default {
data-testid="selected-profile-summary" data-testid="selected-profile-summary"
class="gl-mt-6 gl-pt-6 gl-border-t-solid gl-border-gray-100 gl-border-t-1" class="gl-mt-6 gl-pt-6 gl-border-t-solid gl-border-gray-100 gl-border-t-1"
> >
<slot name="summary" :profile="value"></slot> <slot name="summary"></slot>
</div> </div>
</gl-form-group> </gl-form-group>
<template v-else> <template v-else>
......
...@@ -57,8 +57,8 @@ export default { ...@@ -57,8 +57,8 @@ export default {
) )
}}</template> }}</template>
<template #new-profile>{{ s__('OnDemandScans|Create a new scanner profile') }}</template> <template #new-profile>{{ s__('OnDemandScans|Create a new scanner profile') }}</template>
<template #summary="{ profile }"> <template #summary>
<slot name="summary" :profile="profile"></slot> <slot name="summary"></slot>
</template> </template>
</profile-selector> </profile-selector>
</template> </template>
...@@ -60,8 +60,8 @@ export default { ...@@ -60,8 +60,8 @@ export default {
) )
}}</template> }}</template>
<template #new-profile>{{ s__('OnDemandScans|Create a new site profile') }}</template> <template #new-profile>{{ s__('OnDemandScans|Create a new site profile') }}</template>
<template #summary="{ profile }"> <template #summary>
<slot name="summary" :profile="profile"></slot> <slot name="summary"></slot>
</template> </template>
</profile-selector> </profile-selector>
</template> </template>
---
title: 'On-demand scans: automatically select DAST profile when only one is available'
merge_request: 49435
author:
type: changed
import { GlForm, GlSkeletonLoader } from '@gitlab/ui'; import { GlForm, GlSkeletonLoader } from '@gitlab/ui';
import { shallowMount, mount } from '@vue/test-utils'; import { shallowMount, mount, createLocalVue } from '@vue/test-utils';
import { merge } from 'lodash'; import { merge } from 'lodash';
import VueApollo from 'vue-apollo';
import createApolloProvider from 'helpers/mock_apollo_helper';
import OnDemandScansForm from 'ee/on_demand_scans/components/on_demand_scans_form.vue'; import OnDemandScansForm from 'ee/on_demand_scans/components/on_demand_scans_form.vue';
import ScannerProfileSelector from 'ee/on_demand_scans/components/profile_selector/scanner_profile_selector.vue'; import ScannerProfileSelector from 'ee/on_demand_scans/components/profile_selector/scanner_profile_selector.vue';
import SiteProfileSelector from 'ee/on_demand_scans/components/profile_selector/site_profile_selector.vue'; import SiteProfileSelector from 'ee/on_demand_scans/components/profile_selector/site_profile_selector.vue';
import dastOnDemandScanCreate from 'ee/on_demand_scans/graphql/dast_on_demand_scan_create.mutation.graphql'; import dastOnDemandScanCreate from 'ee/on_demand_scans/graphql/dast_on_demand_scan_create.mutation.graphql';
import dastScannerProfilesQuery from 'ee/security_configuration/dast_profiles/graphql/dast_scanner_profiles.query.graphql';
import dastSiteProfilesQuery from 'ee/security_configuration/dast_profiles/graphql/dast_site_profiles.query.graphql';
import * as responses from '../mocks/apollo_mocks';
import { scannerProfiles, siteProfiles } from '../mocks/mock_data';
import { redirectTo } from '~/lib/utils/url_utility'; import { redirectTo } from '~/lib/utils/url_utility';
import { scannerProfiles, siteProfiles } from '../mock_data';
const helpPagePath = '/application_security/dast/index#on-demand-scans'; const helpPagePath = '/application_security/dast/index#on-demand-scans';
const projectPath = 'group/project'; const projectPath = 'group/project';
...@@ -22,17 +27,6 @@ const defaultProps = { ...@@ -22,17 +27,6 @@ const defaultProps = {
defaultBranch, defaultBranch,
}; };
const defaultMocks = {
$apollo: {
mutate: jest.fn(),
queries: {
scannerProfiles: {},
siteProfiles: {},
},
addSmartQuery: jest.fn(),
},
};
const pipelineUrl = `/${projectPath}/pipelines/123`; const pipelineUrl = `/${projectPath}/pipelines/123`;
const [passiveScannerProfile, activeScannerProfile] = scannerProfiles; const [passiveScannerProfile, activeScannerProfile] = scannerProfiles;
const [nonValidatedSiteProfile, validatedSiteProfile] = siteProfiles; const [nonValidatedSiteProfile, validatedSiteProfile] = siteProfiles;
...@@ -43,7 +37,9 @@ jest.mock('~/lib/utils/url_utility', () => ({ ...@@ -43,7 +37,9 @@ jest.mock('~/lib/utils/url_utility', () => ({
})); }));
describe('OnDemandScansForm', () => { describe('OnDemandScansForm', () => {
let localVue;
let subject; let subject;
let requestHandlers;
const findForm = () => subject.find(GlForm); const findForm = () => subject.find(GlForm);
const findByTestId = testId => subject.find(`[data-testid="${testId}"]`); const findByTestId = testId => subject.find(`[data-testid="${testId}"]`);
...@@ -52,13 +48,44 @@ describe('OnDemandScansForm', () => { ...@@ -52,13 +48,44 @@ describe('OnDemandScansForm', () => {
const findSubmitButton = () => findByTestId('on-demand-scan-submit-button'); const findSubmitButton = () => findByTestId('on-demand-scan-submit-button');
const setValidFormData = () => { const setValidFormData = () => {
subject.find(ScannerProfileSelector).vm.$emit('input', passiveScannerProfile); subject.find(ScannerProfileSelector).vm.$emit('input', passiveScannerProfile.id);
subject.find(SiteProfileSelector).vm.$emit('input', nonValidatedSiteProfile); subject.find(SiteProfileSelector).vm.$emit('input', nonValidatedSiteProfile.id);
return subject.vm.$nextTick(); return subject.vm.$nextTick();
}; };
const submitForm = () => findForm().vm.$emit('submit', { preventDefault: () => {} }); const submitForm = () => findForm().vm.$emit('submit', { preventDefault: () => {} });
const subjectMounterFactory = (mountFn = shallowMount) => (options = {}) => { const createMockApolloProvider = handlers => {
localVue.use(VueApollo);
requestHandlers = {
dastScannerProfiles: jest.fn().mockResolvedValue(responses.dastScannerProfiles()),
dastSiteProfiles: jest.fn().mockResolvedValue(responses.dastSiteProfiles()),
...handlers,
};
return createApolloProvider([
[dastScannerProfilesQuery, requestHandlers.dastScannerProfiles],
[dastSiteProfilesQuery, requestHandlers.dastSiteProfiles],
]);
};
const subjectMounterFactory = (mountFn = shallowMount) => (options = {}, withHandlers) => {
localVue = createLocalVue();
let defaultMocks = {
$apollo: {
mutate: jest.fn(),
queries: {
scannerProfiles: {},
siteProfiles: {},
},
addSmartQuery: jest.fn(),
},
};
let apolloProvider;
if (withHandlers) {
apolloProvider = createMockApolloProvider(withHandlers);
defaultMocks = {};
}
subject = mountFn( subject = mountFn(
OnDemandScansForm, OnDemandScansForm,
merge( merge(
...@@ -76,7 +103,7 @@ describe('OnDemandScansForm', () => { ...@@ -76,7 +103,7 @@ describe('OnDemandScansForm', () => {
}, },
}, },
}, },
options, { ...options, localVue, apolloProvider },
{ {
data() { data() {
return { ...options.data }; return { ...options.data };
...@@ -243,8 +270,8 @@ describe('OnDemandScansForm', () => { ...@@ -243,8 +270,8 @@ describe('OnDemandScansForm', () => {
'profiles conflict prevention', 'profiles conflict prevention',
({ description, selectedScannerProfile, selectedSiteProfile, hasConflict }) => { ({ description, selectedScannerProfile, selectedSiteProfile, hasConflict }) => {
const setFormData = () => { const setFormData = () => {
subject.find(ScannerProfileSelector).vm.$emit('input', selectedScannerProfile); subject.find(ScannerProfileSelector).vm.$emit('input', selectedScannerProfile.id);
subject.find(SiteProfileSelector).vm.$emit('input', selectedSiteProfile); subject.find(SiteProfileSelector).vm.$emit('input', selectedSiteProfile.id);
return subject.vm.$nextTick(); return subject.vm.$nextTick();
}; };
...@@ -253,7 +280,12 @@ describe('OnDemandScansForm', () => { ...@@ -253,7 +280,12 @@ describe('OnDemandScansForm', () => {
? `warns about conflicting profiles when user selects ${description}` ? `warns about conflicting profiles when user selects ${description}`
: `does not report any conflict when user selects ${description}`, : `does not report any conflict when user selects ${description}`,
async () => { async () => {
mountShallowSubject(); mountShallowSubject({
data: {
scannerProfiles,
siteProfiles,
},
});
await setFormData(); await setFormData();
expect(findProfilesConflictAlert().exists()).toBe(hasConflict); expect(findProfilesConflictAlert().exists()).toBe(hasConflict);
...@@ -269,6 +301,10 @@ describe('OnDemandScansForm', () => { ...@@ -269,6 +301,10 @@ describe('OnDemandScansForm', () => {
securityOnDemandScansSiteValidation: false, securityOnDemandScansSiteValidation: false,
}, },
}, },
data: {
scannerProfiles,
siteProfiles,
},
}); });
return setFormData(); return setFormData();
}); });
...@@ -280,4 +316,25 @@ describe('OnDemandScansForm', () => { ...@@ -280,4 +316,25 @@ describe('OnDemandScansForm', () => {
}); });
}, },
); );
describe.each`
profileType | query | selector | profiles
${'scanner'} | ${'dastScannerProfiles'} | ${ScannerProfileSelector} | ${scannerProfiles}
${'site'} | ${'dastSiteProfiles'} | ${SiteProfileSelector} | ${siteProfiles}
`('when there is a single $profileType profile', ({ query, selector, profiles }) => {
const [profile] = profiles;
beforeEach(() => {
mountShallowSubject(
{},
{
[query]: jest.fn().mockResolvedValue(responses[query]([profile])),
},
);
});
it('automatically selects the only available profile', () => {
expect(subject.find(selector).attributes('value')).toBe(profile.id);
});
});
}); });
...@@ -4,7 +4,7 @@ exports[`OnDemandScansScannerProfileSelector renders properly with profiles 1`] ...@@ -4,7 +4,7 @@ exports[`OnDemandScansScannerProfileSelector renders properly with profiles 1`]
<div <div
class="gl-card" class="gl-card"
data-foo="bar" data-foo="bar"
value="[object Object]" value="gid://gitlab/DastScannerProfile/1"
> >
<div <div
class="gl-card-header" class="gl-card-header"
......
...@@ -4,7 +4,7 @@ exports[`OnDemandScansSiteProfileSelector renders properly with profiles 1`] = ` ...@@ -4,7 +4,7 @@ exports[`OnDemandScansSiteProfileSelector renders properly with profiles 1`] = `
<div <div
class="gl-card" class="gl-card"
data-foo="bar" data-foo="bar"
value="[object Object]" value="gid://gitlab/DastSiteProfile/1"
> >
<div <div
class="gl-card-header" class="gl-card-header"
......
...@@ -2,7 +2,7 @@ import { GlDropdownItem } from '@gitlab/ui'; ...@@ -2,7 +2,7 @@ import { GlDropdownItem } from '@gitlab/ui';
import { mount } from '@vue/test-utils'; import { mount } from '@vue/test-utils';
import { merge } from 'lodash'; import { merge } from 'lodash';
import OnDemandScansProfileSelector from 'ee/on_demand_scans/components/profile_selector/profile_selector.vue'; import OnDemandScansProfileSelector from 'ee/on_demand_scans/components/profile_selector/profile_selector.vue';
import { scannerProfiles } from '../../mock_data'; import { scannerProfiles } from '../../mocks/mock_data';
describe('OnDemandScansProfileSelector', () => { describe('OnDemandScansProfileSelector', () => {
let wrapper; let wrapper;
...@@ -41,12 +41,10 @@ describe('OnDemandScansProfileSelector', () => { ...@@ -41,12 +41,10 @@ describe('OnDemandScansProfileSelector', () => {
slots: { slots: {
title: 'Section title', title: 'Section title',
label: 'Use existing scanner profile', label: 'Use existing scanner profile',
summary: `<div>Profile's summary</div>`,
'no-profiles': 'No profile yet', 'no-profiles': 'No profile yet',
'new-profile': 'Create a new profile', 'new-profile': 'Create a new profile',
}, },
scopedSlots: {
summary: "<div>{{ props.profile.profileName }}'s summary</div>",
},
}, },
options, options,
), ),
...@@ -105,7 +103,7 @@ describe('OnDemandScansProfileSelector', () => { ...@@ -105,7 +103,7 @@ describe('OnDemandScansProfileSelector', () => {
it('when a profile is selected, input event is emitted', async () => { it('when a profile is selected, input event is emitted', async () => {
await selectFirstProfile(); await selectFirstProfile();
expect(wrapper.emitted('input')).toEqual([[scannerProfiles[0]]]); expect(wrapper.emitted('input')).toEqual([[scannerProfiles[0].id]]);
}); });
it('shows dropdown items for each profile', () => { it('shows dropdown items for each profile', () => {
...@@ -130,7 +128,7 @@ describe('OnDemandScansProfileSelector', () => { ...@@ -130,7 +128,7 @@ describe('OnDemandScansProfileSelector', () => {
createFullComponent({ createFullComponent({
propsData: { propsData: {
profiles: scannerProfiles, profiles: scannerProfiles,
value: selectedProfile, value: selectedProfile.id,
}, },
}); });
}); });
...@@ -139,7 +137,7 @@ describe('OnDemandScansProfileSelector', () => { ...@@ -139,7 +137,7 @@ describe('OnDemandScansProfileSelector', () => {
const summary = findSelectedProfileSummary(); const summary = findSelectedProfileSummary();
expect(summary.exists()).toBe(true); expect(summary.exists()).toBe(true);
expect(summary.text()).toContain(`${scannerProfiles[0].profileName}'s summary`); expect(summary.text()).toContain(`Profile's summary`);
}); });
it('displays item as checked', () => { it('displays item as checked', () => {
......
...@@ -2,7 +2,7 @@ import { mount, shallowMount } from '@vue/test-utils'; ...@@ -2,7 +2,7 @@ import { mount, shallowMount } from '@vue/test-utils';
import { merge } from 'lodash'; import { merge } from 'lodash';
import ProfileSelector from 'ee/on_demand_scans/components/profile_selector/profile_selector.vue'; import ProfileSelector from 'ee/on_demand_scans/components/profile_selector/profile_selector.vue';
import OnDemandScansScannerProfileSelector from 'ee/on_demand_scans/components/profile_selector/scanner_profile_selector.vue'; import OnDemandScansScannerProfileSelector from 'ee/on_demand_scans/components/profile_selector/scanner_profile_selector.vue';
import { scannerProfiles } from '../../mock_data'; import { scannerProfiles } from '../../mocks/mock_data';
const TEST_LIBRARY_PATH = '/test/scanner/profiles/library/path'; const TEST_LIBRARY_PATH = '/test/scanner/profiles/library/path';
const TEST_NEW_PATH = '/test/new/scanner/profile/path'; const TEST_NEW_PATH = '/test/new/scanner/profile/path';
...@@ -31,8 +31,8 @@ describe('OnDemandScansScannerProfileSelector', () => { ...@@ -31,8 +31,8 @@ describe('OnDemandScansScannerProfileSelector', () => {
newScannerProfilePath: TEST_NEW_PATH, newScannerProfilePath: TEST_NEW_PATH,
glFeatures: { securityOnDemandScansSiteValidation: true }, glFeatures: { securityOnDemandScansSiteValidation: true },
}, },
scopedSlots: { slots: {
summary: '<div slot-scope="{ profile }">{{ profile.profileName }}\'s summary</div>', summary: `<div>${profiles[0].profileName}'s summary</div>`,
}, },
}, },
options, options,
...@@ -50,7 +50,7 @@ describe('OnDemandScansScannerProfileSelector', () => { ...@@ -50,7 +50,7 @@ describe('OnDemandScansScannerProfileSelector', () => {
it('renders properly with profiles', () => { it('renders properly with profiles', () => {
createFullComponent({ createFullComponent({
propsData: { profiles, value: profiles[0] }, propsData: { profiles, value: profiles[0].id },
}); });
expect(wrapper.element).toMatchSnapshot(); expect(wrapper.element).toMatchSnapshot();
......
...@@ -2,7 +2,7 @@ import { mount, shallowMount } from '@vue/test-utils'; ...@@ -2,7 +2,7 @@ import { mount, shallowMount } from '@vue/test-utils';
import { merge } from 'lodash'; import { merge } from 'lodash';
import ProfileSelector from 'ee/on_demand_scans/components/profile_selector/profile_selector.vue'; import ProfileSelector from 'ee/on_demand_scans/components/profile_selector/profile_selector.vue';
import OnDemandScansSiteProfileSelector from 'ee/on_demand_scans/components/profile_selector/site_profile_selector.vue'; import OnDemandScansSiteProfileSelector from 'ee/on_demand_scans/components/profile_selector/site_profile_selector.vue';
import { siteProfiles } from '../../mock_data'; import { siteProfiles } from '../../mocks/mock_data';
const TEST_LIBRARY_PATH = '/test/site/profiles/library/path'; const TEST_LIBRARY_PATH = '/test/site/profiles/library/path';
const TEST_NEW_PATH = '/test/new/site/profile/path'; const TEST_NEW_PATH = '/test/new/site/profile/path';
...@@ -34,8 +34,8 @@ describe('OnDemandScansSiteProfileSelector', () => { ...@@ -34,8 +34,8 @@ describe('OnDemandScansSiteProfileSelector', () => {
newSiteProfilePath: TEST_NEW_PATH, newSiteProfilePath: TEST_NEW_PATH,
glFeatures: { securityOnDemandScansSiteValidation: true }, glFeatures: { securityOnDemandScansSiteValidation: true },
}, },
scopedSlots: { slots: {
summary: '<div slot-scope="{ profile }">{{ profile.profileName }}\'s summary</div>', summary: `<div>${profiles[0].profileName}'s summary</div>`,
}, },
}, },
options, options,
...@@ -53,7 +53,7 @@ describe('OnDemandScansSiteProfileSelector', () => { ...@@ -53,7 +53,7 @@ describe('OnDemandScansSiteProfileSelector', () => {
it('renders properly with profiles', () => { it('renders properly with profiles', () => {
createFullComponent({ createFullComponent({
propsData: { profiles, value: profiles[0] }, propsData: { profiles, value: profiles[0].id },
}); });
expect(wrapper.element).toMatchSnapshot(); expect(wrapper.element).toMatchSnapshot();
......
import { scannerProfiles, siteProfiles } from './mock_data';
const defaults = {
pageInfo: {
hasNextPage: false,
hasPreviousPage: false,
startCursor: null,
endCursor: null,
},
};
export const dastScannerProfiles = (profiles = scannerProfiles) => ({
data: {
project: {
scannerProfiles: {
...defaults,
edges: profiles.map(profile => ({
cursor: '',
node: profile,
})),
},
},
},
});
export const dastSiteProfiles = (profiles = siteProfiles) => ({
data: {
project: {
siteProfiles: {
...defaults,
edges: profiles.map(profile => ({
cursor: '',
node: profile,
})),
},
},
},
});
...@@ -7,6 +7,7 @@ export const scannerProfiles = [ ...@@ -7,6 +7,7 @@ export const scannerProfiles = [
scanType: 'PASSIVE', scanType: 'PASSIVE',
useAjaxSpider: false, useAjaxSpider: false,
showDebugMessages: false, showDebugMessages: false,
editPath: '/scanner_profile/edit/1',
}, },
{ {
id: 'gid://gitlab/DastScannerProfile/2', id: 'gid://gitlab/DastScannerProfile/2',
...@@ -16,6 +17,7 @@ export const scannerProfiles = [ ...@@ -16,6 +17,7 @@ export const scannerProfiles = [
scanType: 'ACTIVE', scanType: 'ACTIVE',
useAjaxSpider: true, useAjaxSpider: true,
showDebugMessages: true, showDebugMessages: true,
editPath: '/scanner_profile/edit/2',
}, },
]; ];
...@@ -24,12 +26,16 @@ export const siteProfiles = [ ...@@ -24,12 +26,16 @@ export const siteProfiles = [
id: 'gid://gitlab/DastSiteProfile/1', id: 'gid://gitlab/DastSiteProfile/1',
profileName: 'Site profile #1', profileName: 'Site profile #1',
targetUrl: 'https://foo.com', targetUrl: 'https://foo.com',
normalizedTargetUrl: 'https://foo.com:443',
editPath: '/site_profiles/edit/1',
validationStatus: 'PENDING_VALIDATION', validationStatus: 'PENDING_VALIDATION',
}, },
{ {
id: 'gid://gitlab/DastSiteProfile/2', id: 'gid://gitlab/DastSiteProfile/2',
profileName: 'Site profile #2', profileName: 'Site profile #2',
targetUrl: 'https://bar.com', targetUrl: 'https://bar.com',
normalizedTargetUrl: 'https://bar.com:443',
editPath: '/site_profiles/edit/2',
validationStatus: 'PASSED_VALIDATION', validationStatus: 'PASSED_VALIDATION',
}, },
]; ];
...@@ -6,7 +6,7 @@ import DastScannerProfileForm from 'ee/security_configuration/dast_scanner_profi ...@@ -6,7 +6,7 @@ import DastScannerProfileForm from 'ee/security_configuration/dast_scanner_profi
import { SCAN_TYPE } from 'ee/security_configuration/dast_scanner_profiles/constants'; import { SCAN_TYPE } from 'ee/security_configuration/dast_scanner_profiles/constants';
import dastScannerProfileCreateMutation from 'ee/security_configuration/dast_scanner_profiles/graphql/dast_scanner_profile_create.mutation.graphql'; import dastScannerProfileCreateMutation from 'ee/security_configuration/dast_scanner_profiles/graphql/dast_scanner_profile_create.mutation.graphql';
import dastScannerProfileUpdateMutation from 'ee/security_configuration/dast_scanner_profiles/graphql/dast_scanner_profile_update.mutation.graphql'; import dastScannerProfileUpdateMutation from 'ee/security_configuration/dast_scanner_profiles/graphql/dast_scanner_profile_update.mutation.graphql';
import { scannerProfiles } from 'ee_jest/on_demand_scans/mock_data'; import { scannerProfiles } from 'ee_jest/on_demand_scans/mocks/mock_data';
import { TEST_HOST } from 'helpers/test_constants'; import { TEST_HOST } from 'helpers/test_constants';
import { redirectTo } from '~/lib/utils/url_utility'; import { redirectTo } from '~/lib/utils/url_utility';
......
...@@ -7,7 +7,7 @@ import VueApollo from 'vue-apollo'; ...@@ -7,7 +7,7 @@ import VueApollo from 'vue-apollo';
import DastSiteProfileForm from 'ee/security_configuration/dast_site_profiles_form/components/dast_site_profile_form.vue'; import DastSiteProfileForm from 'ee/security_configuration/dast_site_profiles_form/components/dast_site_profile_form.vue';
import dastSiteProfileCreateMutation from 'ee/security_configuration/dast_site_profiles_form/graphql/dast_site_profile_create.mutation.graphql'; import dastSiteProfileCreateMutation from 'ee/security_configuration/dast_site_profiles_form/graphql/dast_site_profile_create.mutation.graphql';
import dastSiteProfileUpdateMutation from 'ee/security_configuration/dast_site_profiles_form/graphql/dast_site_profile_update.mutation.graphql'; import dastSiteProfileUpdateMutation from 'ee/security_configuration/dast_site_profiles_form/graphql/dast_site_profile_update.mutation.graphql';
import { siteProfiles } from 'ee_jest/on_demand_scans/mock_data'; import { siteProfiles } from 'ee_jest/on_demand_scans/mocks/mock_data';
import * as responses from 'ee_jest/security_configuration/dast_site_profiles_form/mock_data/apollo_mock'; import * as responses from 'ee_jest/security_configuration/dast_site_profiles_form/mock_data/apollo_mock';
import { TEST_HOST } from 'helpers/test_constants'; import { TEST_HOST } from 'helpers/test_constants';
import waitForPromises from 'jest/helpers/wait_for_promises'; import waitForPromises from 'jest/helpers/wait_for_promises';
......
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