Skip to content

Commit

Permalink
fix: bails affects yup non-object validators
Browse files Browse the repository at this point in the history
  • Loading branch information
logaretm committed Jul 30, 2020
1 parent d6946d5 commit a50645b
Show file tree
Hide file tree
Showing 3 changed files with 83 additions and 10 deletions.
3 changes: 2 additions & 1 deletion packages/core/src/useForm.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { computed, ref, Ref, provide, reactive } from 'vue';
import type { ValidationError } from 'yup';
import type { useField } from './useField';
import {
Flag,
Expand Down Expand Up @@ -247,7 +248,7 @@ async function validateYupSchema(
const errors: any[] = await (form.schema as any)
.validate(form.values, { abortEarly: false })
.then(() => [])
.catch((err: any) => {
.catch((err: ValidationError) => {
// Yup errors have a name prop one them.
// https://github.com/jquense/yup#validationerrorerrors-string--arraystring-value-any-path-string
if (err.name !== 'ValidationError') {
Expand Down
17 changes: 9 additions & 8 deletions packages/core/src/validate.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import type { ValidationError } from 'yup';
import { resolveRule } from './defineRule';
import { isLocator, normalizeRules, isYupValidator } from './utils';
import { getConfig } from './config';
Expand Down Expand Up @@ -98,24 +99,24 @@ async function _validate(field: FieldValidationContext, value: any) {
* Handles yup validation
*/
async function validateFieldWithYup(field: FieldValidationContext, value: any) {
const result = await field.rules
.validate(value)
.then(() => true)
.catch((err: Error) => {
const errors = await field.rules
.validate(value, {
abortEarly: field.bails,
})
.then(() => [])
.catch((err: ValidationError) => {
// Yup errors have a name prop one them.
// https://github.com/jquense/yup#validationerrorerrors-string--arraystring-value-any-path-string
if (err.name === 'ValidationError') {
return err.message;
return err.errors;
}

// re-throw the error so we don't hide it
throw err;
});

const isValid = typeof result !== 'string' && result;

return {
errors: !isValid ? [result as string] : [],
errors,
};
}

Expand Down
73 changes: 72 additions & 1 deletion packages/core/tests/Field.spec.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,17 @@
import flushPromises from 'flush-promises';
import { defineRule } from '@vee-validate/core';
import { defineRule, configure } from '@vee-validate/core';
import { mountWithHoc, setValue, dispatchEvent } from './helpers';
import * as yup from 'yup';
import { ref, Ref } from 'vue';

jest.useFakeTimers();

beforeEach(() => {
configure({
bails: true,
});
});

describe('<Field />', () => {
const REQUIRED_MESSAGE = `This field is required`;
defineRule('required', value => {
Expand Down Expand Up @@ -479,4 +485,69 @@ describe('<Field />', () => {
await flushPromises();
expect(input.getAttribute('aria-invalid')).toBe('false');
});

test('yup abortEarly is set by bails global option', async () => {
configure({
bails: false,
});
const wrapper = mountWithHoc({
setup() {
const rules = yup.string().min(8).url();

return {
rules,
};
},
template: `
<div>
<Field name="field" :rules="rules" v-slot="{ errors, field }">
<input type="text" v-bind="field">
<ul>
<li v-for="error in errors">{{ error }}</li>
</ul>
</Field>
</div>
`,
});

await flushPromises();
const errors = wrapper.$el.querySelector('ul');
const input = wrapper.$el.querySelector('input');
expect(errors.children).toHaveLength(0);

setValue(input, '1234');
await flushPromises();
expect(errors.children).toHaveLength(2);
});

test('yup abortEarly is set by bails prop', async () => {
const wrapper = mountWithHoc({
setup() {
const rules = yup.string().min(8).url();

return {
rules,
};
},
template: `
<div>
<Field name="field" :rules="rules" v-slot="{ errors, field }" :bails="false">
<input type="text" v-bind="field">
<ul>
<li v-for="error in errors">{{ error }}</li>
</ul>
</Field>
</div>
`,
});

await flushPromises();
const errors = wrapper.$el.querySelector('ul');
const input = wrapper.$el.querySelector('input');
expect(errors.children).toHaveLength(0);

setValue(input, '1234');
await flushPromises();
expect(errors.children).toHaveLength(2);
});
});

0 comments on commit a50645b

Please sign in to comment.