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: `
-
-
- ${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 (
+
+ );
+ },
+ });
+
+ 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,
+ };
}