|
| 1 | +import { fireEvent, mockTimeout, render, vi } from '@test/utils'; |
1 | 2 | import React from 'react'; |
2 | 3 | import { MinusCircleIcon } from 'tdesign-icons-react'; |
3 | | -import { fireEvent, mockTimeout, render, vi } from '@test/utils'; |
4 | 4 |
|
5 | 5 | import Button from '../../button'; |
6 | 6 | import Input from '../../input'; |
@@ -605,4 +605,152 @@ describe('Form List 组件测试', () => { |
605 | 605 | await mockTimeout(); |
606 | 606 | expect(queryByText('用户名必填')).not.toBeTruthy(); |
607 | 607 | }); |
| 608 | + |
| 609 | + test('FormList with shouldUpdate', async () => { |
| 610 | + const TestView = () => { |
| 611 | + const [form] = Form.useForm(); |
| 612 | + |
| 613 | + const nestedInitialData = { |
| 614 | + services: [ |
| 615 | + { |
| 616 | + modelName: 'modelA', |
| 617 | + routes: [ |
| 618 | + { type: 'weight', weight: 50, abtest: 'cid' }, |
| 619 | + { type: 'abtest', weight: 30, abtest: 'uid' }, |
| 620 | + ], |
| 621 | + }, |
| 622 | + ], |
| 623 | + }; |
| 624 | + |
| 625 | + return ( |
| 626 | + <Form form={form} initialData={nestedInitialData}> |
| 627 | + <FormList name="services"> |
| 628 | + {(fields) => ( |
| 629 | + <> |
| 630 | + {fields.map(({ key, name: serviceName }) => ( |
| 631 | + <div key={key}> |
| 632 | + <FormList name={[serviceName, 'routes']}> |
| 633 | + {(routeFields, { add: addRoute }) => ( |
| 634 | + <div> |
| 635 | + {routeFields.map((f) => ( |
| 636 | + <div key={f.key} data-route-index={f.name}> |
| 637 | + <FormItem name={[f.name, 'type']} label="类型"> |
| 638 | + <Input placeholder={`route-type-${serviceName}-${f.name}`} /> |
| 639 | + </FormItem> |
| 640 | + <FormItem |
| 641 | + shouldUpdate={(p, n) => |
| 642 | + p.services?.[serviceName]?.routes?.[f.name]?.type !== |
| 643 | + n.services?.[serviceName]?.routes?.[f.name]?.type |
| 644 | + } |
| 645 | + > |
| 646 | + {({ getFieldValue }) => { |
| 647 | + const type = getFieldValue(['services', serviceName, 'routes', f.name, 'type']); |
| 648 | + if (type === 'weight') { |
| 649 | + return ( |
| 650 | + <FormItem key={type} name={[f.name, 'weight']} label="权重"> |
| 651 | + <Input placeholder={`route-weight-${serviceName}-${f.name}`} /> |
| 652 | + </FormItem> |
| 653 | + ); |
| 654 | + } |
| 655 | + if (type === 'abtest') { |
| 656 | + return ( |
| 657 | + <FormItem key={type} name={[f.name, 'abtest']} label="分流Key"> |
| 658 | + <Input placeholder={`route-abtest-${serviceName}-${f.name}`} /> |
| 659 | + </FormItem> |
| 660 | + ); |
| 661 | + } |
| 662 | + return null; |
| 663 | + }} |
| 664 | + </FormItem> |
| 665 | + </div> |
| 666 | + ))} |
| 667 | + <Button id={`test-add-route-${serviceName}`} onClick={() => addRoute()}> |
| 668 | + 新增路由 |
| 669 | + </Button> |
| 670 | + </div> |
| 671 | + )} |
| 672 | + </FormList> |
| 673 | + </div> |
| 674 | + ))} |
| 675 | + </> |
| 676 | + )} |
| 677 | + </FormList> |
| 678 | + </Form> |
| 679 | + ); |
| 680 | + }; |
| 681 | + |
| 682 | + const { container, getByPlaceholderText } = render(<TestView />); |
| 683 | + |
| 684 | + // 第一个 route |
| 685 | + expect((getByPlaceholderText('route-type-0-0') as HTMLInputElement).value).toBe('weight'); |
| 686 | + expect((getByPlaceholderText('route-weight-0-0') as HTMLInputElement).value).toBe('50'); |
| 687 | + // 切换到 abtest |
| 688 | + const typeInput0 = getByPlaceholderText('route-type-0-0') as HTMLInputElement; |
| 689 | + fireEvent.change(typeInput0, { target: { value: 'abtest' } }); |
| 690 | + await mockTimeout(); |
| 691 | + expect((getByPlaceholderText('route-abtest-0-0') as HTMLInputElement).value).toBe('cid'); |
| 692 | + expect(container.querySelector('[placeholder="route-weight-0-0"]')).toBeFalsy(); |
| 693 | + // 切换回 weight |
| 694 | + fireEvent.change(typeInput0, { target: { value: 'weight' } }); |
| 695 | + await mockTimeout(); |
| 696 | + expect((getByPlaceholderText('route-weight-0-0') as HTMLInputElement).value).toBe('50'); |
| 697 | + |
| 698 | + // 第二个 route |
| 699 | + expect((getByPlaceholderText('route-type-0-1') as HTMLInputElement).value).toBe('abtest'); |
| 700 | + expect((getByPlaceholderText('route-abtest-0-1') as HTMLInputElement).value).toBe('uid'); |
| 701 | + // 切换到 weight |
| 702 | + const typeInput1 = getByPlaceholderText('route-type-0-1') as HTMLInputElement; |
| 703 | + fireEvent.change(typeInput1, { target: { value: 'weight' } }); |
| 704 | + await mockTimeout(); |
| 705 | + expect((getByPlaceholderText('route-weight-0-1') as HTMLInputElement).value).toBe('30'); |
| 706 | + expect(container.querySelector('[placeholder="route-abtest-0-1"]')).toBeFalsy(); |
| 707 | + // 切换回 abtest |
| 708 | + fireEvent.change(typeInput1, { target: { value: 'abtest' } }); |
| 709 | + await mockTimeout(); |
| 710 | + expect((getByPlaceholderText('route-abtest-0-1') as HTMLInputElement).value).toBe('uid'); |
| 711 | + |
| 712 | + // 添加新的 route(没有初始数据) |
| 713 | + const addRouteBtn = container.querySelector('#test-add-route-0'); |
| 714 | + fireEvent.click(addRouteBtn); |
| 715 | + await mockTimeout(); |
| 716 | + const newTypeInput = getByPlaceholderText('route-type-0-2') as HTMLInputElement; |
| 717 | + expect(newTypeInput).toBeTruthy(); |
| 718 | + // 新添加的项,type 初始应该为空 |
| 719 | + expect(newTypeInput.value).toBe(''); |
| 720 | + |
| 721 | + // 设置新 route 的 type 为 weight |
| 722 | + fireEvent.change(newTypeInput, { target: { value: 'weight' } }); |
| 723 | + await mockTimeout(); |
| 724 | + |
| 725 | + const newWeightInput = getByPlaceholderText('route-weight-0-2') as HTMLInputElement; |
| 726 | + expect(newWeightInput).toBeTruthy(); |
| 727 | + // 新添加的项,weight 初始应该为空 |
| 728 | + expect(newWeightInput.value).toBe(''); |
| 729 | + |
| 730 | + // 切换到 abtest |
| 731 | + fireEvent.change(newTypeInput, { target: { value: 'abtest' } }); |
| 732 | + await mockTimeout(); |
| 733 | + const newAbtestInput = getByPlaceholderText('route-abtest-0-2') as HTMLInputElement; |
| 734 | + expect(newAbtestInput).toBeTruthy(); |
| 735 | + expect(newAbtestInput.value).toBe(''); |
| 736 | + // 设置值 |
| 737 | + fireEvent.change(newAbtestInput, { target: { value: 'new-key' } }); |
| 738 | + await mockTimeout(); |
| 739 | + expect(newAbtestInput.value).toBe('new-key'); |
| 740 | + |
| 741 | + // 切换回 weight |
| 742 | + fireEvent.change(newTypeInput, { target: { value: 'weight' } }); |
| 743 | + expect(container.querySelector('[placeholder="route-abtest-0-2"]')).toBeFalsy(); |
| 744 | + await mockTimeout(); |
| 745 | + // weight 重置为空 |
| 746 | + const weightInputAgain = getByPlaceholderText('route-weight-0-2') as HTMLInputElement; |
| 747 | + expect(weightInputAgain.value).toBe(''); |
| 748 | + |
| 749 | + // 切换回 abtest |
| 750 | + fireEvent.change(newTypeInput, { target: { value: 'abtest' } }); |
| 751 | + await mockTimeout(); |
| 752 | + // abtest 重置为空 |
| 753 | + const abtestInputAgain = getByPlaceholderText('route-abtest-0-2') as HTMLInputElement; |
| 754 | + expect(abtestInputAgain.value).toBe(''); |
| 755 | + }); |
608 | 756 | }); |
0 commit comments