Skip to content
This repository has been archived by the owner on Feb 28, 2023. It is now read-only.

Commit

Permalink
feat: add validation schema to form props
Browse files Browse the repository at this point in the history
  • Loading branch information
logaretm committed Aug 14, 2021
1 parent 10610eb commit 7b54fca
Show file tree
Hide file tree
Showing 2 changed files with 94 additions and 20 deletions.
17 changes: 14 additions & 3 deletions packages/plugin-vee-validate/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,8 @@ export default function VeeValidatePlugin (opts) {
// Maps the validation state exposed by vee-validate to components
const mapProps = (opts && opts.mapProps) || defaultMapProps

return function veeValidatePlugin (baseReturns) {
// Take the parsed schema from SchemaForm setup returns
function veeValidatePlugin (baseReturns, props) {
// Take the parsed schema from SchemaForm setup returns
const { parsedSchema, formBinds } = baseReturns

// Get additional properties not defined on the `SchemaForm` derivatives
Expand All @@ -36,7 +36,7 @@ export default function VeeValidatePlugin (opts) {
if (!formContext) {
// if non-existent create one and provide it for nested schemas
formContext = useForm({
validationSchema: formAttrs['validation-schema'] || formAttrs.validationSchema,
validationSchema: props.validationSchema ? computed(() => props.validationSchema) : undefined,
initialErrors: formAttrs['initial-errors'] || formAttrs.initialErrors,
initialTouched: formAttrs['initial-touched'] || formAttrs.initialTouched
})
Expand Down Expand Up @@ -119,6 +119,17 @@ export default function VeeValidatePlugin (opts) {
parsedSchema: formSchemaWithVeeValidate
}
}

veeValidatePlugin.beforeSetup = ({ extendProps }) => {
extendProps({
validationSchema: {
type: null,
default: undefined
}
})
}

return veeValidatePlugin
}

// Used to track if a component was already marked
Expand Down
97 changes: 80 additions & 17 deletions packages/plugin-vee-validate/tests/integration/integration.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ const FormText = {
template: `
<div>
<input @input="$emit('update:modelValue', $event.target.value)" />
<span>{{ validation.errorMessage }}</span>
<span class="error">{{ validation.errorMessage }}</span>
</div>
`,
emits: ['update:modelValue'],
Expand All @@ -32,7 +32,7 @@ const FormTextWithProps = {
template: `
<div>
<input @input="$emit('update:modelValue', $event.target.value)" />
<span>{{ errorMessage }}</span>
<span class="error">{{ errorMessage }}</span>
</div>
`,
emits: ['update:modelValue'],
Expand Down Expand Up @@ -77,10 +77,10 @@ describe('FVL integration', () => {
const input = wrapper.findComponent(FormText)
input.setValue('')
await flushPromises()
expect(wrapper.find('span').text()).toBe(REQUIRED_MESSAGE)
expect(wrapper.find('.error').text()).toBe(REQUIRED_MESSAGE)
input.setValue('hello')
await flushPromises()
expect(wrapper.find('span').text()).toBe('')
expect(wrapper.find('.error').text()).toBe('')
})

it('maps validation state to props', async () => {
Expand Down Expand Up @@ -123,10 +123,10 @@ describe('FVL integration', () => {
const input = wrapper.findComponent(FormTextWithProps)
input.setValue('')
await flushPromises()
expect(wrapper.find('span').text()).toBe(REQUIRED_MESSAGE)
expect(wrapper.find('.error').text()).toBe(REQUIRED_MESSAGE)
input.setValue('hello')
await flushPromises()
expect(wrapper.find('span').text()).toBe('')
expect(wrapper.find('.error').text()).toBe('')
})

it('does form-level validation with validation-schema attr', async () => {
Expand Down Expand Up @@ -170,7 +170,7 @@ describe('FVL integration', () => {
})

const inputs = wrapper.findAllComponents(FormText)
const errors = wrapper.findAll('span')
const errors = wrapper.findAll('.error')
inputs[0].setValue('not email')
await flushPromises()
expect(errors[0].text()).toBe(EMAIL_MESSAGE)
Expand Down Expand Up @@ -289,7 +289,7 @@ describe('FVL integration', () => {
})

await flushPromises()
const messages = wrapper.findAll('span')
const messages = wrapper.findAll('.error')
expect(messages[0].text()).toBe('wrong')
expect(messages[1].text()).toBe('short')
})
Expand Down Expand Up @@ -420,10 +420,10 @@ describe('FVL integration', () => {
const input = wrapper.findComponent(FormText)
input.setValue('')
await flushPromises()
expect(wrapper.find('span').text()).toBe(REQUIRED_MESSAGE)
expect(wrapper.find('.error').text()).toBe(REQUIRED_MESSAGE)
input.setValue('hello')
await flushPromises()
expect(wrapper.find('span').text()).toBe('')
expect(wrapper.find('.error').text()).toBe('')
})

it('validates nested fields with array schema', async () => {
Expand Down Expand Up @@ -463,10 +463,10 @@ describe('FVL integration', () => {
const input = wrapper.findComponent(FormText)
input.setValue('')
await flushPromises()
expect(wrapper.find('span').text()).toBe(REQUIRED_MESSAGE)
expect(wrapper.find('.error').text()).toBe(REQUIRED_MESSAGE)
input.setValue('hello')
await flushPromises()
expect(wrapper.find('span').text()).toBe('')
expect(wrapper.find('.error').text()).toBe('')
})

it('validates nested fields with object schema', async () => {
Expand Down Expand Up @@ -505,10 +505,10 @@ describe('FVL integration', () => {
const input = wrapper.findComponent(FormText)
input.setValue('')
await flushPromises()
expect(wrapper.find('span').text()).toBe(REQUIRED_MESSAGE)
expect(wrapper.find('.error').text()).toBe(REQUIRED_MESSAGE)
input.setValue('hello')
await flushPromises()
expect(wrapper.find('span').text()).toBe('')
expect(wrapper.find('.error').text()).toBe('')
})

it('preserves reactivity in computed schemas', async () => {
Expand Down Expand Up @@ -554,14 +554,14 @@ describe('FVL integration', () => {
let input = wrapper.findComponent(FormText)
input.setValue('')
await flushPromises()
expect(wrapper.find('span').text()).toBe('NAME')
expect(wrapper.find('.error').text()).toBe('NAME')

toggle.value = 'B'
await flushPromises()
input = wrapper.findComponent(FormText)
input.setValue('')
await flushPromises()
expect(wrapper.find('span').text()).toBe('EMAIL')
expect(wrapper.find('.error').text()).toBe('EMAIL')
})

it('exposes form-level validation state on afterForm slot', async () => {
Expand Down Expand Up @@ -705,7 +705,7 @@ describe('FVL integration', () => {
})

const inputs = wrapper.findAllComponents(FormText)
const errors = wrapper.findAll('span')
const errors = wrapper.findAll('.error')

inputs[0].setValue('')
await flushPromises()
Expand All @@ -731,4 +731,67 @@ describe('FVL integration', () => {
await flushPromises()
expect(errors[2].text()).toBe('')
})

it('handles computed schema', async () => {
const schema = [
{
label: 'Email',
model: 'email',
component: FormText
},
{
label: 'Password',
model: 'password',
component: FormText
}
]

const SchemaWithValidation = SchemaFormFactory([veeValidatePlugin()])

const onSubmit = jest.fn()
const isRequired = ref(true)

const wrapper = mount({
template: `
<SchemaWithValidation :schema="schema" :validation-schema="validationSchema" @submit.prevent="onSubmit" />
`,
components: {
SchemaWithValidation
},
setup () {
const formData = ref({})
useSchemaForm(formData)
const validationSchema = computed(() => {
const email = yup.string().email(EMAIL_MESSAGE)
const password = yup.string()

return yup.object({
email: isRequired.value ? email.required() : email,
password: isRequired.value ? password.required() : password
})
})

return {
schema,
formData,
validationSchema,
onSubmit
}
}
})

const form = wrapper.find('form')

form.trigger('submit')
await flushPromises()
expect(onSubmit).toHaveBeenCalledTimes(0)
expect(wrapper.findAll('.error')).toHaveLength(2)

isRequired.value = false
await flushPromises()

form.trigger('submit')
await flushPromises()
expect(onSubmit).toHaveBeenCalledTimes(1)
})
})

0 comments on commit 7b54fca

Please sign in to comment.