From f2a5d2f8814b945236a7b515cfc68a4106eb6529 Mon Sep 17 00:00:00 2001 From: muxin Date: Fri, 10 Jun 2022 17:58:58 +0800 Subject: [PATCH 01/20] fix: Button has no disabled style when link type (#35975) Co-authored-by: MadCcc <1075746765@qq.com> --- components/button/__tests__/index.test.tsx | 9 +++++++++ components/button/button.tsx | 4 +++- components/button/style/index.less | 4 ++++ components/button/style/mixin.less | 18 ++++++++++++++++++ 4 files changed, 34 insertions(+), 1 deletion(-) diff --git a/components/button/__tests__/index.test.tsx b/components/button/__tests__/index.test.tsx index 06de4e4609..207eb8f5b3 100644 --- a/components/button/__tests__/index.test.tsx +++ b/components/button/__tests__/index.test.tsx @@ -328,6 +328,15 @@ describe('Button', () => { expect(onClick).not.toHaveBeenCalled(); }); + it('should match class .ant-btn-disabled when button is disabled and href is not undefined', () => { + const wrapper = render( + , + ); + expect(wrapper.container.querySelector('.ant-btn')).toHaveClass('ant-btn-disabled'); + }); + // https://github.com/ant-design/ant-design/issues/30953 it('should handle fragment as children', () => { const wrapper = render( diff --git a/components/button/button.tsx b/components/button/button.tsx index b4b33c9b70..1b36082dfd 100644 --- a/components/button/button.tsx +++ b/components/button/button.tsx @@ -247,6 +247,8 @@ const InternalButton: React.ForwardRefRenderFunction = (pr const iconType = innerLoading ? 'loading' : icon; + const linkButtonRestProps = omit(rest as AnchorButtonProps & { navigate: any }, ['navigate']); + const classes = classNames( prefixCls, { @@ -260,6 +262,7 @@ const InternalButton: React.ForwardRefRenderFunction = (pr [`${prefixCls}-block`]: block, [`${prefixCls}-dangerous`]: !!danger, [`${prefixCls}-rtl`]: direction === 'rtl', + [`${prefixCls}-disabled`]: linkButtonRestProps.href !== undefined && mergedDisabled, }, className, ); @@ -276,7 +279,6 @@ const InternalButton: React.ForwardRefRenderFunction = (pr ? spaceChildren(children, isNeedInserted() && autoInsertSpace) : null; - const linkButtonRestProps = omit(rest as AnchorButtonProps & { navigate: any }, ['navigate']); if (linkButtonRestProps.href !== undefined) { return ( diff --git a/components/button/style/index.less b/components/button/style/index.less index cdb67c8d0e..43ccba54dc 100644 --- a/components/button/style/index.less +++ b/components/button/style/index.less @@ -278,6 +278,10 @@ a.@{btn-prefix-cls} { padding-top: 0.01px !important; line-height: @btn-height-base - 2px; + &-disabled { + .btn-href-disabled(); + } + &-lg { line-height: @btn-height-lg - 2px; } diff --git a/components/button/style/mixin.less b/components/button/style/mixin.less index 084ecaa5bf..04037fd70f 100644 --- a/components/button/style/mixin.less +++ b/components/button/style/mixin.less @@ -385,6 +385,24 @@ } .button-disabled(@disabled-color; transparent; transparent); } +// link button disabled style +.btn-href-disabled() { + cursor: not-allowed; + + > * { + pointer-events: none; + } + + &, + &:hover, + &:focus, + &:active { + .button-color(@btn-disable-color,transparent, transparent); + + text-shadow: none; + box-shadow: none; + } +} // text button style .btn-text() { .button-variant-other(@text-color, transparent, transparent); From a86feb702e94ba418bc454dad3af425334e1e344 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8B=AF=E8=8B=AF?= <91561865+robothot@users.noreply.github.com> Date: Fri, 10 Jun 2022 17:59:26 +0800 Subject: [PATCH 02/20] fix: `DropdownProps` definition (#35990) Co-authored-by: jhonebee Co-authored-by: MadCcc <1075746765@qq.com> --- components/dropdown/dropdown.tsx | 1 + 1 file changed, 1 insertion(+) diff --git a/components/dropdown/dropdown.tsx b/components/dropdown/dropdown.tsx index 74a0a9aab7..bf03a3a495 100644 --- a/components/dropdown/dropdown.tsx +++ b/components/dropdown/dropdown.tsx @@ -44,6 +44,7 @@ export type DropdownArrowOptions = { }; export interface DropdownProps { + autoFocus?: boolean arrow?: boolean | DropdownArrowOptions; trigger?: ('click' | 'hover' | 'contextMenu')[]; overlay: React.ReactElement | OverlayFunc; From 9ddde89d4d80fd75679f4ec26bb4d67bc91b9e78 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Jun 2022 20:11:15 +0800 Subject: [PATCH 03/20] chore(deps-dev): bump stylelint from 14.8.3 to 14.9.0 (#35998) Bumps [stylelint](https://github.com/stylelint/stylelint) from 14.8.3 to 14.9.0. - [Release notes](https://github.com/stylelint/stylelint/releases) - [Changelog](https://github.com/stylelint/stylelint/blob/main/CHANGELOG.md) - [Commits](https://github.com/stylelint/stylelint/compare/14.8.3...14.9.0) --- updated-dependencies: - dependency-name: stylelint dependency-type: direct:development update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 66ce00c449..ad6bdb479d 100644 --- a/package.json +++ b/package.json @@ -282,7 +282,7 @@ "scrollama": "^3.0.0", "semver": "^7.3.5", "simple-git": "^3.0.0", - "stylelint": "14.8.3", + "stylelint": "14.9.0", "stylelint-config-prettier": "^9.0.2", "stylelint-config-rational-order": "^0.1.2", "stylelint-config-standard": "^25.0.0", From c7aa754efebddbebbfc446eccd8c4d1fc2ce3387 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E6=9C=BA=E5=99=A8=E4=BA=BA?= Date: Fri, 10 Jun 2022 20:35:28 +0800 Subject: [PATCH 04/20] chore: update ts config (#36000) --- components/auto-complete/__tests__/index.test.js | 4 ++-- tsconfig.json | 4 +++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/components/auto-complete/__tests__/index.test.js b/components/auto-complete/__tests__/index.test.js index d8181eac37..7686e70722 100644 --- a/components/auto-complete/__tests__/index.test.js +++ b/components/auto-complete/__tests__/index.test.js @@ -1,9 +1,9 @@ import React from 'react'; -import { render, fireEvent } from '../../../tests/utils'; import AutoComplete from '..'; -import Input from '../../input'; import mountTest from '../../../tests/shared/mountTest'; import rtlTest from '../../../tests/shared/rtlTest'; +import { fireEvent, render } from '../../../tests/utils'; +import Input from '../../input'; describe('AutoComplete', () => { mountTest(AutoComplete); diff --git a/tsconfig.json b/tsconfig.json index f594bea7bc..987d53ff4e 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -10,7 +10,9 @@ "moduleResolution": "node", "esModuleInterop": true, "experimentalDecorators": true, - "jsx": "preserve", + "jsx": "react", + "jsxFactory": "React.createElement", + "jsxFragmentFactory": "React.Fragment", "noUnusedParameters": true, "noUnusedLocals": true, "noImplicitAny": true, From c7638a92944c973df699e0b28b3448c4d57261f6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8B=AF=E8=8B=AF?= <91561865+robothot@users.noreply.github.com> Date: Sat, 11 Jun 2022 13:54:50 +0800 Subject: [PATCH 05/20] fix: Fixed the getContainer property in Image not reading the settings in ConfigProvider (#36002) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: 35942 * test: 添加测试用例 * fix: * fix: --- components/image/__tests__/index.test.js | 16 +++++++++++++++- components/image/index.tsx | 12 +++++++++--- 2 files changed, 24 insertions(+), 4 deletions(-) diff --git a/components/image/__tests__/index.test.js b/components/image/__tests__/index.test.js index 91093149ed..873be7e01b 100644 --- a/components/image/__tests__/index.test.js +++ b/components/image/__tests__/index.test.js @@ -1,8 +1,9 @@ import React from 'react'; -import { render, fireEvent } from '../../../tests/utils'; import Image from '..'; import mountTest from '../../../tests/shared/mountTest'; import rtlTest from '../../../tests/shared/rtlTest'; +import { fireEvent, render } from '../../../tests/utils'; +import ConfigProvider from '../../config-provider'; const src = 'https://zos.alipayobjects.com/rmsportal/jkjgkEfvpUPVyRjUImniVslZfWPnJuuZ.png'; @@ -76,4 +77,17 @@ describe('Image', () => { expect(baseElement.querySelector('.ant-image-preview')).toHaveClass('abc'); expect(baseElement.querySelector('.ant-image-preview-mask')).toHaveClass('def'); }); + it('ConfigProvider getPopupContainer', () => { + const { container: wrapper, baseElement } = render( + <> +
+ document.querySelector('.container')}> + + + , + ); + fireEvent.click(wrapper.querySelector('.ant-image')); + const containerElement = baseElement.querySelector('.container'); + expect(containerElement.children.length).not.toBe(0); + }); }); diff --git a/components/image/index.tsx b/components/image/index.tsx index 17405cfc5e..f62b00cf3c 100644 --- a/components/image/index.tsx +++ b/components/image/index.tsx @@ -16,7 +16,12 @@ const Image: CompositionImage = ({ preview, ...otherProps }) => { - const { getPrefixCls, locale: contextLocale = defaultLocale } = useContext(ConfigContext); + const { + getPrefixCls, + locale: contextLocale = defaultLocale, + getPopupContainer: getContextPopupContainer, + } = useContext(ConfigContext); + const prefixCls = getPrefixCls('image', customizePrefixCls); const rootPrefixCls = getPrefixCls(); @@ -27,7 +32,7 @@ const Image: CompositionImage = ({ return preview; } const _preview = typeof preview === 'object' ? preview : {}; - + const { getContainer, ...restPreviewProps } = _preview; return { mask: (
@@ -36,7 +41,8 @@ const Image: CompositionImage = ({
), icons, - ..._preview, + ...restPreviewProps, + getContainer: getContainer || getContextPopupContainer, transitionName: getTransitionName(rootPrefixCls, 'zoom', _preview.transitionName), maskTransitionName: getTransitionName(rootPrefixCls, 'fade', _preview.maskTransitionName), }; From 961383fa0ce460fd72295b9254ac19d467bc67e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E8=8B=AF=E8=8B=AF?= <91561865+robothot@users.noreply.github.com> Date: Sat, 11 Jun 2022 15:10:03 +0800 Subject: [PATCH 06/20] fix: missing semicolon (#36008) --- components/dropdown/dropdown.tsx | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/components/dropdown/dropdown.tsx b/components/dropdown/dropdown.tsx index bf03a3a495..e28a3d67fd 100644 --- a/components/dropdown/dropdown.tsx +++ b/components/dropdown/dropdown.tsx @@ -1,15 +1,15 @@ -import * as React from 'react'; -import RcDropdown from 'rc-dropdown'; -import classNames from 'classnames'; import RightOutlined from '@ant-design/icons/RightOutlined'; -import DropdownButton from './dropdown-button'; +import classNames from 'classnames'; +import RcDropdown from 'rc-dropdown'; +import * as React from 'react'; import { ConfigContext } from '../config-provider'; -import warning from '../_util/warning'; -import { tuple } from '../_util/type'; -import { cloneElement } from '../_util/reactNode'; -import getPlacements from '../_util/placements'; -import OverrideContext from '../menu/OverrideContext'; import type { OverrideContextProps } from '../menu/OverrideContext'; +import OverrideContext from '../menu/OverrideContext'; +import getPlacements from '../_util/placements'; +import { cloneElement } from '../_util/reactNode'; +import { tuple } from '../_util/type'; +import warning from '../_util/warning'; +import DropdownButton from './dropdown-button'; const Placements = tuple( 'topLeft', @@ -44,7 +44,7 @@ export type DropdownArrowOptions = { }; export interface DropdownProps { - autoFocus?: boolean + autoFocus?: boolean; arrow?: boolean | DropdownArrowOptions; trigger?: ('click' | 'hover' | 'contextMenu')[]; overlay: React.ReactElement | OverlayFunc; From e9630608fe62656fac3fb8ceba6a349f28becaff Mon Sep 17 00:00:00 2001 From: afc163 Date: Sat, 11 Jun 2022 15:16:06 +0800 Subject: [PATCH 07/20] Update package.json --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index ad6bdb479d..3880e4e0a9 100644 --- a/package.json +++ b/package.json @@ -282,7 +282,7 @@ "scrollama": "^3.0.0", "semver": "^7.3.5", "simple-git": "^3.0.0", - "stylelint": "14.9.0", + "stylelint": "^14.9.0", "stylelint-config-prettier": "^9.0.2", "stylelint-config-rational-order": "^0.1.2", "stylelint-config-standard": "^25.0.0", From f93480a61d6e111c566c32c3349de79d1f82bbe3 Mon Sep 17 00:00:00 2001 From: Taisuke Hinata Date: Sun, 12 Jun 2022 19:29:40 +0900 Subject: [PATCH 08/20] docs: fix onChange description repeated twice (#36013) --- components/auto-complete/index.en-US.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/auto-complete/index.en-US.md b/components/auto-complete/index.en-US.md index ada53bfa10..b8963850b0 100644 --- a/components/auto-complete/index.en-US.md +++ b/components/auto-complete/index.en-US.md @@ -41,7 +41,7 @@ The differences with Select are: | status | Set validation status | 'error' \| 'warning' | - | 4.19.0 | | value | Selected option | string | - | | | onBlur | Called when leaving the component | function() | - | | -| onChange | Called when select an option or input value change, or value of input is changed | function(value) | - | | +| onChange | Called when selecting an option or changing an input value | function(value) | - | | | onDropdownVisibleChange | Call when dropdown open | function(open) | - | | | onFocus | Called when entering the component | function() | - | | | onSearch | Called when searching items | function(value) | - | | From e1a6241519c4730655f2efaae29495f28c8902e1 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Sun, 12 Jun 2022 20:44:55 +0800 Subject: [PATCH 09/20] chore(deps): update dependency stylelint-config-standard to v26 (#36017) * chore(deps): update dependency stylelint-config-standard to v26 * chore: ignore selector-not-notation rule Co-authored-by: Renovate Bot Co-authored-by: afc163 --- .stylelintrc.json | 3 ++- package.json | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.stylelintrc.json b/.stylelintrc.json index 3ee014415a..89e5943dab 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -37,7 +37,8 @@ "alpha-value-notation": "number", "color-function-notation": "legacy", "selector-class-pattern": null, - "selector-id-pattern": null + "selector-id-pattern": null, + "selector-not-notation": null }, "ignoreFiles": ["components/style/color/{bezierEasing,colorPalette,tinyColor}.less"] } diff --git a/package.json b/package.json index 3880e4e0a9..69dff97d47 100644 --- a/package.json +++ b/package.json @@ -285,7 +285,7 @@ "stylelint": "^14.9.0", "stylelint-config-prettier": "^9.0.2", "stylelint-config-rational-order": "^0.1.2", - "stylelint-config-standard": "^25.0.0", + "stylelint-config-standard": "^26.0.0", "stylelint-declaration-block-no-ignored-properties": "^2.1.0", "stylelint-order": "^5.0.0", "theme-switcher": "^1.0.2", From 3f822ac43f03e8731de38f9d851bc06a224b4044 Mon Sep 17 00:00:00 2001 From: Yuki Zhang Date: Mon, 13 Jun 2022 09:05:49 +0800 Subject: [PATCH 10/20] test: move test cases to testing lib for Statistic (#36019) Co-authored-by: afc163 --- .../{demo.test.js.snap => demo.test.ts.snap} | 0 ...index.test.js.snap => index.test.tsx.snap} | 0 .../__tests__/{demo.test.js => demo.test.ts} | 0 .../{index.test.js => index.test.tsx} | 117 ++++++++++-------- 4 files changed, 67 insertions(+), 50 deletions(-) rename components/statistic/__tests__/__snapshots__/{demo.test.js.snap => demo.test.ts.snap} (100%) rename components/statistic/__tests__/__snapshots__/{index.test.js.snap => index.test.tsx.snap} (100%) rename components/statistic/__tests__/{demo.test.js => demo.test.ts} (100%) rename components/statistic/__tests__/{index.test.js => index.test.tsx} (51%) diff --git a/components/statistic/__tests__/__snapshots__/demo.test.js.snap b/components/statistic/__tests__/__snapshots__/demo.test.ts.snap similarity index 100% rename from components/statistic/__tests__/__snapshots__/demo.test.js.snap rename to components/statistic/__tests__/__snapshots__/demo.test.ts.snap diff --git a/components/statistic/__tests__/__snapshots__/index.test.js.snap b/components/statistic/__tests__/__snapshots__/index.test.tsx.snap similarity index 100% rename from components/statistic/__tests__/__snapshots__/index.test.js.snap rename to components/statistic/__tests__/__snapshots__/index.test.tsx.snap diff --git a/components/statistic/__tests__/demo.test.js b/components/statistic/__tests__/demo.test.ts similarity index 100% rename from components/statistic/__tests__/demo.test.js rename to components/statistic/__tests__/demo.test.ts diff --git a/components/statistic/__tests__/index.test.js b/components/statistic/__tests__/index.test.tsx similarity index 51% rename from components/statistic/__tests__/index.test.js rename to components/statistic/__tests__/index.test.tsx index abd47d69d8..46fc6a0763 100644 --- a/components/statistic/__tests__/index.test.js +++ b/components/statistic/__tests__/index.test.tsx @@ -1,11 +1,10 @@ import React from 'react'; import MockDate from 'mockdate'; import moment from 'moment'; -import { mount } from 'enzyme'; -import { fireEvent, render } from '@testing-library/react'; import Statistic from '..'; +import type Countdown from '../Countdown'; import { formatTimeStr } from '../utils'; -import { sleep } from '../../../tests/utils'; +import { sleep, render, fireEvent } from '../../../tests/utils'; import mountTest from '../../../tests/shared/mountTest'; import rtlTest from '../../../tests/shared/rtlTest'; @@ -23,63 +22,69 @@ describe('Statistic', () => { }); it('`-` is not a number', () => { - const wrapper = mount(); - expect(wrapper.find('.ant-statistic-content').text()).toEqual('-'); + const { container } = render(); + expect(container.querySelector('.ant-statistic-content')!.textContent).toEqual('-'); }); it('customize formatter', () => { const formatter = jest.fn(() => 93); - const wrapper = mount(); + const { container } = render(); expect(formatter).toHaveBeenCalledWith(1128); - expect(wrapper.find('.ant-statistic-content-value').text()).toEqual('93'); + expect(container.querySelector('.ant-statistic-content-value')!.textContent).toEqual('93'); }); it('groupSeparator', () => { - const wrapper = mount(); - expect(wrapper.find('.ant-statistic-content-value').text()).toEqual('1__TEST__128'); + const { container } = render(); + expect(container.querySelector('.ant-statistic-content-value')!.textContent).toEqual( + '1__TEST__128', + ); }); it('not a number', () => { - const wrapper = mount(); - expect(wrapper.find('.ant-statistic-content-value').text()).toEqual('bamboo'); + const { container } = render(); + expect(container.querySelector('.ant-statistic-content-value')!.textContent).toEqual('bamboo'); }); it('support negetive number', () => { - const wrapper = mount( + const { asFragment } = render( , ); - expect(wrapper.render()).toMatchSnapshot(); + expect(asFragment().firstChild).toMatchSnapshot(); }); it('allow negetive precision', () => { [ [-1, -1112893.1212, '-1,112,893'], [-2, -1112893.1212, '-1,112,893'], - [-3, -1112893.1212, '-1,112,893'], - [-1, -1112893, '-1,112,893'], - [-1, 1112893, '1,112,893'], - ].forEach(([precision, value, expectValue]) => { - const wrapper = mount(); - expect(wrapper.find('.ant-statistic-content-value-int').text()).toEqual(expectValue); - expect(wrapper.find('.ant-statistic-content-value-decimal').length).toBe(0); - }) + [-3, -1112893.1212, '-1,112,893'], + [-1, -1112893, '-1,112,893'], + [-1, 1112893, '1,112,893'], + ].forEach(([precision, value, expectValue]: [number, number, string]) => { + const { container } = render(); + expect(container.querySelector('.ant-statistic-content-value-int')!.textContent).toEqual( + expectValue, + ); + expect(container.querySelectorAll('.ant-statistic-content-value-decimal').length).toBe(0); + }); }); it('loading with skeleton', async () => { let loading = false; - const wrapper = mount(); - expect(wrapper.find('.ant-skeleton')).toHaveLength(0); - expect(wrapper.find('.ant-statistic-content')).toHaveLength(1); + const { container, rerender } = render( + , + ); + expect(container.querySelectorAll('.ant-skeleton')).toHaveLength(0); + expect(container.querySelectorAll('.ant-statistic-content')).toHaveLength(1); loading = true; - wrapper.setProps({ loading }); - expect(wrapper.find('.ant-skeleton')).toHaveLength(1); - expect(wrapper.find('.ant-statistic-content')).toHaveLength(0); + rerender(); + expect(container.querySelectorAll('.ant-skeleton')).toHaveLength(1); + expect(container.querySelectorAll('.ant-statistic-content')).toHaveLength(0); }); describe('Countdown', () => { it('render correctly', () => { - const now = moment().add(2, 'd').add(11, 'h').add(28, 'm').add(9, 's').add(3, 'ms'); + const now = moment().add(2, 'd').add(11, 'h').add(28, 'm').add(9, 's').add(3, 'ms').valueOf(); [ ['H:m:s', '59:28:9'], @@ -87,25 +92,31 @@ describe('Statistic', () => { ['HH:mm:ss:SSS', '59:28:09:003'], ['DD-HH:mm:ss', '02-11:28:09'], ].forEach(([format, value]) => { - const wrapper = mount(); - expect(wrapper.find('.ant-statistic-content-value').text()).toEqual(value); + const { container } = render(); + expect(container.querySelector('.ant-statistic-content-value')!.textContent).toEqual(value); }); }); it('time going', async () => { const now = Date.now() + 1000; const onFinish = jest.fn(); - const wrapper = mount(); - wrapper.update(); + let instance: Countdown | null; + const { unmount } = render( + { + instance = n; + }} + value={now} + onFinish={onFinish} + />, + ); // setInterval should work - const instance = wrapper.find('Countdown').instance(); - expect(instance.countdownId).not.toBe(undefined); + expect(instance!.countdownId).not.toBe(undefined); await sleep(10); - wrapper.unmount(); - expect(instance.countdownId).toBe(undefined); + unmount(); expect(onFinish).not.toHaveBeenCalled(); }); @@ -115,21 +126,21 @@ describe('Statistic', () => { const { container } = render( , ); - fireEvent.mouseEnter(container.firstChild); + fireEvent.mouseEnter(container.firstChild!); expect(onMouseEnter).toHaveBeenCalled(); - fireEvent.mouseLeave(container.firstChild); + fireEvent.mouseLeave(container.firstChild!); expect(onMouseLeave).toHaveBeenCalled(); }); it('responses hover events for Countdown', () => { const onMouseEnter = jest.fn(); const onMouseLeave = jest.fn(); - const wrapper = mount( + const { container } = render( , ); - wrapper.simulate('mouseenter'); + fireEvent.mouseEnter(container.firstChild!); expect(onMouseEnter).toHaveBeenCalled(); - wrapper.simulate('mouseleave'); + fireEvent.mouseLeave(container.firstChild!); expect(onMouseLeave).toHaveBeenCalled(); }); @@ -138,11 +149,11 @@ describe('Statistic', () => { const deadline = Date.now() + 10 * 1000; let remainingTime; - const onChange = value => { + const onChange = (value: number) => { remainingTime = value; }; - const wrapper = mount(); - wrapper.update(); + render(); + // container.update(); await sleep(100); expect(remainingTime).toBeGreaterThan(0); }); @@ -151,20 +162,26 @@ describe('Statistic', () => { describe('time finished', () => { it('not call if time already passed', () => { const now = Date.now() - 1000; - + let instance: Countdown | null; const onFinish = jest.fn(); - const wrapper = mount(); - wrapper.update(); + render( + { + instance = n; + }} + value={now} + onFinish={onFinish} + />, + ); - expect(wrapper.find('Countdown').instance().countdownId).toBe(undefined); + expect(instance!.countdownId).toBe(undefined); expect(onFinish).not.toHaveBeenCalled(); }); it('called if finished', async () => { const now = Date.now() + 10; const onFinish = jest.fn(); - const wrapper = mount(); - wrapper.update(); + render(); MockDate.set(moment('2019-11-28 00:00:00').valueOf()); await sleep(100); expect(onFinish).toHaveBeenCalled(); From 52b049d17049d38315880a1c6f73f651d5430d77 Mon Sep 17 00:00:00 2001 From: dingkang Date: Mon, 13 Jun 2022 11:26:16 +0800 Subject: [PATCH 11/20] test: replace Table part test with test lib (#35989) * test: replace Table part test with test lib * test: replace table test with test library * test: update snapshot * test: replace last mount * test: fix 18 testing Co-authored-by: zombiej --- components/form/FormList.tsx | 2 +- .../__tests__/Table.rowSelection.test.js | 877 ++++++++++-------- .../Table.rowSelection.test.js.snap | 55 +- 3 files changed, 538 insertions(+), 396 deletions(-) diff --git a/components/form/FormList.tsx b/components/form/FormList.tsx index 9b361e4bc5..d69436fcc3 100644 --- a/components/form/FormList.tsx +++ b/components/form/FormList.tsx @@ -9,7 +9,7 @@ export interface FormListFieldData { name: number; key: number; /** @deprecated No need anymore Use key instead */ - fieldKey?:number + fieldKey?: number; } export interface FormListOperation { diff --git a/components/table/__tests__/Table.rowSelection.test.js b/components/table/__tests__/Table.rowSelection.test.js index 2e7dd11a12..7877ffd26d 100644 --- a/components/table/__tests__/Table.rowSelection.test.js +++ b/components/table/__tests__/Table.rowSelection.test.js @@ -1,11 +1,9 @@ import React from 'react'; import { act } from 'react-dom/test-utils'; -import { mount } from 'enzyme'; import Table from '..'; -import Checkbox from '../../checkbox'; -import { resetWarned } from '../../_util/warning'; +import { fireEvent, render } from '../../../tests/utils'; import ConfigProvider from '../../config-provider'; -import { render } from '../../../tests/utils'; +import { resetWarned } from '../../_util/warning'; describe('Table.rowSelection', () => { window.requestAnimationFrame = callback => window.setTimeout(callback, 16); @@ -39,80 +37,88 @@ describe('Table.rowSelection', () => { return ; } - function renderedNames(wrapper) { - return wrapper.find('BodyRow').map(row => row.props().record.name); + function renderedNames(contain) { + const namesList = []; + contain + .querySelector('.ant-table-tbody') + .querySelectorAll('tr') + .forEach(tr => { + namesList.push(tr.querySelectorAll('td')[1].textContent); + }); + return namesList; } - function getSelections(wrapper) { - return wrapper - .find('BodyRow') - .map(row => { - const { key } = row.props().record; - if (!row.find('input').at(0).props().checked) { - return null; + function getSelections(container) { + const keys = []; + container.querySelectorAll('.ant-table-tbody tr').forEach(row => { + const key = row.getAttribute('data-row-key'); + if (row.querySelector('input').checked) { + if (isNaN(Number(key))) { + // rowKey + keys.push(key); + } else { + keys.push(Number(key)); } - - return key; - }) - .filter(key => key !== null); + } + }); + return keys; } - function getIndeterminateSelection(wrapper) { - return wrapper - .find('BodyRow') - .map(row => { - const { key } = row.props().record; - if (!row.find('Checkbox').at(0).props().indeterminate) { - return null; + function getIndeterminateSelection(container) { + const keys = []; + container.querySelectorAll('.ant-table-tbody tr').forEach(row => { + const key = row.getAttribute('data-row-key'); + if (row.querySelector('.ant-checkbox-indeterminate')) { + if (isNaN(Number(key))) { + // rowKey + keys.push(key); + } else { + keys.push(Number(key)); } - - return key; - }) - .filter(key => key !== null); + } + }); + return keys; } it('select default row', () => { - const wrapper = mount(createTable({ rowSelection: { defaultSelectedRowKeys: [0] } })); - const checkboxes = wrapper.find('input'); + const { container } = render(createTable({ rowSelection: { defaultSelectedRowKeys: [0] } })); + const checkboxes = container.querySelectorAll('input[type="checkbox"]'); + expect(getSelections(container)).toEqual([0]); - expect(getSelections(wrapper)).toEqual([0]); + fireEvent.click(checkboxes[1]); + expect(getSelections(container)).toEqual([]); - checkboxes.at(1).simulate('change', { target: { checked: false } }); - expect(getSelections(wrapper)).toEqual([]); + fireEvent.click(checkboxes[0]); + expect(getSelections(container)).toEqual([0, 1, 2, 3]); - checkboxes.at(0).simulate('change', { target: { checked: true } }); - expect(getSelections(wrapper)).toEqual([0, 1, 2, 3]); - - checkboxes.at(0).simulate('change', { target: { checked: false } }); - expect(getSelections(wrapper)).toEqual([]); + fireEvent.click(checkboxes[0]); + expect(getSelections(container)).toEqual([]); }); it('select by checkbox', () => { - const wrapper = mount(createTable()); - const checkboxes = wrapper.find('input'); - const checkboxAll = checkboxes.first(); + const { container } = render(createTable()); + const checkboxes = container.querySelectorAll('input[type="checkbox"]'); - checkboxAll.simulate('change', { target: { checked: true } }); - expect(getSelections(wrapper)).toEqual([0, 1, 2, 3]); + fireEvent.click(checkboxes[0]); + expect(getSelections(container)).toEqual([0, 1, 2, 3]); - checkboxes.at(1).simulate('change', { target: { checked: false } }); - expect(getSelections(wrapper)).toEqual([1, 2, 3]); + fireEvent.click(checkboxes[1]); + expect(getSelections(container)).toEqual([1, 2, 3]); - checkboxes.at(1).simulate('change', { target: { checked: true } }); - expect(getSelections(wrapper)).toEqual([0, 1, 2, 3]); + fireEvent.click(checkboxes[1]); + expect(getSelections(container)).toEqual([0, 1, 2, 3]); }); it('select by radio', () => { - const wrapper = mount(createTable({ rowSelection: { type: 'radio' } })); - const radios = wrapper.find('input'); + const { container } = render(createTable({ rowSelection: { type: 'radio' } })); + const radios = container.querySelectorAll('input[type="radio"]'); expect(radios.length).toBe(4); - radios.first().simulate('click'); - radios.first().simulate('change', { target: { checked: true } }); - expect(getSelections(wrapper)).toEqual([0]); + fireEvent.click(radios[0]); + expect(getSelections(container)).toEqual([0]); - radios.last().simulate('change', { target: { checked: true } }); - expect(getSelections(wrapper)).toEqual([3]); + fireEvent.click(radios[radios.length - 1]); + expect(getSelections(container)).toEqual([3]); }); it('pass getCheckboxProps to checkbox', () => { @@ -124,15 +130,15 @@ describe('Table.rowSelection', () => { }), }; - const wrapper = mount(createTable({ rowSelection })); - const checkboxes = wrapper.find('input'); + const { container } = render(createTable({ rowSelection })); + const checkboxes = container.querySelectorAll('input[type="checkbox"]'); - expect(checkboxes.at(1).props().disabled).toBe(false); - expect(checkboxes.at(1).props().name).toEqual(data[0].name); - expect(checkboxes.at(2).props().disabled).toBe(true); - expect(checkboxes.at(2).props().name).toEqual(data[1].name); + expect(checkboxes[1].disabled).toBe(false); + expect(checkboxes[1].name).toEqual(data[0].name); + expect(checkboxes[2].disabled).toBe(true); + expect(checkboxes[2].name).toEqual(data[1].name); - expect(getIndeterminateSelection(wrapper)).toEqual([2]); + expect(getIndeterminateSelection(container)).toEqual([2]); }); it("make getCheckboxProps's `indeterminate` override selectedRowKeys' effect", () => { @@ -145,31 +151,31 @@ describe('Table.rowSelection', () => { selectedRowKeys: [2], }; - const wrapper = mount(createTable({ rowSelection })); - expect(getIndeterminateSelection(wrapper)).toEqual([2]); + const { container } = render(createTable({ rowSelection })); + expect(getIndeterminateSelection(container)).toEqual([2]); }); it('works with pagination', () => { - const wrapper = mount(createTable({ pagination: { pageSize: 2 } })); - const pagers = wrapper.find('Pager'); + const { container } = render(createTable({ pagination: { pageSize: 2 } })); - wrapper - .find('input') - .first() - .simulate('change', { target: { checked: true } }); - expect(wrapper.find('Checkbox').first().props()).toEqual( - expect.objectContaining({ checked: true, indeterminate: false }), - ); + const pagers = container.querySelectorAll('.ant-pagination-item'); + const checkboxAll = container.querySelector('input[type="checkbox"]'); - pagers.at(1).simulate('click'); - expect(wrapper.find('Checkbox').first().props()).toEqual( - expect.objectContaining({ checked: false, indeterminate: false }), - ); + const objectContaining = {}; + fireEvent.click(checkboxAll); + objectContaining.checked = checkboxAll.checked; // true + objectContaining.indeterminate = getIndeterminateSelection(container).length > 0; // false + expect.objectContaining(objectContaining); - pagers.at(0).simulate('click'); - expect(wrapper.find('Checkbox').first().props()).toEqual( - expect.objectContaining({ checked: true, indeterminate: false }), - ); + fireEvent.click(pagers[1]); + objectContaining.checked = checkboxAll.checked; // false + objectContaining.indeterminate = getIndeterminateSelection(container).length > 0; // false + expect.objectContaining(objectContaining); + + fireEvent.click(pagers[0]); + objectContaining.checked = checkboxAll.checked; // true + objectContaining.indeterminate = getIndeterminateSelection(container).length > 0; // false + expect.objectContaining(objectContaining); }); // https://github.com/ant-design/ant-design/issues/4020 @@ -181,7 +187,7 @@ describe('Table.rowSelection', () => { }), }; - mount(createTable({ rowSelection })); + render(createTable({ rowSelection })); expect(errorSpy).toHaveBeenCalledWith( 'Warning: [antd: Table] Do not set `checked` or `defaultChecked` in `getCheckboxProps`. Please use `selectedRowKeys` instead.', @@ -189,13 +195,13 @@ describe('Table.rowSelection', () => { }); it('can be controlled', () => { - const wrapper = mount(createTable({ rowSelection: { selectedRowKeys: [0] } })); + const { container, rerender } = render(createTable({ rowSelection: { selectedRowKeys: [0] } })); - expect(getSelections(wrapper)).toEqual([0]); + expect(getSelections(container)).toEqual([0]); - wrapper.setProps({ rowSelection: { selectedRowKeys: [1] } }); + rerender(createTable({ rowSelection: { selectedRowKeys: [1] } })); - expect(getSelections(wrapper)).toEqual([1]); + expect(getSelections(container)).toEqual([1]); }); it('fires change & select events', () => { @@ -210,12 +216,9 @@ describe('Table.rowSelection', () => { onChange: handleChange, onSelect: handleSelect, }; - const wrapper = mount(createTable({ rowSelection })); + const { container } = render(createTable({ rowSelection })); - wrapper - .find('input') - .last() - .simulate('change', { target: { checked: true } }); + fireEvent.click(container.querySelectorAll('input[type="checkbox"]')[4]); expect(handleChange).toHaveBeenCalledWith([3], [{ key: 3, name: 'Jerry' }], { type: 'single', @@ -224,7 +227,7 @@ describe('Table.rowSelection', () => { expect(handleSelect.mock.calls[0][0]).toEqual({ key: 3, name: 'Jerry' }); expect(handleSelect.mock.calls[0][1]).toEqual(true); expect(handleSelect.mock.calls[0][2]).toEqual([{ key: 3, name: 'Jerry' }]); - expect(handleSelect.mock.calls[0][3].type).toBe('change'); + expect(handleSelect.mock.calls[0][3].type).toBe('click'); expect(order).toEqual(['onSelect', 'onChange']); }); @@ -244,27 +247,20 @@ describe('Table.rowSelection', () => { onSelect: handleSelect, onSelectMultiple: handleSelectMulti, }; - const wrapper = mount(createTable({ rowSelection })); + const { container } = render(createTable({ rowSelection })); + fireEvent.click(container.querySelectorAll('tbody input[type="checkbox"]')[0], { + shiftKey: true, + }); - wrapper - .find('input') - .at(1) - .simulate('change', { - target: { checked: true }, - nativeEvent: { shiftKey: true }, - }); expect(handleSelect).toHaveBeenCalled(); expect(handleChange).toHaveBeenLastCalledWith([0], [{ key: 0, name: 'Jack' }], { type: 'single', }); - wrapper - .find('input') - .at(3) - .simulate('change', { - target: { checked: true }, - nativeEvent: { shiftKey: true }, - }); + fireEvent.click(container.querySelectorAll('tbody input[type="checkbox"]')[2], { + shiftKey: true, + }); + expect(handleSelectMulti).toHaveBeenCalledWith( true, [data[0], data[1], data[2]], @@ -280,13 +276,9 @@ describe('Table.rowSelection', () => { { type: 'multiple' }, ); - wrapper - .find('input') - .at(1) - .simulate('change', { - target: { checked: false }, - nativeEvent: { shiftKey: true }, - }); + fireEvent.click(container.querySelectorAll('tbody input[type="checkbox"]')[0], { + shiftKey: true, + }); expect(handleSelectMulti).toHaveBeenCalledWith(false, [], [data[0], data[1], data[2]]); expect(handleChange).toHaveBeenLastCalledWith([], [], { type: 'multiple' }); @@ -312,46 +304,51 @@ describe('Table.rowSelection', () => { onChange: handleChange, onSelectAll: handleSelectAll, }; - const wrapper = mount(createTable({ rowSelection })); + const { container } = render(createTable({ rowSelection })); - wrapper - .find('input') - .first() - .simulate('change', { target: { checked: true } }); + const checkAll = container.querySelector('input[type="checkbox"]'); + + fireEvent.click(checkAll); expect(handleSelectAll).toHaveBeenCalledWith(true, data, data); expect(order).toEqual(['onSelectAll', 'onChange']); - wrapper - .find('input') - .first() - .simulate('change', { target: { checked: false } }); + fireEvent.click(checkAll); expect(handleSelectAll).toHaveBeenCalledWith(false, [], data); }); it('works with selectAll option inside selection menu', () => { + jest.useFakeTimers(); const handleChange = jest.fn(); const rowSelection = { onChange: handleChange, selections: true, }; - const wrapper = mount(createTable({ rowSelection })); + const { container } = render(createTable({ rowSelection })); // Open - wrapper.find('Trigger').setState({ popupVisible: true }); + fireEvent.mouseEnter(container.querySelector('.ant-dropdown-trigger')); + act(() => { + jest.runAllTimers(); + }); + + fireEvent.click(container.querySelectorAll('.ant-dropdown-menu-item')[0]); - const dropdownWrapper = mount(wrapper.find('Trigger').first().instance().getComponent()); - dropdownWrapper.find('.ant-dropdown-menu-item').first().simulate('click'); expect(handleChange.mock.calls[0][0]).toEqual([0, 1, 2, 3]); }); it('render with default selection correctly', () => { + jest.useFakeTimers(); const rowSelection = { selections: true, }; - const wrapper = mount(createTable({ rowSelection })); - const dropdownWrapper = mount(wrapper.find('Trigger').instance().getComponent()); - expect(dropdownWrapper.render()).toMatchSnapshot(); + const { container } = render(createTable({ rowSelection })); + fireEvent.mouseEnter(container.querySelector('.ant-dropdown-trigger')); + act(() => { + jest.runAllTimers(); + }); + + expect(container.querySelector('.ant-dropdown')).toMatchSnapshot(); }); it('fires selectInvert event', () => { @@ -369,33 +366,26 @@ describe('Table.rowSelection', () => { onSelectInvert: handleSelectInvert, selections: true, }; - const wrapper = mount(createTable({ rowSelection })); - const checkboxes = wrapper.find('input'); - - checkboxes.at(1).simulate('change', { target: { checked: true } }); + const { container } = render(createTable({ rowSelection })); + fireEvent.click(container.querySelectorAll('.ant-checkbox')[1]); // Open - wrapper.find('span.ant-dropdown-trigger').simulate('mouseEnter'); + fireEvent.mouseEnter(container.querySelector('.ant-dropdown-trigger')); - // enzyme has bug for state sync. - // Let fresh multiple times to force sync back. - for (let i = 0; i < 3; i += 1) { - act(() => { - jest.runAllTimers(); - wrapper.update(); - }); - } + act(() => { + jest.runAllTimers(); + }); - wrapper.find('li.ant-dropdown-menu-item').at(1).simulate('click'); + fireEvent.click(container.querySelectorAll('li.ant-dropdown-menu-item')[1]); expect(handleSelectInvert).toHaveBeenCalledWith([1, 2, 3]); - expect(order).toEqual(['onChange', 'onSelectInvert', 'onChange']); jest.useRealTimers(); }); it('fires selectNone event', () => { + jest.useFakeTimers(); const order = []; const handleChange = jest.fn().mockImplementation(() => { order.push('onChange'); @@ -408,22 +398,23 @@ describe('Table.rowSelection', () => { onSelectNone: handleSelectNone, selections: true, }; - const wrapper = mount(createTable({ rowSelection })); - const checkboxes = wrapper.find('input'); - - checkboxes.at(1).simulate('change', { target: { checked: true } }); + const { container } = render(createTable({ rowSelection })); + fireEvent.click(container.querySelectorAll('.ant-checkbox')[1]); // Open - wrapper.find('Trigger').setState({ popupVisible: true }); - - const dropdownWrapper = mount(wrapper.find('Trigger').first().instance().getComponent()); - dropdownWrapper.find('.ant-dropdown-menu-item').last().simulate('click'); + fireEvent.mouseEnter(container.querySelector('.ant-dropdown-trigger')); + act(() => { + jest.runAllTimers(); + }); + const dropdownMenuItems = container.querySelectorAll('.ant-dropdown-menu-item'); + fireEvent.click(dropdownMenuItems[dropdownMenuItems.length - 1]); expect(handleSelectNone).toHaveBeenCalled(); expect(order).toEqual(['onChange', 'onSelectNone', 'onChange']); }); it('fires selection event', () => { + jest.useFakeTimers(); const handleSelectOdd = jest.fn(); const handleSelectEven = jest.fn(); const rowSelection = { @@ -442,18 +433,22 @@ describe('Table.rowSelection', () => { }, ], }; - const wrapper = mount(createTable({ rowSelection })); + const { container } = render(createTable({ rowSelection })); // Open - wrapper.find('Trigger').setState({ popupVisible: true }); + fireEvent.mouseEnter(container.querySelector('.ant-dropdown-trigger')); + act(() => { + jest.runAllTimers(); + }); - const dropdownWrapper = mount(wrapper.find('Trigger').first().instance().getComponent()); - expect(dropdownWrapper.find('li.ant-dropdown-menu-item').length).toBe(4); + const dropdownMenuItems = container.querySelectorAll('.ant-dropdown-menu-item'); - dropdownWrapper.find('li.ant-dropdown-menu-item').at(2).simulate('click'); + expect(dropdownMenuItems.length).toBe(4); + + fireEvent.click(dropdownMenuItems[2]); expect(handleSelectOdd).toHaveBeenCalledWith([0, 1, 2, 3]); - dropdownWrapper.find('li.ant-dropdown-menu-item').at(3).simulate('click'); + fireEvent.click(dropdownMenuItems[3]); expect(handleSelectEven).toHaveBeenCalledWith([0, 1, 2, 3]); }); @@ -467,8 +462,9 @@ describe('Table.rowSelection', () => { const getCheckboxProps = record => record; it('SELECTION_ALL', () => { + jest.useFakeTimers(); const onChange = jest.fn(); - const wrapper = mount( + const { container } = render( createTable({ dataSource: presetData, rowSelection: { @@ -480,15 +476,20 @@ describe('Table.rowSelection', () => { }), ); - wrapper.find('Trigger').setState({ popupVisible: true }); - wrapper.find('li.ant-dropdown-menu-item').first().simulate('click'); + fireEvent.mouseEnter(container.querySelector('.ant-dropdown-trigger')); + act(() => { + jest.runAllTimers(); + }); + + fireEvent.click(container.querySelector('li.ant-dropdown-menu-item')); expect(onChange).toHaveBeenCalledWith([0, 2], expect.anything(), { type: 'all' }); }); it('SELECTION_INVERT', () => { + jest.useFakeTimers(); const onChange = jest.fn(); - const wrapper = mount( + const { container } = render( createTable({ dataSource: presetData, rowSelection: { @@ -500,15 +501,21 @@ describe('Table.rowSelection', () => { }), ); - wrapper.find('Trigger').setState({ popupVisible: true }); - wrapper.find('li.ant-dropdown-menu-item').first().simulate('click'); + fireEvent.mouseEnter(container.querySelector('.ant-dropdown-trigger')); + + act(() => { + jest.runAllTimers(); + }); + + fireEvent.click(container.querySelector('li.ant-dropdown-menu-item')); expect(onChange).toHaveBeenCalledWith([0], expect.anything(), { type: 'invert' }); }); it('SELECTION_NONE', () => { + jest.useFakeTimers(); const onChange = jest.fn(); - const wrapper = mount( + const { container } = render( createTable({ dataSource: presetData, rowSelection: { @@ -520,8 +527,13 @@ describe('Table.rowSelection', () => { }), ); - wrapper.find('Trigger').setState({ popupVisible: true }); - wrapper.find('li.ant-dropdown-menu-item').first().simulate('click'); + fireEvent.mouseEnter(container.querySelector('.ant-dropdown-trigger')); + + act(() => { + jest.runAllTimers(); + }); + + fireEvent.click(container.querySelector('li.ant-dropdown-menu-item')); expect(onChange).toHaveBeenCalledWith([1], expect.anything(), { type: 'none' }); }); @@ -531,11 +543,12 @@ describe('Table.rowSelection', () => { const rowSelection = { hideSelectAll: true, }; - const wrapper = mount(createTable({ rowSelection })); - expect(wrapper.find('.ant-selection').exists()).toBeFalsy(); + const { container } = render(createTable({ rowSelection })); + expect(container.querySelector('.ant-selection')).toBeFalsy(); }); it('handle custom selection onSelect correctly when hide default selection options', () => { + jest.useFakeTimers(); const handleSelectOdd = jest.fn(); const handleSelectEven = jest.fn(); const rowSelection = { @@ -552,18 +565,21 @@ describe('Table.rowSelection', () => { }, ], }; - const wrapper = mount(createTable({ rowSelection })); + const { container } = render(createTable({ rowSelection })); // Open - wrapper.find('Trigger').setState({ popupVisible: true }); + fireEvent.mouseEnter(container.querySelector('.ant-dropdown-trigger')); + act(() => { + jest.runAllTimers(); + }); - const dropdownWrapper = mount(wrapper.find('Trigger').first().instance().getComponent()); - expect(dropdownWrapper.find('li.ant-dropdown-menu-item').length).toBe(2); + const dropdownMenuItems = container.querySelectorAll('li.ant-dropdown-menu-item'); + expect(dropdownMenuItems.length).toBe(2); - dropdownWrapper.find('li.ant-dropdown-menu-item').at(0).simulate('click'); + fireEvent.click(dropdownMenuItems[0]); expect(handleSelectOdd).toHaveBeenCalledWith([0, 1, 2, 3]); - dropdownWrapper.find('li.ant-dropdown-menu-item').at(1).simulate('click'); + fireEvent.click(dropdownMenuItems[1]); expect(handleSelectEven).toHaveBeenCalledWith([0, 1, 2, 3]); }); @@ -572,14 +588,15 @@ describe('Table.rowSelection', () => { const rowSelection = { getCheckboxProps: record => ({ disabled: record.disabled }), }; - const wrapper = mount(createTable({ rowSelection })); + const { container, rerender } = render(createTable({ rowSelection })); const newData = [ { key: 0, name: 'Jack', disabled: true }, { key: 1, name: 'Lucy', disabled: true }, ]; - wrapper.setProps({ dataSource: newData }); - wrapper.find('input').forEach(checkbox => { - expect(checkbox.props().disabled).toBe(true); + + rerender(createTable({ rowSelection, dataSource: newData })); + container.querySelectorAll('input').forEach(checkbox => { + expect(checkbox.disabled).toBe(true); }); }); @@ -622,20 +639,16 @@ describe('Table.rowSelection', () => { name: i.toString(), }); } - const wrapper = mount( + const { container } = render( createTable({ rowSelection: {}, dataSource: newData, }), ); - wrapper.find('Pager').last().simulate('click'); // switch to second page - wrapper.update(); - wrapper - .find('input') - .first() - .simulate('change', { target: { checked: true } }); - wrapper.update(); - expect(renderedNames(wrapper)).toEqual([ + fireEvent.click(container.querySelectorAll('.ant-pagination-item')[1]); // switch to second page + fireEvent.click(container.querySelector('.ant-checkbox')); + + expect(renderedNames(container)).toEqual([ '10', '11', '12', @@ -650,27 +663,27 @@ describe('Table.rowSelection', () => { }); it('highlight selected row', () => { - const wrapper = mount(createTable()); - wrapper - .find('input') - .at(1) - .simulate('change', { target: { checked: true } }); - expect(wrapper.find('tbody tr').at(0).hasClass('ant-table-row-selected')).toBe(true); + const { container } = render(createTable()); + + fireEvent.click(container.querySelectorAll('input')[1]); + expect( + container.querySelectorAll('tbody tr')[0].className.includes('ant-table-row-selected'), + ).toBe(true); }); it('fix selection column on the left', () => { - const wrapper = mount( + const { asFragment } = render( createTable({ rowSelection: { fixed: true }, scroll: { x: 903 }, }), ); - expect(wrapper.render()).toMatchSnapshot(); + expect(asFragment().firstChild).toMatchSnapshot(); }); it('fix expand on th left when selection column fixed on the left', () => { - const wrapper = mount( + const { asFragment } = render( createTable({ expandable: { expandedRowRender() { @@ -682,11 +695,11 @@ describe('Table.rowSelection', () => { }), ); - expect(wrapper.render()).toMatchSnapshot(); + expect(asFragment().firstChild).toMatchSnapshot(); }); it('fix selection column on the left when any other column is fixed', () => { - const wrapper = mount( + const { asFragment } = render( createTable({ rowSelection: {}, columns: [ @@ -700,11 +713,11 @@ describe('Table.rowSelection', () => { }), ); - expect(wrapper.render()).toMatchSnapshot(); + expect(asFragment().firstChild).toMatchSnapshot(); }); it('use column as selection column when key is `selection-column`', () => { - const wrapper = mount( + const { asFragment } = render( createTable({ rowSelection: {}, columns: [ @@ -717,12 +730,12 @@ describe('Table.rowSelection', () => { }), ); - expect(wrapper.render()).toMatchSnapshot(); + expect(asFragment().firstChild).toMatchSnapshot(); }); // https://github.com/ant-design/ant-design/issues/10629 it('should keep all checked state when remove item from dataSource', () => { - const wrapper = mount( + const { container, rerender } = render(
{ dataSource={data} />, ); - expect(wrapper.find(Checkbox).length).toBe(5); - wrapper.find(Checkbox).forEach(checkbox => { - expect(checkbox.props().checked).toBe(true); - expect(checkbox.props().indeterminate).toBe(false); + const checkboxs = container.querySelectorAll('.ant-checkbox'); + expect(checkboxs.length).toBe(5); + checkboxs.forEach(checkbox => { + expect(checkbox.querySelector('input').checked).toBe(true); + expect(checkbox.className.includes('ant-checkbox-indeterminate')).toBe(false); }); - wrapper.setProps({ - dataSource: data.slice(1), - rowSelection: { - selectedRowKeys: [1, 2, 3], - }, - }); - expect(wrapper.find(Checkbox).length).toBe(4); - wrapper.find(Checkbox).forEach(checkbox => { - expect(checkbox.props().checked).toBe(true); - expect(checkbox.props().indeterminate).toBe(false); + + rerender( +
, + ); + + expect(container.querySelectorAll('.ant-checkbox').length).toBe(4); + container.querySelectorAll('.ant-checkbox').forEach(checkbox => { + expect(checkbox.querySelector('input').checked).toBe(true); + expect(checkbox.className.includes('ant-checkbox-indeterminate')).toBe(false); }); }); // https://github.com/ant-design/ant-design/issues/11042 it('add columnTitle for rowSelection', () => { - const wrapper = mount( + const { container, rerender } = render(
{ }} />, ); - expect(wrapper.find('thead tr th').at(0).text()).toBe('多选'); - wrapper.setProps({ - rowSelection: { - type: 'radio', - columnTitle: '单选', - }, - }); - expect(wrapper.find('thead tr th').at(0).text()).toBe('单选'); + expect(container.querySelector('thead tr th').textContent).toBe('多选'); + rerender( +
, + ); + expect(container.querySelector('thead tr th').textContent).toBe('单选'); }); // https://github.com/ant-design/ant-design/issues/11384 @@ -796,36 +819,43 @@ describe('Table.rowSelection', () => { onChange, }; - const wrapper = mount( + const { container } = render(
, ); function clickFilter(indexList) { indexList.forEach(index => { - wrapper.find('.ant-dropdown-menu-item .ant-checkbox-wrapper').at(index).simulate('click'); + // wrapper.find('.ant-dropdown-menu-item .ant-checkbox-wrapper').at(index).simulate('click'); + fireEvent.click( + container.querySelectorAll('.ant-dropdown-menu-item .ant-checkbox-wrapper')[index], + ); }); - wrapper.find('.ant-table-filter-dropdown-btns .ant-btn-primary').simulate('click'); + // wrapper.find('.ant-table-filter-dropdown-btns .ant-btn-primary').simulate('click'); + fireEvent.click(container.querySelector('.ant-table-filter-dropdown-btns .ant-btn-primary')); } function clickItem() { - wrapper - .find('tbody .ant-table-selection-column .ant-checkbox-input') - .at(0) - .simulate('change', { - target: { checked: true }, - }); + fireEvent.click( + container.querySelectorAll('tbody .ant-table-selection-column .ant-checkbox-input')[0], + ); + // wrapper + // .find('tbody .ant-table-selection-column .ant-checkbox-input') + // .at(0) + // .simulate('change', { + // target: { checked: true }, + // }); } // Check Jack clickFilter([0]); - expect(wrapper.find('tbody tr').length).toBe(1); + expect(container.querySelectorAll('tbody tr').length).toBe(1); clickItem(); expect(onChange.mock.calls[0][0].length).toBe(1); expect(onChange.mock.calls[0][1].length).toBe(1); // Check Lucy clickFilter([0, 1]); - expect(wrapper.find('tbody tr').length).toBe(1); + expect(container.querySelectorAll('tbody tr').length).toBe(1); clickItem(); expect(onChange.mock.calls[1][0].length).toBe(2); expect(onChange.mock.calls[1][1].length).toBe(2); @@ -854,20 +884,20 @@ describe('Table.rowSelection', () => { ], }, ]; - const wrapper = mount( + const { container } = render(
, ); - const checkboxes = wrapper.find('input'); + const checkboxes = container.querySelectorAll('input'); + const objectContaining = {}; + fireEvent.click(checkboxes[1]); + objectContaining.checked = checkboxes[0].checked; // false + objectContaining.indeterminate = getIndeterminateSelection(container).length > 0; // true + expect.objectContaining(objectContaining); - checkboxes.at(1).simulate('change', { target: { checked: true } }); - expect(wrapper.find('Checkbox').first().props()).toEqual( - expect.objectContaining({ indeterminate: true, checked: false }), - ); - - checkboxes.at(2).simulate('change', { target: { checked: true } }); - expect(wrapper.find('Checkbox').first().props()).toEqual( - expect.objectContaining({ indeterminate: false, checked: true }), - ); + fireEvent.click(checkboxes[2]); + objectContaining.checked = checkboxes[0].checked; // true + objectContaining.indeterminate = getIndeterminateSelection(container).length > 0; // false + expect.objectContaining(objectContaining); }); // https://github.com/ant-design/ant-design/issues/16614 @@ -885,7 +915,7 @@ describe('Table.rowSelection', () => { ], }, ]; - const wrapper = mount( + const { container } = render(
{ expandedRowKeys={[1]} />, ); - const checkboxes = wrapper.find('input'); - checkboxes.at(2).simulate('change', { target: { checked: true } }); + const checkboxes = container.querySelectorAll('input'); + + fireEvent.click(checkboxes[2]); + expect(onChange).toHaveBeenLastCalledWith([11], [newDatas[0].list[0]], { type: 'single' }); onChange.mockReset(); - checkboxes.at(1).simulate('change', { target: { checked: true } }); + fireEvent.click(checkboxes[1]); const item0 = newDatas[0]; expect(onChange).toHaveBeenLastCalledWith([11, 1], [newDatas[0].list[0], item0], { type: 'single', @@ -912,7 +944,7 @@ describe('Table.rowSelection', () => { { id: 2, name: 'World', age: 30 }, ]; - const wrapper = mount( + const { container, rerender } = render(
{ rowKey="id" />, ); - const checkboxes = wrapper.find('input'); - checkboxes.at(1).simulate('change', { target: { checked: true } }); + const checkboxes = container.querySelectorAll('input'); + fireEvent.click(checkboxes[1]); - expect(wrapper.find('tr.ant-table-row-selected').length).toBe(1); + expect(container.querySelectorAll('tr.ant-table-row-selected').length).toBe(1); - wrapper.setProps({ rowSelection: null }); - wrapper.update(); - expect(wrapper.find('tr.ant-table-row-selected').length).toBe(0); + rerender( +
null} + rowKey="id" + />, + ); + + expect(container.querySelectorAll('tr.ant-table-row-selected').length).toBe(0); }); it('select by checkbox to trigger stopPropagation', () => { - const wrapper = mount(createTable()); + const { container } = render(createTable()); expect(() => { - wrapper.find('span').at(10).simulate('click'); + fireEvent.click(container.querySelectorAll('span')[10]); }).not.toThrow(); }); it('all disabled should not make select all checked', () => { - const wrapper = mount( + const { container } = render( createTable({ rowSelection: { getCheckboxProps: () => ({ @@ -949,12 +989,12 @@ describe('Table.rowSelection', () => { }), ); - expect(wrapper.find('thead .ant-checkbox-input').props().disabled).toBeTruthy(); - expect(wrapper.find('thead .ant-checkbox-input').props().checked).toBeFalsy(); + expect(container.querySelector('thead .ant-checkbox-input').disabled).toBeTruthy(); + expect(container.querySelector('thead .ant-checkbox-input').checked).toBeFalsy(); }); it('should make select all checked when each item is checked and disabled', () => { - const wrapper = mount( + const { container } = render( createTable({ rowSelection: { selectedRowKeys: [0, 1, 2, 3], @@ -965,12 +1005,12 @@ describe('Table.rowSelection', () => { }), ); - expect(wrapper.find('thead .ant-checkbox-input').props().disabled).toBeTruthy(); - expect(wrapper.find('thead .ant-checkbox-input').props().checked).toBeTruthy(); + expect(container.querySelector('thead .ant-checkbox-input').disabled).toBeTruthy(); + expect(container.querySelector('thead .ant-checkbox-input').checked).toBeTruthy(); }); it('should make select all indeterminated when each item is disabled and some item is checked', () => { - const wrapper = mount( + const { container } = render( createTable({ rowSelection: { selectedRowKeys: [0], @@ -981,15 +1021,15 @@ describe('Table.rowSelection', () => { }), ); - expect(wrapper.find('thead .ant-checkbox-input').props().disabled).toBeTruthy(); - expect(wrapper.find('thead .ant-checkbox-input').props().checked).toBeFalsy(); + expect(container.querySelector('thead .ant-checkbox-input').disabled).toBeTruthy(); + expect(container.querySelector('thead .ant-checkbox-input').checked).toBeFalsy(); expect( - wrapper.find('thead .ant-checkbox-indeterminate.ant-checkbox-disabled').exists(), + container.querySelector('thead .ant-checkbox-indeterminate.ant-checkbox-disabled'), ).toBeTruthy(); }); it('should make select all checked when each item is checked and some item is disabled', () => { - const wrapper = mount( + const { container } = render( createTable({ rowSelection: { selectedRowKeys: [0, 1, 2, 3], @@ -1000,12 +1040,12 @@ describe('Table.rowSelection', () => { }), ); - expect(wrapper.find('thead .ant-checkbox-input').props().disabled).toBeFalsy(); - expect(wrapper.find('thead .ant-checkbox-input').props().checked).toBeTruthy(); + expect(container.querySelector('thead .ant-checkbox-input').disabled).toBeFalsy(); + expect(container.querySelector('thead .ant-checkbox-input').checked).toBeTruthy(); }); it('should not make select all checked when some item is checked and disabled', () => { - const wrapper = mount( + const { container } = render( createTable({ rowSelection: { selectedRowKeys: [1], @@ -1016,23 +1056,23 @@ describe('Table.rowSelection', () => { }), ); - expect(wrapper.find('thead .ant-checkbox-input').props().disabled).toBeFalsy(); - expect(wrapper.find('thead .ant-checkbox-input').props().checked).toBeFalsy(); - expect(wrapper.find('thead .ant-checkbox-indeterminate').exists()).toBeTruthy(); + expect(container.querySelector('thead .ant-checkbox-input').disabled).toBeFalsy(); + expect(container.querySelector('thead .ant-checkbox-input').checked).toBeFalsy(); + expect(container.querySelector('thead .ant-checkbox-indeterminate')).toBeTruthy(); }); it('should onRowClick not called when checkbox clicked', () => { const onRowClick = jest.fn(); - const wrapper = mount( + const { container } = render( createTable({ onRow: () => ({ onClick: onRowClick, }), }), ); - - wrapper.find('input').last().simulate('click'); + const checkboxes = container.querySelectorAll('input'); + fireEvent.click(checkboxes[checkboxes.length - 1]); expect(onRowClick).not.toHaveBeenCalled(); }); @@ -1042,16 +1082,18 @@ describe('Table.rowSelection', () => { selections: true, }; const getPopupContainer = jest.fn(node => node); - const wrapper = mount( + const { container } = render( createTable({ rowSelection, getPopupContainer, }), ); jest.useFakeTimers(); - wrapper.find('.ant-dropdown-trigger').simulate('mouseenter'); - jest.runAllTimers(); - expect(wrapper.render()).toMatchSnapshot(); + fireEvent.mouseEnter(container.querySelector('.ant-dropdown-trigger')); + act(() => { + jest.runAllTimers(); + }); + expect(container.firstChild).toMatchSnapshot(); expect(getPopupContainer).toHaveBeenCalled(); }); @@ -1059,7 +1101,7 @@ describe('Table.rowSelection', () => { const rowSelection = { selections: true, }; - const wrapper = mount( + const { container } = render( node.parentNode}> {createTable({ rowSelection, @@ -1067,14 +1109,16 @@ describe('Table.rowSelection', () => { , ); jest.useFakeTimers(); - wrapper.find('.ant-dropdown-trigger').simulate('mouseenter'); - jest.runAllTimers(); - expect(wrapper.render()).toMatchSnapshot(); + fireEvent.mouseEnter(container.querySelector('.ant-dropdown-trigger')); + act(() => { + jest.runAllTimers(); + }); + expect(container.firstChild).toMatchSnapshot(); }); it('Table selection should check', () => { const onChange = jest.fn(); - const wrapper = mount( + const { container } = render(
{ />, ); - wrapper - .find('input') - .last() - .simulate('change', { target: { checked: true } }); + const checkboxs = container.querySelectorAll('input'); + fireEvent.click(checkboxs[checkboxs.length - 1]); + expect(onChange.mock.calls[0][1]).toEqual([expect.objectContaining({ name: 'bamboo' })]); }); @@ -1140,16 +1183,19 @@ describe('Table.rowSelection', () => { onChange, }, }); - const wrapper = mount(table); - const checkboxes = wrapper.find('input'); + const { container } = render(table); + const checkboxes = container.querySelectorAll('input'); - checkboxes.at(4).simulate('change', { target: { checked: true } }); - expect(getSelections(wrapper)).toEqual([3, 4, 5, 6, 7, 8, 9]); - expect(getIndeterminateSelection(wrapper)).toEqual([]); + fireEvent.click(checkboxes[4]); + + expect(getSelections(container)).toEqual([3, 4, 5, 6, 7, 8, 9]); + expect(getIndeterminateSelection(container)).toEqual([]); expect(onChange.mock.calls[0][0]).toEqual([3, 4, 5, 6, 7, 8, 9]); - checkboxes.at(7).simulate('change', { target: { checked: true } }); - expect(getSelections(wrapper)).toEqual([4, 5]); - expect(getIndeterminateSelection(wrapper)).toEqual([3]); + + fireEvent.click(checkboxes[7]); + + expect(getSelections(container)).toEqual([4, 5]); + expect(getIndeterminateSelection(container)).toEqual([3]); expect(onChange.mock.calls[1][0]).toEqual([4, 5]); }); it('use function rowkey', () => { @@ -1163,12 +1209,20 @@ describe('Table.rowSelection', () => { }, rowKey: entity => entity.name, }); - const wrapper = mount(table); - const checkboxes = wrapper.find('input'); + const { container } = render(table); + const checkboxes = container.querySelectorAll('input'); - checkboxes.at(4).simulate('change', { target: { checked: true } }); - expect(getSelections(wrapper)).toEqual([3, 4, 5, 6, 7, 8, 9]); - expect(getIndeterminateSelection(wrapper)).toEqual([]); + fireEvent.click(checkboxes[4]); + expect(getSelections(container)).toEqual([ + 'Jerry', + 'Jerry Jack', + 'Jerry Lucy', + 'Jerry Tom', + 'Jerry Tom Jack', + 'Jerry Tom Lucy', + 'Jerry Tom Tom', + ]); + expect(getIndeterminateSelection(container)).toEqual([]); expect(onChange.mock.calls[0][0]).toEqual([ 'Jerry', 'Jerry Jack', @@ -1178,9 +1232,10 @@ describe('Table.rowSelection', () => { 'Jerry Tom Lucy', 'Jerry Tom Tom', ]); - checkboxes.at(7).simulate('change', { target: { checked: true } }); - expect(getSelections(wrapper)).toEqual([4, 5]); - expect(getIndeterminateSelection(wrapper)).toEqual([3]); + + fireEvent.click(checkboxes[7]); + expect(getSelections(container)).toEqual(['Jerry Jack', 'Jerry Lucy']); + expect(getIndeterminateSelection(container)).toEqual(['Jerry']); expect(onChange.mock.calls[1][0]).toEqual(['Jerry Jack', 'Jerry Lucy']); }); it('use string rowkey', () => { @@ -1194,12 +1249,20 @@ describe('Table.rowSelection', () => { }, rowKey: 'name', }); - const wrapper = mount(table); - const checkboxes = wrapper.find('input'); + const { container } = render(table); + const checkboxes = container.querySelectorAll('input'); - checkboxes.at(4).simulate('change', { target: { checked: true } }); - expect(getSelections(wrapper)).toEqual([3, 4, 5, 6, 7, 8, 9]); - expect(getIndeterminateSelection(wrapper)).toEqual([]); + fireEvent.click(checkboxes[4]); + expect(getSelections(container)).toEqual([ + 'Jerry', + 'Jerry Jack', + 'Jerry Lucy', + 'Jerry Tom', + 'Jerry Tom Jack', + 'Jerry Tom Lucy', + 'Jerry Tom Tom', + ]); + expect(getIndeterminateSelection(container)).toEqual([]); expect(onChange.mock.calls[0][0]).toEqual([ 'Jerry', 'Jerry Jack', @@ -1209,9 +1272,10 @@ describe('Table.rowSelection', () => { 'Jerry Tom Lucy', 'Jerry Tom Tom', ]); - checkboxes.at(7).simulate('change', { target: { checked: true } }); - expect(getSelections(wrapper)).toEqual([4, 5]); - expect(getIndeterminateSelection(wrapper)).toEqual([3]); + + fireEvent.click(checkboxes[7]); + expect(getSelections(container)).toEqual(['Jerry Jack', 'Jerry Lucy']); + expect(getIndeterminateSelection(container)).toEqual(['Jerry']); expect(onChange.mock.calls[1][0]).toEqual(['Jerry Jack', 'Jerry Lucy']); }); it('initialized correctly', () => { @@ -1224,9 +1288,9 @@ describe('Table.rowSelection', () => { }, rowKey: 'key', }); - const wrapper = mount(table); - expect(getSelections(wrapper)).toEqual([6, 7, 8, 9]); - expect(getIndeterminateSelection(wrapper)).toEqual([3]); + const { container } = render(table); + expect(getSelections(container)).toEqual([6, 7, 8, 9]); + expect(getIndeterminateSelection(container)).toEqual([3]); }); it('works with disabled checkbox', () => { const onChange = jest.fn(); @@ -1244,17 +1308,20 @@ describe('Table.rowSelection', () => { }, }, }); - const wrapper = mount(table); - const checkboxes = wrapper.find('input'); + const { container } = render(table); - checkboxes.at(10).simulate('change', { target: { checked: true } }); - checkboxes.at(4).simulate('change', { target: { checked: true } }); - expect(getSelections(wrapper).sort()).toEqual([3, 4, 5, 9]); - expect(getIndeterminateSelection(wrapper)).toEqual([]); + const checkboxes = container.querySelectorAll('input'); + + fireEvent.click(checkboxes[10]); + fireEvent.click(checkboxes[4]); + + expect(getSelections(container).sort()).toEqual([3, 4, 5, 9]); + expect(getIndeterminateSelection(container)).toEqual([]); expect(Array.from(onChange.mock.calls[1][0]).sort()).toEqual([3, 4, 5, 9]); - checkboxes.at(4).simulate('change', { target: { checked: false } }); - expect(getSelections(wrapper)).toEqual([9]); - expect(getIndeterminateSelection(wrapper)).toEqual([]); + + fireEvent.click(checkboxes[4]); + expect(getSelections(container)).toEqual([9]); + expect(getIndeterminateSelection(container)).toEqual([]); expect(onChange.mock.calls[2][0]).toEqual([9]); }); it('works with disabled checkbox and function rowkey', () => { @@ -1274,22 +1341,28 @@ describe('Table.rowSelection', () => { }, rowKey: entity => entity.name, }); - const wrapper = mount(table); - const checkboxes = wrapper.find('input'); + const { container } = render(table); + const checkboxes = container.querySelectorAll('input'); - checkboxes.at(10).simulate('change', { target: { checked: true } }); - checkboxes.at(4).simulate('change', { target: { checked: true } }); - expect(getSelections(wrapper).sort()).toEqual([3, 4, 5, 9]); - expect(getIndeterminateSelection(wrapper)).toEqual([]); + fireEvent.click(checkboxes[10]); + fireEvent.click(checkboxes[4]); + expect(getSelections(container)).toEqual([ + 'Jerry', + 'Jerry Jack', + 'Jerry Lucy', + 'Jerry Tom Tom', + ]); + expect(getIndeterminateSelection(container)).toEqual([]); expect(Array.from(onChange.mock.calls[1][0]).sort()).toEqual([ 'Jerry', 'Jerry Jack', 'Jerry Lucy', 'Jerry Tom Tom', ]); - checkboxes.at(4).simulate('change', { target: { checked: false } }); - expect(getSelections(wrapper)).toEqual([9]); - expect(getIndeterminateSelection(wrapper)).toEqual([]); + + fireEvent.click(checkboxes[4]); + expect(getSelections(container)).toEqual(['Jerry Tom Tom']); + expect(getIndeterminateSelection(container)).toEqual([]); expect(onChange.mock.calls[2][0]).toEqual(['Jerry Tom Tom']); }); it('works with disabled checkbox and string rowkey', () => { @@ -1309,22 +1382,28 @@ describe('Table.rowSelection', () => { }, rowKey: 'name', }); - const wrapper = mount(table); - const checkboxes = wrapper.find('input'); + const { container } = render(table); + const checkboxes = container.querySelectorAll('input'); - checkboxes.at(10).simulate('change', { target: { checked: true } }); - checkboxes.at(4).simulate('change', { target: { checked: true } }); - expect(getSelections(wrapper).sort()).toEqual([3, 4, 5, 9]); - expect(getIndeterminateSelection(wrapper)).toEqual([]); + fireEvent.click(checkboxes[10]); + fireEvent.click(checkboxes[4]); + expect(getSelections(container)).toEqual([ + 'Jerry', + 'Jerry Jack', + 'Jerry Lucy', + 'Jerry Tom Tom', + ]); + expect(getIndeterminateSelection(container)).toEqual([]); expect(Array.from(onChange.mock.calls[1][0]).sort()).toEqual([ 'Jerry', 'Jerry Jack', 'Jerry Lucy', 'Jerry Tom Tom', ]); - checkboxes.at(4).simulate('change', { target: { checked: false } }); - expect(getSelections(wrapper)).toEqual([9]); - expect(getIndeterminateSelection(wrapper)).toEqual([]); + + fireEvent.click(checkboxes[4]); + expect(getSelections(container)).toEqual(['Jerry Tom Tom']); + expect(getIndeterminateSelection(container)).toEqual([]); expect(onChange.mock.calls[2][0]).toEqual(['Jerry Tom Tom']); }); @@ -1351,17 +1430,17 @@ describe('Table.rowSelection', () => { onChange, }, }); - const wrapper = mount(table); - const checkboxes = wrapper.find('input'); + const { container } = render(table); + const checkboxes = container.querySelectorAll('input'); expect(checkboxes).toHaveLength(1 + 3); - checkboxes.at(1).simulate('change', { target: { checked: true } }); - expect(getSelections(wrapper)).toEqual([0, 1, 2]); + fireEvent.click(checkboxes[1]); + expect(getSelections(container)).toEqual([0, 1, 2]); }); }); it('warns when set `indeterminate` using `rowSelection.getCheckboxProps` is not allowed with tree structured data.', () => { resetWarned(); - mount( + render( createTable({ dataSource: dataWithChildren, defaultExpandAllRows: true, @@ -1384,7 +1463,7 @@ describe('Table.rowSelection', () => { describe('cache with selected keys', () => { it('default not cache', () => { const onChange = jest.fn(); - const wrapper = mount( + const { container, rerender } = render(
{ />, ); - wrapper - .find('tbody input') - .first() - .simulate('change', { target: { checked: true } }); + fireEvent.click(container.querySelector('tbody input')); expect(onChange).toHaveBeenCalledWith(['light'], [{ name: 'light' }], { type: 'single' }); - - wrapper.setProps({ dataSource: [{ name: 'bamboo' }] }); - wrapper - .find('tbody input') - .first() - .simulate('change', { target: { checked: true } }); + rerender( +
, + ); + fireEvent.click(container.querySelector('tbody input')); expect(onChange).toHaveBeenCalledWith(['bamboo'], [{ name: 'bamboo' }], { type: 'single' }); }); it('cache with preserveSelectedRowKeys', () => { const onChange = jest.fn(); - const wrapper = mount( + const { container, rerender } = render(
{ />, ); - wrapper - .find('tbody input') - .first() - .simulate('change', { target: { checked: true } }); + fireEvent.click(container.querySelector('tbody input')); expect(onChange).toHaveBeenCalledWith(['light'], [{ name: 'light' }], { type: 'single' }); - wrapper.setProps({ dataSource: [{ name: 'bamboo' }] }); - wrapper - .find('tbody input') - .first() - .simulate('change', { target: { checked: true } }); + rerender( +
, + ); + fireEvent.click(container.querySelector('tbody input')); expect(onChange).toHaveBeenCalledWith( ['light', 'bamboo'], [{ name: 'light' }, { name: 'bamboo' }], @@ -1437,7 +1511,7 @@ describe('Table.rowSelection', () => { it('works with receive selectedRowKeys fron [] to undefined', () => { const onChange = jest.fn(); const dataSource = [{ name: 'Jack' }]; - const wrapper = mount( + const { container, rerender } = render(
{ />, ); - wrapper.setProps({ rowSelection: { onChange, selectedRowKeys: undefined } }); - wrapper - .find('tbody input') - .first() - .simulate('change', { target: { checked: true } }); + rerender( +
, + ); + + fireEvent.click(container.querySelector('tbody input')); expect(onChange).toHaveBeenCalledWith(['Jack'], [{ name: 'Jack' }], { type: 'single' }); }); it('works with selectionType radio receive selectedRowKeys from [] to undefined', () => { const onChange = jest.fn(); const dataSource = [{ name: 'Jack' }]; - const wrapper = mount( + const { container, rerender } = render(
, ); + rerender( +
, + ); - wrapper.setProps({ rowSelection: { onChange, selectedRowKeys: undefined, type: 'radio' } }); - wrapper - .find('tbody input') - .first() - .simulate('change', { target: { checked: true } }); + fireEvent.click(container.querySelector('tbody input')); expect(onChange).toHaveBeenCalledWith(['Jack'], [{ name: 'Jack' }], { type: 'single' }); }); @@ -1480,7 +1561,7 @@ describe('Table.rowSelection', () => { onChange, selectedRowKeys: ['Jack'], }; - const wrapper = mount( + const { container, rerender } = render(
{ />, ); - wrapper.setProps({ - dataSource: dataSource.slice(2, 4), - }); - wrapper - .find('tbody input') - .first() - .simulate('change', { target: { checked: true } }); + rerender( +
, + ); + fireEvent.click(container.querySelector('tbody input')); expect(onChange).toHaveBeenCalledWith( ['Jack', 'Lucy'], [{ name: 'Jack' }, { name: 'Lucy' }], diff --git a/components/table/__tests__/__snapshots__/Table.rowSelection.test.js.snap b/components/table/__tests__/__snapshots__/Table.rowSelection.test.js.snap index 2fb7edc9d6..e773204a00 100644 --- a/components/table/__tests__/__snapshots__/Table.rowSelection.test.js.snap +++ b/components/table/__tests__/__snapshots__/Table.rowSelection.test.js.snap @@ -976,7 +976,60 @@ exports[`Table.rowSelection fix selection column on the left when any other colu `; -exports[`Table.rowSelection render with default selection correctly 1`] = `
`; +exports[`Table.rowSelection render with default selection correctly 1`] = ` +
+ + +`; exports[`Table.rowSelection should support getPopupContainer 1`] = `
Date: Mon, 13 Jun 2022 19:30:45 +0800 Subject: [PATCH 12/20] docs: add changelog 4.21.1 (#36022) --- CHANGELOG.en-US.md | 16 ++++++++++++++++ CHANGELOG.zh-CN.md | 16 ++++++++++++++++ package.json | 2 +- 3 files changed, 33 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.en-US.md b/CHANGELOG.en-US.md index d823bff528..3b4393e107 100644 --- a/CHANGELOG.en-US.md +++ b/CHANGELOG.en-US.md @@ -15,6 +15,22 @@ timeline: true --- +## 4.21.1 + +`2022-06-13` + +- 🐞 Fixed Image the `getContainer` property not reading from ConfigProvider. [#36002](https://github.com/ant-design/ant-design/pull/36002) [@robothot](https://github.com/robothot) +- 🐞 Fixed Button issue [#35952](https://github.com/ant-design/ant-design/issues/35952) where the `disabled` attribute does not take effect with `href`. [#35975](https://github.com/ant-design/ant-design/pull/35975) [@MuxinFeng](https://github.com/MuxinFeng) +- 🐞 Fix less color palette algorithm according to `@ant-design/colors`. [#35954](https://github.com/ant-design/ant-design/pull/35954) [@christian-lechner](https://github.com/christian-lechner) +- 🐞 Fix Upload image flickering. [#35943](https://github.com/ant-design/ant-design/pull/35943) +- 💄 Remove styles from Form such as `status` for children of Modal and Drawer. [#35849](https://github.com/ant-design/ant-design/pull/35849) +- TypeScript + - 🤖 Fix type definition for `autoFocus` in Dropdown. [#35990](https://github.com/ant-design/ant-design/pull/35990) [@robothot](https://github.com/robothot) + - 🤖 Fix type definition for `MenuItemGroupType` in Menu. [#35790](https://github.com/ant-design/ant-design/pull/35790) [@MasaoBlue](https://github.com/MasaoBlue) + - 🤖 Fix Carousel type definition in React 18. [#35959](https://github.com/ant-design/ant-design/pull/35959) +- 🌐 Localization + - 🇮🇹 Fix italian translation for `Table.cancelSort` key. [#35970](https://github.com/ant-design/ant-design/pull/35970) [@gariggio](https://github.com/gariggio) + ## 4.21.0 `2022-06-06` diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index 776e53f87b..3fe0132f77 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -15,6 +15,22 @@ timeline: true --- +## 4.21.1 + +`2022-06-13` + +- 🐞 修复 Image `getContainer` 属性没有从 ConfigProvider 中读取的问题。[#36002](https://github.com/ant-design/ant-design/pull/36002) [@robothot](https://github.com/robothot) +- 🐞 修复 Button 有 `href` 时 `disabled` 属性不生效的问题。[#35952](https://github.com/ant-design/ant-design/issues/35952)。[#35975](https://github.com/ant-design/ant-design/pull/35975) [@MuxinFeng](https://github.com/MuxinFeng) +- 🐞 修复 Upload 组件动画闪烁的问题。[#35943](https://github.com/ant-design/ant-design/pull/35943) +- 🐞 修复 less 色彩算法,使其和 `@ant-design/colors` 保持一致。[#35954](https://github.com/ant-design/ant-design/pull/35954) [@christian-lechner](https://github.com/christian-lechner) +- 💄 Form.Item 中的 Modal 或 Drawer 组件包含的控件去除 `status` 等受 Form 影响的样式。[#35849](https://github.com/ant-design/ant-design/pull/35849) +- TypeScript + - 🤖 修复 Dropdown `autoFocus` 属性定义。[#35990](https://github.com/ant-design/ant-design/pull/35990) [@robothot](https://github.com/robothot) + - 🤖 修复 Menu 中 `MenuItemGroupType` 的类型定义。[#35790](https://github.com/ant-design/ant-design/pull/35790) [@MasaoBlue](https://github.com/MasaoBlue) + - 🤖 修复 Carousel 在 React 18 下的 TS 定义问题。[#35959](https://github.com/ant-design/ant-design/pull/35959) +- 🌐 国际化 + - 🇮🇹 修复 `Table.cancelSort` 的意大利语翻译。[#35970](https://github.com/ant-design/ant-design/pull/35970) [@gariggio](https://github.com/gariggio) + ## 4.21.0 `2022-06-06` diff --git a/package.json b/package.json index 69dff97d47..2d4aa42010 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "antd", - "version": "4.21.0", + "version": "4.21.1", "description": "An enterprise-class UI design language and React components implementation", "title": "Ant Design", "keywords": [ From 29565273cb5d8d128d6c4f7867740ab8d5a2ee51 Mon Sep 17 00:00:00 2001 From: csr632 <632882184@qq.com> Date: Tue, 14 Jun 2022 11:04:18 +0800 Subject: [PATCH 13/20] docs: title is no loger supported by SubMenuType (#36037) --- components/menu/index.en-US.md | 1 - 1 file changed, 1 deletion(-) diff --git a/components/menu/index.en-US.md b/components/menu/index.en-US.md index 1d583837f8..15ee83fa86 100644 --- a/components/menu/index.en-US.md +++ b/components/menu/index.en-US.md @@ -127,7 +127,6 @@ The legacy demo code for version `<4.20.0` could be found at [https://github.com | label | Menu label | ReactNode | - | | | popupClassName | Sub-menu class name, not working when `mode="inline"` | string | - | | | popupOffset | Sub-menu offset, not working when `mode="inline"` | \[number, number] | - | | -| title | Title of sub menu | ReactNode | - | | | theme | Color theme of the SubMenu (inherits from Menu by default) | | `light` \| `dark` | - | | | onTitleClick | Callback executed when the sub-menu title is clicked | function({ key, domEvent }) | - | | From c72c70024e5a5a28eb3c31788c9df0d6d28783a9 Mon Sep 17 00:00:00 2001 From: afc163 Date: Tue, 14 Jun 2022 11:08:16 +0800 Subject: [PATCH 14/20] docs: fix menu API table (#36043) * docs: fix menu API table * Update index.en-US.md --- components/menu/index.en-US.md | 2 +- components/menu/index.zh-CN.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/components/menu/index.en-US.md b/components/menu/index.en-US.md index 15ee83fa86..af44b41bab 100644 --- a/components/menu/index.en-US.md +++ b/components/menu/index.en-US.md @@ -119,7 +119,7 @@ The legacy demo code for version `<4.20.0` could be found at [https://github.com #### SubMenuType | Param | Description | Type | Default value | Version | -| --- | --- | --- | --- | --- | --- | +| --- | --- | --- | --- | --- | | children | Sub-menus or sub-menu items | [ItemType\[\]](#ItemType) | - | | | disabled | Whether sub-menu is disabled | boolean | false | | | icon | Icon of sub menu | ReactNode | - | | diff --git a/components/menu/index.zh-CN.md b/components/menu/index.zh-CN.md index 0e82dda7ba..543767f944 100644 --- a/components/menu/index.zh-CN.md +++ b/components/menu/index.zh-CN.md @@ -120,7 +120,7 @@ return ; #### SubMenuType | 参数 | 说明 | 类型 | 默认值 | 版本 | -| --- | --- | --- | --- | --- | --- | +| --- | --- | --- | --- | --- | | children | 子菜单的菜单项 | [ItemType\[\]](#ItemType) | - | | | disabled | 是否禁用 | boolean | false | | | icon | 菜单图标 | ReactNode | - | | From 524c93642c8ae41c585b909ac980813730f26df0 Mon Sep 17 00:00:00 2001 From: kalykun <984757534@qq.com> Date: Tue, 14 Jun 2022 14:58:06 +0800 Subject: [PATCH 15/20] docs: fix demos (#36040) * docs: fix demos * ++ --- components/upload/demo/upload-manually.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/upload/demo/upload-manually.md b/components/upload/demo/upload-manually.md index c98e30a400..ff1141032b 100644 --- a/components/upload/demo/upload-manually.md +++ b/components/upload/demo/upload-manually.md @@ -26,7 +26,7 @@ const App: React.FC = () => { const handleUpload = () => { const formData = new FormData(); fileList.forEach(file => { - formData.append('files[]', file.originFileObj as RcFile); + formData.append('files[]', file as RcFile); }); setUploading(true); // You can use any AJAX library you like From 147468a69cb528f2a987a3d9d0cab899e05c2357 Mon Sep 17 00:00:00 2001 From: MadCcc <1075746765@qq.com> Date: Wed, 15 Jun 2022 00:09:31 +0800 Subject: [PATCH 16/20] fix: fix incorrect form status with noStyle (#36054) * fix: form status * test: update test case --- components/form/FormItem.tsx | 31 ++++--------------- .../__snapshots__/demo-extend.test.ts.snap | 4 +-- .../__tests__/__snapshots__/demo.test.js.snap | 4 +-- components/form/__tests__/index.test.js | 28 +++++++---------- 4 files changed, 22 insertions(+), 45 deletions(-) diff --git a/components/form/FormItem.tsx b/components/form/FormItem.tsx index bb602f29db..1422a946ed 100644 --- a/components/form/FormItem.tsx +++ b/components/form/FormItem.tsx @@ -217,14 +217,9 @@ function FormItem(props: FormItemProps): React.ReactElemen const getItemRef = useItemRef(); // ======================== Status ======================== - const { status: contextStatus, hasFeedback: contextHasFeedback } = - useContext(FormItemInputContext); - - let mergedValidateStatus: ValidateStatus | undefined; + let mergedValidateStatus: ValidateStatus = ''; if (validateStatus !== undefined) { mergedValidateStatus = validateStatus; - } else if (contextStatus !== undefined) { - mergedValidateStatus = contextStatus; } else if (meta?.validating) { mergedValidateStatus = 'validating'; } else if (debounceErrors.length) { @@ -235,11 +230,9 @@ function FormItem(props: FormItemProps): React.ReactElemen mergedValidateStatus = 'success'; } - const mergedHasFeedback = hasFeedback || contextHasFeedback; - const formItemStatusContext = useMemo(() => { let feedbackIcon: ReactNode; - if (mergedHasFeedback) { + if (hasFeedback) { const IconNode = mergedValidateStatus && iconMap[mergedValidateStatus]; feedbackIcon = IconNode ? ( (props: FormItemProps): React.ReactElemen return { status: mergedValidateStatus, - hasFeedback: mergedHasFeedback, + hasFeedback, feedbackIcon, isFormItemInput: true, }; - }, [mergedValidateStatus, mergedHasFeedback]); - - const noOverrideFormItemContext = useMemo( - () => ({ - ...formItemStatusContext, - isFormItemInput: false, - }), - [formItemStatusContext], - ); + }, [mergedValidateStatus, hasFeedback]); // ======================== Render ======================== function renderLayout( @@ -276,11 +261,7 @@ function FormItem(props: FormItemProps): React.ReactElemen isRequired?: boolean, ): React.ReactNode { if (noStyle && !hidden) { - return ( - - {baseChildren} - - ); + return baseChildren; } const itemClassName = { @@ -290,7 +271,7 @@ function FormItem(props: FormItemProps): React.ReactElemen [`${className}`]: !!className, // Status - [`${prefixCls}-item-has-feedback`]: mergedValidateStatus && mergedHasFeedback, + [`${prefixCls}-item-has-feedback`]: mergedValidateStatus && hasFeedback, [`${prefixCls}-item-has-success`]: mergedValidateStatus === 'success', [`${prefixCls}-item-has-warning`]: mergedValidateStatus === 'warning', [`${prefixCls}-item-has-error`]: mergedValidateStatus === 'error', diff --git a/components/form/__tests__/__snapshots__/demo-extend.test.ts.snap b/components/form/__tests__/__snapshots__/demo-extend.test.ts.snap index 54c70913dc..348af0076d 100644 --- a/components/form/__tests__/__snapshots__/demo-extend.test.ts.snap +++ b/components/form/__tests__/__snapshots__/demo-extend.test.ts.snap @@ -6836,7 +6836,7 @@ exports[`renders ./components/form/demo/normal-login.md extend context correctly class="ant-form-item-control-input-content" >