mirror of
https://gitee.com/vant-contrib/vant.git
synced 2026-07-10 00:11:06 +08:00
Compare commits
3 Commits
bfc5b16c6d
...
eec2ac4c0f
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
eec2ac4c0f | ||
|
|
8585842712 | ||
|
|
4778b07d40 |
@ -7,6 +7,7 @@
|
||||
- [build.site.publicPath](#buildsitepublicpath)
|
||||
- [build.srcDir](#buildsrcdir)
|
||||
- [build.namedExport](#buildnamedexport)
|
||||
- [build.configureVite](#buildconfigurevite)
|
||||
- [site.title](#sitetitle)
|
||||
- [site.logo](#sitelogo)
|
||||
- [site.description](#sitedescription)
|
||||
@ -138,6 +139,47 @@ module.exports = {
|
||||
|
||||
开启此选项后,会通过 `export * from 'xxx'` 导出组件内部的所有模块、类型定义。
|
||||
|
||||
### build.configureVite
|
||||
|
||||
- Type: `(config: InlineConfig): InlineConfig`
|
||||
- Default: `undefined`
|
||||
|
||||
vant-cli 使用 vite 来构建组件库和文档站点,通过 `configureVite` 选项可以自定义 vite 配置(从 4.0.0 版本开始支持)。
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
build: {
|
||||
configureVite(config) {
|
||||
// 添加一个自定义插件
|
||||
config.plugins.push(vitePluginXXX);
|
||||
return config;
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
在自定义配置时,可以通过 `process.env.BUILD_TARGET` 对构建目标进行区分:
|
||||
|
||||
```js
|
||||
module.exports = {
|
||||
build: {
|
||||
configureVite(config) {
|
||||
const { BUILD_TARGET } = process.env;
|
||||
|
||||
if (BUILD_TARGET === 'package') {
|
||||
// 修改组件库构建配置
|
||||
}
|
||||
|
||||
if (BUILD_TARGET === 'site') {
|
||||
// 修改文档站点构建配置
|
||||
}
|
||||
|
||||
return config;
|
||||
},
|
||||
},
|
||||
};
|
||||
```
|
||||
|
||||
### site.title
|
||||
|
||||
- Type: `string`
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@vant/cli",
|
||||
"version": "4.0.0-rc.1",
|
||||
"version": "4.0.0-rc.2",
|
||||
"main": "lib/index.js",
|
||||
"typings": "lib/index.d.ts",
|
||||
"bin": {
|
||||
|
||||
@ -1,3 +1,4 @@
|
||||
import { get } from 'lodash';
|
||||
import { sep, join } from 'path';
|
||||
import {
|
||||
lstatSync,
|
||||
@ -7,6 +8,7 @@ import {
|
||||
outputFileSync,
|
||||
} from 'fs-extra';
|
||||
import { SRC_DIR, getVantConfig } from './constant';
|
||||
import type { InlineConfig } from 'vite';
|
||||
|
||||
export const EXT_REGEXP = /\.\w+$/;
|
||||
export const SFC_REGEXP = /\.(vue)$/;
|
||||
@ -134,4 +136,14 @@ export function smartOutputFile(filePath: string, content: string) {
|
||||
outputFileSync(filePath, content);
|
||||
}
|
||||
|
||||
export function mergeCustomViteConfig(config: InlineConfig) {
|
||||
const vantConfig = getVantConfig();
|
||||
const configureVite = get(vantConfig, 'build.configureVite');
|
||||
|
||||
if (configureVite) {
|
||||
return configureVite(config);
|
||||
}
|
||||
return config;
|
||||
}
|
||||
|
||||
export { getVantConfig };
|
||||
|
||||
@ -1,6 +1,8 @@
|
||||
import { build } from 'vite';
|
||||
import { mergeCustomViteConfig } from '../common';
|
||||
import { getViteConfigForPackage } from '../config/vite.package';
|
||||
|
||||
export async function compilePackage(minify: boolean) {
|
||||
return build(getViteConfigForPackage(minify));
|
||||
const config = mergeCustomViteConfig(getViteConfigForPackage(minify));
|
||||
return build(config);
|
||||
}
|
||||
|
||||
@ -4,7 +4,7 @@ import {
|
||||
getViteConfigForSiteDev,
|
||||
getViteConfigForSiteProd,
|
||||
} from '../config/vite.site';
|
||||
import { replaceExt } from '../common';
|
||||
import { mergeCustomViteConfig, replaceExt } from '../common';
|
||||
import { CSS_LANG } from '../common/css';
|
||||
import { genPackageEntry } from './gen-package-entry';
|
||||
import { genPackageStyle } from './gen-package-style';
|
||||
@ -37,9 +37,11 @@ export async function genSiteEntry(): Promise<void> {
|
||||
export async function compileSite(production = false) {
|
||||
await genSiteEntry();
|
||||
if (production) {
|
||||
await build(getViteConfigForSiteProd());
|
||||
const config = mergeCustomViteConfig(getViteConfigForSiteProd());
|
||||
await build(config);
|
||||
} else {
|
||||
const server = await createServer(getViteConfigForSiteDev());
|
||||
const config = mergeCustomViteConfig(getViteConfigForSiteDev());
|
||||
const server = await createServer(config);
|
||||
await server.listen();
|
||||
|
||||
const { version } = require('vite/package.json');
|
||||
|
||||
@ -92,7 +92,7 @@ function getHTMLMeta(vantConfig: any) {
|
||||
}
|
||||
|
||||
export function getViteConfigForSiteDev(): InlineConfig {
|
||||
setBuildTarget('package');
|
||||
setBuildTarget('site');
|
||||
|
||||
const vantConfig = getVantConfig();
|
||||
const siteConfig = getSiteConfig(vantConfig);
|
||||
|
||||
@ -1,100 +0,0 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`colon prop 1`] = `
|
||||
<form class="van-form">
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__title van-field__label"><span>Label:</span></div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body"><input type="text" class="van-field__control"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__title van-field__label">Custom Label:</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body"><input type="text" class="van-field__control"></div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
`;
|
||||
|
||||
exports[`error-message-align prop 1`] = `
|
||||
<form class="van-form">
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__value van-cell__value--alone van-field__value">
|
||||
<div class="van-field__body"><input type="text" class="van-field__control"></div>
|
||||
<div class="van-field__error-message van-field__error-message--right">Error</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
`;
|
||||
|
||||
exports[`input-align prop 1`] = `
|
||||
<form class="van-form">
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__value van-cell__value--alone van-field__value">
|
||||
<div class="van-field__body"><input type="text" class="van-field__control van-field__control--right"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__value van-cell__value--alone van-field__value">
|
||||
<div class="van-field__body">
|
||||
<div class="van-field__control van-field__control--right van-field__control--custom">
|
||||
<div></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
`;
|
||||
|
||||
exports[`label-align prop 1`] = `
|
||||
<form class="van-form">
|
||||
<div class="van-cell van-field van-field--label-right">
|
||||
<div class="van-cell__title van-field__label van-field__label--right"><span>Label</span></div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body"><input type="text" class="van-field__control"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-cell van-field van-field--label-center">
|
||||
<div class="van-cell__title van-field__label van-field__label--center"><span>Label</span></div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body"><input type="text" class="van-field__control"></div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
`;
|
||||
|
||||
exports[`label-width prop 1`] = `
|
||||
<form class="van-form">
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__title van-field__label" style="width: 5rem;"><span>Label</span></div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body"><input type="text" class="van-field__control"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__title van-field__label" style="width: 10vw;"><span>Label</span></div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body"><input type="text" class="van-field__control"></div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
`;
|
||||
|
||||
exports[`validate-first prop 1`] = `
|
||||
<form class="van-form">
|
||||
<div class="van-cell van-field van-field--error">
|
||||
<div class="van-cell__value van-cell__value--alone van-field__value">
|
||||
<div class="van-field__body"><input type="text" name="A" class="van-field__control"></div>
|
||||
<div class="van-field__error-message">A failed</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__value van-cell__value--alone van-field__value">
|
||||
<div class="van-field__body"><input type="text" name="B" class="van-field__control"></div>
|
||||
</div>
|
||||
</div> <button type="submit" class="van-button van-button--default van-button--normal">
|
||||
<div class="van-button__content"></div>
|
||||
</button>
|
||||
</form>
|
||||
`;
|
||||
171
packages/vant/src/form/test/__snapshots__/props.spec.tsx.snap
Normal file
171
packages/vant/src/form/test/__snapshots__/props.spec.tsx.snap
Normal file
@ -0,0 +1,171 @@
|
||||
// Jest Snapshot v1, https://goo.gl/fbAQLP
|
||||
|
||||
exports[`should render colon when using colon prop 1`] = `
|
||||
<form class="van-form">
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__title van-field__label">
|
||||
<label>
|
||||
Label:
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="text"
|
||||
class="van-field__control"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__title van-field__label">
|
||||
Custom Label:
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="text"
|
||||
class="van-field__control"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
`;
|
||||
|
||||
exports[`should render error-message-align prop correctly 1`] = `
|
||||
<form class="van-form">
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__value van-cell__value--alone van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="text"
|
||||
class="van-field__control"
|
||||
>
|
||||
</div>
|
||||
<div class="van-field__error-message van-field__error-message--right">
|
||||
Error
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
`;
|
||||
|
||||
exports[`should render input-align prop correctly 1`] = `
|
||||
<form class="van-form">
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__value van-cell__value--alone van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="text"
|
||||
class="van-field__control van-field__control--right"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__value van-cell__value--alone van-field__value">
|
||||
<div class="van-field__body">
|
||||
<div class="van-field__control van-field__control--right van-field__control--custom">
|
||||
<div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
`;
|
||||
|
||||
exports[`should render label-align prop correctly 1`] = `
|
||||
<form class="van-form">
|
||||
<div class="van-cell van-field van-field--label-right">
|
||||
<div class="van-cell__title van-field__label van-field__label--right">
|
||||
<label>
|
||||
Label
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="text"
|
||||
class="van-field__control"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-cell van-field van-field--label-center">
|
||||
<div class="van-cell__title van-field__label van-field__label--center">
|
||||
<label>
|
||||
Label
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="text"
|
||||
class="van-field__control"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
`;
|
||||
|
||||
exports[`should render label-width prop correctly 1`] = `
|
||||
<form class="van-form">
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__title van-field__label"
|
||||
style="width: 5rem;"
|
||||
>
|
||||
<label>
|
||||
Label
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="text"
|
||||
class="van-field__control"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__title van-field__label"
|
||||
style="width: 10vw;"
|
||||
>
|
||||
<label>
|
||||
Label
|
||||
</label>
|
||||
</div>
|
||||
<div class="van-cell__value van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="text"
|
||||
class="van-field__control"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
`;
|
||||
|
||||
exports[`should validate first field when using validate-first prop 1`] = `
|
||||
<form class="van-form">
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__value van-cell__value--alone van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="text"
|
||||
name="A"
|
||||
class="van-field__control"
|
||||
>
|
||||
</div>
|
||||
<div class="van-field__error-message">
|
||||
A failed
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="van-cell van-field">
|
||||
<div class="van-cell__value van-cell__value--alone van-field__value">
|
||||
<div class="van-field__body">
|
||||
<input type="text"
|
||||
name="B"
|
||||
class="van-field__control"
|
||||
>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</form>
|
||||
`;
|
||||
@ -1,433 +0,0 @@
|
||||
import { later, mockScrollIntoView } from '../../../test';
|
||||
import { mountForm, submitForm, getSimpleRules } from './shared';
|
||||
|
||||
test('rules prop - execute order', async () => {
|
||||
const onFailed = jest.fn();
|
||||
const wrapper = mountForm({
|
||||
template: `
|
||||
<van-form @failed="onFailed">
|
||||
<van-field name="A" :rules="rules" value="123" />
|
||||
<van-button native-type="submit" />
|
||||
</van-form>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
rules: [
|
||||
{ required: true, message: 'A' },
|
||||
{ validator: (val) => val.length > 6, message: 'B' },
|
||||
{ validator: (val) => val !== 'foo', message: 'C' },
|
||||
],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onFailed,
|
||||
},
|
||||
});
|
||||
|
||||
await submitForm(wrapper);
|
||||
|
||||
expect(onFailed).toHaveBeenCalledWith({
|
||||
errors: [{ message: 'B', name: 'A' }],
|
||||
values: { A: '123' },
|
||||
});
|
||||
});
|
||||
|
||||
test('rules prop - pattern', async () => {
|
||||
const onFailed = jest.fn();
|
||||
const wrapper = mountForm({
|
||||
template: `
|
||||
<van-form @failed="onFailed">
|
||||
<van-field name="A" :rules="rules" value="123" />
|
||||
<van-button native-type="submit" />
|
||||
</van-form>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
rules: [{ pattern: /\d{6}/, message: 'foo' }],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onFailed,
|
||||
},
|
||||
});
|
||||
|
||||
await submitForm(wrapper);
|
||||
|
||||
expect(onFailed).toHaveBeenCalledWith({
|
||||
errors: [{ message: 'foo', name: 'A' }],
|
||||
values: { A: '123' },
|
||||
});
|
||||
});
|
||||
|
||||
test('rules prop - message function', async () => {
|
||||
const onFailed = jest.fn();
|
||||
const wrapper = mountForm({
|
||||
template: `
|
||||
<van-form @failed="onFailed">
|
||||
<van-field name="A" :rules="rules" value="123" />
|
||||
<van-button native-type="submit" />
|
||||
</van-form>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
rules: [{ pattern: /\d{6}/, message: (val) => val }],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onFailed,
|
||||
},
|
||||
});
|
||||
|
||||
await submitForm(wrapper);
|
||||
|
||||
expect(onFailed).toHaveBeenCalledWith({
|
||||
errors: [{ message: '123', name: 'A' }],
|
||||
values: { A: '123' },
|
||||
});
|
||||
});
|
||||
|
||||
test('rules prop - formatter', async () => {
|
||||
const onFailed = jest.fn();
|
||||
const wrapper = mountForm({
|
||||
template: `
|
||||
<van-form @failed="onFailed">
|
||||
<van-field name="A" :rules="rules" value=" " />
|
||||
<van-button native-type="submit" />
|
||||
</van-form>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
rules: [
|
||||
{
|
||||
message: 'foo',
|
||||
required: true,
|
||||
formatter: (val, rule) => {
|
||||
expect(rule.message).toEqual('foo');
|
||||
return val.trim();
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onFailed,
|
||||
},
|
||||
});
|
||||
|
||||
await submitForm(wrapper);
|
||||
|
||||
expect(onFailed).toHaveBeenCalledWith({
|
||||
errors: [{ message: 'foo', name: 'A' }],
|
||||
values: { A: ' ' },
|
||||
});
|
||||
});
|
||||
|
||||
test('rules prop - async validator', async () => {
|
||||
const onFailed = jest.fn();
|
||||
const wrapper = mountForm({
|
||||
template: `
|
||||
<van-form @failed="onFailed">
|
||||
<van-field name="A" :rules="rules" value="123" />
|
||||
<van-button native-type="submit" />
|
||||
</van-form>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
rules: [
|
||||
{
|
||||
validator: (value, rule) => {
|
||||
expect(value).toEqual('123');
|
||||
expect(typeof rule).toEqual('object');
|
||||
return new Promise((resolve) => resolve(true));
|
||||
},
|
||||
message: 'should pass',
|
||||
},
|
||||
{
|
||||
validator: () => new Promise((resolve) => resolve(false)),
|
||||
message: 'should fail',
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onFailed,
|
||||
},
|
||||
});
|
||||
|
||||
await submitForm(wrapper);
|
||||
|
||||
expect(onFailed).toHaveBeenCalledWith({
|
||||
errors: [{ message: 'should fail', name: 'A' }],
|
||||
values: { A: '123' },
|
||||
});
|
||||
});
|
||||
|
||||
test('validate-first prop', async () => {
|
||||
const onSubmit = jest.fn();
|
||||
const onFailed = jest.fn();
|
||||
|
||||
const wrapper = mountForm({
|
||||
template: `
|
||||
<van-form validate-first @submit="onSubmit" @failed="onFailed">
|
||||
<van-field name="A" :rules="rulesA" :value="value" />
|
||||
<van-field name="B" :rules="rulesB" :value="value" />
|
||||
<van-button native-type="submit" />
|
||||
</van-form>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
...getSimpleRules(),
|
||||
value: '',
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
onSubmit,
|
||||
onFailed,
|
||||
},
|
||||
});
|
||||
|
||||
await submitForm(wrapper);
|
||||
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
expect(onFailed).toHaveBeenCalledWith({
|
||||
errors: [{ message: 'A failed', name: 'A' }],
|
||||
values: { A: '', B: '' },
|
||||
});
|
||||
|
||||
wrapper.setData({ value: 'foo' });
|
||||
await submitForm(wrapper);
|
||||
|
||||
expect(onSubmit).toHaveBeenCalledWith({ A: 'foo', B: 'foo' });
|
||||
});
|
||||
|
||||
test('colon prop', () => {
|
||||
const wrapper = mountForm({
|
||||
template: `
|
||||
<van-form colon>
|
||||
<van-field label="Label" />
|
||||
<van-field>
|
||||
<template #label>Custom Label</template>
|
||||
</van-field>
|
||||
</van-form>
|
||||
`,
|
||||
});
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('label-align prop', () => {
|
||||
const wrapper = mountForm({
|
||||
template: `
|
||||
<van-form label-align="right">
|
||||
<van-field label="Label" />
|
||||
<van-field label="Label" label-align="center" />
|
||||
</van-form>
|
||||
`,
|
||||
});
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('label-width prop', () => {
|
||||
const wrapper = mountForm({
|
||||
template: `
|
||||
<van-form label-width="5rem">
|
||||
<van-field label="Label" />
|
||||
<van-field label="Label" label-width="10vw" />
|
||||
</van-form>
|
||||
`,
|
||||
});
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('input-align prop', () => {
|
||||
const wrapper = mountForm({
|
||||
template: `
|
||||
<van-form input-align="right">
|
||||
<van-field />
|
||||
<van-field>
|
||||
<template #input>
|
||||
<div />
|
||||
</template>
|
||||
</van-field>
|
||||
</van-form>
|
||||
`,
|
||||
});
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('error-message-align prop', () => {
|
||||
const wrapper = mountForm({
|
||||
template: `
|
||||
<van-form error-message-align="right">
|
||||
<van-field error-message="Error" />
|
||||
</van-form>
|
||||
`,
|
||||
});
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('validate-trigger - onBlur', async () => {
|
||||
const wrapper = mountForm({
|
||||
template: `
|
||||
<van-form ref="form">
|
||||
<van-field name="A" :rules="rulesA" value="" />
|
||||
</van-form>
|
||||
`,
|
||||
data: getSimpleRules,
|
||||
});
|
||||
|
||||
const input = wrapper.find('input');
|
||||
|
||||
input.trigger('input');
|
||||
await later();
|
||||
expect(wrapper.contains('.van-field__error-message')).toBeFalsy();
|
||||
|
||||
input.trigger('blur');
|
||||
await later();
|
||||
expect(wrapper.contains('.van-field__error-message')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('validate-trigger - onChange', async () => {
|
||||
const wrapper = mountForm({
|
||||
template: `
|
||||
<van-form validate-trigger="onChange" ref="form">
|
||||
<van-field v-model="value" name="A" :rules="rulesA" />
|
||||
</van-form>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
...getSimpleRules(),
|
||||
value: '',
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
const input = wrapper.find('input');
|
||||
|
||||
input.trigger('blur');
|
||||
await later();
|
||||
expect(wrapper.contains('.van-field__error-message')).toBeFalsy();
|
||||
|
||||
wrapper.setData({ value: '1' });
|
||||
await later();
|
||||
expect(wrapper.contains('.van-field__error-message')).toBeFalsy();
|
||||
|
||||
wrapper.setData({ value: '' });
|
||||
await later();
|
||||
expect(wrapper.contains('.van-field__error-message')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('validate-trigger - custom trigger in rules', async () => {
|
||||
const wrapper = mountForm({
|
||||
template: `
|
||||
<van-form validate-trigger="none" ref="form">
|
||||
<van-field name="A" :rules="rulesA" :value="valueA" />
|
||||
<van-field name="B" :rules="rulesB" :value="valueB" />
|
||||
</van-form>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
valueA: '',
|
||||
valueB: '',
|
||||
rulesA: [
|
||||
{
|
||||
message: 'A',
|
||||
required: true,
|
||||
trigger: 'onChange',
|
||||
},
|
||||
],
|
||||
rulesB: [
|
||||
{
|
||||
message: 'B',
|
||||
required: true,
|
||||
trigger: 'onBlur',
|
||||
},
|
||||
],
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
const inputs = wrapper.findAll('input');
|
||||
|
||||
inputs[0].trigger('blur');
|
||||
wrapper.setData({ valueB: '1' });
|
||||
await later();
|
||||
wrapper.setData({ valueB: '' });
|
||||
await later();
|
||||
expect(wrapper.contains('.van-field__error-message')).toBeFalsy();
|
||||
|
||||
inputs[1].trigger('blur');
|
||||
wrapper.setData({ valueA: '1' });
|
||||
await later();
|
||||
wrapper.setData({ valueA: '' });
|
||||
await later();
|
||||
expect(
|
||||
wrapper.element.querySelectorAll('.van-field__error-message').length
|
||||
).toEqual(2);
|
||||
});
|
||||
|
||||
test('scroll-to-error prop', async () => {
|
||||
const fn = mockScrollIntoView();
|
||||
const wrapper = mountForm({
|
||||
template: `
|
||||
<van-form scroll-to-error>
|
||||
<van-field name="A" :rules="rulesA" value="" />
|
||||
<van-button native-type="submit" />
|
||||
</van-form>
|
||||
`,
|
||||
data: getSimpleRules,
|
||||
});
|
||||
|
||||
await submitForm(wrapper);
|
||||
|
||||
expect(fn).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('show-error-message prop', async () => {
|
||||
const wrapper = mountForm({
|
||||
template: `
|
||||
<van-form :show-error-message="showErrorMessage">
|
||||
<van-field name="A" :rules="rulesA" value="" />
|
||||
<van-button native-type="submit" />
|
||||
</van-form>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
...getSimpleRules(),
|
||||
showErrorMessage: false,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
await submitForm(wrapper);
|
||||
expect(wrapper.contains('.van-field__error-message')).toBeFalsy();
|
||||
|
||||
wrapper.setData({ showErrorMessage: true });
|
||||
|
||||
await submitForm(wrapper);
|
||||
expect(wrapper.contains('.van-field__error-message')).toBeTruthy();
|
||||
});
|
||||
|
||||
test('show-error prop', async () => {
|
||||
const wrapper = mountForm({
|
||||
template: `
|
||||
<van-form :show-error="showError">
|
||||
<van-field name="A" :rules="rulesA" value="" />
|
||||
<van-button native-type="submit" />
|
||||
</van-form>
|
||||
`,
|
||||
data() {
|
||||
return {
|
||||
...getSimpleRules(),
|
||||
showError: false,
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
await submitForm(wrapper);
|
||||
expect(wrapper.contains('.van-field--error')).toBeFalsy();
|
||||
|
||||
wrapper.setData({ showError: true });
|
||||
|
||||
await submitForm(wrapper);
|
||||
expect(wrapper.contains('.van-field--error')).toBeTruthy();
|
||||
});
|
||||
405
packages/vant/src/form/test/props.spec.tsx
Normal file
405
packages/vant/src/form/test/props.spec.tsx
Normal file
@ -0,0 +1,405 @@
|
||||
import { mount, later, mockScrollIntoView } from '../../../test';
|
||||
import { submitForm, getSimpleRules } from './shared';
|
||||
import { Form } from '..';
|
||||
import { Field, FieldRule } from '../../field';
|
||||
|
||||
test('should ensure execute order of rules prop', async () => {
|
||||
const onFailed = jest.fn();
|
||||
const rules: FieldRule[] = [
|
||||
{ required: true, message: 'A' },
|
||||
{ validator: (val) => val.length > 6, message: 'B' },
|
||||
{ validator: (val) => val !== 'foo', message: 'C' },
|
||||
];
|
||||
const wrapper = mount({
|
||||
render() {
|
||||
return (
|
||||
<Form onFailed={onFailed}>
|
||||
<Field name="A" rules={rules} modelValue="123" />
|
||||
</Form>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
await submitForm(wrapper);
|
||||
|
||||
expect(onFailed).toHaveBeenCalledWith({
|
||||
errors: [{ message: 'B', name: 'A' }],
|
||||
values: { A: '123' },
|
||||
});
|
||||
});
|
||||
|
||||
test('should support pattern in rules prop', async () => {
|
||||
const onFailed = jest.fn();
|
||||
const rules: FieldRule[] = [{ pattern: /\d{6}/, message: 'foo' }];
|
||||
const wrapper = mount({
|
||||
render() {
|
||||
return (
|
||||
<Form onFailed={onFailed}>
|
||||
<Field name="A" rules={rules} modelValue="123" />
|
||||
</Form>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
await submitForm(wrapper);
|
||||
|
||||
expect(onFailed).toHaveBeenCalledWith({
|
||||
errors: [{ message: 'foo', name: 'A' }],
|
||||
values: { A: '123' },
|
||||
});
|
||||
});
|
||||
|
||||
test('should support message function in rules prop', async () => {
|
||||
const onFailed = jest.fn();
|
||||
const rules: FieldRule[] = [{ pattern: /\d{6}/, message: (val) => val }];
|
||||
const wrapper = mount({
|
||||
render() {
|
||||
return (
|
||||
<Form onFailed={onFailed}>
|
||||
<Field name="A" rules={rules} modelValue="123" />
|
||||
</Form>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
await submitForm(wrapper);
|
||||
|
||||
expect(onFailed).toHaveBeenCalledWith({
|
||||
errors: [{ message: '123', name: 'A' }],
|
||||
values: { A: '123' },
|
||||
});
|
||||
});
|
||||
|
||||
test('should support formatter in rules prop', async () => {
|
||||
const onFailed = jest.fn();
|
||||
const rules: FieldRule[] = [
|
||||
{
|
||||
message: 'foo',
|
||||
required: true,
|
||||
formatter: (val, rule) => {
|
||||
expect(rule.message).toEqual('foo');
|
||||
return val.trim();
|
||||
},
|
||||
},
|
||||
];
|
||||
const wrapper = mount({
|
||||
render() {
|
||||
return (
|
||||
<Form onFailed={onFailed}>
|
||||
<Field name="A" rules={rules} modelValue=" " />
|
||||
</Form>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
await submitForm(wrapper);
|
||||
|
||||
expect(onFailed).toHaveBeenCalledWith({
|
||||
errors: [{ message: 'foo', name: 'A' }],
|
||||
values: { A: ' ' },
|
||||
});
|
||||
});
|
||||
|
||||
test('should support async validator in rules prop', async () => {
|
||||
const onFailed = jest.fn();
|
||||
const rules: FieldRule[] = [
|
||||
{
|
||||
validator: (value, rule) => {
|
||||
expect(value).toEqual('123');
|
||||
expect(typeof rule).toEqual('object');
|
||||
return new Promise((resolve) => resolve(true));
|
||||
},
|
||||
message: 'should pass',
|
||||
},
|
||||
{
|
||||
validator: () => new Promise((resolve) => resolve(false)),
|
||||
message: 'should fail',
|
||||
},
|
||||
];
|
||||
const wrapper = mount({
|
||||
render() {
|
||||
return (
|
||||
<Form onFailed={onFailed}>
|
||||
<Field name="A" rules={rules} modelValue="123" />
|
||||
</Form>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
await submitForm(wrapper);
|
||||
|
||||
expect(onFailed).toHaveBeenCalledWith({
|
||||
errors: [{ message: 'should fail', name: 'A' }],
|
||||
values: { A: '123' },
|
||||
});
|
||||
});
|
||||
|
||||
test('should validate first field when using validate-first prop', async () => {
|
||||
const onSubmit = jest.fn();
|
||||
const onFailed = jest.fn();
|
||||
|
||||
const wrapper = mount({
|
||||
data() {
|
||||
return {
|
||||
...getSimpleRules(),
|
||||
value: '',
|
||||
};
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<Form validateFirst onSubmit={onSubmit} onFailed={onFailed}>
|
||||
<Field name="A" rules={this.rulesA} modelValue={this.value} />
|
||||
<Field name="B" rules={this.rulesB} modelValue={this.value} />
|
||||
</Form>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
await submitForm(wrapper);
|
||||
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
expect(onFailed).toHaveBeenCalledWith({
|
||||
errors: [{ message: 'A failed', name: 'A' }],
|
||||
values: { A: '', B: '' },
|
||||
});
|
||||
|
||||
await wrapper.setData({ value: 'foo' });
|
||||
await submitForm(wrapper);
|
||||
|
||||
expect(onSubmit).toHaveBeenCalledWith({ A: 'foo', B: 'foo' });
|
||||
});
|
||||
|
||||
test('should render colon when using colon prop', () => {
|
||||
const wrapper = mount({
|
||||
render() {
|
||||
return (
|
||||
<Form colon>
|
||||
<Field label="Label" />
|
||||
<Field v-slots={{ label: () => 'Custom Label' }} />
|
||||
</Form>
|
||||
);
|
||||
},
|
||||
});
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should render label-align prop correctly', () => {
|
||||
const wrapper = mount({
|
||||
render() {
|
||||
return (
|
||||
<Form labelAlign="right">
|
||||
<Field label="Label" />
|
||||
<Field label="Label" labelAlign="center" />
|
||||
</Form>
|
||||
);
|
||||
},
|
||||
});
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should render label-width prop correctly', () => {
|
||||
const wrapper = mount({
|
||||
render() {
|
||||
return (
|
||||
<Form labelWidth="5rem">
|
||||
<Field label="Label" />
|
||||
<Field label="Label" labelWidth="10vw" />
|
||||
</Form>
|
||||
);
|
||||
},
|
||||
});
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should render input-align prop correctly', () => {
|
||||
const wrapper = mount({
|
||||
render() {
|
||||
return (
|
||||
<Form inputAlign="right">
|
||||
<Field />
|
||||
<Field v-slots={{ input: () => <div /> }} />
|
||||
</Form>
|
||||
);
|
||||
},
|
||||
});
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should render error-message-align prop correctly', () => {
|
||||
const wrapper = mount({
|
||||
render() {
|
||||
return (
|
||||
<Form errorMessageAlign="right">
|
||||
<Field errorMessage="Error" />
|
||||
</Form>
|
||||
);
|
||||
},
|
||||
});
|
||||
expect(wrapper.html()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test('should trigger validate after blurring when validate-trigger prop is onBlur', async () => {
|
||||
const wrapper = mount({
|
||||
data: getSimpleRules,
|
||||
render() {
|
||||
return (
|
||||
<Form ref="form" validateTrigger="onBlur">
|
||||
<Field name="A" rules={this.rulesA} modelValue="" />
|
||||
</Form>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
const input = wrapper.find('input');
|
||||
|
||||
await input.trigger('input');
|
||||
expect(wrapper.find('.van-field__error-message').exists()).toBeFalsy();
|
||||
|
||||
await input.trigger('blur');
|
||||
expect(wrapper.find('.van-field__error-message').exists()).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should trigger validate after inputting when validate-trigger prop is onChange', async () => {
|
||||
const wrapper = mount({
|
||||
data() {
|
||||
return {
|
||||
...getSimpleRules(),
|
||||
value: '',
|
||||
};
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<Form validateTrigger="onChange" ref="form">
|
||||
<Field v-model={this.value} name="A" rules={this.rulesA} />
|
||||
</Form>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
const input = wrapper.find('input');
|
||||
|
||||
await input.trigger('blur');
|
||||
expect(wrapper.find('.van-field__error-message').exists()).toBeFalsy();
|
||||
|
||||
await wrapper.setData({ value: '1' });
|
||||
expect(wrapper.find('.van-field__error-message').exists()).toBeFalsy();
|
||||
|
||||
await wrapper.setData({ value: '' });
|
||||
expect(wrapper.find('.van-field__error-message').exists).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should allow to custom trigger in rules', async () => {
|
||||
const rulesA = [
|
||||
{
|
||||
message: 'A',
|
||||
required: true,
|
||||
trigger: 'onChange' as const,
|
||||
},
|
||||
];
|
||||
const rulesB = [
|
||||
{
|
||||
message: 'B',
|
||||
required: true,
|
||||
trigger: 'onBlur' as const,
|
||||
},
|
||||
];
|
||||
const wrapper = mount({
|
||||
data() {
|
||||
return {
|
||||
valueA: '',
|
||||
valueB: '',
|
||||
};
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<Form validate-trigger="none" ref="form">
|
||||
<Field name="A" rules={rulesA} modelValue={this.valueA} />
|
||||
<Field name="B" rules={rulesB} modelValue={this.valueB} />
|
||||
</Form>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
const inputs = wrapper.findAll('input');
|
||||
|
||||
await inputs[0].trigger('blur');
|
||||
await wrapper.setData({ valueB: '1' });
|
||||
await wrapper.setData({ valueB: '' });
|
||||
expect(wrapper.find('.van-field__error-message').exists()).toBeFalsy();
|
||||
|
||||
await inputs[1].trigger('blur');
|
||||
await wrapper.setData({ valueA: '1' });
|
||||
await wrapper.setData({ valueA: '' });
|
||||
await later();
|
||||
expect(
|
||||
wrapper.element.querySelectorAll('.van-field__error-message').length
|
||||
).toEqual(2);
|
||||
});
|
||||
|
||||
test('should trigger scroll when using scroll-to-error prop', async () => {
|
||||
const fn = mockScrollIntoView();
|
||||
const wrapper = mount({
|
||||
data: getSimpleRules,
|
||||
render() {
|
||||
return (
|
||||
<Form scrollToError>
|
||||
<Field name="A" rules={this.rulesA} modelValue="" />
|
||||
</Form>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
await submitForm(wrapper);
|
||||
|
||||
expect(fn).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
test('should allow to control the display of error message by show-error-message prop', async () => {
|
||||
const wrapper = mount({
|
||||
data() {
|
||||
return {
|
||||
...getSimpleRules(),
|
||||
showErrorMessage: false,
|
||||
};
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<Form showErrorMessage={this.showErrorMessage}>
|
||||
<Field name="A" rules={this.rulesA} modelValue="" />
|
||||
</Form>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
await submitForm(wrapper);
|
||||
expect(wrapper.find('.van-field__error-message').exists()).toBeFalsy();
|
||||
|
||||
await wrapper.setData({ showErrorMessage: true });
|
||||
await submitForm(wrapper);
|
||||
expect(wrapper.find('.van-field__error-message').exists()).toBeTruthy();
|
||||
});
|
||||
|
||||
test('should allow to control the display of error status by show-error prop', async () => {
|
||||
const wrapper = mount({
|
||||
data() {
|
||||
return {
|
||||
...getSimpleRules(),
|
||||
showError: false,
|
||||
};
|
||||
},
|
||||
render() {
|
||||
return (
|
||||
<Form showError={this.showError}>
|
||||
<Field name="A" rules={this.rulesA} modelValue="" />
|
||||
</Form>
|
||||
);
|
||||
},
|
||||
});
|
||||
|
||||
await submitForm(wrapper);
|
||||
expect(wrapper.find('.van-field--error').exists()).toBeFalsy();
|
||||
|
||||
await wrapper.setData({ showError: true });
|
||||
await submitForm(wrapper);
|
||||
expect(wrapper.find('.van-field--error').exists()).toBeTruthy();
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user