fix: Getting validators
BREAKING CHANGE: Removed form registry
This commit is contained in:
parent
467dca656b
commit
c85f3332eb
@ -10,7 +10,6 @@ import merge from '@/utils/merge'
|
|||||||
import FileUpload from '@/FileUpload'
|
import FileUpload from '@/FileUpload'
|
||||||
|
|
||||||
import FormularioForm from '@/FormularioForm.vue'
|
import FormularioForm from '@/FormularioForm.vue'
|
||||||
import FormularioFormInterface from '@/FormularioFormInterface'
|
|
||||||
import FormularioInput from '@/FormularioInput.vue'
|
import FormularioInput from '@/FormularioInput.vue'
|
||||||
import FormularioGrouping from '@/FormularioGrouping.vue'
|
import FormularioGrouping from '@/FormularioGrouping.vue'
|
||||||
|
|
||||||
@ -35,7 +34,6 @@ interface FormularioOptions {
|
|||||||
*/
|
*/
|
||||||
export default class Formulario {
|
export default class Formulario {
|
||||||
public options: FormularioOptions
|
public options: FormularioOptions
|
||||||
public registry: Map<string, FormularioFormInterface>
|
|
||||||
public idRegistry: { [name: string]: number }
|
public idRegistry: { [name: string]: number }
|
||||||
|
|
||||||
constructor () {
|
constructor () {
|
||||||
@ -54,7 +52,6 @@ export default class Formulario {
|
|||||||
validationMessages: messages,
|
validationMessages: messages,
|
||||||
idPrefix: 'formulario-'
|
idPrefix: 'formulario-'
|
||||||
}
|
}
|
||||||
this.registry = new Map()
|
|
||||||
this.idRegistry = {}
|
this.idRegistry = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -116,68 +113,6 @@ export default class Formulario {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Given an instance of a FormularioForm register it.
|
|
||||||
*/
|
|
||||||
register (form: FormularioFormInterface): void {
|
|
||||||
if (typeof form.name === 'string') {
|
|
||||||
this.registry.set(form.name, form)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given an instance of a form, remove it from the registry.
|
|
||||||
*/
|
|
||||||
deregister (form: FormularioFormInterface): void {
|
|
||||||
if (typeof form.name === 'string' && this.registry.has(form.name)) {
|
|
||||||
this.registry.delete(form.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Given an array, this function will attempt to make sense of the given error
|
|
||||||
* and hydrate a form with the resulting errors.
|
|
||||||
*/
|
|
||||||
handle ({ formErrors, inputErrors }: {
|
|
||||||
formErrors?: string[];
|
|
||||||
inputErrors?: Record<string, any>;
|
|
||||||
}, formName: string): void {
|
|
||||||
if (this.registry.has(formName)) {
|
|
||||||
const form = this.registry.get(formName) as FormularioFormInterface
|
|
||||||
|
|
||||||
form.loadErrors({
|
|
||||||
formErrors: formErrors || [],
|
|
||||||
inputErrors: inputErrors || {}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset a form.
|
|
||||||
*/
|
|
||||||
reset (formName: string, initialValue: Record<string, any> = {}): void {
|
|
||||||
this.resetValidation(formName)
|
|
||||||
this.setValues(formName, initialValue)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Reset the form's validation messages.
|
|
||||||
*/
|
|
||||||
resetValidation (formName: string): void {
|
|
||||||
if (this.registry.has(formName)) {
|
|
||||||
(this.registry.get(formName) as FormularioFormInterface).resetValidation()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Set the form values.
|
|
||||||
*/
|
|
||||||
setValues (formName: string, values?: Record<string, any>): void {
|
|
||||||
if (this.registry.has(formName) && values) {
|
|
||||||
(this.registry.get(formName) as FormularioFormInterface).setValues({ ...values })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the file uploader.
|
* Get the file uploader.
|
||||||
*/
|
*/
|
||||||
|
@ -27,10 +27,8 @@ import { ValidationErrorBag } from '@/validation/types'
|
|||||||
|
|
||||||
import FileUpload from '@/FileUpload'
|
import FileUpload from '@/FileUpload'
|
||||||
|
|
||||||
import FormularioFormInterface from '@/FormularioFormInterface'
|
|
||||||
|
|
||||||
@Component({ name: 'FormularioForm' })
|
@Component({ name: 'FormularioForm' })
|
||||||
export default class FormularioForm extends Vue implements FormularioFormInterface {
|
export default class FormularioForm extends Vue {
|
||||||
@Provide() formularioFieldValidation (errorBag: ValidationErrorBag): void {
|
@Provide() formularioFieldValidation (errorBag: ValidationErrorBag): void {
|
||||||
this.$emit('validation', errorBag)
|
this.$emit('validation', errorBag)
|
||||||
}
|
}
|
||||||
@ -133,14 +131,9 @@ export default class FormularioForm extends Vue implements FormularioFormInterfa
|
|||||||
}
|
}
|
||||||
|
|
||||||
created (): void {
|
created (): void {
|
||||||
this.$formulario.register(this)
|
|
||||||
this.initProxy()
|
this.initProxy()
|
||||||
}
|
}
|
||||||
|
|
||||||
destroyed (): void {
|
|
||||||
this.$formulario.deregister(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
onFormSubmit (): Promise<void> {
|
onFormSubmit (): Promise<void> {
|
||||||
this.childrenShouldShowErrors = true
|
this.childrenShouldShowErrors = true
|
||||||
this.registry.forEach((input: FormularioInput) => {
|
this.registry.forEach((input: FormularioInput) => {
|
||||||
@ -183,12 +176,6 @@ export default class FormularioForm extends Vue implements FormularioFormInterfa
|
|||||||
this.registry.remove(field)
|
this.registry.remove(field)
|
||||||
}
|
}
|
||||||
|
|
||||||
loadErrors ({ formErrors, inputErrors }: { formErrors: string[]; inputErrors: Record<string, string[]> }): void {
|
|
||||||
// given an object of errors, apply them to this form
|
|
||||||
this.localFormErrors = formErrors
|
|
||||||
this.localFieldErrors = inputErrors
|
|
||||||
}
|
|
||||||
|
|
||||||
resetValidation (): void {
|
resetValidation (): void {
|
||||||
this.localFormErrors = []
|
this.localFormErrors = []
|
||||||
this.localFieldErrors = {}
|
this.localFieldErrors = {}
|
||||||
@ -278,5 +265,11 @@ export default class FormularioForm extends Vue implements FormularioFormInterfa
|
|||||||
this.$emit('input', { ...this.proxy })
|
this.$emit('input', { ...this.proxy })
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setErrors ({ formErrors, inputErrors }: { formErrors?: string[]; inputErrors?: Record<string, string[]> }): void {
|
||||||
|
// given an object of errors, apply them to this form
|
||||||
|
this.localFormErrors = formErrors || []
|
||||||
|
this.localFieldErrors = inputErrors || {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -1,7 +0,0 @@
|
|||||||
export default interface FormularioFormInterface {
|
|
||||||
name: string | boolean;
|
|
||||||
$options: Record<string, any>;
|
|
||||||
setValues(values: Record<string, any>): void;
|
|
||||||
loadErrors ({ formErrors, inputErrors }: { formErrors: string[]; inputErrors: Record<string, string[]> }): void;
|
|
||||||
resetValidation (): void;
|
|
||||||
}
|
|
@ -305,12 +305,6 @@ export default class FormularioInput extends Vue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
get validators (): any {
|
|
||||||
return createValidatorGroups(
|
|
||||||
parseRules(this.validation, this.$formulario.rules(this.parsedValidationRules))
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
performValidation (): Promise<void> {
|
performValidation (): Promise<void> {
|
||||||
this.pendingValidation = this.validate().then(errors => {
|
this.pendingValidation = this.validate().then(errors => {
|
||||||
this.didValidate(errors)
|
this.didValidate(errors)
|
||||||
@ -348,7 +342,9 @@ export default class FormularioInput extends Vue {
|
|||||||
resolve([])
|
resolve([])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
resolveGroups(this.validators)
|
resolveGroups(createValidatorGroups(
|
||||||
|
parseRules(this.validation, this.$formulario.rules(this.parsedValidationRules))
|
||||||
|
))
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,161 +38,128 @@ describe('FormularioForm', () => {
|
|||||||
expect(spy).toHaveBeenCalled()
|
expect(spy).toHaveBeenCalled()
|
||||||
})
|
})
|
||||||
|
|
||||||
it('Registers its subcomponents', () => {
|
it('Adds subcomponents to the registry', () => {
|
||||||
const wrapper = mount(FormularioForm, {
|
const wrapper = mount(FormularioForm, {
|
||||||
propsData: { formularioValue: { testinput: 'has initial value' } },
|
propsData: { formularioValue: {} },
|
||||||
slots: {
|
slots: {
|
||||||
default: `
|
default: `
|
||||||
<FormularioInput type="text" name="subinput1" />
|
<FormularioInput type="text" name="sub1" />
|
||||||
<FormularioInput type="checkbox" name="subinput2" />
|
<FormularioInput type="checkbox" name="sub2" />
|
||||||
`
|
`
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
expect(wrapper.vm.registry.keys()).toEqual(['subinput1', 'subinput2'])
|
expect(wrapper.vm.registry.keys()).toEqual(['sub1', 'sub2'])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('deregisters a subcomponents', async () => {
|
it('Removes subcomponents from the registry', async () => {
|
||||||
const wrapper = mount({
|
const wrapper = mount({
|
||||||
data () {
|
data: () => ({ active: true }),
|
||||||
return {
|
|
||||||
active: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
template: `
|
template: `
|
||||||
<FormularioForm>
|
<FormularioForm>
|
||||||
<FormularioInput v-if="active" type="text" name="subinput1" />
|
<FormularioInput v-if="active" type="text" name="sub1" />
|
||||||
<FormularioInput type="checkbox" name="subinput2" />
|
<FormularioInput type="checkbox" name="sub2" />
|
||||||
</FormularioForm>
|
</FormularioForm>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
expect(wrapper.findComponent(FormularioForm).vm.registry.keys()).toEqual(['subinput1', 'subinput2'])
|
expect(wrapper.findComponent(FormularioForm).vm.registry.keys()).toEqual(['sub1', 'sub2'])
|
||||||
wrapper.setData({ active: false })
|
wrapper.setData({ active: false })
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
expect(wrapper.findComponent(FormularioForm).vm.registry.keys()).toEqual(['subinput2'])
|
expect(wrapper.findComponent(FormularioForm).vm.registry.keys()).toEqual(['sub2'])
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can set a field’s initial value', async () => {
|
it('Can set a field’s initial value', async () => {
|
||||||
const wrapper = mount(FormularioForm, {
|
const wrapper = mount(FormularioForm, {
|
||||||
propsData: { formularioValue: { testinput: 'has initial value' } },
|
propsData: { formularioValue: { test: 'Has initial value' } },
|
||||||
slots: { default: `
|
slots: {
|
||||||
<FormularioInput v-slot="inputProps" validation="required|in:bar" name="testinput" >
|
default: `
|
||||||
<input v-model="inputProps.context.model" type="text">
|
<FormularioInput v-slot="{ context }" validation="required|in:bar" name="test" >
|
||||||
</FormularioInput>
|
<input v-model="context.model" type="text">
|
||||||
` }
|
</FormularioInput>
|
||||||
|
`
|
||||||
|
}
|
||||||
})
|
})
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
expect(wrapper.find('input').element.value).toBe('has initial value')
|
expect(wrapper.find('input').element['value']).toBe('Has initial value')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('lets individual fields override form initial value', () => {
|
it('Lets individual fields override form initial value', () => {
|
||||||
const wrapper = mount(FormularioForm, {
|
const wrapper = mount(FormularioForm, {
|
||||||
propsData: { formularioValue: { testinput: 'has initial value' } },
|
propsData: { formularioValue: { test: 'has initial value' } },
|
||||||
slots: { default: `
|
slots: {
|
||||||
<FormularioInput v-slot="inputProps" formulario-value="123" name="testinput" >
|
default: `
|
||||||
<input v-model="inputProps.context.model" type="text">
|
<FormularioInput v-slot="{ context }" formulario-value="123" name="test" >
|
||||||
</FormularioInput>
|
<input v-model="context.model" type="text">
|
||||||
` }
|
</FormularioInput>
|
||||||
|
`
|
||||||
|
}
|
||||||
})
|
})
|
||||||
expect(wrapper.find('input').element.value).toBe('123')
|
expect(wrapper.find('input').element['value']).toBe('123')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('lets fields set form initial value with value prop', () => {
|
it('Lets fields set form initial value with value prop', () => {
|
||||||
const wrapper = mount({
|
const wrapper = mount({
|
||||||
data () {
|
data: () => ({ values: {} }),
|
||||||
return {
|
|
||||||
formValues: {}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
template: `<FormularioForm v-model="formValues">
|
|
||||||
<FormularioInput name="name" value="123" />
|
|
||||||
</FormularioForm>`
|
|
||||||
})
|
|
||||||
expect(wrapper.vm.formValues).toEqual({ name: '123' })
|
|
||||||
})
|
|
||||||
|
|
||||||
it('receives updates to form model when individual fields are edited', () => {
|
|
||||||
const wrapper = mount({
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
formValues: {
|
|
||||||
testinput: '',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
template: `
|
template: `
|
||||||
<FormularioForm v-model="formValues">
|
<FormularioForm v-model="values">
|
||||||
<FormularioInput v-slot="inputProps" name="testinput" >
|
<FormularioInput name="test" value="123" />
|
||||||
<input v-model="inputProps.context.model" type="text">
|
</FormularioForm>
|
||||||
|
`
|
||||||
|
})
|
||||||
|
expect(wrapper.vm['values']).toEqual({ test: '123' })
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Receives updates to form model when individual fields are edited', () => {
|
||||||
|
const wrapper = mount({
|
||||||
|
data: () => ({ values: { test: '' } }),
|
||||||
|
template: `
|
||||||
|
<FormularioForm v-model="values">
|
||||||
|
<FormularioInput v-slot="{ context }" name="test" >
|
||||||
|
<input v-model="context.model" type="text">
|
||||||
</FormularioInput>
|
</FormularioInput>
|
||||||
</FormularioForm>
|
</FormularioForm>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
wrapper.find('input').setValue('edited value')
|
wrapper.find('input').setValue('Edited value')
|
||||||
expect(wrapper.vm.formValues).toEqual({ testinput: 'edited value' })
|
expect(wrapper.vm['values']).toEqual({ test: 'Edited value' })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('field data updates when it is type of date', async () => {
|
it('Field data updates when it is type of date', async () => {
|
||||||
const wrapper = mount({
|
const wrapper = mount({
|
||||||
data () {
|
data: () => ({ formValues: { date: new Date(123) } }),
|
||||||
return {
|
|
||||||
formValues: {
|
|
||||||
testdate: new Date(123),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
template: `
|
template: `
|
||||||
<FormularioForm v-model="formValues" ref="form">
|
<FormularioForm v-model="formValues" ref="form">
|
||||||
<FormularioInput v-slot="inputProps" name="testdate" >
|
<FormularioInput v-slot="{ context }" name="date" >
|
||||||
<span v-if="inputProps.context.model">{{ inputProps.context.model.getTime() }}</span>
|
<span v-if="context.model">{{ context.model.getTime() }}</span>
|
||||||
</FormularioInput>
|
</FormularioInput>
|
||||||
</FormularioForm>
|
</FormularioForm>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
|
|
||||||
expect(wrapper.find('span').text()).toBe('123')
|
expect(wrapper.find('span').text()).toBe('123')
|
||||||
|
|
||||||
wrapper.setData({ formValues: { testdate: new Date(234) } })
|
wrapper.setData({ formValues: { date: new Date(234) } })
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|
||||||
expect(wrapper.find('span').text()).toBe('234')
|
expect(wrapper.find('span').text()).toBe('234')
|
||||||
})
|
})
|
||||||
|
|
||||||
// ===========================================================================
|
it('Updates initial form values when input contains a populated v-model', async () => {
|
||||||
/**
|
|
||||||
* @todo in vue-test-utils version 1.0.0-beta.29 has some bugs related to
|
|
||||||
* synchronous updating. Some details are here:
|
|
||||||
*
|
|
||||||
* @update this test was re-implemented in version 1.0.0-beta.31 and seems to
|
|
||||||
* be workign now with flushPromises(). Leaving these docs here for now.
|
|
||||||
*
|
|
||||||
* https://github.com/vuejs/vue-test-utils/issues/1130
|
|
||||||
*
|
|
||||||
* This test is being commented out until there is a resolution on this issue,
|
|
||||||
* and instead being replaced with a mock call.
|
|
||||||
*/
|
|
||||||
|
|
||||||
it('updates initial form values when input contains a populated v-model', async () => {
|
|
||||||
const wrapper = mount({
|
const wrapper = mount({
|
||||||
data () {
|
data: () => ({
|
||||||
return {
|
formValues: { test: '' },
|
||||||
formValues: {
|
fieldValue: '123',
|
||||||
testinput: '',
|
}),
|
||||||
},
|
|
||||||
fieldValue: '123'
|
|
||||||
}
|
|
||||||
},
|
|
||||||
template: `
|
template: `
|
||||||
<FormularioForm v-model="formValues">
|
<FormularioForm v-model="formValues">
|
||||||
<FormularioInput type="text" name="testinput" v-model="fieldValue" />
|
<FormularioInput type="text" name="test" v-model="fieldValue" />
|
||||||
</FormularioForm>
|
</FormularioForm>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
expect(wrapper.vm.formValues).toEqual({ testinput: '123' })
|
expect(wrapper.vm['formValues']).toEqual({ test: '123' })
|
||||||
})
|
})
|
||||||
|
|
||||||
// ===========================================================================
|
|
||||||
|
|
||||||
// Replacement test for the above test - not quite as good of a test.
|
// Replacement test for the above test - not quite as good of a test.
|
||||||
it('updates calls setFieldValue on form when a field contains a populated v-model on registration', () => {
|
it('updates calls setFieldValue on form when a field contains a populated v-model on registration', () => {
|
||||||
const wrapper = mount(FormularioForm, {
|
const wrapper = mount(FormularioForm, {
|
||||||
@ -208,25 +175,19 @@ describe('FormularioForm', () => {
|
|||||||
|
|
||||||
it('updates an inputs value when the form v-model is modified', async () => {
|
it('updates an inputs value when the form v-model is modified', async () => {
|
||||||
const wrapper = mount({
|
const wrapper = mount({
|
||||||
data () {
|
data: () => ({ formValues: { test: 'abcd' } }),
|
||||||
return {
|
|
||||||
formValues: {
|
|
||||||
testinput: 'abcd',
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
template: `
|
template: `
|
||||||
<FormularioForm v-model="formValues">
|
<FormularioForm v-model="formValues">
|
||||||
<FormularioInput v-slot="inputProps" name="testinput" >
|
<FormularioInput v-slot="{ context }" name="test" >
|
||||||
<input v-model="inputProps.context.model" type="text">
|
<input v-model="context.model" type="text">
|
||||||
</FormularioInput>
|
</FormularioInput>
|
||||||
</FormularioForm>
|
</FormularioForm>
|
||||||
`
|
`
|
||||||
})
|
})
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
wrapper.vm.formValues = { testinput: '1234' }
|
wrapper.vm.formValues = { test: '1234' }
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
expect(wrapper.find('input[type="text"]').element.value).toBe('1234')
|
expect(wrapper.find('input[type="text"]').element['value']).toBe('1234')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('resolves hasValidationErrors to true', async () => {
|
it('resolves hasValidationErrors to true', async () => {
|
||||||
@ -266,64 +227,12 @@ describe('FormularioForm', () => {
|
|||||||
` }
|
` }
|
||||||
})
|
})
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
expect(wrapper.find('input[type="text"]').element.value).toBe('Dave Barnett')
|
expect(wrapper.find('input[type="text"]').element['value']).toBe('Dave Barnett')
|
||||||
})
|
})
|
||||||
|
|
||||||
it('automatically registers with root plugin', async () => {
|
it('Receives a form-errors prop and displays it', async () => {
|
||||||
const wrapper = mount(FormularioForm, {
|
const wrapper = mount(FormularioForm, {
|
||||||
propsData: { formularioValue: { box3: [] }, name: 'login' }
|
propsData: { formErrors: ['first', 'second'] },
|
||||||
})
|
|
||||||
expect(wrapper.vm.$formulario.registry.has('login')).toBe(true)
|
|
||||||
expect(wrapper.vm.$formulario.registry.get('login')).toBe(wrapper.vm)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('Calls custom error handler with error and name', async () => {
|
|
||||||
const wrapper = mount({
|
|
||||||
template: `
|
|
||||||
<div>
|
|
||||||
<FormularioForm name="login" />
|
|
||||||
<FormularioForm name="register" />
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
})
|
|
||||||
wrapper.vm.$formulario.handle({ formErrors: ['This is an error message'] }, 'login')
|
|
||||||
})
|
|
||||||
|
|
||||||
it('Errors are displayed on correctly named components', async () => {
|
|
||||||
const wrapper = mount({
|
|
||||||
template: `
|
|
||||||
<div>
|
|
||||||
<FormularioForm
|
|
||||||
class="form form--login"
|
|
||||||
name="login"
|
|
||||||
v-slot="{ errors }"
|
|
||||||
>
|
|
||||||
<span v-for="error in errors" class="error">{{ error }}</span>
|
|
||||||
</FormularioForm>
|
|
||||||
<FormularioForm
|
|
||||||
class="form form--register"
|
|
||||||
name="register"
|
|
||||||
v-slot="{ errors }"
|
|
||||||
>
|
|
||||||
<span v-for="error in errors" class="error">{{ error }}</span>
|
|
||||||
</FormularioForm>
|
|
||||||
</div>
|
|
||||||
`
|
|
||||||
})
|
|
||||||
expect(
|
|
||||||
wrapper.vm.$formulario.registry.has('login') &&
|
|
||||||
wrapper.vm.$formulario.registry.has('register')
|
|
||||||
).toBe(true)
|
|
||||||
wrapper.vm.$formulario.handle({ formErrors: ['This is an error message'] }, 'login')
|
|
||||||
await flushPromises()
|
|
||||||
expect(wrapper.findAll('.form').length).toBe(2)
|
|
||||||
expect(wrapper.find('.form--login .error').exists()).toBe(true)
|
|
||||||
expect(wrapper.find('.form--register .error').exists()).toBe(false)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('receives a form-errors prop and displays it', async () => {
|
|
||||||
const wrapper = mount(FormularioForm, {
|
|
||||||
propsData: { name: 'main', formErrors: ['first', 'second'] },
|
|
||||||
scopedSlots: {
|
scopedSlots: {
|
||||||
default: `
|
default: `
|
||||||
<div>
|
<div>
|
||||||
@ -334,18 +243,18 @@ describe('FormularioForm', () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
expect(wrapper.vm.$formulario.registry.get('main').mergedFormErrors.length).toBe(2)
|
expect(wrapper.vm.mergedFormErrors.length).toBe(2)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('it aggregates form-errors prop with form-named errors', async () => {
|
it('Aggregates form-errors prop with form-named errors', async () => {
|
||||||
const wrapper = mount(FormularioForm, {
|
const wrapper = mount(FormularioForm, {
|
||||||
propsData: { formErrors: ['first', 'second'], name: 'login' }
|
propsData: { formErrors: ['first', 'second'] }
|
||||||
})
|
})
|
||||||
wrapper.vm.$formulario.handle({ formErrors: ['third'] }, 'login')
|
wrapper.vm.setErrors({ formErrors: ['third'] })
|
||||||
|
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|
||||||
let errors = wrapper.vm.$formulario.registry.get('login').mergedFormErrors
|
expect(Object.keys(wrapper.vm.mergedFormErrors).length).toBe(3)
|
||||||
expect(Object.keys(errors).length).toBe(3)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
it('displays field errors on inputs with errors prop', async () => {
|
it('displays field errors on inputs with errors prop', async () => {
|
||||||
@ -365,76 +274,75 @@ describe('FormularioForm', () => {
|
|||||||
expect(wrapper.find('span').text()).toEqual('This field has an error')
|
expect(wrapper.find('span').text()).toEqual('This field has an error')
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('Is able to display multiple errors on multiple elements', async () => {
|
||||||
|
const wrapper = mount(FormularioForm, {
|
||||||
|
propsData: {
|
||||||
|
errors: { inputA: ['first'], inputB: ['first', 'second']},
|
||||||
|
},
|
||||||
|
slots: {
|
||||||
|
default: `
|
||||||
|
<FormularioInput name="inputA" />
|
||||||
|
<FormularioInput name="inputB" type="textarea" />
|
||||||
|
`
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
await wrapper.vm.$nextTick()
|
||||||
|
|
||||||
|
expect(Object.keys(wrapper.vm.mergedFieldErrors).length).toBe(2)
|
||||||
|
expect(wrapper.vm.mergedFieldErrors.inputA.length).toBe(1)
|
||||||
|
expect(wrapper.vm.mergedFieldErrors.inputB.length).toBe(2)
|
||||||
|
})
|
||||||
|
|
||||||
|
it('Can set multiple field errors with setErrors()', async () => {
|
||||||
|
const wrapper = mount(FormularioForm, {
|
||||||
|
slots: {
|
||||||
|
default: `
|
||||||
|
<FormularioInput name="inputA" />
|
||||||
|
<FormularioInput name="inputB" type="textarea" />
|
||||||
|
`
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
expect(Object.keys(wrapper.vm.mergedFieldErrors).length).toBe(0)
|
||||||
|
|
||||||
|
wrapper.vm.setErrors({
|
||||||
|
inputErrors: {
|
||||||
|
inputA: ['first'],
|
||||||
|
inputB: ['first', 'second'],
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
await wrapper.vm.$nextTick()
|
||||||
|
await flushPromises()
|
||||||
|
|
||||||
|
expect(Object.keys(wrapper.vm.mergedFieldErrors).length).toBe(2)
|
||||||
|
expect(wrapper.vm.mergedFieldErrors.inputA.length).toBe(1)
|
||||||
|
expect(wrapper.vm.mergedFieldErrors.inputB.length).toBe(2)
|
||||||
|
})
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|
||||||
it('is able to display multiple errors on multiple elements', async () => {
|
it('Emits correct validation event on entry', async () => {
|
||||||
const wrapper = mount({
|
|
||||||
template: `
|
|
||||||
<FormularioForm
|
|
||||||
name="register"
|
|
||||||
:errors="{inputA: ['first', 'second'], inputB: 'only one here', inputC: ['and one here']}"
|
|
||||||
>
|
|
||||||
<FormularioInput name="inputA" />
|
|
||||||
<FormularioInput name="inputB" type="textarea" />
|
|
||||||
<FormularioInput name="inputC" type="checkbox" />
|
|
||||||
</FormularioForm>
|
|
||||||
`
|
|
||||||
})
|
|
||||||
await wrapper.vm.$nextTick()
|
|
||||||
|
|
||||||
let errors = wrapper.vm.$formulario.registry.get('register').mergedFieldErrors
|
|
||||||
expect(Object.keys(errors).length).toBe(3)
|
|
||||||
expect(errors.inputA.length).toBe(2)
|
|
||||||
expect(errors.inputB.length).toBe(1)
|
|
||||||
expect(errors.inputC.length).toBe(1)
|
|
||||||
})
|
|
||||||
|
|
||||||
it('it can set multiple field errors with handle()', async () => {
|
|
||||||
const wrapper = mount({
|
|
||||||
template: `
|
|
||||||
<FormularioForm name="register">
|
|
||||||
<FormularioInput name="inputA" />
|
|
||||||
<FormularioInput name="inputB" type="textarea" />
|
|
||||||
<FormularioInput name="inputC" type="checkbox" />
|
|
||||||
</FormularioForm>
|
|
||||||
`
|
|
||||||
})
|
|
||||||
|
|
||||||
let errors = wrapper.vm.$formulario.registry.get('register').mergedFieldErrors
|
|
||||||
expect(Object.keys(errors).length).toBe(0)
|
|
||||||
|
|
||||||
wrapper.vm.$formulario.handle({ inputErrors: {inputA: ['first', 'second'], inputB: 'only one here', inputC: ['and one here']} }, "register")
|
|
||||||
await wrapper.vm.$nextTick()
|
|
||||||
await flushPromises()
|
|
||||||
|
|
||||||
errors = wrapper.vm.$formulario.registry.get('register').mergedFieldErrors
|
|
||||||
expect(Object.keys(errors).length).toBe(3)
|
|
||||||
expect(errors.inputA.length).toBe(2)
|
|
||||||
expect(errors.inputB.length).toBe(1)
|
|
||||||
expect(errors.inputC.length).toBe(1)
|
|
||||||
|
|
||||||
})
|
|
||||||
|
|
||||||
it('emits correct validation event on entry', async () => {
|
|
||||||
const wrapper = mount(FormularioForm, {
|
const wrapper = mount(FormularioForm, {
|
||||||
slots: { default: `
|
slots: { default: `
|
||||||
<div>
|
<FormularioInput v-slot="{ context }" validation="required|in:foo" name="foo" >
|
||||||
<FormularioInput v-slot="inputProps" validation="required|in:bar" name="testinput" >
|
<input v-model="context.model" type="text">
|
||||||
<input v-model="inputProps.context.model" type="text">
|
</FormularioInput>
|
||||||
</FormularioInput>
|
<FormularioInput type="radio" validation="required" name="bar" />
|
||||||
<FormularioInput type="radio" validation="required" name="bar" />
|
|
||||||
</div>
|
|
||||||
` }
|
` }
|
||||||
})
|
})
|
||||||
wrapper.find('input[type="text"]').setValue('foo')
|
wrapper.find('input[type="text"]').setValue('bar')
|
||||||
|
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|
||||||
const errorObjects = wrapper.emitted('validation')
|
const errorObjects = wrapper.emitted('validation')
|
||||||
// There should be 3 events, both inputs mounting, and the value being set removing required on testinput
|
// There should be 3 events, both inputs mounting, and the value being set removing required on testinput
|
||||||
expect(errorObjects.length).toBe(3)
|
expect(errorObjects.length).toBe(3)
|
||||||
// this should be the event from the setValue()
|
// this should be the event from the setValue()
|
||||||
const errorObject = errorObjects[2][0]
|
const errorObject = errorObjects[2][0]
|
||||||
expect(errorObject).toEqual({
|
expect(errorObject).toEqual({
|
||||||
name: 'testinput',
|
name: 'foo',
|
||||||
errors: [
|
errors: [
|
||||||
expect.any(String)
|
expect.any(String)
|
||||||
],
|
],
|
||||||
@ -490,41 +398,41 @@ describe('FormularioForm', () => {
|
|||||||
expect(wrapper.vm.formData).toEqual({ foo: 'bar' })
|
expect(wrapper.vm.formData).toEqual({ foo: 'bar' })
|
||||||
})
|
})
|
||||||
|
|
||||||
it('it allows resetting a form, hiding validation and clearing inputs.', async () => {
|
it('Allows resetting a form, hiding validation and clearing inputs.', async () => {
|
||||||
const wrapper = mount({
|
const wrapper = mount({
|
||||||
|
data: () => ({ values: {} }),
|
||||||
template: `
|
template: `
|
||||||
<FormularioForm
|
<FormularioForm
|
||||||
v-model="formData"
|
v-model="values"
|
||||||
name="login"
|
name="login"
|
||||||
ref="form"
|
ref="form"
|
||||||
>
|
>
|
||||||
<FormularioInput v-slot="inputProps" name="username" validation="required">
|
<FormularioInput v-slot="{ context }" name="username" validation="required">
|
||||||
<input v-model="inputProps.context.model" type="text">
|
<input v-model="context.model" type="text">
|
||||||
</FormularioInput>
|
</FormularioInput>
|
||||||
<FormularioInput v-slot="inputProps" name="password" validation="required|min:4,length">
|
<FormularioInput v-slot="{ context }" name="password" validation="required|min:4,length">
|
||||||
<input v-model="inputProps.context.model" type="password">
|
<input v-model="context.model" type="password">
|
||||||
</FormularioInput>
|
</FormularioInput>
|
||||||
</FormularioForm>
|
</FormularioForm>
|
||||||
`,
|
`,
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
formData: {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const password = wrapper.find('input[type="password"]')
|
const password = wrapper.find('input[type="password"]')
|
||||||
password.setValue('foo')
|
password.setValue('foo')
|
||||||
password.trigger('blur')
|
password.trigger('blur')
|
||||||
|
|
||||||
wrapper.find('form').trigger('submit')
|
wrapper.find('form').trigger('submit')
|
||||||
wrapper.vm.$formulario.handle({
|
wrapper.vm.$refs.form.setErrors({ inputErrors: { username: ['Failed'] } })
|
||||||
inputErrors: { username: ['Failed'] }
|
|
||||||
}, 'login')
|
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
// First make sure we caugth the errors
|
|
||||||
|
// First make sure we caught the errors
|
||||||
expect(Object.keys(wrapper.vm.$refs.form.mergedFieldErrors).length).toBe(1)
|
expect(Object.keys(wrapper.vm.$refs.form.mergedFieldErrors).length).toBe(1)
|
||||||
wrapper.vm.$formulario.reset('login')
|
wrapper.vm.$refs.form.resetValidation()
|
||||||
|
wrapper.vm.$refs.form.setValues({ })
|
||||||
|
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
expect(Object.keys(wrapper.vm.$refs.form.mergedFieldErrors).length).toBe(0)
|
expect(Object.keys(wrapper.vm.$refs.form.mergedFieldErrors).length).toBe(0)
|
||||||
expect(wrapper.vm.formData).toEqual({})
|
expect(wrapper.vm.values).toEqual({})
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
Loading…
Reference in New Issue
Block a user