diff --git a/packages/vant/src/form/test/events.spec.tsx b/packages/vant/src/form/test/events.spec.tsx index 97c29b8d3..221b537af 100644 --- a/packages/vant/src/form/test/events.spec.tsx +++ b/packages/vant/src/form/test/events.spec.tsx @@ -22,15 +22,15 @@ test('should emit submit event when submitting form', async () => { test('should emit failed event when validating failed', async () => { const onFailed = jest.fn(); - const wrapper = mountSimpleRulesForm({ + const { form } = mountSimpleRulesForm({ methods: { onFailed, }, }); - await submitForm(wrapper); + await submitForm(form); - expect(wrapper.html()).toMatchSnapshot(); + expect(form.html()).toMatchSnapshot(); expect(onFailed).toHaveBeenCalledWith({ errors: [ { name: 'A', message: 'A failed' }, diff --git a/packages/vant/src/form/test/field-type.legacy.js b/packages/vant/src/form/test/field-type.legacy.js deleted file mode 100644 index 47b68292f..000000000 --- a/packages/vant/src/form/test/field-type.legacy.js +++ /dev/null @@ -1,212 +0,0 @@ -import { mountForm, submitForm } from './shared'; - -function mountFormWithChild({ template, data }) { - const onSubmit = jest.fn(); - const onFailed = jest.fn(); - - const wrapper = mountForm({ - template: ` - - - - - - - `, - data, - methods: { - onSubmit, - onFailed, - }, - }); - - return { - wrapper, - onSubmit, - onFailed, - }; -} - -test('use switch', async () => { - const { wrapper, onSubmit, onFailed } = mountFormWithChild({ - template: '', - data() { - return { value: false }; - }, - }); - - await submitForm(wrapper); - expect(onFailed).toHaveBeenCalledWith({ - errors: [{ message: 'foo', name: 'A' }], - values: { A: false }, - }); - - wrapper.setData({ value: true }); - - await submitForm(wrapper); - expect(onSubmit).toHaveBeenCalledWith({ A: true }); -}); - -test('use checkbox', async () => { - const { wrapper, onSubmit, onFailed } = mountFormWithChild({ - template: '', - data() { - return { value: false }; - }, - }); - - await submitForm(wrapper); - expect(onFailed).toHaveBeenCalledWith({ - errors: [{ message: 'foo', name: 'A' }], - values: { A: false }, - }); - - wrapper.setData({ value: true }); - - await submitForm(wrapper); - expect(onSubmit).toHaveBeenCalledWith({ A: true }); -}); - -test('use checkbox-group', async () => { - const { wrapper, onSubmit, onFailed } = mountFormWithChild({ - template: ` - - 1 - 2 - - `, - data() { - return { checkboxGroup: [] }; - }, - }); - - await submitForm(wrapper); - expect(onFailed).toHaveBeenCalledWith({ - errors: [{ message: 'foo', name: 'A' }], - values: { A: [] }, - }); - - wrapper.setData({ checkboxGroup: ['1'] }); - - await submitForm(wrapper); - expect(onSubmit).toHaveBeenCalledWith({ A: ['1'] }); -}); - -test('use radio', async () => { - const { wrapper, onSubmit, onFailed } = mountFormWithChild({ - template: ` - - 1 - 2 - - `, - data() { - return { radio: '' }; - }, - }); - - await submitForm(wrapper); - expect(onFailed).toHaveBeenCalledWith({ - errors: [{ message: 'foo', name: 'A' }], - values: { A: '' }, - }); - - wrapper.setData({ radio: '1' }); - - await submitForm(wrapper); - expect(onSubmit).toHaveBeenCalledWith({ A: '1' }); -}); - -test('use stepper', async () => { - const { wrapper, onSubmit, onFailed } = mountFormWithChild({ - template: '', - data() { - return { value: 0 }; - }, - }); - - await submitForm(wrapper); - expect(onFailed).toBeCalledTimes(0); - - wrapper.setData({ value: 1 }); - - await submitForm(wrapper); - expect(onSubmit).toHaveBeenCalledWith({ A: 1 }); -}); - -test('use rate', async () => { - const { wrapper, onSubmit, onFailed } = mountFormWithChild({ - template: '', - data() { - return { value: 0 }; - }, - }); - - await submitForm(wrapper); - expect(onFailed).toBeCalledTimes(0); - - wrapper.setData({ value: 1 }); - - await submitForm(wrapper); - expect(onSubmit).toHaveBeenCalledWith({ A: 1 }); -}); - -test('use slider', async () => { - const { wrapper, onSubmit, onFailed } = mountFormWithChild({ - template: '', - data() { - return { value: 0 }; - }, - }); - - await submitForm(wrapper); - expect(onFailed).toBeCalledTimes(0); - - wrapper.setData({ value: 50 }); - - await submitForm(wrapper); - expect(onSubmit).toHaveBeenCalledWith({ A: 50 }); -}); - -test('use uploader', async () => { - const { wrapper, onSubmit, onFailed } = mountFormWithChild({ - template: '', - data() { - return { value: [] }; - }, - }); - - await submitForm(wrapper); - expect(onFailed).toHaveBeenCalledWith({ - errors: [{ message: 'foo', name: 'A' }], - values: { A: [] }, - }); - - wrapper.setData({ value: [{ url: 'foo' }] }); - - await submitForm(wrapper); - expect(onSubmit).toHaveBeenCalledWith({ A: [{ url: 'foo' }] }); -}); - -test('should not get formValue from button slot', async () => { - const onSubmit = jest.fn(); - - const wrapper = mountForm({ - template: ` - - - - - - - `, - methods: { - onSubmit, - }, - }); - - await submitForm(wrapper); - expect(onSubmit).toHaveBeenCalledWith({ A: 'foo' }); -}); diff --git a/packages/vant/src/form/test/field-type.spec.tsx b/packages/vant/src/form/test/field-type.spec.tsx new file mode 100644 index 000000000..997a62230 --- /dev/null +++ b/packages/vant/src/form/test/field-type.spec.tsx @@ -0,0 +1,201 @@ +import { ref } from 'vue'; +import { mount, later } from '../../../test'; +import { submitForm } from './shared'; +import { Form } from '..'; +import { Rate } from '../../rate'; +import { Field } from '../../field'; +import { Radio } from '../../radio'; +import { Switch } from '../../switch'; +import { Slider } from '../../slider'; +import { Stepper } from '../../stepper'; +import { Checkbox } from '../../checkbox'; +import { RadioGroup } from '../../radio-group'; +import { CheckboxGroup } from '../../checkbox-group'; +import { Uploader, UploaderFileListItem } from '../../uploader'; + +function mountFormWithChild(input: () => JSX.Element) { + const onSubmit = jest.fn(); + const onFailed = jest.fn(); + const form = mount({ + render() { + return ( +
+ + + ); + }, + }); + + return { + form, + onSubmit, + onFailed, + }; +} + +test('should allow to use Switch as a form item', async () => { + const switched = ref(false); + const { form, onSubmit, onFailed } = mountFormWithChild(() => ( + + )); + + await submitForm(form); + expect(onFailed).toHaveBeenCalledWith({ + errors: [{ message: 'foo', name: 'A' }], + values: { A: false }, + }); + + switched.value = true; + await later(); + await submitForm(form); + expect(onSubmit).toHaveBeenCalledWith({ A: true }); +}); + +test('should allow to use Checkbox as a form item', async () => { + const checked = ref(false); + const { form, onSubmit, onFailed } = mountFormWithChild(() => ( + + )); + + await submitForm(form); + expect(onFailed).toHaveBeenCalledWith({ + errors: [{ message: 'foo', name: 'A' }], + values: { A: false }, + }); + + checked.value = true; + await later(); + await submitForm(form); + expect(onSubmit).toHaveBeenCalledWith({ A: true }); +}); + +test('should allow to use CheckboxGroup as a form item', async () => { + const checked = ref([]); + const { form, onSubmit, onFailed } = mountFormWithChild(() => ( + + 1 + 2 + + )); + + await submitForm(form); + expect(onFailed).toHaveBeenCalledWith({ + errors: [{ message: 'foo', name: 'A' }], + values: { A: [] }, + }); + + checked.value = ['1']; + await later(); + await submitForm(form); + expect(onSubmit).toHaveBeenCalledWith({ A: ['1'] }); +}); + +test('should allow to use RadioGroup as a form item', async () => { + const checked = ref(''); + const { form, onSubmit, onFailed } = mountFormWithChild(() => ( + + 1 + 2 + + )); + + await submitForm(form); + expect(onFailed).toHaveBeenCalledWith({ + errors: [{ message: 'foo', name: 'A' }], + values: { A: '' }, + }); + + checked.value = '1'; + await later(); + await submitForm(form); + expect(onSubmit).toHaveBeenCalledWith({ A: '1' }); +}); + +test('should allow to use Stepper as a form item', async () => { + const value = ref(0); + const { form, onSubmit, onFailed } = mountFormWithChild(() => ( + + )); + + await submitForm(form); + expect(onFailed).toBeCalledTimes(0); + + value.value = 1; + await later(); + await submitForm(form); + expect(onSubmit).toHaveBeenCalledWith({ A: 1 }); +}); + +test('should allow to use Rate as a form item', async () => { + const rate = ref(0); + const { form, onSubmit, onFailed } = mountFormWithChild(() => ( + + )); + + await submitForm(form); + expect(onFailed).toBeCalledTimes(0); + + rate.value = 1; + await later(); + await submitForm(form); + expect(onSubmit).toHaveBeenCalledWith({ A: 1 }); +}); + +test('should allow to use Slider as a form item', async () => { + const value = ref(0); + const { form, onSubmit, onFailed } = mountFormWithChild(() => ( + + )); + + await submitForm(form); + expect(onFailed).toBeCalledTimes(0); + + value.value = 50; + await later(); + await submitForm(form); + expect(onSubmit).toHaveBeenCalledWith({ A: 50 }); +}); + +test('should allow to use Uploader as a form item', async () => { + const fileList = ref([]); + const { form, onSubmit, onFailed } = mountFormWithChild(() => ( + + )); + + await submitForm(form); + expect(onFailed).toHaveBeenCalledWith({ + errors: [{ message: 'foo', name: 'A' }], + values: { A: [] }, + }); + + fileList.value = [{ url: 'foo' }]; + await later(); + await submitForm(form); + expect(onSubmit).toHaveBeenCalledWith({ A: [{ url: 'foo' }] }); +}); + +test('should not get formValue from button slot', async () => { + const onSubmit = jest.fn(); + + const form = mount({ + render() { + return ( +
+ }} + name="A" + rules={[{ required: true, message: 'foo' }]} + modelValue="foo" + /> + + ); + }, + }); + + await submitForm(form); + expect(onSubmit).toHaveBeenCalledWith({ A: 'foo' }); +}); diff --git a/packages/vant/src/form/test/methods.legacy.js b/packages/vant/src/form/test/methods.legacy.js deleted file mode 100644 index 55256f676..000000000 --- a/packages/vant/src/form/test/methods.legacy.js +++ /dev/null @@ -1,164 +0,0 @@ -import { later, mockScrollIntoView } from '../../../test'; -import { mountForm, mountSimpleRulesForm, getSimpleRules } from './shared'; - -test('submit method', async () => { - const onSubmit = jest.fn(); - - mountForm({ - template: ` - - - - - `, - mounted() { - this.$refs.form.submit(); - }, - methods: { - onSubmit, - }, - }); - - await later(); - expect(onSubmit).toHaveBeenCalledWith({ A: 'bar' }); -}); - -test('validate method - validate all fields', (done) => { - mountSimpleRulesForm({ - mounted() { - this.$refs.form.validate().catch((err) => { - expect(err).toEqual([ - { message: 'A failed', name: 'A' }, - { message: 'B failed', name: 'B' }, - ]); - done(); - }); - }, - }); -}); - -test('validate method - validate one field and failed', (done) => { - mountSimpleRulesForm({ - mounted() { - this.$refs.form.validate('A').catch((err) => { - expect(err).toEqual({ message: 'A failed', name: 'A' }); - done(); - }); - }, - }); -}); - -test('validate method - validate one field and passed', (done) => { - mountForm({ - template: ` - - - - - - `, - data: getSimpleRules, - mounted() { - this.$refs.form.validate('A').then(done); - }, - }); -}); - -test('validate method - validate two fields and failed', (done) => { - mountForm({ - template: ` - - - - - - `, - data: getSimpleRules, - mounted() { - this.$refs.form.validate(['A', 'B']).catch((error) => { - expect(error).toEqual([{ message: 'B failed', name: 'B' }]); - done(); - }); - }, - }); -}); - -test('validate method - unexisted name', (done) => { - mountSimpleRulesForm({ - mounted() { - this.$refs.form.validate('unexisted').catch(done); - }, - }); -}); - -test('resetValidation method - reset all fields', (done) => { - const wrapper = mountSimpleRulesForm({ - mounted() { - this.$refs.form.validate().catch(() => { - this.$refs.form.resetValidation(); - const errors = wrapper.findAll('.van-field__error-message'); - expect(errors.length).toEqual(0); - done(); - }); - }, - }); -}); - -test('resetValidation method - reset two fields', (done) => { - const wrapper = mountSimpleRulesForm({ - mounted() { - this.$refs.form.validate().catch(() => { - this.$refs.form.resetValidation(['A', 'B']); - const errors = wrapper.findAll('.van-field__error-message'); - expect(errors.length).toEqual(0); - done(); - }); - }, - }); -}); - -test('resetValidation method - reset one field', (done) => { - const wrapper = mountSimpleRulesForm({ - mounted() { - this.$refs.form.validate().catch(() => { - this.$refs.form.resetValidation('A'); - expect(wrapper.findAll('.van-field--error').length).toEqual(1); - this.$refs.form.resetValidation('B'); - expect(wrapper.findAll('.van-field--error').length).toEqual(0); - done(); - }); - }, - }); -}); - -test('resetValidation method - reset when rule message is empty', (done) => { - const wrapper = mountSimpleRulesForm({ - data() { - return { - rulesA: [{ required: true, message: '' }], - rulesB: [{ required: true, message: '' }], - }; - }, - mounted() { - this.$refs.form.validate().catch(() => { - this.$refs.form.resetValidation('A'); - expect(wrapper.findAll('.van-field--error').length).toEqual(1); - done(); - }); - }, - }); -}); - -test('scrollToField method', (done) => { - const fn = mockScrollIntoView(); - mountSimpleRulesForm({ - mounted() { - this.$refs.form.scrollToField('unknown'); - expect(fn).toHaveBeenCalledTimes(0); - - this.$refs.form.scrollToField('A'); - expect(fn).toHaveBeenCalledTimes(1); - done(); - }, - }); -}); diff --git a/packages/vant/src/form/test/methods.spec.tsx b/packages/vant/src/form/test/methods.spec.tsx new file mode 100644 index 000000000..7066bab86 --- /dev/null +++ b/packages/vant/src/form/test/methods.spec.tsx @@ -0,0 +1,139 @@ +import { ref } from 'vue'; +import { mount, later, mockScrollIntoView } from '../../../test'; +import { mountSimpleRulesForm, getSimpleRules } from './shared'; +import { Form, FormInstance } from '..'; +import { Field } from '../../field'; + +test('should emit submit event after calling the submit method', async () => { + const onSubmit = jest.fn(); + const form = ref(); + mount({ + render() { + return ( +
+ + + ); + }, + }); + + form.value?.submit(); + await later(); + expect(onSubmit).toHaveBeenCalledWith({ A: 'bar' }); +}); + +test('validate method - validate all fields', async () => { + const { formRef } = mountSimpleRulesForm(); + try { + await formRef.value?.validate(); + } catch (err) { + expect(err).toEqual([ + { message: 'A failed', name: 'A' }, + { message: 'B failed', name: 'B' }, + ]); + } +}); + +test('validate method - validate one field and failed', async () => { + const { formRef } = mountSimpleRulesForm(); + try { + await formRef.value?.validate('A'); + } catch (err) { + expect(err).toEqual({ message: 'A failed', name: 'A' }); + } +}); + +test('validate method - validate one field and passed', () => { + const formRef = ref(); + mount({ + render() { + return ( +
+ + + + ); + }, + data: getSimpleRules, + }); + + expect(async () => formRef.value?.validate('A')).not.toThrowError(); +}); + +test('validate method - validate two fields and failed', async () => { + const formRef = ref(); + mount({ + render() { + return ( +
+ + + + ); + }, + data: getSimpleRules, + }); + + try { + await formRef.value?.validate(['A', 'B']); + } catch (err) { + expect(err).toEqual([{ message: 'B failed', name: 'B' }]); + } +}); + +test('validate method - unexist name', (done) => { + const { formRef } = mountSimpleRulesForm(); + formRef.value?.validate('unexist').catch(done); +}); + +test('resetValidation method - reset all fields', async () => { + const { form, formRef } = mountSimpleRulesForm(); + try { + await formRef.value?.validate(); + } catch (err) { + formRef.value?.resetValidation(); + await later(); + const errors = form.findAll('.van-field__error-message'); + expect(errors.length).toEqual(0); + } +}); + +test('resetValidation method - reset two fields', async () => { + const { form, formRef } = mountSimpleRulesForm(); + + try { + await formRef.value?.validate(); + } catch (err) { + formRef.value?.resetValidation(['A', 'B']); + await later(); + const errors = form.findAll('.van-field__error-message'); + expect(errors.length).toEqual(0); + } +}); + +test('resetValidation method - reset one field', async () => { + const { form, formRef } = mountSimpleRulesForm(); + + try { + await formRef.value?.validate(); + } catch (err) { + formRef.value?.resetValidation('A'); + await later(); + expect(form.findAll('.van-field__error-message').length).toEqual(1); + + formRef.value?.resetValidation('B'); + await later(); + expect(form.findAll('.van-field__error-message').length).toEqual(0); + } +}); + +test('scrollToField method', () => { + const fn = mockScrollIntoView(); + const { formRef } = mountSimpleRulesForm(); + + formRef.value?.scrollToField('unknown'); + expect(fn).toHaveBeenCalledTimes(0); + + formRef.value?.scrollToField('A'); + expect(fn).toHaveBeenCalledTimes(1); +}); diff --git a/packages/vant/src/form/test/shared.tsx b/packages/vant/src/form/test/shared.tsx index f66cfabc8..27e011bfb 100644 --- a/packages/vant/src/form/test/shared.tsx +++ b/packages/vant/src/form/test/shared.tsx @@ -1,5 +1,6 @@ +import { ref } from 'vue'; import { mount, later } from '../../../test'; -import { Form } from '..'; +import { Form, FormInstance } from '..'; import { Field } from '../../field'; import type { VueWrapper } from '@vue/test-utils'; @@ -15,11 +16,13 @@ export function getSimpleRules() { }; } -export function mountSimpleRulesForm(options: any) { - return mount({ +export function mountSimpleRulesForm(options: any = {}) { + const formRef = ref(); + const form = mount({ render() { + const onFailed = 'onFailed' in this ? this.onFailed : () => {}; return ( -
+ @@ -28,4 +31,9 @@ export function mountSimpleRulesForm(options: any) { data: getSimpleRules, ...options, }); + + return { + form, + formRef, + }; }