formApi.test.js 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604
  1. // formApi test
  2. import { Form, Select, Button } from '../../index';
  3. import { noop } from 'lodash';
  4. import { sleep as baseSleep } from '../../_test_/utils/index';
  5. const sleep = (ms = 200) => baseSleep(ms);
  6. function getForm(props) {
  7. return mount(<Form {...props}></Form>, {
  8. attachTo: document.getElementById('container'),
  9. });
  10. }
  11. const Option = Select.Option;
  12. const FormSelect = (
  13. <Form.Select label="business" field="business" style={{ width: 200 }}>
  14. <Option value="abc">Abc</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 = `.semi-form-field`;
  21. const fields = (
  22. <>
  23. {FormInput}
  24. {FormSelect}
  25. </>
  26. );
  27. const getDomValue = (field, form) => {
  28. let inputDOM = form.find(`[x-field-id="${field}"] input`).getDOMNode();
  29. return inputDOM.getAttribute("value");
  30. };
  31. describe('Form-formApi', () => {
  32. beforeEach(() => {
  33. document.body.innerHTML = '';
  34. // Avoid `attachTo: document.body` Warning
  35. const div = document.createElement('div');
  36. div.setAttribute('id', 'container');
  37. document.body.appendChild(div);
  38. });
  39. afterEach(() => {
  40. const div = document.getElementById('container');
  41. if (div) {
  42. document.body.removeChild(div);
  43. }
  44. });
  45. it('formApi-getFieldExist', () => {
  46. let formApi = null;
  47. let getFormApi = api => {
  48. formApi = api;
  49. };
  50. let spyGet = sinon.spy(getFormApi);
  51. let props = {
  52. getFormApi: spyGet,
  53. children: FormInput,
  54. };
  55. const form = getForm(props);
  56. expect(formApi.getFieldExist('name')).toEqual(true);
  57. expect(formApi.getFieldExist('business')).toEqual(false);
  58. });
  59. it('formApi-getInitValue / getInitValues', () => {
  60. let formApi = null;
  61. let getFormApi = api => {
  62. formApi = api;
  63. };
  64. let initValues = {
  65. name: 'semi',
  66. business: 'abc',
  67. };
  68. let props = {
  69. initValues,
  70. getFormApi,
  71. children: fields,
  72. };
  73. const form = getForm(props);
  74. expect(formApi.getInitValue('name')).toEqual('semi');
  75. expect(formApi.getInitValue('business')).toEqual('abc');
  76. expect(formApi.getInitValue('notExistField')).toEqual(undefined);
  77. expect(formApi.getInitValue()).toEqual(initValues);
  78. expect(formApi.getInitValues()).toEqual(initValues);
  79. });
  80. it('formApi-getTouched', () => {
  81. let formApi = null;
  82. let getFormApi = api => {
  83. formApi = api;
  84. };
  85. let props = {
  86. getFormApi,
  87. children: fields,
  88. };
  89. const form = getForm(props);
  90. let event = {};
  91. form.find(`.semi-input`).simulate('blur', event);
  92. expect(formApi.getTouched('name')).toEqual(true);
  93. expect(!formApi.getTouched('business')).toEqual(true);
  94. });
  95. it('formApi-getValue', () => {
  96. let formApi = null;
  97. let getFormApi = api => {
  98. formApi = api;
  99. };
  100. let props = {
  101. getFormApi,
  102. children: fields,
  103. };
  104. const form = getForm(props);
  105. // get specific field value
  106. expect(formApi.getValue('name')).toEqual(undefined);
  107. let event = { target: { value: 'semi' } };
  108. form.find(`.semi-input`).simulate('change', event);
  109. expect(formApi.getValue('name')).toEqual('semi');
  110. // get all field's value
  111. expect(formApi.getValue()).toEqual({ name: 'semi' });
  112. expect(formApi.getValues()).toEqual({ name: 'semi' });
  113. });
  114. it('formApi-getError', done => {
  115. let formApi = null;
  116. let getFormApi = api => {
  117. formApi = api;
  118. };
  119. let errorMessage = 'not muji';
  120. const props = {
  121. getFormApi,
  122. children: (
  123. <Form.Input
  124. trigger="change"
  125. field="name"
  126. rules={[{ validator: (rule, value) => value === 'muji', message: errorMessage }]}
  127. />
  128. ),
  129. };
  130. const form = getForm(props);
  131. let event = { target: { value: 'semi' } };
  132. form.find(`.semi-input`).simulate('change', event);
  133. setTimeout(() => {
  134. expect(formApi.getError('name')).toEqual(errorMessage);
  135. done();
  136. }, 300);
  137. });
  138. it('formApi-getFormState', done => {
  139. let formApi = null;
  140. let getFormApi = api => {
  141. formApi = api;
  142. };
  143. const props = {
  144. getFormApi,
  145. children: (
  146. <Form.Input
  147. trigger="change"
  148. field="name"
  149. rules={[{ validator: (rule, value) => value === 'muji', message: 'not muji' }]}
  150. />
  151. ),
  152. };
  153. const form = getForm(props);
  154. let event = { target: { value: 'semi' } };
  155. form.find(`.semi-input`).simulate('change', event);
  156. let expectFormState = {
  157. values: { name: 'semi' },
  158. errors: { name: 'not muji' },
  159. touched: { name: true },
  160. };
  161. setTimeout(() => {
  162. expect(formApi.getFormState()).toEqual(expectFormState);
  163. done();
  164. }, 300);
  165. });
  166. it('formApi-setError', () => {
  167. let formApi = null;
  168. let getFormApi = api => {
  169. formApi = api;
  170. };
  171. const props = {
  172. getFormApi,
  173. children: <Form.Input trigger="change" field="name" fieldClassName="test" />,
  174. };
  175. const form = getForm(props);
  176. let errorMessage = 'not muji';
  177. formApi.setError('name', errorMessage);
  178. let expectFormState = {
  179. values: {},
  180. errors: { name: errorMessage },
  181. touched: {},
  182. };
  183. expect(formApi.getFormState()).toEqual(expectFormState);
  184. form.update();
  185. expect(form.find(`.test .semi-form-field-error-message`).text()).toEqual(errorMessage);
  186. });
  187. it('formApi-setTouched', () => {
  188. let formApi = null;
  189. let getFormApi = api => {
  190. formApi = api;
  191. };
  192. let props = {
  193. getFormApi,
  194. children: fields,
  195. };
  196. const form = getForm(props);
  197. let event = {};
  198. form.find(`.semi-input`).simulate('blur', event);
  199. expect(formApi.getTouched('name')).toEqual(true);
  200. expect(!formApi.getTouched('business')).toEqual(true);
  201. });
  202. it('formApi-setValue', () => {
  203. let formApi = null;
  204. let getFormApi = api => {
  205. formApi = api;
  206. };
  207. let props = {
  208. getFormApi,
  209. children: fields,
  210. };
  211. let expectVal = 'semi';
  212. const form = getForm(props);
  213. formApi.setValue('name', expectVal);
  214. expect(formApi.getValue('name')).toEqual(expectVal);
  215. expect(form.find(`.semi-input`).instance().value).toEqual(expectVal);
  216. });
  217. it('formApi-reset', () => {
  218. let formApi = null;
  219. const props = {
  220. children: fields,
  221. getFormApi: api => {
  222. formApi = api;
  223. },
  224. initValues: {
  225. name: 'a',
  226. },
  227. };
  228. const form = getForm(props);
  229. let event = { target: { value: 'b' } };
  230. form.find(`.semi-input`).simulate('change', event);
  231. formApi.reset();
  232. expect(form.find(`.semi-input`).instance().value).toEqual('a');
  233. expect(formApi.getFormState()).toEqual({
  234. values: { name: 'a' },
  235. errors: {},
  236. touched: {},
  237. });
  238. });
  239. it('formApi-setValues-override', () => {
  240. let formApi = null;
  241. const props = {
  242. children: fields,
  243. getFormApi: api => {
  244. formApi = api;
  245. },
  246. initValues: {
  247. name: 'a',
  248. extraKeyA: 'uno',
  249. },
  250. };
  251. const form = getForm(props);
  252. let expectVal = {
  253. name: 'semi',
  254. business: 'abc',
  255. extraKeyB: 'Kay tse',
  256. };
  257. formApi.setValues(expectVal, { isOverride: true });
  258. expect(formApi.getValue()).toEqual(expectVal);
  259. });
  260. it('formApi-setValues-merge', () => {
  261. let formApi = null;
  262. let initValues = {
  263. name: 'a',
  264. extraKeyA: 'uno',
  265. };
  266. const props = {
  267. children: fields,
  268. getFormApi: api => {
  269. formApi = api;
  270. },
  271. initValues,
  272. };
  273. const form = getForm(props);
  274. let expectVal = {
  275. name: 'semi',
  276. business: 'abc',
  277. extraKeyB: 'not exist',
  278. };
  279. let mergeVal = { name: 'semi', business: 'abc', extraKeyA: 'uno' };
  280. formApi.setValues(expectVal);
  281. expect(formApi.getValue()).toEqual(mergeVal);
  282. });
  283. it('formApi-validate, validate all field, specail field', async () => {
  284. let fields = (
  285. <>
  286. <Form.Input field="a.b" className='ab' validate={(val) => val ? '' : 'ab-err'} />
  287. <Form.Input field="a.c" className='ac' validate={(val) => val ? '' : 'ac-err'} />
  288. </>
  289. )
  290. let formApi = null;
  291. let getFormApi = api => {
  292. formApi = api;
  293. };
  294. let formProps = {
  295. children: fields,
  296. getFormApi,
  297. };
  298. let form = getForm(formProps);
  299. formApi.validate().then(values=>{}).catch(error=> {});
  300. await sleep(400);
  301. expect(formApi.getFormState().errors).toEqual({ a: { b: 'ab-err', c: 'ac-err'}});
  302. formApi.reset();
  303. formApi.validate(['a.c']).then(values=>{}).catch(error=> {});
  304. await sleep(300);
  305. expect(formApi.getFormState().errors).toEqual({ a: { c: 'ac-err'}});
  306. });
  307. it('formApi-validate, nested field', async () => {
  308. let fields = (
  309. <>
  310. <Form.Input field="a.b" className='ab' validate={(val) => val ? '' : 'ab-err'} />
  311. <Form.Input field="a.c" className='ac' validate={(val) => val ? '' : 'ac-err'} />
  312. <Form.Input field="e" className='e' validate={(val) => val ? '' : 'e-err'} />
  313. </>
  314. )
  315. let formApi = null;
  316. let getFormApi = api => {
  317. formApi = api;
  318. };
  319. let formProps = {
  320. children: fields,
  321. getFormApi,
  322. };
  323. let form = getForm(formProps);
  324. formApi.validate(['a']).then(values=>{}).catch(error=> {});
  325. await sleep(300);
  326. expect(formApi.getFormState().errors).toEqual({ a: { b: 'ab-err', c: 'ac-err' }});
  327. })
  328. it('formApi-setValue, when include nested field', async () => {
  329. let fields = (
  330. <>
  331. <Form.Input field="a.b" className='ab' validate={(val) => val ? '' : 'ab-err'} />
  332. <Form.Input field="a.c" className='ac' validate={(val) => val ? '' : 'ac-err'} />
  333. <Form.Input field="e" className='e' validate={(val) => val ? '' : 'e-err'} />
  334. </>
  335. )
  336. let formApi = null;
  337. let getFormApi = api => {
  338. formApi = api;
  339. };
  340. let formProps = {
  341. children: fields,
  342. getFormApi,
  343. };
  344. let form = getForm(formProps);
  345. formApi.setValue('a', { b: 'semi-b', c: 'semi-c'})
  346. await sleep(300);
  347. expect(formApi.getFormState().values).toEqual({ a: { b: 'semi-b', c: 'semi-c' }});
  348. expect(form.find('.ab .semi-input').instance().value).toEqual('semi-b');
  349. expect(form.find('.ac .semi-input').instance().value).toEqual('semi-c');
  350. expect(form.find('.e .semi-input').instance().value).toEqual('');
  351. });
  352. it('formApi-setEror, when include nested field', async () => {
  353. let fields = (
  354. <>
  355. <Form.Input field="a.b" className='ab' validate={(val) => val ? '' : 'ab-err'} />
  356. <Form.Input field="a.c" className='ac' validate={(val) => val ? '' : 'ac-err'} />
  357. <Form.Input field="e" className='e' validate={(val) => val ? '' : 'e-err'} />
  358. </>
  359. )
  360. let formApi = null;
  361. let getFormApi = api => {
  362. formApi = api;
  363. };
  364. let formProps = {
  365. children: fields,
  366. getFormApi,
  367. };
  368. let form = getForm(formProps);
  369. formApi.setError('a', { b: 'ab-err', c: 'ac-err'});
  370. form.update();
  371. await sleep(500);
  372. expect(formApi.getFormState().errors).toEqual({ a: { b: 'ab-err', c: 'ac-err' }});
  373. expect(form.find('.ab .semi-form-field-error-message span').at(1).text()).toEqual('ab-err');
  374. expect(form.find('.ac .semi-form-field-error-message span').at(1).text()).toEqual('ac-err');
  375. });
  376. it('formApi-setTouched, when include nested field', async () => {
  377. let fields = (
  378. <>
  379. <Form.Input field="a.b" className='ab' validate={(val) => val ? '' : 'ab-err'} />
  380. <Form.Input field="a.c" className='ac' validate={(val) => val ? '' : 'ac-err'} />
  381. <Form.Input field="e" className='e' validate={(val) => val ? '' : 'e-err'} />
  382. </>
  383. )
  384. let formApi = null;
  385. let getFormApi = api => {
  386. formApi = api;
  387. };
  388. let formProps = {
  389. children: fields,
  390. getFormApi,
  391. };
  392. let form = getForm(formProps);
  393. formApi.setTouched('a', { b: true, c: true })
  394. await sleep(300);
  395. expect(formApi.getFormState().touched).toEqual({ a: { b: true, c: true }});
  396. })
  397. it('formApi-setValue, field path precise', () => {
  398. // case like:
  399. // Exist 3 Field: a.b、a.c、a.d
  400. // formApi.setValue('a.b', '123');
  401. let formApi = null;
  402. const fields = (
  403. <>
  404. <Form.Input field='a.b' />
  405. <Form.Input field='a.c' />
  406. <Form.Input field='a.d' />
  407. </>
  408. );
  409. const props = {
  410. children: fields,
  411. getFormApi: api => {
  412. formApi = api;
  413. },
  414. };
  415. const form = getForm(props);
  416. formApi.setValue('a.c', 'semi');
  417. // check formState.values
  418. let val = formApi.getValue('a.c');
  419. expect(val).toEqual('semi');
  420. form.update();
  421. // check dom render
  422. expect(getDomValue('a.c', form)).toEqual('semi');
  423. });
  424. it('formApi-setValue, field path belongs to parent aggregate', () => {
  425. // case like:
  426. // Exist 3 Field: a.b、a.c、a.d
  427. // formApi.setValue('a', { b: 'semi', c: 'design' });
  428. let formApi = null;
  429. const fields = (
  430. <>
  431. <Form.Input field='a.b' />
  432. <Form.Input field='a.c' />
  433. <Form.Input field='a.d' />
  434. </>
  435. );
  436. const props = {
  437. children: fields,
  438. getFormApi: api => {
  439. formApi = api;
  440. },
  441. };
  442. const form = getForm(props);
  443. formApi.setValue('a', { b: 'semi', c: 'design' });
  444. let acVal = formApi.getValue('a.c');
  445. let abVal = formApi.getValue('a.b');
  446. expect(abVal).toEqual('semi');
  447. expect(acVal).toEqual('design');
  448. form.update();
  449. // check dom render
  450. expect(getDomValue('a.b', form)).toEqual('semi');
  451. expect(getDomValue('a.c', form)).toEqual('design');
  452. });
  453. it('formApi-setValue with array field path, 0 -> 3', () => {
  454. const fields = ({ formState, values }) => {
  455. return values.a && values.a.map((effect, i) => (
  456. <div key={effect.key}>
  457. <Form.Input field={`a[${i}].name`} />
  458. <Form.Input field={`a[${i}].type`} />
  459. </div>
  460. ));
  461. };
  462. let formApi = null;
  463. const props = {
  464. children: fields,
  465. getFormApi: api => {
  466. formApi = api;
  467. },
  468. };
  469. const form = getForm(props);
  470. let targetValue = [
  471. { name: '0-name', type: '0-type' },
  472. { name: '1-name', type: '1-type' },
  473. { name: '2-name', type: '2-type' },
  474. ];
  475. formApi.setValue('a', targetValue);
  476. let formStateValues = formApi.getValue();
  477. form.update();
  478. // check dom render
  479. expect(getDomValue('a[0].name', form)).toEqual('0-name');
  480. expect(getDomValue('a[0].type', form)).toEqual('0-type');
  481. expect(getDomValue('a[1].name', form)).toEqual('1-name');
  482. expect(getDomValue('a[1].type', form)).toEqual('1-type');
  483. expect(getDomValue('a[2].name', form)).toEqual('2-name');
  484. expect(getDomValue('a[2].type', form)).toEqual('2-type');
  485. });
  486. // // this case result was different in cypress / jest, jest result is wrong
  487. // it('formApi-setValue with array field path, 3 -> 2, delete some field', done => {
  488. // const fields = ({ formState, values }) => {
  489. // return values.a && values.a.map((item, i) => (
  490. // <div key={item.key} style={{ width: 300 }}>
  491. // <Form.Input field={`a[${i}].name`} />
  492. // <Form.Input field={`a[${i}].type`} />
  493. // </div>
  494. // ));
  495. // };
  496. // let formApi = null;
  497. // const props = {
  498. // children: fields,
  499. // initValues: {
  500. // a: [
  501. // { name: '0-name', type: '0-type', key: 0 },
  502. // { name: '1-name', type: '1-type', key: 1 },
  503. // { name: '2-name', type: '2-type', key: 2 },
  504. // ]
  505. // },
  506. // getFormApi: api => {
  507. // formApi = api;
  508. // },
  509. // };
  510. // let form = getForm(props);
  511. // // remove middle one
  512. // formApi.setValue('a', [
  513. // { name: '0-name', type: '0-type', key: 0 },
  514. // { name: '2-name', type: '2-type', key: 2 },
  515. // ]);
  516. // let formStateValues = formApi.getValue();
  517. // form.update();
  518. // setTimeout(() => {
  519. // // check dom render
  520. // expect(getDomValue('a[0].name', form)).toEqual('0-name');
  521. // expect(getDomValue('a[0].type', form)).toEqual('0-type');
  522. // expect(getDomValue('a[1].name', form)).toEqual('2-name');
  523. // expect(getDomValue('a[1].type', form)).toEqual('2-type');
  524. // expect(form.exists(`[x-field-id="a[2].name"] input`)).toEqual(false);
  525. // expect(form.exists(`[x-field-id="a[2].type"] input`)).toEqual(false);
  526. // done();
  527. // }, 5000);
  528. // });
  529. it('formApi-setValue with array field path, 1 -> 3, add some field', () => {
  530. const fields = ({ formState, values }) => {
  531. return values.a && values.a.map((effect, i) => (
  532. <div key={effect.key}>
  533. <Form.Input field={`a[${i}].name`} />
  534. <Form.Input field={`a[${i}].type`} />
  535. </div>
  536. ));
  537. };
  538. let formApi = null;
  539. const props = {
  540. children: fields,
  541. initValues: {
  542. a: [{ name: 'semi', type: 'design' }]
  543. },
  544. getFormApi: api => {
  545. formApi = api;
  546. },
  547. };
  548. let form = getForm(props);
  549. formApi.setValue('a', [
  550. { name: '0-name', type: '0-type' },
  551. { name: '1-name', type: '1-type' },
  552. { name: '2-name', type: '2-type' },
  553. ]);
  554. let formStateValues = formApi.getValue();
  555. form.update();
  556. // check dom render
  557. expect(getDomValue('a[0].name', form)).toEqual('0-name');
  558. expect(getDomValue('a[0].type', form)).toEqual('0-type');
  559. expect(getDomValue('a[1].name', form)).toEqual('1-name');
  560. expect(getDomValue('a[1].type', form)).toEqual('1-type');
  561. expect(getDomValue('a[2].name', form)).toEqual('2-name');
  562. expect(getDomValue('a[2].type', form)).toEqual('2-type');
  563. });
  564. // it('formApi-submitForm', () => {
  565. // // submit should call validate first
  566. // });
  567. });