1
0

field.test.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426
  1. import { Form, Select } from '../../index';
  2. import { noop } from 'lodash';
  3. import { func } from 'prop-types';
  4. import { BASE_CLASS_PREFIX } from '../../../semi-foundation/base/constants';
  5. function getForm(props) {
  6. return mount(<Form {...props}></Form>);
  7. }
  8. function getInput(props) {
  9. return <Form.Input {...props} />;
  10. }
  11. const Option = Select.Option;
  12. const FormSelect = (
  13. <Form.Select label="business" field="business" style={{ width: 200 }}>
  14. <Option value="dy">Douyin</Option>
  15. <Option value="hotsoon">Hotsoon</Option>
  16. <Option value="topbuzz">TopBuzz</Option>
  17. </Form.Select>
  18. );
  19. const FormInput = <Form.Input field="name" />;
  20. const FieldCls = `.${BASE_CLASS_PREFIX}-form-field`;
  21. const fields = (
  22. <>
  23. {FormInput}
  24. {FormSelect}
  25. </>
  26. );
  27. describe('Form-field', () => {
  28. it('className & style & fieldClassName', () => {
  29. const fieldProps = {
  30. className: 'test-a',
  31. style: {
  32. color: 'red',
  33. },
  34. fieldClassName: 'field-test-b',
  35. };
  36. const props = {
  37. children: getInput(fieldProps),
  38. };
  39. const form = getForm(props);
  40. expect(form.exists(`.${BASE_CLASS_PREFIX}-input-wrapper.test-a`)).toEqual(true);
  41. expect(form.find(`.${BASE_CLASS_PREFIX}-input-wrapper.test-a`)).toHaveStyle('color', 'red');
  42. expect(form.find(`.${BASE_CLASS_PREFIX}-form-field.field-test-b`).length).toEqual(1);
  43. });
  44. it('label', () => {
  45. const props = {
  46. children: getInput({
  47. label: 'Company',
  48. field: 'name',
  49. }),
  50. };
  51. const form = getForm(props);
  52. expect(form.find(`.${BASE_CLASS_PREFIX}-form-field-label`).text()).toEqual('Company');
  53. });
  54. it('labelPosition', () => {
  55. // field's labelPosition has a higher weight than form
  56. const props = {
  57. labelPosition: 'top',
  58. children: (
  59. <>
  60. {getInput({ labelPosition: 'left', fieldClassName: 'left-input' })}
  61. {getInput({ fieldClassName: 'top-input' })}
  62. </>
  63. ),
  64. };
  65. const form = getForm(props);
  66. expect(
  67. form
  68. .find('.left-input')
  69. .instance()
  70. .getAttribute('x-label-pos')
  71. ).toEqual('left');
  72. expect(
  73. form
  74. .find('.top-input')
  75. .instance()
  76. .getAttribute('x-label-pos')
  77. ).toEqual('top');
  78. });
  79. it('labelAlign', () => {
  80. // field's labelAlign has a higher weight than form
  81. const props = {
  82. labelAlign: 'right',
  83. children: (
  84. <>
  85. {getInput({ labelAlign: 'left', fieldClassName: 'left-input' })}
  86. {getInput({ fieldClassName: 'right-input' })}
  87. </>
  88. ),
  89. };
  90. const form = getForm(props);
  91. expect(form.exists(`.left-input .${BASE_CLASS_PREFIX}-form-field-label-left`)).toEqual(true);
  92. expect(form.exists(`.right-input .${BASE_CLASS_PREFIX}-form-field-label-right`)).toEqual(true);
  93. });
  94. it('noLabel', () => {
  95. const fieldProps = {
  96. noLabel: true,
  97. field: 'name',
  98. };
  99. const props = {
  100. children: getInput(fieldProps),
  101. };
  102. const form = getForm(props);
  103. expect(form.exists(`.${BASE_CLASS_PREFIX}-form-field-label`)).toEqual(false);
  104. });
  105. it('name', () => {
  106. const props = {
  107. children: getInput({ field: 'name', name: 'company' }),
  108. };
  109. const form = getForm(props);
  110. expect(form.exists(`.${BASE_CLASS_PREFIX}-form-field.${BASE_CLASS_PREFIX}-form-field-company`)).toEqual(true);
  111. });
  112. it('initValue', () => {
  113. // field's initValue has a higher weight than form initValues
  114. const props = {
  115. children: getInput({ initValue: 'b', field: 'name' }),
  116. initValues: {
  117. name: 'a',
  118. },
  119. };
  120. const form = getForm(props);
  121. expect(form.find(`.${BASE_CLASS_PREFIX}-input`).instance().value).toEqual('b');
  122. });
  123. it('onChange', () => {
  124. const onChange = () => {};
  125. const spyOnChange = sinon.spy(onChange);
  126. const fieldProps = {
  127. onChange: spyOnChange,
  128. field: 'name',
  129. };
  130. const props = {
  131. children: getInput(fieldProps),
  132. };
  133. const form = getForm(props);
  134. const event = { target: { value: 'semi' } };
  135. form.find(`.${BASE_CLASS_PREFIX}-input`).simulate('change', event);
  136. expect(spyOnChange.calledOnce).toEqual(true);
  137. expect(spyOnChange.calledWithMatch('semi')).toEqual(true);
  138. });
  139. it('validate-sync', () => {
  140. const validate = value => {
  141. return value !== 'semi' ? 'invalid' : '';
  142. };
  143. const spyValidate = sinon.spy(validate);
  144. const fieldProps = {
  145. field: 'name',
  146. trigger: 'change',
  147. validate: spyValidate,
  148. // rules are invalidated when validate is also declared
  149. rules: [
  150. { type: 'string', message: 'rules error1' },
  151. { validator: (rule, value) => value === 'muji', message: 'rules error2' },
  152. ],
  153. };
  154. const props = {
  155. children: getInput(fieldProps),
  156. };
  157. const form = getForm(props);
  158. // fail
  159. const failedEvent = { target: { value: 'milk' } };
  160. form.find(`.${BASE_CLASS_PREFIX}-input`).simulate('change', failedEvent);
  161. expect(spyValidate.calledWithMatch('milk')).toEqual(true);
  162. expect(form.find(`.${BASE_CLASS_PREFIX}-form-field-error-message`).text()).toEqual('invalid');
  163. // success
  164. const successEvent = { target: { value: 'semi' } };
  165. form.find(`.${BASE_CLASS_PREFIX}-input`).simulate('change', successEvent);
  166. expect(form.exists(`.${BASE_CLASS_PREFIX}-form-field-error-message`)).toEqual(false);
  167. });
  168. it('validate-async', done => {
  169. const sleep = ms => new Promise(resolve => setTimeout(resolve, ms));
  170. const validate = val => {
  171. return sleep(50).then(() => {
  172. if (val !== 'semi') {
  173. return 'invalid';
  174. }
  175. return '';
  176. });
  177. };
  178. const spyValidate = sinon.spy(validate);
  179. const fieldProps = {
  180. trigger: 'change',
  181. validate: spyValidate,
  182. field: 'name',
  183. };
  184. let formApi = null;
  185. const getFormApi = api => {
  186. formApi = api;
  187. };
  188. const props = {
  189. getFormApi,
  190. children: getInput(fieldProps),
  191. };
  192. const form = getForm(props);
  193. // fail
  194. const failedEvent = { target: { value: 'milk' } };
  195. form.find(`.${BASE_CLASS_PREFIX}-input`).simulate('change', failedEvent);
  196. setTimeout(() => {
  197. form.update();
  198. expect(spyValidate.firstCall.calledWithMatch('milk')).toEqual(true);
  199. expect(formApi.getError('name')).toEqual('invalid');
  200. expect(form.find(`.${BASE_CLASS_PREFIX}-form-field-error-message`).text()).toEqual('invalid');
  201. const successEvent = { target: { value: 'semi' } };
  202. form.find(`.${BASE_CLASS_PREFIX}-input`).simulate('change', successEvent);
  203. }, 200);
  204. setTimeout(() => {
  205. form.update();
  206. // success
  207. expect(spyValidate.secondCall.calledWithMatch('semi')).toEqual(true);
  208. expect(formApi.getError('name')).toEqual(undefined);
  209. expect(form.exists(`.${BASE_CLASS_PREFIX}-form-field-error-message`)).toEqual(false);
  210. done();
  211. }, 800);
  212. });
  213. it('rules', done => {
  214. // rules work
  215. let fieldProps = {
  216. field: 'name',
  217. trigger: 'change',
  218. rules: [
  219. { type: 'string', message: 'type error' },
  220. { validator: (rule, value) => value === 'muji', message: 'not muji' },
  221. ],
  222. };
  223. let formApi = null;
  224. const getFormApi = api => {
  225. formApi = api;
  226. };
  227. const props = {
  228. getFormApi,
  229. children: getInput(fieldProps),
  230. };
  231. const form = getForm(props);
  232. const event2 = { target: { value: 2 } };
  233. form.find(`.${BASE_CLASS_PREFIX}-input`).simulate('change', event2);
  234. setTimeout(() => {
  235. form.update();
  236. expect(form.find(`.${BASE_CLASS_PREFIX}-form-field-error-message`).text()).toEqual('type error, not muji');
  237. }, 50);
  238. setTimeout(() => {
  239. const event3 = { target: { value: 'semi' } };
  240. form.find(`.${BASE_CLASS_PREFIX}-input`).simulate('change', event3);
  241. form.update();
  242. }, 100);
  243. setTimeout(() => {
  244. // console.log(formApi);
  245. expect(form.find(`.${BASE_CLASS_PREFIX}-form-field-error-message`).text()).toEqual('not muji');
  246. done();
  247. }, 200);
  248. });
  249. it('transform', () => {
  250. const transform = stringVal => {
  251. return Number(stringVal);
  252. };
  253. const validate = value => {
  254. return value !== 5 ? 'invalid' : '';
  255. };
  256. const spyValidate = sinon.spy(validate);
  257. const fieldProps = {
  258. transform,
  259. validate: spyValidate,
  260. field: 'count',
  261. };
  262. let formApi = null;
  263. const getFormApi = api => {
  264. formApi = api;
  265. };
  266. const props = {
  267. getFormApi,
  268. children: getInput(fieldProps),
  269. };
  270. const form = getForm(props);
  271. const event = { target: { value: '5' } };
  272. form.find(`.${BASE_CLASS_PREFIX}-input`).simulate('change', event);
  273. expect(spyValidate.calledWithMatch(5)).toEqual(true);
  274. // only transform value before validate, can't change value in formState
  275. expect(formApi.getValue('count')).toEqual('5');
  276. });
  277. it('convert', () => {
  278. const convert = stringVal => {
  279. return Number(stringVal);
  280. };
  281. const spyConvert = sinon.spy(convert);
  282. const fieldProps = {
  283. convert: spyConvert,
  284. field: 'count',
  285. };
  286. let formApi = null;
  287. const getFormApi = api => {
  288. formApi = api;
  289. };
  290. const props = {
  291. getFormApi,
  292. children: getInput(fieldProps),
  293. };
  294. const form = getForm(props);
  295. const event = { target: { value: '5' } };
  296. form.find(`.${BASE_CLASS_PREFIX}-input`).simulate('change', event);
  297. expect(spyConvert.calledWithMatch('5')).toEqual(true);
  298. expect(formApi.getValue('count')).toEqual(5);
  299. });
  300. it('trigger - mounted / change / blur ', done => {
  301. const validate = val => (val !== 'semi' ? 'invalid' : '');
  302. const propsChange = {
  303. trigger: 'change',
  304. field: 'a',
  305. fieldClassName: 'a',
  306. validate,
  307. };
  308. const propsBlur = {
  309. trigger: 'blur',
  310. field: 'b',
  311. fieldClassName: 'b',
  312. initValue: 'milk',
  313. validate,
  314. };
  315. //TODO mounted
  316. const propsMounted = {
  317. trigger: 'mounted',
  318. field: 'c',
  319. fieldClassName: 'c',
  320. validate,
  321. };
  322. const props = {
  323. children: (
  324. <>
  325. {getInput(propsChange)}
  326. {getInput(propsBlur)}
  327. </>
  328. ),
  329. };
  330. const form = getForm(props);
  331. const event = { target: { value: 'trigger' } };
  332. form.find(`.a .${BASE_CLASS_PREFIX}-input`).simulate('change', event);
  333. form.find(`.b .${BASE_CLASS_PREFIX}-input`).simulate('blur', event);
  334. setTimeout(() => {
  335. form.update();
  336. expect(form.find(`.a .${BASE_CLASS_PREFIX}-form-field-error-message`).text()).toEqual('invalid');
  337. expect(form.find(`.b .${BASE_CLASS_PREFIX}-form-field-error-message`).text()).toEqual('invalid');
  338. done();
  339. }, 100);
  340. });
  341. it('trigger - change & blur', done => {
  342. const validate = val => {
  343. if (val === 'changeVal') {
  344. return 'changeError';
  345. } else if (val === 'blurVal') {
  346. return 'blurError';
  347. } else {
  348. return '';
  349. }
  350. };
  351. const fieldProps = {
  352. trigger: ['change', 'blur'],
  353. field: 'a',
  354. fieldClassName: 'a',
  355. validate,
  356. };
  357. const props = {
  358. children: <>{getInput(fieldProps)}</>,
  359. };
  360. const form = getForm(props);
  361. let event = { target: { value: 'changeVal' } };
  362. form.find(`.a .${BASE_CLASS_PREFIX}-input`).simulate('change', event);
  363. setTimeout(() => {
  364. form.update();
  365. expect(form.find(`.a .${BASE_CLASS_PREFIX}-form-field-error-message`).text()).toEqual('changeError');
  366. }, 50);
  367. setTimeout(() => {
  368. event = { target: { value: 'blurVal' } };
  369. form.find(`.a .${BASE_CLASS_PREFIX}-input`).simulate('change', event);
  370. form.find(`.a .${BASE_CLASS_PREFIX}-input`).simulate('blur', {});
  371. }, 80);
  372. setTimeout(() => {
  373. form.update();
  374. expect(form.find(`.a .${BASE_CLASS_PREFIX}-form-field-error-message`).text()).toEqual('blurError');
  375. done();
  376. }, 100);
  377. });
  378. it('field', () => {
  379. // 1、username
  380. // 2、user[0]
  381. // 3、siblings.1
  382. // 4、siblings['2']
  383. // 5、parents[0].name
  384. // 6、parents[1]['name']
  385. const fields = ['username', 'user[0]', 'siblings.1', 'siblings[2]', 'parents[0].name', "parents[1]['name']"];
  386. const props = {
  387. children: <>{fields.map((field, index) => getInput({ field: field, fieldClassName: `field-${index}` }))}</>,
  388. initValues: {
  389. username: 'a',
  390. user: ['b'],
  391. siblings: [0, 'c', 'd'],
  392. parents: [{ name: 'e' }, { name: 'f' }],
  393. },
  394. };
  395. const form = getForm(props);
  396. // If you do not pass a specific label prop, the label content is consistent with the field
  397. const fieldsDOM = form.find(`.${BASE_CLASS_PREFIX}-form-field .${BASE_CLASS_PREFIX}-input`);
  398. expect(fieldsDOM.at(0).instance().value).toEqual('a');
  399. expect(fieldsDOM.at(1).instance().value).toEqual('b');
  400. expect(fieldsDOM.at(2).instance().value).toEqual('c');
  401. expect(fieldsDOM.at(3).instance().value).toEqual('d');
  402. expect(fieldsDOM.at(4).instance().value).toEqual('e');
  403. expect(fieldsDOM.at(5).instance().value).toEqual('f');
  404. });
  405. // TODO
  406. // it('allowEmptyString', () => {});
  407. // it('extraText')
  408. // it('extraTextPosition')
  409. // it('helpText')
  410. // it('stopValidateWithError')
  411. // it('noErrorMessage)
  412. // it('pure')
  413. // it('fieldStyle')
  414. });