2021-01-29 00:20:46 +05:30
|
|
|
import { shallowMount } from '@vue/test-utils';
|
2021-06-08 01:23:25 +05:30
|
|
|
import validation, { initForm } from '~/vue_shared/directives/validation';
|
2021-01-29 00:20:46 +05:30
|
|
|
|
|
|
|
describe('validation directive', () => {
|
|
|
|
let wrapper;
|
|
|
|
|
2021-11-18 22:05:49 +05:30
|
|
|
const createComponentFactory = (options) => {
|
|
|
|
const {
|
|
|
|
inputAttributes = { type: 'text', required: true },
|
|
|
|
template,
|
|
|
|
data,
|
|
|
|
feedbackMap = {},
|
|
|
|
} = options;
|
2021-01-29 00:20:46 +05:30
|
|
|
|
2021-06-08 01:23:25 +05:30
|
|
|
const defaultTemplate = `
|
|
|
|
<form>
|
|
|
|
<input v-validation:[showValidation] name="exampleField" v-bind="attributes" />
|
|
|
|
</form>
|
|
|
|
`;
|
|
|
|
|
2021-01-29 00:20:46 +05:30
|
|
|
const component = {
|
|
|
|
directives: {
|
2021-11-18 22:05:49 +05:30
|
|
|
validation: validation(feedbackMap),
|
2021-01-29 00:20:46 +05:30
|
|
|
},
|
|
|
|
data() {
|
|
|
|
return {
|
2021-11-18 22:05:49 +05:30
|
|
|
attributes: inputAttributes,
|
2021-06-08 01:23:25 +05:30
|
|
|
...data,
|
|
|
|
};
|
|
|
|
},
|
|
|
|
template: template || defaultTemplate,
|
|
|
|
};
|
|
|
|
|
|
|
|
wrapper = shallowMount(component, { attachTo: document.body });
|
|
|
|
};
|
|
|
|
|
2021-11-18 22:05:49 +05:30
|
|
|
const createComponent = (options = {}) => {
|
|
|
|
const { inputAttributes, showValidation, template, feedbackMap } = options;
|
|
|
|
|
|
|
|
return createComponentFactory({
|
2021-06-08 01:23:25 +05:30
|
|
|
inputAttributes,
|
|
|
|
data: {
|
|
|
|
showValidation,
|
|
|
|
form: {
|
|
|
|
state: null,
|
|
|
|
fields: {
|
|
|
|
exampleField: {
|
|
|
|
state: null,
|
|
|
|
feedback: '',
|
2021-01-29 00:20:46 +05:30
|
|
|
},
|
|
|
|
},
|
2021-06-08 01:23:25 +05:30
|
|
|
},
|
|
|
|
},
|
|
|
|
template,
|
2021-11-18 22:05:49 +05:30
|
|
|
feedbackMap,
|
2021-06-08 01:23:25 +05:30
|
|
|
});
|
2021-11-18 22:05:49 +05:30
|
|
|
};
|
|
|
|
|
|
|
|
const createComponentWithInitForm = (options = {}) => {
|
|
|
|
const { inputAttributes, feedbackMap } = options;
|
2021-06-08 01:23:25 +05:30
|
|
|
|
2021-11-18 22:05:49 +05:30
|
|
|
return createComponentFactory({
|
2021-06-08 01:23:25 +05:30
|
|
|
inputAttributes,
|
|
|
|
data: {
|
|
|
|
form: initForm({
|
|
|
|
fields: {
|
|
|
|
exampleField: {
|
|
|
|
state: null,
|
|
|
|
value: 'lorem',
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}),
|
2021-01-29 00:20:46 +05:30
|
|
|
},
|
|
|
|
template: `
|
|
|
|
<form>
|
2021-06-08 01:23:25 +05:30
|
|
|
<input v-validation:[form.showValidation] name="exampleField" v-bind="attributes" />
|
2021-01-29 00:20:46 +05:30
|
|
|
</form>
|
|
|
|
`,
|
2021-11-18 22:05:49 +05:30
|
|
|
feedbackMap,
|
2021-06-08 01:23:25 +05:30
|
|
|
});
|
2021-11-18 22:05:49 +05:30
|
|
|
};
|
2021-01-29 00:20:46 +05:30
|
|
|
|
|
|
|
afterEach(() => {
|
|
|
|
wrapper.destroy();
|
|
|
|
wrapper = null;
|
|
|
|
});
|
|
|
|
|
|
|
|
const getFormData = () => wrapper.vm.form;
|
|
|
|
const findForm = () => wrapper.find('form');
|
|
|
|
const findInput = () => wrapper.find('input');
|
|
|
|
|
2021-06-08 01:23:25 +05:30
|
|
|
const setValueAndTriggerValidation = (value) => {
|
|
|
|
const input = findInput();
|
|
|
|
input.setValue(value);
|
|
|
|
input.trigger('blur');
|
|
|
|
};
|
|
|
|
|
2021-01-29 00:20:46 +05:30
|
|
|
describe.each([true, false])(
|
|
|
|
'with fields untouched and "showValidation" set to "%s"',
|
2021-03-08 18:12:59 +05:30
|
|
|
(showValidation) => {
|
2021-01-29 00:20:46 +05:30
|
|
|
beforeEach(() => {
|
|
|
|
createComponent({ showValidation });
|
|
|
|
});
|
|
|
|
|
|
|
|
it('sets the fields validity correctly', () => {
|
|
|
|
expect(getFormData().fields.exampleField).toEqual({
|
|
|
|
state: showValidation ? false : null,
|
|
|
|
feedback: showValidation ? expect.any(String) : '',
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('sets the form validity correctly', () => {
|
|
|
|
expect(getFormData().state).toBe(false);
|
|
|
|
});
|
|
|
|
},
|
|
|
|
);
|
|
|
|
|
|
|
|
describe.each`
|
|
|
|
inputAttributes | validValue | invalidValue
|
|
|
|
${{ required: true }} | ${'foo'} | ${''}
|
|
|
|
${{ type: 'url' }} | ${'http://foo.com'} | ${'foo'}
|
|
|
|
${{ type: 'number', min: 1, max: 5 }} | ${3} | ${0}
|
|
|
|
${{ type: 'number', min: 1, max: 5 }} | ${3} | ${6}
|
|
|
|
${{ pattern: 'foo|bar' }} | ${'bar'} | ${'quz'}
|
|
|
|
`(
|
|
|
|
'with input-attributes set to $inputAttributes',
|
|
|
|
({ inputAttributes, validValue, invalidValue }) => {
|
|
|
|
beforeEach(() => {
|
|
|
|
createComponent({ inputAttributes });
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('with valid value', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
setValueAndTriggerValidation(validValue);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('sets the field to be valid', () => {
|
|
|
|
expect(getFormData().fields.exampleField).toEqual({
|
|
|
|
state: true,
|
|
|
|
feedback: '',
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('sets the form to be valid', () => {
|
|
|
|
expect(getFormData().state).toBe(true);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('with invalid value', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
setValueAndTriggerValidation(invalidValue);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('sets the field to be invalid', () => {
|
|
|
|
expect(getFormData().fields.exampleField).toEqual({
|
|
|
|
state: false,
|
|
|
|
feedback: expect.any(String),
|
|
|
|
});
|
|
|
|
expect(getFormData().fields.exampleField.feedback.length).toBeGreaterThan(0);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('sets the form to be invalid', () => {
|
|
|
|
expect(getFormData().state).toBe(false);
|
|
|
|
});
|
|
|
|
|
|
|
|
it('sets focus on the first invalid input when the form is submitted', () => {
|
|
|
|
findForm().trigger('submit');
|
|
|
|
expect(findInput().element).toBe(document.activeElement);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
},
|
|
|
|
);
|
2021-06-08 01:23:25 +05:30
|
|
|
|
|
|
|
describe('with group elements', () => {
|
|
|
|
const template = `
|
|
|
|
<form>
|
|
|
|
<div v-validation:[showValidation]>
|
|
|
|
<input name="exampleField" v-bind="attributes" />
|
|
|
|
</div>
|
|
|
|
</form>
|
|
|
|
`;
|
|
|
|
beforeEach(() => {
|
|
|
|
createComponent({
|
|
|
|
template,
|
|
|
|
inputAttributes: {
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('with invalid value', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
setValueAndTriggerValidation('');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should set correct field state', () => {
|
|
|
|
expect(getFormData().fields.exampleField).toEqual({
|
|
|
|
state: false,
|
|
|
|
feedback: expect.any(String),
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should set correct feedback', () => {
|
|
|
|
expect(getFormData().fields.exampleField.feedback).toBe('Please fill out this field.');
|
|
|
|
});
|
|
|
|
});
|
2021-11-18 22:05:49 +05:30
|
|
|
|
|
|
|
describe('with valid value', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
setValueAndTriggerValidation('hello');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('set the correct state', () => {
|
|
|
|
expect(getFormData().fields.exampleField).toEqual({
|
|
|
|
state: true,
|
|
|
|
feedback: '',
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('with custom feedbackMap', () => {
|
|
|
|
const customMessage = 'Please fill out the name field.';
|
|
|
|
const template = `
|
|
|
|
<form>
|
|
|
|
<div v-validation:[showValidation]>
|
|
|
|
<input name="exampleField" v-bind="attributes" />
|
|
|
|
</div>
|
|
|
|
</form>
|
|
|
|
`;
|
|
|
|
beforeEach(() => {
|
|
|
|
const feedbackMap = {
|
|
|
|
valueMissing: {
|
|
|
|
isInvalid: (el) => el.validity?.valueMissing,
|
|
|
|
message: customMessage,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
createComponent({
|
|
|
|
template,
|
|
|
|
inputAttributes: {
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
feedbackMap,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('with invalid value', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
setValueAndTriggerValidation('');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should set correct field state', () => {
|
|
|
|
expect(getFormData().fields.exampleField).toEqual({
|
|
|
|
state: false,
|
|
|
|
feedback: customMessage,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('with valid value', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
setValueAndTriggerValidation('hello');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('set the correct state', () => {
|
|
|
|
expect(getFormData().fields.exampleField).toEqual({
|
|
|
|
state: true,
|
|
|
|
feedback: '',
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('with validation-message present on the element', () => {
|
|
|
|
const customMessage = 'The name field is required.';
|
|
|
|
const template = `
|
|
|
|
<form>
|
|
|
|
<div v-validation:[showValidation]>
|
|
|
|
<input name="exampleField" v-bind="attributes" validation-message="${customMessage}" />
|
|
|
|
</div>
|
|
|
|
</form>
|
|
|
|
`;
|
|
|
|
beforeEach(() => {
|
|
|
|
const feedbackMap = {
|
|
|
|
valueMissing: {
|
|
|
|
isInvalid: (el) => el.validity?.valueMissing,
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
createComponent({
|
|
|
|
template,
|
|
|
|
inputAttributes: {
|
|
|
|
required: true,
|
|
|
|
},
|
|
|
|
feedbackMap,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('with invalid value', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
setValueAndTriggerValidation('');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('should set correct field state', () => {
|
|
|
|
expect(getFormData().fields.exampleField).toEqual({
|
|
|
|
state: false,
|
|
|
|
feedback: customMessage,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
2021-06-08 01:23:25 +05:30
|
|
|
|
|
|
|
describe('with valid value', () => {
|
|
|
|
beforeEach(() => {
|
|
|
|
setValueAndTriggerValidation('hello');
|
|
|
|
});
|
|
|
|
|
|
|
|
it('set the correct state', () => {
|
|
|
|
expect(getFormData().fields.exampleField).toEqual({
|
|
|
|
state: true,
|
|
|
|
feedback: '',
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('component using initForm', () => {
|
|
|
|
it('sets the form fields correctly', () => {
|
|
|
|
createComponentWithInitForm();
|
|
|
|
|
|
|
|
expect(getFormData().state).toBe(false);
|
|
|
|
expect(getFormData().showValidation).toBe(false);
|
|
|
|
|
|
|
|
expect(getFormData().fields.exampleField).toMatchObject({
|
|
|
|
value: 'lorem',
|
|
|
|
state: null,
|
|
|
|
required: true,
|
|
|
|
feedback: expect.any(String),
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
describe('initForm', () => {
|
|
|
|
const MOCK_FORM = {
|
|
|
|
fields: {
|
|
|
|
name: {
|
|
|
|
value: 'lorem',
|
|
|
|
},
|
|
|
|
description: {
|
|
|
|
value: 'ipsum',
|
|
|
|
required: false,
|
|
|
|
skipValidation: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const EXPECTED_FIELDS = {
|
|
|
|
name: { value: 'lorem', required: true, state: null, feedback: null },
|
|
|
|
description: { value: 'ipsum', required: false, state: true, feedback: null },
|
|
|
|
};
|
|
|
|
|
|
|
|
it('returns form object', () => {
|
|
|
|
expect(initForm(MOCK_FORM)).toMatchObject({
|
|
|
|
state: false,
|
|
|
|
showValidation: false,
|
|
|
|
fields: EXPECTED_FIELDS,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('returns form object with additional parameters', () => {
|
|
|
|
const customFormObject = {
|
|
|
|
foo: {
|
|
|
|
bar: 'lorem',
|
|
|
|
},
|
|
|
|
};
|
|
|
|
|
|
|
|
const form = {
|
|
|
|
...MOCK_FORM,
|
|
|
|
...customFormObject,
|
|
|
|
};
|
|
|
|
|
|
|
|
expect(initForm(form)).toMatchObject({
|
|
|
|
state: false,
|
|
|
|
showValidation: false,
|
|
|
|
fields: EXPECTED_FIELDS,
|
|
|
|
...customFormObject,
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
it('can override existing state and showValidation values', () => {
|
|
|
|
const form = {
|
|
|
|
...MOCK_FORM,
|
|
|
|
state: true,
|
|
|
|
showValidation: true,
|
|
|
|
};
|
|
|
|
|
|
|
|
expect(initForm(form)).toMatchObject({
|
|
|
|
state: true,
|
|
|
|
showValidation: true,
|
|
|
|
fields: EXPECTED_FIELDS,
|
|
|
|
});
|
|
|
|
});
|
2021-01-29 00:20:46 +05:30
|
|
|
});
|