Commit 09166398 authored by Paul Slaughter's avatar Paul Slaughter

Merge branch...

Merge branch '246780-refactor-on-demand-profiles-selection-profile-selector-component' into 'master'

Create profile selector component

See merge request gitlab-org/gitlab!41922
parents 58ffe602 87b94d7c
<script>
import { GlButton, GlCard, GlFormGroup, GlDropdown, GlDropdownItem } from '@gitlab/ui';
export default {
name: 'OnDemandScansProfileSelector',
components: {
GlButton,
GlCard,
GlFormGroup,
GlDropdown,
GlDropdownItem,
},
props: {
libraryPath: {
type: String,
required: true,
},
newProfilePath: {
type: String,
required: true,
},
profiles: {
type: Array,
required: false,
default: () => [],
},
value: {
type: String,
required: false,
default: null,
},
},
computed: {
selectedProfile() {
return this.value ? this.profiles.find(({ id }) => this.value === id) : null;
},
},
};
</script>
<template>
<gl-card>
<template #header>
<div class="row">
<div class="col-7">
<h3 class="gl-font-lg gl-display-inline">
<slot name="title"></slot>
</h3>
</div>
<div class="col-5 gl-text-right">
<gl-button
:href="profiles.length ? libraryPath : null"
:disabled="!profiles.length"
variant="success"
category="secondary"
size="small"
data-testid="manage-profiles-link"
>
{{ s__('OnDemandScans|Manage profiles') }}
</gl-button>
</div>
</div>
</template>
<gl-form-group v-if="profiles.length">
<template #label>
<slot name="label"></slot>
</template>
<gl-dropdown
:text="
selectedProfile
? selectedProfile.dropdownLabel
: s__('OnDemandScans|Select one of the existing profiles')
"
class="mw-460"
data-testid="profiles-dropdown"
>
<gl-dropdown-item
v-for="profile in profiles"
:key="profile.id"
:is-checked="value === profile.id"
is-check-item
@click="$emit('input', profile.id)"
>
{{ profile.profileName }}
</gl-dropdown-item>
</gl-dropdown>
<div
v-if="selectedProfile && $scopedSlots.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"
>
<slot name="summary" :profile="selectedProfile"></slot>
</div>
</gl-form-group>
<template v-else>
<p class="gl-text-gray-700">
<slot name="no-profiles"></slot>
</p>
<gl-button
:href="newProfilePath"
variant="success"
category="secondary"
data-testid="create-profile-link"
>
<slot name="new-profile"></slot>
</gl-button>
</template>
</gl-card>
</template>
<script>
import ProfileSelector from './profile_selector.vue';
import SummaryCell from './summary_cell.vue';
export default {
name: 'OnDemandScansScannerProfileSelector',
components: {
ProfileSelector,
SummaryCell,
},
props: {
profiles: {
type: Array,
required: false,
default: () => [],
},
},
inject: {
scannerProfilesLibraryPath: {
default: '',
},
newScannerProfilePath: {
default: '',
},
},
};
</script>
<template>
<profile-selector
:library-path="scannerProfilesLibraryPath"
:new-profile-path="newScannerProfilePath"
:profiles="profiles.map(profile => ({ ...profile, dropdownLabel: profile.profileName }))"
v-bind="$attrs"
v-on="$listeners"
>
<template #title>{{ s__('OnDemandScans|Scanner profile') }}</template>
<template #label>{{ s__('OnDemandScans|Use existing scanner profile') }}</template>
<template #no-profiles>{{
s__(
'OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed scanner profile.',
)
}}</template>
<template #new-profile>{{ s__('OnDemandScans|Create a new scanner profile') }}</template>
<template #summary="{ profile }">
<div class="row">
<summary-cell :label="s__('DastProfiles|Scan mode')" :value="s__('DastProfiles|Passive')" />
</div>
<div class="row">
<summary-cell
:label="s__('DastProfiles|Spider timeout')"
:value="n__('%d minute', '%d minutes', profile.spiderTimeout)"
/>
<summary-cell
:label="s__('DastProfiles|Target timeout')"
:value="n__('%d second', '%d seconds', profile.targetTimeout)"
/>
</div>
</template>
</profile-selector>
</template>
<script>
import ProfileSelector from './profile_selector.vue';
import SummaryCell from './summary_cell.vue';
export default {
name: 'OnDemandScansSiteProfileSelector',
components: {
ProfileSelector,
SummaryCell,
},
props: {
profiles: {
type: Array,
required: false,
default: () => [],
},
},
inject: {
siteProfilesLibraryPath: {
default: '',
},
newSiteProfilePath: {
default: '',
},
},
};
</script>
<template>
<profile-selector
:library-path="siteProfilesLibraryPath"
:new-profile-path="newSiteProfilePath"
:profiles="
profiles.map(profile => ({
...profile,
dropdownLabel: `${profile.profileName}: ${profile.targetUrl}`,
}))
"
v-bind="$attrs"
v-on="$listeners"
>
<template #title>{{ s__('OnDemandScans|Site profile') }}</template>
<template #label>{{ s__('OnDemandScans|Use existing site profile') }}</template>
<template #no-profiles>{{
s__(
'OnDemandScans|No profile yet. In order to create a new scan, you need to have at least one completed site profile.',
)
}}</template>
<template #new-profile>{{ s__('OnDemandScans|Create a new site profile') }}</template>
<template #summary="{ profile }">
<div class="row">
<summary-cell :label="s__('DastProfiles|Target URL')" :value="profile.targetUrl" />
</div>
</template>
</profile-selector>
</template>
<script>
export default {
name: 'OnDemandScansProfileSummaryCell',
props: {
label: {
type: String,
required: true,
},
value: {
type: String,
required: true,
},
},
};
</script>
<template>
<div class="col-md-6">
<div class="row">
<div class="col-md-3">{{ label }}:</div>
<div class="col-md-9">
<strong>{{ value }}</strong>
</div>
</div>
</div>
</template>
import dastScannerProfilesQuery from 'ee/dast_profiles/graphql/dast_scanner_profiles.query.graphql';
import dastSiteProfilesQuery from 'ee/dast_profiles/graphql/dast_site_profiles.query.graphql';
import { s__ } from '~/locale';
export const ERROR_RUN_SCAN = 'ERROR_RUN_SCAN';
export const ERROR_FETCH_SCANNER_PROFILES = 'ERROR_FETCH_SCANNER_PROFILES';
export const ERROR_FETCH_SITE_PROFILES = 'ERROR_FETCH_SITE_PROFILES';
export const ERROR_MESSAGES = {
[ERROR_RUN_SCAN]: s__('OnDemandScans|Could not run the scan. Please try again.'),
[ERROR_FETCH_SCANNER_PROFILES]: s__(
'OnDemandScans|Could not fetch scanner profiles. Please refresh the page, or try again later.',
),
[ERROR_FETCH_SITE_PROFILES]: s__(
'OnDemandScans|Could not fetch site profiles. Please refresh the page, or try again later.',
),
};
export const SCANNER_PROFILES_QUERY = {
field: 'dastScannerProfileId',
fetchQuery: dastScannerProfilesQuery,
fetchError: ERROR_FETCH_SCANNER_PROFILES,
queryKind: 'scannerProfiles',
};
export const SITE_PROFILES_QUERY = {
field: 'dastSiteProfileId',
fetchQuery: dastSiteProfilesQuery,
fetchError: ERROR_FETCH_SITE_PROFILES,
queryKind: 'siteProfiles',
};
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`OnDemandScansScannerProfileSelector renders properly with profiles 1`] = `
<div
class="card"
data-foo="bar"
value="gid://gitlab/DastScannerProfile/1"
>
<!---->
<div
class="card-header"
>
<div
class="row"
>
<div
class="col-7"
>
<h3
class="gl-font-lg gl-display-inline"
>
Scanner profile
</h3>
</div>
<div
class="col-5 gl-text-right"
>
<a
class="btn btn-success btn-sm gl-button btn-success-secondary"
data-testid="manage-profiles-link"
href="/test/scanner/profiles/library/path"
>
<!---->
<!---->
<span
class="gl-button-text"
>
Manage profiles
</span>
</a>
</div>
</div>
</div>
<div
class="card-body"
>
<!---->
<!---->
<fieldset
class="form-group gl-form-group"
>
<legend
class="bv-no-focus-ring col-form-label pt-0 col-form-label"
tabindex="-1"
>
Use existing scanner profile
</legend>
<div
class="bv-no-focus-ring"
role="group"
tabindex="-1"
>
<div
class="dropdown b-dropdown gl-new-dropdown mw-460 btn-group"
data-testid="profiles-dropdown"
>
<!---->
<button
aria-expanded="false"
aria-haspopup="true"
class="btn dropdown-toggle btn-default btn-md gl-button gl-dropdown-toggle"
type="button"
>
<!---->
<span
class="gl-new-dropdown-button-text"
>
Scanner profile #1
</span>
<svg
class="dropdown-chevron gl-icon s16"
data-testid="chevron-down-icon"
>
<use
href="#chevron-down"
/>
</svg>
</button>
<ul
class="dropdown-menu"
role="menu"
tabindex="-1"
>
<!---->
<li
class="gl-new-dropdown-item"
role="presentation"
>
<button
class="dropdown-item"
role="menuitem"
type="button"
>
<svg
class="gl-icon s16 gl-new-dropdown-item-check-icon"
data-testid="mobile-issue-close-icon"
>
<use
href="#mobile-issue-close"
/>
</svg>
<!---->
<!---->
<div
class="gl-new-dropdown-item-text-wrapper"
>
<p
class="gl-new-dropdown-item-text-primary"
>
Scanner profile #1
</p>
<!---->
</div>
<!---->
</button>
</li>
<li
class="gl-new-dropdown-item"
role="presentation"
>
<button
class="dropdown-item"
role="menuitem"
type="button"
>
<svg
class="gl-icon s16 gl-new-dropdown-item-check-icon gl-visibility-hidden"
data-testid="mobile-issue-close-icon"
>
<use
href="#mobile-issue-close"
/>
</svg>
<!---->
<!---->
<div
class="gl-new-dropdown-item-text-wrapper"
>
<p
class="gl-new-dropdown-item-text-primary"
>
Scanner profile #2
</p>
<!---->
</div>
<!---->
</button>
</li>
</ul>
</div>
<div
class="gl-mt-6 gl-pt-6 gl-border-t-solid gl-border-gray-100 gl-border-t-1"
data-testid="selected-profile-summary"
>
<div
class="row"
>
<div
class="col-md-6"
>
<div
class="row"
>
<div
class="col-md-3"
>
Scan mode:
</div>
<div
class="col-md-9"
>
<strong>
Passive
</strong>
</div>
</div>
</div>
</div>
<div
class="row"
>
<div
class="col-md-6"
>
<div
class="row"
>
<div
class="col-md-3"
>
Spider timeout:
</div>
<div
class="col-md-9"
>
<strong>
5 minutes
</strong>
</div>
</div>
</div>
<div
class="col-md-6"
>
<div
class="row"
>
<div
class="col-md-3"
>
Target timeout:
</div>
<div
class="col-md-9"
>
<strong>
10 seconds
</strong>
</div>
</div>
</div>
</div>
</div>
<!---->
<!---->
<!---->
</div>
</fieldset>
</div>
<!---->
<!---->
</div>
`;
exports[`OnDemandScansScannerProfileSelector renders properly without profiles 1`] = `
<div
class="card"
data-foo="bar"
>
<!---->
<div
class="card-header"
>
<div
class="row"
>
<div
class="col-7"
>
<h3
class="gl-font-lg gl-display-inline"
>
Scanner profile
</h3>
</div>
<div
class="col-5 gl-text-right"
>
<button
class="btn btn-success btn-sm disabled gl-button btn-success-secondary"
data-testid="manage-profiles-link"
disabled="disabled"
type="button"
>
<!---->
<!---->
<span
class="gl-button-text"
>
Manage profiles
</span>
</button>
</div>
</div>
</div>
<div
class="card-body"
>
<!---->
<!---->
<p
class="gl-text-gray-700"
>
No profile yet. In order to create a new scan, you need to have at least one completed scanner profile.
</p>
<a
class="btn btn-success btn-md gl-button btn-success-secondary"
data-testid="create-profile-link"
href="/test/new/scanner/profile/path"
>
<!---->
<!---->
<span
class="gl-button-text"
>
Create a new scanner profile
</span>
</a>
</div>
<!---->
<!---->
</div>
`;
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`OnDemandScansSiteProfileSelector renders properly with profiles 1`] = `
<div
class="card"
data-foo="bar"
value="gid://gitlab/DastSiteProfile/1"
>
<!---->
<div
class="card-header"
>
<div
class="row"
>
<div
class="col-7"
>
<h3
class="gl-font-lg gl-display-inline"
>
Site profile
</h3>
</div>
<div
class="col-5 gl-text-right"
>
<a
class="btn btn-success btn-sm gl-button btn-success-secondary"
data-testid="manage-profiles-link"
href="/test/site/profiles/library/path"
>
<!---->
<!---->
<span
class="gl-button-text"
>
Manage profiles
</span>
</a>
</div>
</div>
</div>
<div
class="card-body"
>
<!---->
<!---->
<fieldset
class="form-group gl-form-group"
>
<legend
class="bv-no-focus-ring col-form-label pt-0 col-form-label"
tabindex="-1"
>
Use existing site profile
</legend>
<div
class="bv-no-focus-ring"
role="group"
tabindex="-1"
>
<div
class="dropdown b-dropdown gl-new-dropdown mw-460 btn-group"
data-testid="profiles-dropdown"
>
<!---->
<button
aria-expanded="false"
aria-haspopup="true"
class="btn dropdown-toggle btn-default btn-md gl-button gl-dropdown-toggle"
type="button"
>
<!---->
<span
class="gl-new-dropdown-button-text"
>
Site profile #1: https://foo.com
</span>
<svg
class="dropdown-chevron gl-icon s16"
data-testid="chevron-down-icon"
>
<use
href="#chevron-down"
/>
</svg>
</button>
<ul
class="dropdown-menu"
role="menu"
tabindex="-1"
>
<!---->
<li
class="gl-new-dropdown-item"
role="presentation"
>
<button
class="dropdown-item"
role="menuitem"
type="button"
>
<svg
class="gl-icon s16 gl-new-dropdown-item-check-icon"
data-testid="mobile-issue-close-icon"
>
<use
href="#mobile-issue-close"
/>
</svg>
<!---->
<!---->
<div
class="gl-new-dropdown-item-text-wrapper"
>
<p
class="gl-new-dropdown-item-text-primary"
>
Site profile #1
</p>
<!---->
</div>
<!---->
</button>
</li>
<li
class="gl-new-dropdown-item"
role="presentation"
>
<button
class="dropdown-item"
role="menuitem"
type="button"
>
<svg
class="gl-icon s16 gl-new-dropdown-item-check-icon gl-visibility-hidden"
data-testid="mobile-issue-close-icon"
>
<use
href="#mobile-issue-close"
/>
</svg>
<!---->
<!---->
<div
class="gl-new-dropdown-item-text-wrapper"
>
<p
class="gl-new-dropdown-item-text-primary"
>
Site profile #2
</p>
<!---->
</div>
<!---->
</button>
</li>
</ul>
</div>
<div
class="gl-mt-6 gl-pt-6 gl-border-t-solid gl-border-gray-100 gl-border-t-1"
data-testid="selected-profile-summary"
>
<div
class="row"
>
<div
class="col-md-6"
>
<div
class="row"
>
<div
class="col-md-3"
>
Target URL:
</div>
<div
class="col-md-9"
>
<strong>
https://foo.com
</strong>
</div>
</div>
</div>
</div>
</div>
<!---->
<!---->
<!---->
</div>
</fieldset>
</div>
<!---->
<!---->
</div>
`;
exports[`OnDemandScansSiteProfileSelector renders properly without profiles 1`] = `
<div
class="card"
data-foo="bar"
>
<!---->
<div
class="card-header"
>
<div
class="row"
>
<div
class="col-7"
>
<h3
class="gl-font-lg gl-display-inline"
>
Site profile
</h3>
</div>
<div
class="col-5 gl-text-right"
>
<button
class="btn btn-success btn-sm disabled gl-button btn-success-secondary"
data-testid="manage-profiles-link"
disabled="disabled"
type="button"
>
<!---->
<!---->
<span
class="gl-button-text"
>
Manage profiles
</span>
</button>
</div>
</div>
</div>
<div
class="card-body"
>
<!---->
<!---->
<p
class="gl-text-gray-700"
>
No profile yet. In order to create a new scan, you need to have at least one completed site profile.
</p>
<a
class="btn btn-success btn-md gl-button btn-success-secondary"
data-testid="create-profile-link"
href="/test/new/site/profile/path"
>
<!---->
<!---->
<span
class="gl-button-text"
>
Create a new site profile
</span>
</a>
</div>
<!---->
<!---->
</div>
`;
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`OnDemandScansProfileSummaryCell renders properly 1`] = `
"<div class=\\"col-md-6\\">
<div class=\\"row\\">
<div class=\\"col-md-3\\">Row Label:</div>
<div class=\\"col-md-9\\"><strong>Row Value</strong></div>
</div>
</div>"
`;
import { merge } from 'lodash';
import { mount } from '@vue/test-utils';
import { GlDropdownItem } from '@gitlab/ui';
import OnDemandScansProfileSelector from 'ee/on_demand_scans/components/profile_selector/profile_selector.vue';
import { scannerProfiles } from '../../mock_data';
describe('OnDemandScansProfileSelector', () => {
let wrapper;
const defaultProps = {
libraryPath: '/path/to/profiles/library',
newProfilePath: '/path/to/new/profile/form',
profiles: [],
};
const findByTestId = testId => wrapper.find(`[data-testid="${testId}"]`);
const findProfilesLibraryPathLink = () => findByTestId('manage-profiles-link');
const findProfilesDropdown = () => findByTestId('profiles-dropdown');
const findCreateNewProfileLink = () => findByTestId('create-profile-link');
const findSelectedProfileSummary = () => findByTestId('selected-profile-summary');
const parseDropdownItems = () =>
findProfilesDropdown()
.findAll(GlDropdownItem)
.wrappers.map(x => ({
text: x.text(),
isChecked: x.props('isChecked'),
}));
const selectFirstProfile = () => {
return findProfilesDropdown()
.find(GlDropdownItem)
.vm.$emit('click');
};
const createFullComponent = (options = {}) => {
wrapper = mount(
OnDemandScansProfileSelector,
merge(
{
propsData: defaultProps,
slots: {
title: 'Section title',
label: 'Use existing scanner profile',
'no-profiles': 'No profile yet',
'new-profile': 'Create a new profile',
},
scopedSlots: {
summary: "<div>{{ props.profile.profileName }}'s summary</div>",
},
},
options,
),
);
};
afterEach(() => {
wrapper.destroy();
});
it('shows section title and link to profiles library', () => {
createFullComponent();
expect(wrapper.text()).toContain('Section title');
});
describe('when there are no profiles yet', () => {
beforeEach(() => {
createFullComponent();
});
it('disables the link to profiles library', () => {
expect(findProfilesLibraryPathLink().props('disabled')).toBe(true);
});
it('shows a help text and a link to create a new profile', () => {
const link = findCreateNewProfileLink();
expect(wrapper.text()).toContain('No profile yet');
expect(link.exists()).toBe(true);
expect(link.attributes('href')).toBe('/path/to/new/profile/form');
expect(link.text()).toBe('Create a new profile');
});
});
describe('when there are profiles', () => {
beforeEach(() => {
createFullComponent({
propsData: { profiles: scannerProfiles },
});
});
it('enables link to profiles management', () => {
expect(findProfilesLibraryPathLink().props('disabled')).toBe(false);
expect(findProfilesLibraryPathLink().attributes('href')).toBe('/path/to/profiles/library');
});
it('shows a dropdown containing the profiles', () => {
const dropdown = findProfilesDropdown();
expect(wrapper.text()).toContain('Use existing scanner profile');
expect(dropdown.exists()).toBe(true);
expect(dropdown.element.children).toHaveLength(scannerProfiles.length);
});
it('when a profile is selected, input event is emitted', async () => {
await selectFirstProfile();
expect(wrapper.emitted('input')).toEqual([[scannerProfiles[0].id]]);
});
it('shows dropdown items for each profile', () => {
expect(parseDropdownItems()).toEqual(
scannerProfiles.map(x => ({
text: x.profileName,
isChecked: false,
})),
);
});
it('does not show summary', () => {
expect(findSelectedProfileSummary().exists()).toBe(false);
});
});
describe('when profile is selected', () => {
let selectedProfile;
beforeEach(() => {
[selectedProfile] = scannerProfiles;
createFullComponent({
propsData: {
profiles: scannerProfiles,
value: selectedProfile.id,
},
});
});
it('displays summary below dropdown', () => {
const summary = findSelectedProfileSummary();
expect(summary.exists()).toBe(true);
expect(summary.text()).toContain(`${scannerProfiles[0].profileName}'s summary`);
});
it('displays item as checked', () => {
expect(parseDropdownItems()).toEqual(
scannerProfiles.map((x, i) => ({
text: x.profileName,
isChecked: i === 0,
})),
);
});
});
});
import { merge } from 'lodash';
import { mount, shallowMount } from '@vue/test-utils';
import OnDemandScansScannerProfileSelector from 'ee/on_demand_scans/components/profile_selector/scanner_profile_selector.vue';
import ProfileSelector from 'ee/on_demand_scans/components/profile_selector/profile_selector.vue';
import { scannerProfiles } from '../../mock_data';
const TEST_LIBRARY_PATH = '/test/scanner/profiles/library/path';
const TEST_NEW_PATH = '/test/new/scanner/profile/path';
const TEST_ATTRS = {
'data-foo': 'bar',
};
describe('OnDemandScansScannerProfileSelector', () => {
let wrapper;
const wrapperFactory = (mountFn = shallowMount) => (options = {}) => {
wrapper = mountFn(
OnDemandScansScannerProfileSelector,
merge(
{
propsData: {
profiles: [],
},
attrs: TEST_ATTRS,
provide: {
scannerProfilesLibraryPath: TEST_LIBRARY_PATH,
newScannerProfilePath: TEST_NEW_PATH,
},
},
options,
),
);
};
const createComponent = wrapperFactory();
const createFullComponent = wrapperFactory(mount);
const findProfileSelector = () => wrapper.find(ProfileSelector);
afterEach(() => {
wrapper.destroy();
});
it('renders properly with profiles', () => {
createFullComponent({
propsData: { profiles: scannerProfiles, value: scannerProfiles[0].id },
});
expect(wrapper.element).toMatchSnapshot();
});
it('renders properly without profiles', () => {
createFullComponent();
expect(wrapper.element).toMatchSnapshot();
});
it('sets listeners on profile selector component', () => {
const inputHandler = jest.fn();
createComponent({
listeners: {
input: inputHandler,
},
});
findProfileSelector().vm.$emit('input');
expect(inputHandler).toHaveBeenCalled();
});
describe('with profiles', () => {
beforeEach(() => {
createComponent({
propsData: { profiles: scannerProfiles },
});
});
it('renders profile selector', () => {
const sel = findProfileSelector();
expect(sel.props()).toEqual({
libraryPath: TEST_LIBRARY_PATH,
newProfilePath: TEST_NEW_PATH,
profiles: scannerProfiles.map(x => ({ ...x, dropdownLabel: x.profileName })),
value: null,
});
expect(sel.attributes()).toMatchObject(TEST_ATTRS);
});
});
});
import { merge } from 'lodash';
import { mount, shallowMount } from '@vue/test-utils';
import OnDemandScansSiteProfileSelector from 'ee/on_demand_scans/components/profile_selector/site_profile_selector.vue';
import ProfileSelector from 'ee/on_demand_scans/components/profile_selector/profile_selector.vue';
import { siteProfiles } from '../../mock_data';
const TEST_LIBRARY_PATH = '/test/site/profiles/library/path';
const TEST_NEW_PATH = '/test/new/site/profile/path';
const TEST_ATTRS = {
'data-foo': 'bar',
};
describe('OnDemandScansSiteProfileSelector', () => {
let wrapper;
const wrapperFactory = (mountFn = shallowMount) => (options = {}) => {
wrapper = mountFn(
OnDemandScansSiteProfileSelector,
merge(
{
propsData: {
profiles: [],
},
attrs: TEST_ATTRS,
provide: {
siteProfilesLibraryPath: TEST_LIBRARY_PATH,
newSiteProfilePath: TEST_NEW_PATH,
},
},
options,
),
);
};
const createComponent = wrapperFactory();
const createFullComponent = wrapperFactory(mount);
const findProfileSelector = () => wrapper.find(ProfileSelector);
afterEach(() => {
wrapper.destroy();
});
it('renders properly with profiles', () => {
createFullComponent({
propsData: { profiles: siteProfiles, value: siteProfiles[0].id },
});
expect(wrapper.element).toMatchSnapshot();
});
it('renders properly without profiles', () => {
createFullComponent();
expect(wrapper.element).toMatchSnapshot();
});
it('sets listeners on profile selector component', () => {
const inputHandler = jest.fn();
createComponent({
listeners: {
input: inputHandler,
},
});
findProfileSelector().vm.$emit('input');
expect(inputHandler).toHaveBeenCalled();
});
describe('with profiles', () => {
beforeEach(() => {
createComponent({
propsData: { profiles: siteProfiles },
});
});
it('renders profile selector', () => {
const sel = findProfileSelector();
expect(sel.props()).toEqual({
libraryPath: TEST_LIBRARY_PATH,
newProfilePath: TEST_NEW_PATH,
profiles: siteProfiles.map(x => ({
...x,
dropdownLabel: `${x.profileName}: ${x.targetUrl}`,
})),
value: null,
});
expect(sel.attributes()).toMatchObject(TEST_ATTRS);
});
});
});
import { mount } from '@vue/test-utils';
import OnDemandScansProfileSummaryCell from 'ee/on_demand_scans/components/profile_selector/summary_cell.vue';
describe('OnDemandScansProfileSummaryCell', () => {
let wrapper;
const createFullComponent = () => {
wrapper = mount(OnDemandScansProfileSummaryCell, {
propsData: {
label: 'Row Label',
value: 'Row Value',
},
});
};
afterEach(() => {
wrapper.destroy();
});
it('renders properly', () => {
createFullComponent();
expect(wrapper.html()).toMatchSnapshot();
});
});
export const scannerProfiles = [
{
id: 'gid://gitlab/DastScannerProfile/1',
profileName: 'Scanner profile #1',
spiderTimeout: 5,
targetTimeout: 10,
},
{
id: 'gid://gitlab/DastScannerProfile/2',
profileName: 'Scanner profile #2',
spiderTimeout: 20,
targetTimeout: 150,
},
];
export const siteProfiles = [
{
id: 'gid://gitlab/DastSiteProfile/1',
profileName: 'Site profile #1',
targetUrl: 'https://foo.com',
},
{
id: 'gid://gitlab/DastSiteProfile/2',
profileName: 'Site profile #2',
targetUrl: 'https://bar.com',
},
];
......@@ -17685,6 +17685,9 @@ msgstr ""
msgid "OnDemandScans|Scan mode"
msgstr ""
msgid "OnDemandScans|Scanner profile"
msgstr ""
msgid "OnDemandScans|Scanner settings"
msgstr ""
......@@ -17694,6 +17697,9 @@ msgstr ""
msgid "OnDemandScans|Select one of the existing profiles"
msgstr ""
msgid "OnDemandScans|Site profile"
msgstr ""
msgid "OnDemandScans|Site profiles"
msgstr ""
......
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