feat: FormularioForm - added ::runValidation() method to run entire form validation manually and return all form violations
This commit is contained in:
parent
4e05844e73
commit
aee0dc977a
@ -56,7 +56,7 @@ export default class FormularioField extends Vue {
|
|||||||
@Inject({ default: undefined }) __FormularioForm_unregister!: Function|undefined
|
@Inject({ default: undefined }) __FormularioForm_unregister!: Function|undefined
|
||||||
|
|
||||||
@Inject({ default: () => (): Record<string, unknown> => ({}) })
|
@Inject({ default: () => (): Record<string, unknown> => ({}) })
|
||||||
__FormularioForm_getValue!: () => Record<string, unknown>
|
__FormularioForm_getState!: () => Record<string, unknown>
|
||||||
|
|
||||||
@Model('input', { default: '' }) value!: unknown
|
@Model('input', { default: '' }) value!: unknown
|
||||||
|
|
||||||
@ -79,7 +79,7 @@ export default class FormularioField extends Vue {
|
|||||||
@Prop({ default: () => <U, T>(value: U|Empty): U|T|Empty => value }) modelGetConverter!: ModelGetConverter
|
@Prop({ default: () => <U, T>(value: U|Empty): U|T|Empty => value }) modelGetConverter!: ModelGetConverter
|
||||||
@Prop({ default: () => <T, U>(value: U|T): U|T => value }) modelSetConverter!: ModelSetConverter
|
@Prop({ default: () => <T, U>(value: U|T): U|T => value }) modelSetConverter!: ModelSetConverter
|
||||||
|
|
||||||
public proxy: unknown = this.getInitialValue()
|
public proxy: unknown = this.hasModel ? this.value : ''
|
||||||
|
|
||||||
private localErrors: string[] = []
|
private localErrors: string[] = []
|
||||||
|
|
||||||
@ -148,10 +148,17 @@ export default class FormularioField extends Vue {
|
|||||||
return messages
|
return messages
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Watch('value')
|
||||||
|
private onValueChange (newValue: unknown, oldValue: unknown): void {
|
||||||
|
if (this.hasModel && !shallowEquals(newValue, oldValue)) {
|
||||||
|
this.model = newValue
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Watch('proxy')
|
@Watch('proxy')
|
||||||
private onProxyChange (newValue: unknown, oldValue: unknown): void {
|
private onProxyChange (newValue: unknown, oldValue: unknown): void {
|
||||||
if (!this.hasModel && !shallowEquals(newValue, oldValue)) {
|
if (!this.hasModel && !shallowEquals(newValue, oldValue)) {
|
||||||
this.context.model = newValue
|
this.model = newValue
|
||||||
}
|
}
|
||||||
if (this.validationBehavior === VALIDATION_BEHAVIOR.LIVE) {
|
if (this.validationBehavior === VALIDATION_BEHAVIOR.LIVE) {
|
||||||
this.runValidation()
|
this.runValidation()
|
||||||
@ -160,54 +167,42 @@ export default class FormularioField extends Vue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Watch('value')
|
/**
|
||||||
private onValueChange (newValue: unknown, oldValue: unknown): void {
|
* @internal
|
||||||
if (this.hasModel && !shallowEquals(newValue, oldValue)) {
|
*/
|
||||||
this.context.model = newValue
|
public created (): void {
|
||||||
}
|
if (!shallowEquals(this.model, this.proxy)) {
|
||||||
|
this.model = this.proxy
|
||||||
}
|
}
|
||||||
|
|
||||||
created (): void {
|
|
||||||
this.initProxy()
|
|
||||||
if (typeof this.__FormularioForm_register === 'function') {
|
if (typeof this.__FormularioForm_register === 'function') {
|
||||||
this.__FormularioForm_register(this.fullPath, this)
|
this.__FormularioForm_register(this.fullPath, this)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.validationBehavior === VALIDATION_BEHAVIOR.LIVE) {
|
if (this.validationBehavior === VALIDATION_BEHAVIOR.LIVE) {
|
||||||
this.runValidation()
|
this.runValidation()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
beforeDestroy (): void {
|
/**
|
||||||
|
* @internal
|
||||||
|
*/
|
||||||
|
public beforeDestroy (): void {
|
||||||
if (typeof this.__FormularioForm_unregister === 'function') {
|
if (typeof this.__FormularioForm_unregister === 'function') {
|
||||||
this.__FormularioForm_unregister(this.fullPath)
|
this.__FormularioForm_unregister(this.fullPath)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private getInitialValue (): unknown {
|
public runValidation (): Promise<Violation[]> {
|
||||||
return has(this.$options.propsData || {}, 'value') ? this.value : ''
|
|
||||||
}
|
|
||||||
|
|
||||||
private initProxy (): void {
|
|
||||||
// This should only be run immediately on created and ensures that the
|
|
||||||
// proxy and the model are both the same before any additional registration.
|
|
||||||
if (!shallowEquals(this.context.model, this.proxy)) {
|
|
||||||
this.context.model = this.proxy
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
runValidation (): Promise<Violation[]> {
|
|
||||||
this.validationRun = this.validate().then(violations => {
|
this.validationRun = this.validate().then(violations => {
|
||||||
const validationChanged = !shallowEquals(violations, this.violations)
|
const validationChanged = !shallowEquals(violations, this.violations)
|
||||||
this.violations = violations
|
this.violations = violations
|
||||||
|
|
||||||
if (validationChanged) {
|
if (validationChanged) {
|
||||||
const payload = {
|
this.emitValidation({
|
||||||
name: this.context.name,
|
name: this.fullPath,
|
||||||
violations: this.violations,
|
violations: this.violations,
|
||||||
}
|
})
|
||||||
this.$emit('validation', payload)
|
|
||||||
if (typeof this.__FormularioForm_emitValidation === 'function') {
|
|
||||||
this.__FormularioForm_emitValidation(payload)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.violations
|
return this.violations
|
||||||
@ -216,7 +211,7 @@ export default class FormularioField extends Vue {
|
|||||||
return this.validationRun
|
return this.validationRun
|
||||||
}
|
}
|
||||||
|
|
||||||
validate (): Promise<Violation[]> {
|
private validate (): Promise<Violation[]> {
|
||||||
return validate(processConstraints(
|
return validate(processConstraints(
|
||||||
this.validation,
|
this.validation,
|
||||||
this.$formulario.getRules(this.normalizedValidationRules),
|
this.$formulario.getRules(this.normalizedValidationRules),
|
||||||
@ -224,11 +219,18 @@ export default class FormularioField extends Vue {
|
|||||||
), {
|
), {
|
||||||
value: this.context.model,
|
value: this.context.model,
|
||||||
name: this.context.name,
|
name: this.context.name,
|
||||||
formValues: this.__FormularioForm_getValue(),
|
formValues: this.__FormularioForm_getState(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
hasValidationErrors (): Promise<boolean> {
|
private emitValidation (payload: { name: string; violations: Violation[] }): void {
|
||||||
|
this.$emit('validation', payload)
|
||||||
|
if (typeof this.__FormularioForm_emitValidation === 'function') {
|
||||||
|
this.__FormularioForm_emitValidation(payload)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public hasValidationErrors (): Promise<boolean> {
|
||||||
return new Promise(resolve => {
|
return new Promise(resolve => {
|
||||||
this.$nextTick(() => {
|
this.$nextTick(() => {
|
||||||
this.validationRun.then(() => resolve(this.violations.length > 0))
|
this.validationRun.then(() => resolve(this.violations.length > 0))
|
||||||
@ -239,7 +241,7 @@ export default class FormularioField extends Vue {
|
|||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
setErrors (errors: string[]): void {
|
public setErrors (errors: string[]): void {
|
||||||
if (!this.errorsDisabled) {
|
if (!this.errorsDisabled) {
|
||||||
this.localErrors = arrayify(errors) as string[]
|
this.localErrors = arrayify(errors) as string[]
|
||||||
}
|
}
|
||||||
@ -248,7 +250,7 @@ export default class FormularioField extends Vue {
|
|||||||
/**
|
/**
|
||||||
* @internal
|
* @internal
|
||||||
*/
|
*/
|
||||||
resetValidation (): void {
|
public resetValidation (): void {
|
||||||
this.localErrors = []
|
this.localErrors = []
|
||||||
this.violations = []
|
this.violations = []
|
||||||
}
|
}
|
||||||
|
@ -28,18 +28,22 @@ import FormularioField from '@/FormularioField.vue'
|
|||||||
|
|
||||||
import { Violation } from '@/validation/validator'
|
import { Violation } from '@/validation/validator'
|
||||||
|
|
||||||
|
type ErrorsRecord = Record<string, string[]>
|
||||||
|
|
||||||
type ValidationEventPayload = {
|
type ValidationEventPayload = {
|
||||||
name: string;
|
name: string;
|
||||||
violations: Violation[];
|
violations: Violation[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type ViolationsRecord = Record<string, Violation[]>
|
||||||
|
|
||||||
@Component({ name: 'FormularioForm' })
|
@Component({ name: 'FormularioForm' })
|
||||||
export default class FormularioForm extends Vue {
|
export default class FormularioForm extends Vue {
|
||||||
@Model('input', { default: () => ({}) })
|
@Model('input', { default: () => ({}) })
|
||||||
public readonly state!: Record<string, unknown>
|
public readonly state!: Record<string, unknown>
|
||||||
|
|
||||||
// Describes validation errors of whole form
|
// Describes validation errors of whole form
|
||||||
@Prop({ default: () => ({}) }) readonly fieldsErrors!: Record<string, string[]>
|
@Prop({ default: () => ({}) }) readonly fieldsErrors!: ErrorsRecord
|
||||||
// Only used on FormularioForm default slot
|
// Only used on FormularioForm default slot
|
||||||
@Prop({ default: () => ([]) }) readonly formErrors!: string[]
|
@Prop({ default: () => ([]) }) readonly formErrors!: string[]
|
||||||
|
|
||||||
@ -48,7 +52,7 @@ export default class FormularioForm extends Vue {
|
|||||||
private registry: PathRegistry<FormularioField> = new PathRegistry()
|
private registry: PathRegistry<FormularioField> = new PathRegistry()
|
||||||
|
|
||||||
// Local error messages are temporal, they wiped each resetValidation call
|
// Local error messages are temporal, they wiped each resetValidation call
|
||||||
private localFieldsErrors: Record<string, string[]> = {}
|
private localFieldsErrors: ErrorsRecord = {}
|
||||||
private localFormErrors: string[] = []
|
private localFormErrors: string[] = []
|
||||||
|
|
||||||
private get hasModel (): boolean {
|
private get hasModel (): boolean {
|
||||||
@ -75,41 +79,6 @@ export default class FormularioForm extends Vue {
|
|||||||
return [...this.formErrors, ...this.localFormErrors]
|
return [...this.formErrors, ...this.localFormErrors]
|
||||||
}
|
}
|
||||||
|
|
||||||
@Watch('state', { deep: true })
|
|
||||||
private onStateChange (values: Record<string, unknown>): void {
|
|
||||||
if (this.hasModel && values && typeof values === 'object') {
|
|
||||||
this.setValues(values)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Watch('fieldsErrorsComputed', { deep: true, immediate: true })
|
|
||||||
private onFieldsErrorsChange (fieldsErrors: Record<string, string[]>): void {
|
|
||||||
this.registry.forEach((field, path) => {
|
|
||||||
field.setErrors(fieldsErrors[path] || [])
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provide('__FormularioForm_getValue')
|
|
||||||
private getValue (): Record<string, unknown> {
|
|
||||||
return this.proxy
|
|
||||||
}
|
|
||||||
|
|
||||||
created (): void {
|
|
||||||
this.syncProxy()
|
|
||||||
}
|
|
||||||
|
|
||||||
private onSubmit (): Promise<void> {
|
|
||||||
return this.hasValidationErrors()
|
|
||||||
.then(hasErrors => hasErrors ? undefined : clone(this.proxy))
|
|
||||||
.then(data => {
|
|
||||||
if (typeof data !== 'undefined') {
|
|
||||||
this.$emit('submit', data)
|
|
||||||
} else {
|
|
||||||
this.$emit('error')
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
@Provide('__FormularioForm_register')
|
@Provide('__FormularioForm_register')
|
||||||
private register (path: string, field: FormularioField): void {
|
private register (path: string, field: FormularioField): void {
|
||||||
this.registry.add(path, field)
|
this.registry.add(path, field)
|
||||||
@ -117,17 +86,13 @@ export default class FormularioForm extends Vue {
|
|||||||
const value = getNested(this.modelCopy, path)
|
const value = getNested(this.modelCopy, path)
|
||||||
|
|
||||||
if (!field.hasModel && this.modelIsDefined && value !== undefined) {
|
if (!field.hasModel && this.modelIsDefined && value !== undefined) {
|
||||||
// In the case that the form is carrying an initial value and the
|
|
||||||
// element is not, set it directly.
|
|
||||||
field.model = value
|
field.model = value
|
||||||
} else if (field.hasModel && !shallowEquals(field.proxy, value)) {
|
} else if (field.hasModel && !shallowEquals(field.proxy, value)) {
|
||||||
// In this case, the field is v-modeled or has an initial value and the
|
|
||||||
// form has no value or a different value, so use the field value
|
|
||||||
this.setFieldValueAndEmit(path, field.proxy)
|
this.setFieldValueAndEmit(path, field.proxy)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (has(this.fieldsErrorsComputed, path)) {
|
if (has(this.fieldsErrorsComputed, path)) {
|
||||||
field.setErrors(this.fieldsErrorsComputed[path] || [])
|
field.setErrors(this.fieldsErrorsComputed[path])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -141,18 +106,82 @@ export default class FormularioForm extends Vue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provide('__FormularioForm_getState')
|
||||||
|
private getState (): Record<string, unknown> {
|
||||||
|
return this.proxy
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provide('__FormularioForm_set')
|
||||||
|
private setFieldValueAndEmit (field: string, value: unknown): void {
|
||||||
|
this.setFieldValue(field, value)
|
||||||
|
this.$emit('input', { ...this.proxy })
|
||||||
|
}
|
||||||
|
|
||||||
@Provide('__FormularioForm_emitValidation')
|
@Provide('__FormularioForm_emitValidation')
|
||||||
private emitValidation (payload: ValidationEventPayload): void {
|
private emitValidation (payload: ValidationEventPayload): void {
|
||||||
this.$emit('validation', payload)
|
this.$emit('validation', payload)
|
||||||
}
|
}
|
||||||
|
|
||||||
private syncProxy (): void {
|
@Watch('state', { deep: true })
|
||||||
if (this.modelIsDefined) {
|
private onStateChange (state: Record<string, unknown>): void {
|
||||||
this.proxy = this.modelCopy
|
if (this.hasModel && state && typeof state === 'object') {
|
||||||
|
this.loadState(state)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setValues (state: Record<string, unknown>): void {
|
@Watch('fieldsErrorsComputed', { deep: true, immediate: true })
|
||||||
|
private onFieldsErrorsChange (fieldsErrors: Record<string, string[]>): void {
|
||||||
|
this.registry.forEach((field, path) => {
|
||||||
|
field.setErrors(fieldsErrors[path] || [])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public created (): void {
|
||||||
|
this.syncProxy()
|
||||||
|
}
|
||||||
|
|
||||||
|
public runValidation (): Promise<ViolationsRecord> {
|
||||||
|
const violations: ViolationsRecord = {}
|
||||||
|
const runs = this.registry.map((field: FormularioField, path: string) => {
|
||||||
|
return field.runValidation().then(v => { violations[path] = v })
|
||||||
|
})
|
||||||
|
|
||||||
|
return Promise.all(runs).then(() => violations)
|
||||||
|
}
|
||||||
|
|
||||||
|
public hasValidationErrors (): Promise<boolean> {
|
||||||
|
return this.runValidation().then(violations => {
|
||||||
|
return Object.keys(violations).some(path => violations[path].length > 0)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
public setErrors ({ fieldsErrors, formErrors }: { fieldsErrors?: ErrorsRecord; formErrors?: string[] }): void {
|
||||||
|
this.localFieldsErrors = fieldsErrors || {}
|
||||||
|
this.localFormErrors = formErrors || []
|
||||||
|
}
|
||||||
|
|
||||||
|
public resetValidation (): void {
|
||||||
|
this.localFieldsErrors = {}
|
||||||
|
this.localFormErrors = []
|
||||||
|
this.registry.forEach((field: FormularioField) => {
|
||||||
|
field.resetValidation()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private onSubmit (): Promise<void> {
|
||||||
|
return this.runValidation()
|
||||||
|
.then(violations => {
|
||||||
|
const hasErrors = Object.keys(violations).some(path => violations[path].length > 0)
|
||||||
|
|
||||||
|
if (!hasErrors) {
|
||||||
|
this.$emit('submit', clone(this.proxy))
|
||||||
|
} else {
|
||||||
|
this.$emit('error', violations)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
private loadState (state: Record<string, unknown>): void {
|
||||||
const paths = Array.from(new Set([
|
const paths = Array.from(new Set([
|
||||||
...Object.keys(state),
|
...Object.keys(state),
|
||||||
...Object.keys(this.proxy),
|
...Object.keys(this.proxy),
|
||||||
@ -187,7 +216,13 @@ export default class FormularioForm extends Vue {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setFieldValue (field: string, value: unknown): void {
|
private syncProxy (): void {
|
||||||
|
if (this.modelIsDefined) {
|
||||||
|
this.proxy = this.modelCopy
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private setFieldValue (field: string, value: unknown): void {
|
||||||
if (value === undefined) {
|
if (value === undefined) {
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
const { [field]: value, ...proxy } = this.proxy
|
const { [field]: value, ...proxy } = this.proxy
|
||||||
@ -196,31 +231,5 @@ export default class FormularioForm extends Vue {
|
|||||||
setNested(this.proxy, field, value)
|
setNested(this.proxy, field, value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Provide('__FormularioForm_set')
|
|
||||||
setFieldValueAndEmit (field: string, value: unknown): void {
|
|
||||||
this.setFieldValue(field, value)
|
|
||||||
this.$emit('input', { ...this.proxy })
|
|
||||||
}
|
|
||||||
|
|
||||||
setErrors ({ fieldsErrors, formErrors }: { fieldsErrors?: Record<string, string[]>; formErrors?: string[] }): void {
|
|
||||||
this.localFieldsErrors = fieldsErrors || {}
|
|
||||||
this.localFormErrors = formErrors || []
|
|
||||||
}
|
|
||||||
|
|
||||||
hasValidationErrors (): Promise<boolean> {
|
|
||||||
return Promise.all(this.registry.reduce((resolvers: Promise<boolean>[], field: FormularioField) => {
|
|
||||||
resolvers.push(field.runValidation() && field.hasValidationErrors())
|
|
||||||
return resolvers
|
|
||||||
}, [])).then(results => results.some(hasErrors => hasErrors))
|
|
||||||
}
|
|
||||||
|
|
||||||
resetValidation (): void {
|
|
||||||
this.localFieldsErrors = {}
|
|
||||||
this.localFormErrors = []
|
|
||||||
this.registry.forEach((field: FormularioField) => {
|
|
||||||
field.resetValidation()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
@ -59,24 +59,13 @@ export default class PathRegistry<T> {
|
|||||||
return this.registry.keys()
|
return this.registry.keys()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Iterate over the registry.
|
|
||||||
*/
|
|
||||||
forEach (callback: (field: T, path: string) => void): void {
|
forEach (callback: (field: T, path: string) => void): void {
|
||||||
this.registry.forEach((field, path) => {
|
this.registry.forEach((field, path) => {
|
||||||
callback(field, path)
|
callback(field, path)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
map<U> (mapper: (item: T, path: string) => U): U[] {
|
||||||
* Reduce the registry.
|
return Array.from(this.registry.keys()).map(path => mapper(this.get(path) as T, path))
|
||||||
* @param {function} callback
|
|
||||||
* @param accumulator
|
|
||||||
*/
|
|
||||||
reduce<U> (callback: (accumulator: U, item: T, path: string) => U, accumulator: U): U {
|
|
||||||
this.registry.forEach((item, path) => {
|
|
||||||
accumulator = callback(accumulator, item, path)
|
|
||||||
})
|
|
||||||
return accumulator
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,10 +5,10 @@ export interface Validator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface Violation {
|
export interface Violation {
|
||||||
|
message: string;
|
||||||
rule: string|null;
|
rule: string|null;
|
||||||
args: any[];
|
args: any[];
|
||||||
context: ValidationContext|null;
|
context: ValidationContext|null;
|
||||||
message: string;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ValidationRuleFn {
|
export interface ValidationRuleFn {
|
||||||
|
@ -136,7 +136,7 @@ describe('FormularioForm', () => {
|
|||||||
test('resolves submitted form values to an object', async () => {
|
test('resolves submitted form values to an object', async () => {
|
||||||
const wrapper = mount(FormularioForm, {
|
const wrapper = mount(FormularioForm, {
|
||||||
slots: {
|
slots: {
|
||||||
default: '<FormularioField name="fieldName" validation="required" value="Justin" />'
|
default: '<FormularioField name="name" validation="required" value="Justin" />'
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -145,10 +145,53 @@ describe('FormularioForm', () => {
|
|||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|
||||||
expect(wrapper.emitted('submit')).toEqual([
|
expect(wrapper.emitted('submit')).toEqual([
|
||||||
[{ fieldName: 'Justin' }],
|
[{ name: 'Justin' }],
|
||||||
])
|
])
|
||||||
})
|
})
|
||||||
|
|
||||||
|
test('resolves runValidation', async () => {
|
||||||
|
const wrapper = mount(FormularioForm, {
|
||||||
|
slots: {
|
||||||
|
default: `
|
||||||
|
<div>
|
||||||
|
<FormularioField name="address.street" validation="required" />
|
||||||
|
<FormularioField name="address.building" validation="required" />
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
|
||||||
|
const violations = await wrapper.vm.runValidation()
|
||||||
|
const state = {
|
||||||
|
address: {
|
||||||
|
street: null,
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(violations).toEqual({
|
||||||
|
'address.street': [{
|
||||||
|
message: expect.any(String),
|
||||||
|
rule: 'required',
|
||||||
|
args: [],
|
||||||
|
context: {
|
||||||
|
name: 'address.street',
|
||||||
|
value: null,
|
||||||
|
formValues: state,
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
'address.building': [{
|
||||||
|
message: expect.any(String),
|
||||||
|
rule: 'required',
|
||||||
|
args: [],
|
||||||
|
context: {
|
||||||
|
name: 'address.building',
|
||||||
|
value: '',
|
||||||
|
formValues: state,
|
||||||
|
},
|
||||||
|
}],
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
test('resolves hasValidationErrors to true', async () => {
|
test('resolves hasValidationErrors to true', async () => {
|
||||||
const wrapper = mount(FormularioForm, {
|
const wrapper = mount(FormularioForm, {
|
||||||
slots: {
|
slots: {
|
||||||
@ -160,10 +203,8 @@ describe('FormularioForm', () => {
|
|||||||
|
|
||||||
await flushPromises()
|
await flushPromises()
|
||||||
|
|
||||||
const emitted = wrapper.emitted()
|
expect(wrapper.emitted('error')).toBeTruthy()
|
||||||
|
expect(wrapper.emitted('error').length).toBe(1)
|
||||||
expect(emitted['error']).toBeTruthy()
|
|
||||||
expect(emitted['error'].length).toBe(1)
|
|
||||||
})
|
})
|
||||||
|
|
||||||
describe('allows setting fields errors', () => {
|
describe('allows setting fields errors', () => {
|
||||||
|
Loading…
Reference in New Issue
Block a user