From 6d18e8db40f6c8f109bb71079ad79dfc4d876ffb Mon Sep 17 00:00:00 2001 From: afc163 Date: Fri, 13 May 2022 14:26:57 +0800 Subject: [PATCH 1/5] docs: update work with us part --- docs/resources.zh-CN.md | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/docs/resources.zh-CN.md b/docs/resources.zh-CN.md index eea327258f..6d67fcdff4 100644 --- a/docs/resources.zh-CN.md +++ b/docs/resources.zh-CN.md @@ -122,11 +122,11 @@ ReactDOM.render(, mountNode); ### UI/UE 设计师 -简历和作品集请投递:lindong.lld#antgroup.com +简历和作品集请投递:jiayin.liu#antgroup.com > 注明简历来自 ant.design 官网 -- 岗位级别:P6/P7/P8 +- 岗位级别:P5/P6/P7/P8 - 岗位地点:杭州 - 岗位要求: - 至少 3-5 年的工作经验,扎实设计功底; @@ -141,7 +141,6 @@ ReactDOM.render(, mountNode); - 参与 Ant Design 的打磨,将其建设成全球卓越的设计体系。 - 参与 AntV 的打磨,将其建设成全球一流的数据可视化体系。 - One More Thing ❤️ : - - 你们总是为世界带去美好,但总是忘却你们也需要美好。我们正在努力打造 [🍳 Kitchen:一款为设计师提效的 Sketch 工具集](https://kitchen.alipay.com/)等专属设计师的产品,让设计真正变成财富。期待志同道合的你,一道给设计行业带来「微小而美好的改变」。 ### 前端工程师 @@ -150,21 +149,20 @@ ReactDOM.render(, mountNode); > 注明简历来自 ant.design 官网 -- 岗位级别:P6/P7/P8 -- 岗位地点:杭州 +- 岗位级别:P5/P6/P7/P8 +- 岗位地点:杭州/上海 - 岗位要求: - 在 React 技术栈持续耕耘,情有独钟。 - 热爱开源。 - 坚持和善于用技术和工具解决其他问题。 - 丰富的中后台前端研发经验。 - - 爱 🐱。 - 岗位职责: - 负责 Ant Design 前端基础设施研发。 - 负责中后台设计/前端工具体系建设。 ### ADI(Artificial Design Intelligence) 工程师 -简历和作品集请投递:lindong.lld#alipay.com +简历和作品集请投递:jiayin.liu#antgroup.com > 注明简历来自 ant.design 官网 From e629b39c204000118ae1b268d51707eca881e85a Mon Sep 17 00:00:00 2001 From: vagusX Date: Fri, 13 May 2022 22:00:01 +0800 Subject: [PATCH 2/5] test: moving to testing-library in `Segmented` (#35538) * test(Segmented): moving to testing-library * chore: cleanup * fix: test * test: use click instead of change to fire event * Update index.test.tsx --- .../{demo.test.js.snap => demo.test.ts.snap} | 0 .../__tests__/{demo.test.js => demo.test.ts} | 0 components/segmented/__tests__/index.test.tsx | 285 +++++++++--------- 3 files changed, 135 insertions(+), 150 deletions(-) rename components/segmented/__tests__/__snapshots__/{demo.test.js.snap => demo.test.ts.snap} (100%) rename components/segmented/__tests__/{demo.test.js => demo.test.ts} (100%) diff --git a/components/segmented/__tests__/__snapshots__/demo.test.js.snap b/components/segmented/__tests__/__snapshots__/demo.test.ts.snap similarity index 100% rename from components/segmented/__tests__/__snapshots__/demo.test.js.snap rename to components/segmented/__tests__/__snapshots__/demo.test.ts.snap diff --git a/components/segmented/__tests__/demo.test.js b/components/segmented/__tests__/demo.test.ts similarity index 100% rename from components/segmented/__tests__/demo.test.js rename to components/segmented/__tests__/demo.test.ts diff --git a/components/segmented/__tests__/index.test.tsx b/components/segmented/__tests__/index.test.tsx index a05776a80c..16f2688ab0 100644 --- a/components/segmented/__tests__/index.test.tsx +++ b/components/segmented/__tests__/index.test.tsx @@ -1,12 +1,12 @@ import React from 'react'; -import { mount } from 'enzyme'; import { AppstoreOutlined, BarsOutlined } from '@ant-design/icons'; import mountTest from '../../../tests/shared/mountTest'; import rtlTest from '../../../tests/shared/rtlTest'; +import { render, fireEvent } from '../../../tests/utils'; + import Segmented from '../index'; import type { SegmentedValue } from '../index'; -import { render } from '../../../tests/utils'; // Make CSSMotion working without transition jest.mock('rc-motion/lib/util/motion', () => ({ @@ -16,6 +16,19 @@ jest.mock('rc-motion/lib/util/motion', () => ({ const prefixCls = 'ant-segmented'; +function expectMatchChecked(container: HTMLElement, checkedList: boolean[]) { + const inputList = Array.from( + container.querySelectorAll(`.${prefixCls}-item-input`), + ); + expect(inputList).toHaveLength(checkedList.length); + + inputList.forEach((input, i) => { + const checked = checkedList[i]; + + expect(input.checked).toBe(checked); + }); +} + describe('Segmented', () => { mountTest(Segmented); rtlTest(Segmented); @@ -29,26 +42,22 @@ describe('Segmented', () => { }); it('render empty segmented', () => { - const wrapper = mount(); - expect(wrapper.render()).toMatchSnapshot(); + const { asFragment } = render(); + expect(asFragment().firstChild).toMatchSnapshot(); }); it('render segmented ok', () => { - const wrapper = mount( + const { asFragment, container } = render( , ); - expect(wrapper.render()).toMatchSnapshot(); + expect(asFragment().firstChild).toMatchSnapshot(); - expect( - wrapper - .find(`.${prefixCls}-item-input`) - .map(el => (el.getDOMNode() as HTMLInputElement).checked), - ).toEqual([true, false, false]); + expectMatchChecked(container, [true, false, false]); }); it('render label with ReactNode', () => { - const wrapper = mount( + const { asFragment, container } = render( { />, ); - expect(wrapper.render()).toMatchSnapshot(); + expect(asFragment().firstChild).toMatchSnapshot(); - expect( - wrapper - .find(`.${prefixCls}-item-input`) - .map(el => (el.getDOMNode() as HTMLInputElement).checked), - ).toEqual([true, false, false]); + expectMatchChecked(container, [true, false, false]); - expect(wrapper.find('#weekly').at(0).text()).toContain('Weekly'); - expect(wrapper.find('h2').at(0).text()).toContain('Monthly'); + expect(container.querySelector('#weekly')?.textContent).toContain('Weekly'); + expect(container.querySelectorAll('h2')[0].textContent).toContain('Monthly'); }); it('render segmented with defaultValue', () => { - const wrapper = mount( + const { container } = render( , ); - expect( - wrapper - .find(`.${prefixCls}-item-input`) - .map(el => (el.getDOMNode() as HTMLInputElement).checked), - ).toEqual([false, false, false, true, false]); + expectMatchChecked(container, [false, false, false, true, false]); }); it('render segmented with string options', () => { const handleValueChange = jest.fn(); - const wrapper = mount( + const { asFragment, container } = render( , ); - expect(wrapper.render()).toMatchSnapshot(); + expect(asFragment().firstChild).toMatchSnapshot(); + expectMatchChecked(container, [true, false, false]); expect( - wrapper - .find(`.${prefixCls}-item-input`) - .map(el => (el.getDOMNode() as HTMLInputElement).checked), - ).toEqual([true, false, false]); - expect( - wrapper.find(`label.${prefixCls}-item`).at(0).hasClass(`${prefixCls}-item-selected`), + container + .querySelectorAll(`label.${prefixCls}-item`)[0] + .classList.contains(`${prefixCls}-item-selected`), ).toBeTruthy(); - wrapper.find(`.${prefixCls}-item-input`).at(2).simulate('change'); + fireEvent.click(container.querySelectorAll(`.${prefixCls}-item-input`)[2]); expect(handleValueChange).toBeCalledWith('Monthly'); - expect( - wrapper - .find(`.${prefixCls}-item-input`) - .map(el => (el.getDOMNode() as HTMLInputElement).checked), - ).toEqual([false, false, true]); + expectMatchChecked(container, [false, false, true]); }); it('render segmented with numeric options', () => { const handleValueChange = jest.fn(); - const wrapper = mount( + const { asFragment, container } = render( handleValueChange(value)} />, ); - expect(wrapper.render()).toMatchSnapshot(); - expect( - wrapper - .find(`.${prefixCls}-item-input`) - .map(el => (el.getDOMNode() as HTMLInputElement).checked), - ).toEqual([true, false, false, false, false]); + expect(asFragment().firstChild).toMatchSnapshot(); + expectMatchChecked(container, [true, false, false, false, false]); - wrapper.find(`.${prefixCls}-item-input`).last().simulate('change'); + fireEvent.click(container.querySelectorAll(`.${prefixCls}-item-input`)[4]); expect(handleValueChange).toBeCalledWith(5); - expect( - wrapper - .find(`.${prefixCls}-item-input`) - .map(el => (el.getDOMNode() as HTMLInputElement).checked), - ).toEqual([false, false, false, false, true]); + expectMatchChecked(container, [false, false, false, false, true]); }); it('render segmented with mixed options', () => { const handleValueChange = jest.fn(); - const wrapper = mount( + const { asFragment, container } = render( handleValueChange(value)} />, ); - expect(wrapper.render()).toMatchSnapshot(); + expect(asFragment().firstChild).toMatchSnapshot(); + expectMatchChecked(container, [true, false, false]); - wrapper.find(`.${prefixCls}-item-input`).at(1).simulate('change'); + fireEvent.click(container.querySelectorAll(`.${prefixCls}-item-input`)[1]); expect(handleValueChange).toBeCalledWith('Weekly'); - expect( - wrapper - .find(`.${prefixCls}-item-input`) - .map(el => (el.getDOMNode() as HTMLInputElement).checked), - ).toEqual([false, true, false]); + expectMatchChecked(container, [false, true, false]); }); it('render segmented with options: disabled', () => { const handleValueChange = jest.fn(); - const wrapper = mount( + const { asFragment, container } = render( handleValueChange(value)} />, ); - expect(wrapper.render()).toMatchSnapshot(); + expect(asFragment().firstChild).toMatchSnapshot(); expect( - wrapper.find(`label.${prefixCls}-item`).at(1).hasClass(`${prefixCls}-item-disabled`), + container + .querySelectorAll(`label.${prefixCls}-item`)[1] + .classList.contains(`${prefixCls}-item-disabled`), ).toBeTruthy(); - expect(wrapper.find(`.${prefixCls}-item-input`).at(1).prop('disabled')).toBeTruthy(); + expect(container.querySelectorAll(`.${prefixCls}-item-input`)[1]).toHaveAttribute('disabled'); - wrapper.find(`.${prefixCls}-item-input`).at(1).simulate('change'); + fireEvent.click(container.querySelectorAll(`.${prefixCls}-item-input`)[1]); expect(handleValueChange).not.toBeCalled(); - expect( - wrapper - .find(`.${prefixCls}-item-input`) - .map(el => (el.getDOMNode() as HTMLInputElement).checked), - ).toEqual([true, false, false]); + expectMatchChecked(container, [true, false, false]); - wrapper.find(`.${prefixCls}-item-input`).at(2).simulate('change'); + fireEvent.click(container.querySelectorAll(`.${prefixCls}-item-input`)[2]); expect(handleValueChange).toBeCalledWith('Monthly'); expect(handleValueChange).toBeCalledTimes(1); - expect( - wrapper - .find(`.${prefixCls}-item-input`) - .map(el => (el.getDOMNode() as HTMLInputElement).checked), - ).toEqual([false, false, true]); + expectMatchChecked(container, [false, false, true]); }); it('render segmented: disabled', () => { const handleValueChange = jest.fn(); - const wrapper = mount( + const { asFragment, container } = render( handleValueChange(value)} />, ); - expect(wrapper.render()).toMatchSnapshot(); - expect(wrapper.find(`.${prefixCls}`).hasClass(`${prefixCls}-disabled`)).toBeTruthy(); + expect(asFragment().firstChild).toMatchSnapshot(); + expect( + container.querySelectorAll(`.${prefixCls}`)[0].classList.contains(`${prefixCls}-disabled`), + ).toBeTruthy(); - wrapper.find(`.${prefixCls}-item-input`).at(1).simulate('change'); + fireEvent.click(container.querySelectorAll(`.${prefixCls}-item-input`)[1]); expect(handleValueChange).not.toBeCalled(); - expect( - wrapper - .find(`.${prefixCls}-item-input`) - .map(el => (el.getDOMNode() as HTMLInputElement).checked), - ).toEqual([true, false, false]); + expectMatchChecked(container, [true, false, false]); - wrapper.find(`.${prefixCls}-item-input`).at(2).simulate('change'); + fireEvent.click(container.querySelectorAll(`.${prefixCls}-item-input`)[2]); expect(handleValueChange).not.toBeCalled(); - expect( - wrapper - .find(`.${prefixCls}-item-input`) - .map(el => (el.getDOMNode() as HTMLInputElement).checked), - ).toEqual([true, false, false]); + expectMatchChecked(container, [true, false, false]); }); it('render segmented with className and other html attributes', () => { @@ -234,11 +206,11 @@ describe('Segmented', () => { it('render segmented with ref', () => { const ref = React.createRef(); - const wrapper = mount( + const { container } = render( , ); - expect((wrapper.find(Segmented).getElement() as any).ref).toBe(ref); + expect(ref.current).toBe(container.querySelector(`.${prefixCls}`)); }); it('render segmented with controlled mode', async () => { @@ -249,115 +221,124 @@ describe('Segmented', () => { render() { return ( - - this.setState({ - value, - }) - } - /> + <> + + this.setState({ + value, + }) + } + /> +
{this.state.value}
+ { + this.setState({ value: e.target.value }); + }} + /> + ); } } - const wrapper = mount(); - wrapper.find('Segmented').find(`.${prefixCls}-item-input`).at(0).simulate('change'); - expect(wrapper.find(Demo).state().value).toBe('Map'); + const { container } = render(); + fireEvent.click(container.querySelectorAll(`.${prefixCls}-item-input`)[0]); + expect(container.querySelector('.value')?.textContent).toBe('Map'); - wrapper.find('Segmented').find(`.${prefixCls}-item-input`).at(1).simulate('change'); - expect(wrapper.find(Demo).state().value).toBe('Transit'); + fireEvent.click(container.querySelectorAll(`.${prefixCls}-item-input`)[1]); + expect(container.querySelector('.value')?.textContent).toBe('Transit'); }); it('render segmented with options null/undefined', () => { const handleValueChange = jest.fn(); - const wrapper = mount( + const { asFragment, container } = render( handleValueChange(value)} />, ); - expect(wrapper.render()).toMatchSnapshot(); - expect(wrapper.find(`.${prefixCls}-item-label`).map(n => n.getDOMNode().textContent)).toEqual([ - '', - '', - '', - ]); + expect(asFragment().firstChild).toMatchSnapshot(); + expect( + Array.from(container.querySelectorAll(`.${prefixCls}-item-label`)).map(n => n.textContent), + ).toEqual(['', '', '']); }); it('render segmented with thumb', () => { const handleValueChange = jest.fn(); - const wrapper = mount( + const { asFragment, container } = render( handleValueChange(value)} />, ); - expect(wrapper.render()).toMatchSnapshot(); + expect(asFragment().firstChild).toMatchSnapshot(); + expectMatchChecked(container, [true, false, false]); expect( - wrapper - .find(`.${prefixCls}-item-input`) - .map(el => (el.getDOMNode() as HTMLInputElement).checked), - ).toEqual([true, false, false]); - expect( - wrapper.find(`label.${prefixCls}-item`).at(0).hasClass(`${prefixCls}-item-selected`), + container + .querySelectorAll(`label.${prefixCls}-item`)[0] + .classList.contains(`${prefixCls}-item-selected`), ).toBeTruthy(); - wrapper.find(`.${prefixCls}-item-input`).at(2).simulate('change'); + fireEvent.click(container.querySelectorAll(`.${prefixCls}-item-input`)[2]); expect(handleValueChange).toBeCalledWith('Satellite'); - expect( - wrapper - .find(`.${prefixCls}-item-input`) - .map(el => (el.getDOMNode() as HTMLInputElement).checked), - ).toEqual([false, false, true]); + expectMatchChecked(container, [false, false, true]); // thumb appeared - expect(wrapper.find(`.${prefixCls}-thumb`).length).toBe(1); + expect(container.querySelectorAll(`.${prefixCls}-thumb`).length).toBe(1); // change selection again - wrapper.find(`.${prefixCls}-item-input`).at(1).simulate('change'); + fireEvent.click(container.querySelectorAll(`.${prefixCls}-item-input`)[1]); expect(handleValueChange).toBeCalledWith('Transit'); - expect( - wrapper - .find(`.${prefixCls}-item-input`) - .map(el => (el.getDOMNode() as HTMLInputElement).checked), - ).toEqual([false, true, false]); + expectMatchChecked(container, [false, true, false]); // thumb appeared - expect(wrapper.find(`.${prefixCls}-thumb`).length).toBe(1); + expect(container.querySelectorAll(`.${prefixCls}-thumb`).length).toBe(1); }); it('render segmented with `block`', () => { - const wrapper = mount(); + const { asFragment, container } = render( + , + ); - expect(wrapper.render()).toMatchSnapshot(); + expect(asFragment().firstChild).toMatchSnapshot(); - expect(wrapper.find(`.${prefixCls}`).at(0).hasClass(`${prefixCls}-block`)).toBeTruthy(); + expect( + container.querySelectorAll(`.${prefixCls}`)[0].classList.contains(`${prefixCls}-block`), + ).toBeTruthy(); }); it('render segmented with `size#small`', () => { - const wrapper = mount(); + const { asFragment, container } = render( + , + ); - expect(wrapper.render()).toMatchSnapshot(); + expect(asFragment().firstChild).toMatchSnapshot(); - expect(wrapper.find(`.${prefixCls}`).at(0).hasClass(`${prefixCls}-sm`)).toBeTruthy(); + expect( + container.querySelectorAll(`.${prefixCls}`)[0].classList.contains(`${prefixCls}-sm`), + ).toBeTruthy(); }); it('render segmented with `size#large`', () => { - const wrapper = mount(); + const { asFragment, container } = render( + , + ); - expect(wrapper.render()).toMatchSnapshot(); + expect(asFragment().firstChild).toMatchSnapshot(); - expect(wrapper.find(`.${prefixCls}`).at(0).hasClass(`${prefixCls}-lg`)).toBeTruthy(); + expect( + container.querySelectorAll(`.${prefixCls}`)[0].classList.contains(`${prefixCls}-lg`), + ).toBeTruthy(); }); it('render with icons', () => { - const wrapper = mount( + const { asFragment, container } = render( { ]} />, ); - expect(wrapper.render()).toMatchSnapshot(); - expect(wrapper.find(`span.${prefixCls}-item-icon`).length).toBe(2); - expect(wrapper.find(`div.${prefixCls}-item-label`).at(1).contains('KanbanYes')).toBeTruthy(); + expect(asFragment().firstChild).toMatchSnapshot(); + expect(container.querySelectorAll(`span.${prefixCls}-item-icon`).length).toBe(2); + expect( + container + .querySelectorAll(`div.${prefixCls}-item-label`)[1] + .textContent?.includes('KanbanYes'), + ).toBeTruthy(); }); }); From 58df74c38e5ab223f69940db30af47631e74aeac Mon Sep 17 00:00:00 2001 From: dingkang Date: Sat, 14 May 2022 16:40:42 +0800 Subject: [PATCH 3/5] docs: replace class component with hooks (#35519) * docs(badge): replace class component with hooks * docs(button): replace class component with hooks * docs(calendar): replace class component with hooks * docs(card): replace class component with hooks * docs(button): replace class component with hooks * chore(deps): remove webpack devDependencies * docs(cascader): replace class component with hooks * docs(checkbox): replace class component with hooks * docs(collapse): replace class component with hooks * docs(comment): replace class component with hooks * docs(descriptions): replace class component with hooks * docs(config-provider): replace class component with hooks * docs(date-picker): replace class component with hooks * docs(drawer): replace class component with hooks * docs(dropdown): replace class component with hooks * docs(dropdown): replace class component with hooks * docs(empty): replace class component with hooks * docs(grid): replace class component with hooks * docs(input): replace class component with hooks * docs(input-number): replace class component with hooks * docs(demo): fix lint error --- components/drawer/demo/form-in-drawer.md | 258 +++++++++--------- components/drawer/demo/multi-level-drawer.md | 79 +++--- components/drawer/demo/placement.md | 84 +++--- components/drawer/demo/render-in-current.md | 62 ++--- components/drawer/demo/user-profile.md | 266 +++++++++---------- components/dropdown/demo/loading.md | 80 +++--- components/dropdown/demo/overlay-visible.md | 81 +++--- components/empty/demo/config-provider.md | 99 ++++--- components/grid/demo/playground.md | 141 +++++----- components/input-number/demo/disabled.md | 40 ++- components/input/demo/autosize-textarea.md | 55 ++-- components/input/demo/textarea-resize.md | 35 +-- components/input/demo/tooltip.md | 78 +++--- 13 files changed, 621 insertions(+), 737 deletions(-) diff --git a/components/drawer/demo/form-in-drawer.md b/components/drawer/demo/form-in-drawer.md index 821842a87c..a79cecffee 100644 --- a/components/drawer/demo/form-in-drawer.md +++ b/components/drawer/demo/form-in-drawer.md @@ -19,144 +19,136 @@ import { PlusOutlined } from '@ant-design/icons'; const { Option } = Select; -class DrawerForm extends React.Component { - state = { visible: false }; +export default () => { + const [visible, setVisible] = React.useState(false); - showDrawer = () => { - this.setState({ - visible: true, - }); + const showDrawer = () => { + setVisible(true); }; - onClose = () => { - this.setState({ - visible: false, - }); + const onClose = () => { + setVisible(false); }; - render() { - return ( - <> - - - - - - } - > -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - trigger.parentElement} - /> - - - - - - - - - - -
-
- - ); - } -} - -export default () => ; + return ( + <> + + + + + + } + > +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + trigger.parentElement} + /> + + + + + + + + + + +
+
+ + ); +}; ``` ```css diff --git a/components/drawer/demo/multi-level-drawer.md b/components/drawer/demo/multi-level-drawer.md index f1be8f443c..63844c4568 100644 --- a/components/drawer/demo/multi-level-drawer.md +++ b/components/drawer/demo/multi-level-drawer.md @@ -16,65 +16,54 @@ Open a new drawer on top of an existing drawer to handle multi branch tasks. ```jsx import { Drawer, Button } from 'antd'; -class App extends React.Component { - state = { visible: false, childrenDrawer: false }; +export default () => { + const [visible, setVisible] = React.useState(false); + const [childrenDrawer, setChildrenDrawer] = React.useState(false); - showDrawer = () => { - this.setState({ - visible: true, - }); + const showDrawer = () => { + setVisible(true); }; - onClose = () => { - this.setState({ - visible: false, - }); + const onClose = () => { + setVisible(false); }; - showChildrenDrawer = () => { - this.setState({ - childrenDrawer: true, - }); + const showChildrenDrawer = () => { + setChildrenDrawer(true); }; - onChildrenDrawerClose = () => { - this.setState({ - childrenDrawer: false, - }); + const onChildrenDrawerClose = () => { + setChildrenDrawer(false); }; - render() { - return ( - <> - + + - - - This is two-level drawer - + This is two-level drawer - - ); - } -} - -export default App; + + + ); +}; ```