Commit 406360c8 authored by David Pisek's avatar David Pisek Committed by Phil Hughes

Add auth-section component

* Adds new component that includes the authentication form
* Adds new component to site-profile form component
parent 75ac49a4
......@@ -12,6 +12,7 @@ import {
GlFormCheckbox,
GlFormRadioGroup,
} from '@gitlab/ui';
import { initFormField } from 'ee/security_configuration/utils';
import * as Sentry from '~/sentry/wrapper';
import { __, s__ } from '~/locale';
import { redirectTo } from '~/lib/utils/url_utility';
......@@ -21,13 +22,6 @@ import dastScannerProfileUpdateMutation from '../graphql/dast_scanner_profile_up
import tooltipIcon from './tooltip_icon.vue';
import { SCAN_TYPE, SCAN_TYPE_OPTIONS } from '../constants';
const initField = (value, isRequired = true) => ({
value,
required: isRequired,
state: null,
feedback: null,
});
const SPIDER_TIMEOUT_MIN = 0;
const SPIDER_TIMEOUT_MAX = 2880;
const TARGET_TIMEOUT_MIN = 1;
......@@ -74,12 +68,12 @@ export default {
} = this.profile;
const form = {
profileName: initField(name),
spiderTimeout: initField(spiderTimeout),
targetTimeout: initField(targetTimeout),
scanType: initField(scanType),
useAjaxSpider: initField(useAjaxSpider),
showDebugMessages: initField(showDebugMessages),
profileName: initFormField({ value: name }),
spiderTimeout: initFormField({ value: spiderTimeout }),
targetTimeout: initFormField({ value: targetTimeout }),
scanType: initFormField({ value: scanType }),
useAjaxSpider: initFormField({ value: useAjaxSpider }),
showDebugMessages: initFormField({ value: showDebugMessages }),
};
return {
......
<script>
import { GlFormGroup, GlFormInput, GlFormCheckbox } from '@gitlab/ui';
import { initFormField } from 'ee/security_configuration/utils';
import validation from '~/vue_shared/directives/validation';
export default {
components: {
GlFormGroup,
GlFormInput,
GlFormCheckbox,
},
directives: {
validation: validation(),
},
props: {
fields: {
type: Object,
required: false,
default: () => ({}),
},
showValidation: {
type: Boolean,
required: false,
default: false,
},
},
data() {
const {
authEnabled,
authenticationUrl,
userName,
password,
// default to commonly used names for `userName` and `password` fields in authentcation forms
userNameFormField = 'username',
passwordFormField = 'password',
} = this.fields;
return {
form: {
state: false,
fields: {
authEnabled: initFormField({ value: authEnabled, skipValidation: true }),
authenticationUrl: initFormField({ value: authenticationUrl }),
userName: initFormField({ value: userName }),
password: initFormField({ value: password }),
userNameFormField: initFormField({ value: userNameFormField }),
passwordFormField: initFormField({ value: passwordFormField }),
},
},
};
},
computed: {
showValidationOrInEditMode() {
return this.showValidation || Object.keys(this.fields).length > 0;
},
},
watch: {
form: { handler: 'emitUpdate', immediate: true, deep: true },
},
methods: {
emitUpdate() {
this.$emit('input', this.form);
},
},
};
</script>
<template>
<section>
<gl-form-group :label="s__('DastProfiles|Authentication')">
<gl-form-checkbox v-model="form.fields.authEnabled.value">{{
s__('DastProfiles|Enable Authentication')
}}</gl-form-checkbox>
</gl-form-group>
<div v-if="form.fields.authEnabled.value" data-testid="auth-form">
<div class="row">
<gl-form-group
:label="s__('DastProfiles|Authentication URL')"
:invalid-feedback="form.fields.authenticationUrl.feedback"
class="col-md-6"
>
<gl-form-input
v-model="form.fields.authenticationUrl.value"
v-validation:[showValidationOrInEditMode]
name="authenticationUrl"
type="url"
required
:state="form.fields.authenticationUrl.state"
/>
</gl-form-group>
</div>
<div class="row">
<gl-form-group
:label="s__('DastProfiles|Username')"
:invalid-feedback="form.fields.userName.feedback"
class="col-md-6"
>
<gl-form-input
v-model="form.fields.userName.value"
v-validation:[showValidationOrInEditMode]
autocomplete="off"
name="userName"
type="text"
required
:state="form.fields.userName.state"
/>
</gl-form-group>
<gl-form-group
:label="s__('DastProfiles|Password')"
:invalid-feedback="form.fields.password.feedback"
class="col-md-6"
>
<gl-form-input
v-model="form.fields.password.value"
v-validation:[showValidationOrInEditMode]
autocomplete="off"
name="password"
type="password"
required
:state="form.fields.password.state"
/>
</gl-form-group>
</div>
<div class="row">
<gl-form-group
:label="s__('DastProfiles|Username form field')"
:invalid-feedback="form.fields.userNameFormField.feedback"
class="col-md-6"
>
<gl-form-input
v-model="form.fields.userNameFormField.value"
v-validation:[showValidationOrInEditMode]
name="userNameFormField"
type="text"
required
:state="form.fields.userNameFormField.state"
/>
</gl-form-group>
<gl-form-group
:label="s__('DastProfiles|Password form field')"
:invalid-feedback="form.fields.passwordFormField.feedback"
class="col-md-6"
>
<gl-form-input
v-model="form.fields.passwordFormField.value"
v-validation:[showValidationOrInEditMode]
name="passwordFormField"
type="text"
required
:state="form.fields.passwordFormField.state"
/>
</gl-form-group>
</div>
</div>
</section>
</template>
......@@ -10,6 +10,7 @@ import {
GlModal,
GlToggle,
} from '@gitlab/ui';
import { initFormField } from 'ee/security_configuration/utils';
import * as Sentry from '~/sentry/wrapper';
import { __, s__ } from '~/locale';
import { redirectTo } from '~/lib/utils/url_utility';
......@@ -26,12 +27,6 @@ import { DAST_SITE_VALIDATION_STATUS, DAST_SITE_VALIDATION_POLL_INTERVAL } from
const { PENDING, INPROGRESS, PASSED, FAILED } = DAST_SITE_VALIDATION_STATUS;
const initField = value => ({
value,
state: null,
feedback: null,
});
export default {
name: 'DastSiteProfileForm',
components: {
......@@ -71,8 +66,8 @@ export default {
state: false,
showValidation: false,
fields: {
profileName: initField(name),
targetUrl: initField(targetUrl),
profileName: initFormField({ value: name }),
targetUrl: initFormField({ value: targetUrl }),
},
};
......
export const initFormField = ({ value, required = true, skipValidation = false }) => ({
value,
required,
state: skipValidation ? true : null,
feedback: null,
});
import { mount } from '@vue/test-utils';
import { GlFormCheckbox } from '@gitlab/ui';
import { extendedWrapper } from 'helpers/vue_test_utils_helper';
import DastSiteAuthSection from 'ee/security_configuration/dast_site_profiles_form/components/dast_site_auth_section.vue';
describe('DastSiteAuthSection', () => {
let wrapper;
const createComponent = ({ fields } = {}) => {
wrapper = extendedWrapper(
mount(DastSiteAuthSection, {
propsData: {
fields,
},
}),
);
};
beforeEach(() => {
createComponent();
});
afterEach(() => {
wrapper.destroy();
});
const findByNameAttribute = name => wrapper.find(`[name="${name}"]`);
const findAuthForm = () => wrapper.findByTestId('auth-form');
const findAuthCheckbox = () => wrapper.find(GlFormCheckbox);
const setAuthentication = ({ enabled }) => {
findAuthCheckbox().vm.$emit('input', enabled);
return wrapper.vm.$nextTick();
};
const getLatestInputEventPayload = () => {
const latestInputEvent = [...wrapper.emitted('input')].pop();
const [payload] = latestInputEvent;
return payload;
};
describe('authentication toggle', () => {
it.each([true, false])(
'is set correctly when the "authEnabled" field is set to "%s"',
authEnabled => {
createComponent({ fields: { authEnabled } });
expect(findAuthCheckbox().vm.$attrs.checked).toBe(authEnabled);
},
);
it('controls the visibility of the authentication-fields form', async () => {
expect(findAuthForm().exists()).toBe(false);
await setAuthentication({ enabled: true });
expect(findAuthForm().exists()).toBe(true);
});
it.each([true, false])(
'makes the component emit an "input" event when changed',
async enabled => {
await setAuthentication({ enabled });
expect(getLatestInputEventPayload().fields.authEnabled.value).toBe(enabled);
},
);
});
describe('authentication form', () => {
beforeEach(async () => {
await setAuthentication({ enabled: true });
});
const inputFieldsWithValues = {
authenticationUrl: 'http://www.gitlab.com',
userName: 'foo',
password: 'foo',
userNameFormField: 'foo',
passwordFormField: 'foo',
};
const inputFieldNames = Object.keys(inputFieldsWithValues);
describe.each(inputFieldNames)('input field "%s"', inputFieldName => {
it('is rendered', () => {
expect(findByNameAttribute(inputFieldName).exists()).toBe(true);
});
it('makes the component emit an "input" event when its value changes', () => {
const input = findByNameAttribute(inputFieldName);
const newValue = 'foo';
input.setValue(newValue);
expect(getLatestInputEventPayload().fields[inputFieldName].value).toBe(newValue);
});
});
describe('validity', () => {
it('is not valid per default', () => {
expect(getLatestInputEventPayload().state).toBe(false);
});
it('is valid when correct values are passed in via the "fields" prop', async () => {
createComponent({ fields: inputFieldsWithValues });
await setAuthentication({ enabled: true });
expect(getLatestInputEventPayload().state).toBe(true);
});
it('is valid once all fields have been entered correctly', () => {
Object.entries(inputFieldsWithValues).forEach(([inputFieldName, inputFieldValue]) => {
const input = findByNameAttribute(inputFieldName);
input.setValue(inputFieldValue);
input.trigger('blur');
});
expect(getLatestInputEventPayload().state).toBe(true);
});
});
});
});
......@@ -8277,6 +8277,12 @@ msgstr ""
msgid "DastProfiles|Are you sure you want to delete this profile?"
msgstr ""
msgid "DastProfiles|Authentication"
msgstr ""
msgid "DastProfiles|Authentication URL"
msgstr ""
msgid "DastProfiles|Could not create site validation token. Please refresh the page, or try again later."
msgstr ""
......@@ -8337,6 +8343,9 @@ msgstr ""
msgid "DastProfiles|Edit site profile"
msgstr ""
msgid "DastProfiles|Enable Authentication"
msgstr ""
msgid "DastProfiles|Error Details"
msgstr ""
......@@ -8373,6 +8382,12 @@ msgstr ""
msgid "DastProfiles|Passive"
msgstr ""
msgid "DastProfiles|Password"
msgstr ""
msgid "DastProfiles|Password form field"
msgstr ""
msgid "DastProfiles|Please enter a valid timeout value"
msgstr ""
......@@ -8442,6 +8457,12 @@ msgstr ""
msgid "DastProfiles|Turn on AJAX spider"
msgstr ""
msgid "DastProfiles|Username"
msgstr ""
msgid "DastProfiles|Username form field"
msgstr ""
msgid "DastProfiles|Validate"
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