diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 75eafde987..1fc87e596f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -205,12 +205,18 @@ jobs: if: ${{ matrix.module == 'dom' }} run: npm test -- --maxWorkers=2 --shard=${{matrix.shard}} --coverage - - name: coverage - uses: codecov/codecov-action@v3 + - name: persist coverages if: ${{ matrix.module == 'dom' && matrix.react == '17' }} + run: | + mkdir persist-coverage + mv coverage/coverage-final.json persist-coverage/react-${{matrix.react}}-test-${{matrix.module}}-${{strategy.job-index}}.json + + - uses: actions/upload-artifact@v3 + if: ${{ matrix.module == 'dom' && matrix.react == '17' }} + name: upload coverages with: - # use own token to upload coverage reports - token: ${{ secrets.CODECOV_TOKEN }} + name: coverage-artifacts + path: persist-coverage/ # node test - name: node test @@ -225,6 +231,28 @@ jobs: LIB_DIR: dist needs: [setup, dist] + ############################ Test Coverage ########################### + upload-test-coverage: + name: test-coverage + runs-on: ubuntu-latest + needs: [normal-test] + steps: + - uses: actions/checkout@v3 + - uses: actions/download-artifact@v3 + with: + name: coverage-artifacts + path: persist-coverage + - name: Merge Code Coverage + run: | + npx nyc merge persist-coverage/ coverage/coverage-final.json + npx nyc report --reporter text -t coverage --report-dir coverage + rm -rf persist-coverage + - name: Upload coverage to codecov + uses: codecov/codecov-action@v3 + with: + # use own token to upload coverage reports + token: ${{ secrets.CODECOV_TOKEN }} + ########################### Compile & Test ########################### compile: runs-on: ubuntu-latest diff --git a/CHANGELOG.en-US.md b/CHANGELOG.en-US.md index e7e05bfc6a..f96db93e9f 100644 --- a/CHANGELOG.en-US.md +++ b/CHANGELOG.en-US.md @@ -15,6 +15,37 @@ timeline: true --- +## 4.23.0 + +`2022-09-04` + +- 🆕 Tooltip support nested Fragment child nodes to display bubbles. [#37045](https://github.com/ant-design/ant-design/pull/37045) [@HQ-Lin](https://github.com/HQ-Lin) +- 🆕 Dropdown.Button support `danger` props. [#36810](https://github.com/ant-design/ant-design/pull/36810) [@nuintun](https://github.com/nuintun) +- 🆕 Input.TextArea add `value` parameter to `showCount.formatter`. [#36793](https://github.com/ant-design/ant-design/pull/36793) [@JarvisArt](https://github.com/JarvisArt) +- 🆕 Table support `expandable.columnTitle` now. [#36794](https://github.com/ant-design/ant-design/pull/36794) [@losgif](https://github.com/losgif) +- Deprecate `visible` in all components and change to `open`. + - 🛠 Dropdown changes `visible` to `open`. [#37232](https://github.com/ant-design/ant-design/pull/37232) [@yykoypj](https://github.com/yykoypj) + - 🛠 Modal changes `visible` to `open`. [#37084](https://github.com/ant-design/ant-design/pull/37084) [@yykoypj](https://github.com/yykoypj) + - 🛠 Drawer changes `visible` to `open`. [#37047](https://github.com/ant-design/ant-design/pull/37047) [@yykoypj](https://github.com/yykoypj) + - 🛠 Table changes `filterDropdownVisible` to `filterDropdownOpen`. [#37026](https://github.com/ant-design/ant-design/pull/37026) [@yykoypj](https://github.com/yykoypj) + - 🛠 Slider add `tooltip` prop for all props related with Tooltip. [#37000](https://github.com/ant-design/ant-design/pull/37000) [@yykoypj](https://github.com/yykoypj) + - 🛠 Tooltip Popover and Popconfirm change `visible` to `open`. [#37241](https://github.com/ant-design/ant-design/pull/37241) [@yykoypj](https://github.com/yykoypj) + - 🛠 Remove `visible` prop of Tag. [#36934](https://github.com/ant-design/ant-design/pull/36934) [@yykoypj](https://github.com/yykoypj) +- 🛠 Deprecate `dropdownClassName` prop of all components and change to `popupClassName`. [#36880](https://github.com/ant-design/ant-design/pull/36880) [@heiyu4585](https://github.com/heiyu4585) +- 🛠 Tabs support `items` props and origin jsx usage will be depreacted. [#36889](https://github.com/ant-design/ant-design/pull/36889) +- 🐞 Fix that some css variables are not consistent with less variables. + - [#37064](https://github.com/ant-design/ant-design/pull/37064) [@TrickyPi](https://github.com/TrickyPi) + - [#37304](https://github.com/ant-design/ant-design/pull/37304) [@peritot](https://github.com/peritot) +- 🐞 Fix Menu disabled item focus style. [#37332](https://github.com/ant-design/ant-design/pull/37332) +- 💄 `@border-radius-sm` should not follow `@border-radius-base` by default. [#37309](https://github.com/ant-design/ant-design/pull/37309) +- 💄 add `@slider-handle-margin-left` to custom type. [#37001](https://github.com/ant-design/ant-design/pull/37001) [@alanhaledc](https://github.com/alanhaledc) +- 💄 Replace Tabs with fade switch motion to import switch experience. [#36943](https://github.com/ant-design/ant-design/pull/36943) +- ⌨️ Improve Form validation accessibility experience. [#36762](https://github.com/ant-design/ant-design/pull/36762) [@VladimirOtroshchenko](https://github.com/VladimirOtroshchenko) +- 🌐 Add missing translations for filterCheckall in ru_RU. [#37311](https://github.com/ant-design/ant-design/pull/37311) [@HelLuv](https://github.com/HelLuv) +- 🌐 Add missing translations in `cs_CZ`. [#37388](https://github.com/ant-design/ant-design/pull/37388) [@ZdenekKrcal](https://github.com/ZdenekKrcal) + +--- + ## 4.22.8 `2022-08-26` diff --git a/CHANGELOG.zh-CN.md b/CHANGELOG.zh-CN.md index 6bbaa24748..cf6b448e21 100644 --- a/CHANGELOG.zh-CN.md +++ b/CHANGELOG.zh-CN.md @@ -15,6 +15,37 @@ timeline: true --- +## 4.23.0 + +`2022-09-04` + +- 🆕 Tooltip 支持 Fragment 子节点展示气泡。[#37045](https://github.com/ant-design/ant-design/pull/37045) [@HQ-Lin](https://github.com/HQ-Lin) +- 🆕 Dropdown.Button 支持 `danger` 样式。[#36810](https://github.com/ant-design/ant-design/pull/36810) [@nuintun](https://github.com/nuintun) +- 🆕 Input.TextArea 组件 `showCount.formatter` API 添加 `value` 参数。[#36793](https://github.com/ant-design/ant-design/pull/36793) [@JarvisArt](https://github.com/JarvisArt) +- 🆕 Table 新增 `expandable.columnTitle` 属性以支持自定义展开列表头。[#36794](https://github.com/ant-design/ant-design/pull/36794) [@losgif](https://github.com/losgif) +- 🛠 废弃所有弹窗组件的 `visible` 属性,统一为 `open`。 + - 🛠 Dropdown 的 `visible` 改为 `open`。[#37232](https://github.com/ant-design/ant-design/pull/37232) [@yykoypj](https://github.com/yykoypj) + - 🛠 Modal 组件的 `visible` 改为 `open`。[#37084](https://github.com/ant-design/ant-design/pull/37084) [@yykoypj](https://github.com/yykoypj) + - 🛠 Drawer 的 `visible` 改为 `open`。[#37047](https://github.com/ant-design/ant-design/pull/37047) [@yykoypj](https://github.com/yykoypj) + - 🛠 Table 组件 `columns` 中的 `filterDropdownVisible` 改为 `filterDropdownOpen`。[#37026](https://github.com/ant-design/ant-design/pull/37026) [@yykoypj](https://github.com/yykoypj) + - 🛠 Tooltip, Popover 和 Popconfirm 中的 `visible` 改为 `open`。[#37241](https://github.com/ant-design/ant-design/pull/37241) [@yykoypj](https://github.com/yykoypj) + - 🛠 Slider 的 `tooltip` 相关属性合并到 `tooltip` 属性中。[#37000](https://github.com/ant-design/ant-design/pull/37000) [@yykoypj](https://github.com/yykoypj) + - 🛠 移除 Tag 组件的 `visible` 属性。[#36934](https://github.com/ant-design/ant-design/pull/36934) [@yykoypj](https://github.com/yykoypj) +- 🛠 废弃所有组件的 `dropdownClassName`,统一为 `popupClassName`。[#36880](https://github.com/ant-design/ant-design/pull/36880) [@heiyu4585](https://github.com/heiyu4585) +- 🛠 Tabs 支持 `items` 属性,并且废弃原 jsx 语法糖用法。[#36889](https://github.com/ant-design/ant-design/pull/36889) +- 🐞 修复 css 变量与 less 变量不一致的问题。 + - [#37064](https://github.com/ant-design/ant-design/pull/37064) [@TrickyPi](https://github.com/TrickyPi) + - [#37304](https://github.com/ant-design/ant-design/pull/37304) [@peritot](https://github.com/peritot) +- 🐞 修复 Menu 禁用项依然有 focus 样式的问题。[#37332](https://github.com/ant-design/ant-design/pull/37332) +- 💄 `@border-radius-sm` 变量默认值不与 `@border-radius-base` 关联,以修复 Checkbox 等组件圆角样式异常。[#37309](https://github.com/ant-design/ant-design/pull/37309) +- 💄 支持使用 `@slider-handle-margin-left` 定制样式。[#37001](https://github.com/ant-design/ant-design/pull/37001) [@alanhaledc](https://github.com/alanhaledc) +- 💄 替换 Tabs 切换样式为渐隐过渡,以提升在切换时的体验。[#36943](https://github.com/ant-design/ant-design/pull/36943) +- ⌨️ 改进 Form 校验无障碍体验。[#36762](https://github.com/ant-design/ant-design/pull/36762) [@VladimirOtroshchenko](https://github.com/VladimirOtroshchenko) +- 🌐 补全 `ru_RU` 中 `filterCheckall` 的翻译。[#37311](https://github.com/ant-design/ant-design/pull/37311) [@HelLuv](https://github.com/HelLuv) +- 🌐 补全 `cs_CZ` 的翻译。[#37388](https://github.com/ant-design/ant-design/pull/37388) [@ZdenekKrcal](https://github.com/ZdenekKrcal) + +--- + ## 4.22.8 `2022-08-26` diff --git a/components/__tests__/__snapshots__/index.test.js.snap b/components/__tests__/__snapshots__/index.test.ts.snap similarity index 100% rename from components/__tests__/__snapshots__/index.test.js.snap rename to components/__tests__/__snapshots__/index.test.ts.snap diff --git a/components/__tests__/index.test.js b/components/__tests__/index.test.ts similarity index 100% rename from components/__tests__/index.test.js rename to components/__tests__/index.test.ts diff --git a/components/affix/__tests__/Affix.test.tsx b/components/affix/__tests__/Affix.test.tsx index 5d3b0473d2..bd37d46298 100644 --- a/components/affix/__tests__/Affix.test.tsx +++ b/components/affix/__tests__/Affix.test.tsx @@ -1,11 +1,9 @@ -import type { ReactWrapper } from 'enzyme'; -import { mount } from 'enzyme'; import React from 'react'; -import type { AffixProps, AffixState, InternalAffixClass } from '..'; +import type { InternalAffixClass } from '..'; import Affix from '..'; import accessibilityTest from '../../../tests/shared/accessibilityTest'; import rtlTest from '../../../tests/shared/rtlTest'; -import { render, sleep } from '../../../tests/utils'; +import { render, sleep, triggerResize } from '../../../tests/utils'; import Button from '../../button'; import { getObserverEntities } from '../utils'; @@ -16,11 +14,10 @@ class AffixMounter extends React.Component<{ offsetTop?: number; onTestUpdatePosition?(): void; onChange?: () => void; + getInstance?: (inst: InternalAffixClass) => void; }> { private container: HTMLDivElement; - public affix: React.Component; - componentDidMount() { this.container.addEventListener = jest .fn() @@ -32,6 +29,7 @@ class AffixMounter extends React.Component<{ getTarget = () => this.container; render() { + const { getInstance, ...restProps } = this.props; return (
{ @@ -43,9 +41,9 @@ class AffixMounter extends React.Component<{ className="fixed" target={this.getTarget} ref={ele => { - this.affix = ele!; + getInstance?.(ele!); }} - {...this.props} + {...restProps} > @@ -59,7 +57,6 @@ describe('Affix Render', () => { accessibilityTest(Affix); const domMock = jest.spyOn(HTMLElement.prototype, 'getBoundingClientRect'); - let affixMounterWrapper: ReactWrapper; const classRect: Record = { container: { @@ -194,34 +191,43 @@ describe('Affix Render', () => { }); describe('updatePosition when size changed', () => { - it.each([ - { name: 'inner', index: 0 }, - { name: 'outer', index: 1 }, - ])('inner or outer', async ({ index }) => { + it('add class automatically', async () => { document.body.innerHTML = '
'; - const updateCalled = jest.fn(); - affixMounterWrapper = mount( - , + let affixInstance: InternalAffixClass | null = null; + render( + { + affixInstance = inst; + }} + offsetBottom={0} + />, { - attachTo: document.getElementById('mounter'), + container: document.getElementById('mounter')!, }, ); await sleep(20); - await movePlaceholder(300); - expect( - (affixMounterWrapper.find(AffixMounter).instance() as any).affix.state.affixStyle, - ).toBeTruthy(); - await sleep(20); - affixMounterWrapper.update(); + expect(affixInstance!.state.affixStyle).toBeTruthy(); + }); + + // Trigger inner and outer element for the two s. + it.each([ + { selector: '.ant-btn' }, // inner + { selector: '.fixed' }, // outer + ])('trigger listener when size change', async ({ selector }) => { + const updateCalled = jest.fn(); + const { container } = render( + , + { + container: document.getElementById('mounter')!, + }, + ); - // Mock trigger resize updateCalled.mockReset(); - (affixMounterWrapper as any).triggerResize(index); + triggerResize(container.querySelector(selector)!); await sleep(20); - expect(updateCalled).toHaveBeenCalled(); }); }); diff --git a/components/auto-complete/__tests__/__snapshots__/demo.test.js.snap b/components/auto-complete/__tests__/__snapshots__/demo.test.ts.snap similarity index 100% rename from components/auto-complete/__tests__/__snapshots__/demo.test.js.snap rename to components/auto-complete/__tests__/__snapshots__/demo.test.ts.snap diff --git a/components/auto-complete/__tests__/demo.test.js b/components/auto-complete/__tests__/demo.test.ts similarity index 100% rename from components/auto-complete/__tests__/demo.test.js rename to components/auto-complete/__tests__/demo.test.ts diff --git a/components/auto-complete/__tests__/focus.test.js b/components/auto-complete/__tests__/focus.test.tsx similarity index 74% rename from components/auto-complete/__tests__/focus.test.js rename to components/auto-complete/__tests__/focus.test.tsx index 4303b0f94d..032d0e90e9 100644 --- a/components/auto-complete/__tests__/focus.test.js +++ b/components/auto-complete/__tests__/focus.test.tsx @@ -8,7 +8,7 @@ describe('AutoComplete children could be focus', () => { jest.useFakeTimers(); }); - let container; + let container: HTMLDivElement; beforeEach(() => { container = document.createElement('div'); document.body.appendChild(container); @@ -24,10 +24,8 @@ describe('AutoComplete children could be focus', () => { it('focus() and onFocus', () => { const handleFocus = jest.fn(); - const { container: wrapper } = render(, { - attachTo: container, - }); - wrapper.querySelector('input').focus(); + const { container: wrapper } = render(, { container }); + wrapper.querySelector('input')?.focus(); act(() => { jest.runAllTimers(); }); @@ -36,14 +34,12 @@ describe('AutoComplete children could be focus', () => { it('blur() and onBlur', () => { const handleBlur = jest.fn(); - const { container: wrapper } = render(, { - attachTo: container, - }); - wrapper.querySelector('input').focus(); + const { container: wrapper } = render(, { container }); + wrapper.querySelector('input')?.focus(); act(() => { jest.runAllTimers(); }); - wrapper.querySelector('input').blur(); + wrapper.querySelector('input')?.blur(); act(() => { jest.runAllTimers(); }); @@ -61,17 +57,13 @@ describe('AutoComplete children could be focus', () => { }); it('child.ref instance should support be focused and blured', () => { - let inputRef; + const inputRef = React.createRef(); render( - { - inputRef = node; - }} - /> + , ); - expect(typeof inputRef.focus).toBe('function'); - expect(typeof inputRef.blur).toBe('function'); + expect(typeof inputRef.current?.focus).toBe('function'); + expect(typeof inputRef.current?.blur).toBe('function'); }); }); diff --git a/components/back-top/__tests__/__snapshots__/demo.test.js.snap b/components/back-top/__tests__/__snapshots__/demo.test.ts.snap similarity index 100% rename from components/back-top/__tests__/__snapshots__/demo.test.js.snap rename to components/back-top/__tests__/__snapshots__/demo.test.ts.snap diff --git a/components/back-top/__tests__/__snapshots__/index.test.js.snap b/components/back-top/__tests__/__snapshots__/index.test.tsx.snap similarity index 100% rename from components/back-top/__tests__/__snapshots__/index.test.js.snap rename to components/back-top/__tests__/__snapshots__/index.test.tsx.snap diff --git a/components/back-top/__tests__/demo.test.js b/components/back-top/__tests__/demo.test.ts similarity index 100% rename from components/back-top/__tests__/demo.test.js rename to components/back-top/__tests__/demo.test.ts diff --git a/components/back-top/__tests__/index.test.js b/components/back-top/__tests__/index.test.tsx similarity index 79% rename from components/back-top/__tests__/index.test.js rename to components/back-top/__tests__/index.test.tsx index 2a0422c279..0ff9cea619 100644 --- a/components/back-top/__tests__/index.test.js +++ b/components/back-top/__tests__/index.test.tsx @@ -10,14 +10,14 @@ describe('BackTop', () => { it('should scroll to top after click it', async () => { const { container } = render(); - const scrollToSpy = jest.spyOn(window, 'scrollTo').mockImplementation((x, y) => { + const scrollToSpy = jest.spyOn(window, 'scrollTo').mockImplementation((_, y) => { window.scrollY = y; window.pageYOffset = y; document.documentElement.scrollTop = y; }); window.scrollTo(0, 400); expect(document.documentElement.scrollTop).toBe(400); - fireEvent.click(container.querySelector('.ant-back-top')); + fireEvent.click(container.querySelector('.ant-back-top')!); await sleep(500); expect(document.documentElement.scrollTop).toBe(0); scrollToSpy.mockRestore(); @@ -26,23 +26,21 @@ describe('BackTop', () => { it('support onClick', async () => { const onClick = jest.fn(); const { container } = render(); - const scrollToSpy = jest.spyOn(window, 'scrollTo').mockImplementation((x, y) => { + const scrollToSpy = jest.spyOn(window, 'scrollTo').mockImplementation((_, y) => { window.scrollY = y; window.pageYOffset = y; }); document.dispatchEvent(new Event('scroll')); window.scrollTo(0, 400); - fireEvent.click(container.querySelector('.ant-back-top')); + fireEvent.click(container.querySelector('.ant-back-top')!); expect(onClick).toHaveBeenCalled(); scrollToSpy.mockRestore(); }); it('invalid target', async () => { const onClick = jest.fn(); - const { container } = render( - ({ documentElement: {} })} />, - ); - fireEvent.click(container.querySelector('.ant-back-top')); + const { container } = render(); + fireEvent.click(container.querySelector('.ant-back-top')!); expect(onClick).toHaveBeenCalled(); }); }); diff --git a/components/breadcrumb/__tests__/Breadcrumb.test.js b/components/breadcrumb/__tests__/Breadcrumb.test.tsx similarity index 95% rename from components/breadcrumb/__tests__/Breadcrumb.test.js rename to components/breadcrumb/__tests__/Breadcrumb.test.tsx index 5c25047b73..ea4ac0c5ed 100644 --- a/components/breadcrumb/__tests__/Breadcrumb.test.js +++ b/components/breadcrumb/__tests__/Breadcrumb.test.tsx @@ -3,6 +3,7 @@ import accessibilityTest from '../../../tests/shared/accessibilityTest'; import mountTest from '../../../tests/shared/mountTest'; import rtlTest from '../../../tests/shared/rtlTest'; import { render } from '../../../tests/utils'; +import type { Route } from '../Breadcrumb'; import Breadcrumb from '../index'; describe('Breadcrumb', () => { @@ -22,7 +23,7 @@ describe('Breadcrumb', () => { // https://github.com/airbnb/enzyme/issues/875 it('warns on non-Breadcrumb.Item and non-Breadcrumb.Separator children', () => { - const MyCom = () =>
foo
; + const MyCom: React.FC = () =>
foo
; render( @@ -74,7 +75,7 @@ describe('Breadcrumb', () => { }); it('should render a menu', () => { - const routes = [ + const routes: Route[] = [ { path: 'index', breadcrumbName: 'home', @@ -103,6 +104,7 @@ describe('Breadcrumb', () => { }, { path: 'third', + breadcrumbName: '', }, ]; const { asFragment } = render(); @@ -142,7 +144,7 @@ describe('Breadcrumb', () => { // https://github.com/ant-design/ant-design/issues/25975 it('should support Breadcrumb.Item default separator', () => { - const MockComponent = () => ( + const MockComponent: React.FC = () => ( Mock Node diff --git a/components/breadcrumb/__tests__/__snapshots__/Breadcrumb.test.js.snap b/components/breadcrumb/__tests__/__snapshots__/Breadcrumb.test.tsx.snap similarity index 100% rename from components/breadcrumb/__tests__/__snapshots__/Breadcrumb.test.js.snap rename to components/breadcrumb/__tests__/__snapshots__/Breadcrumb.test.tsx.snap diff --git a/components/breadcrumb/__tests__/__snapshots__/demo.test.js.snap b/components/breadcrumb/__tests__/__snapshots__/demo.test.ts.snap similarity index 100% rename from components/breadcrumb/__tests__/__snapshots__/demo.test.js.snap rename to components/breadcrumb/__tests__/__snapshots__/demo.test.ts.snap diff --git a/components/breadcrumb/__tests__/__snapshots__/router.test.js.snap b/components/breadcrumb/__tests__/__snapshots__/router.test.tsx.snap similarity index 100% rename from components/breadcrumb/__tests__/__snapshots__/router.test.js.snap rename to components/breadcrumb/__tests__/__snapshots__/router.test.tsx.snap diff --git a/components/breadcrumb/__tests__/demo.test.js b/components/breadcrumb/__tests__/demo.test.ts similarity index 100% rename from components/breadcrumb/__tests__/demo.test.js rename to components/breadcrumb/__tests__/demo.test.ts diff --git a/components/breadcrumb/__tests__/router.test.js b/components/breadcrumb/__tests__/router.test.tsx similarity index 86% rename from components/breadcrumb/__tests__/router.test.js rename to components/breadcrumb/__tests__/router.test.tsx index 3f3ddadac3..5e4ec0ad85 100644 --- a/components/breadcrumb/__tests__/router.test.js +++ b/components/breadcrumb/__tests__/router.test.tsx @@ -1,9 +1,10 @@ -import React from 'react'; +import React, { useMemo } from 'react'; +import type { RouterProps } from 'react-router-dom'; import { Link, MemoryRouter, Route, Routes, useLocation, useNavigate } from 'react-router-dom'; import { fireEvent, render } from '../../../tests/utils'; import Breadcrumb from '../index'; -const Apps = () => ( +const Apps: React.FC = () => (
  • Application1:Detail @@ -33,7 +34,7 @@ describe('react router', () => { // https://github.com/airbnb/enzyme/issues/875 it('react router 6', () => { - const Home = () => { + const Home: React.FC = () => { const location = useLocation(); const navigate = useNavigate(); const pathSnippets = location.pathname.split('/').filter(i => i); @@ -41,7 +42,7 @@ describe('react router', () => { const url = `/${pathSnippets.slice(0, index + 1).join('/')}`; return ( - {breadcrumbNameMap[url]} + {breadcrumbNameMap[url as keyof typeof breadcrumbNameMap]} ); }); @@ -50,6 +51,14 @@ describe('react router', () => { Home , ].concat(extraBreadcrumbItems); + const componentProps = useMemo( + () => ({ component: Apps } as unknown as RouterProps), + [], + ); + const renderProps = useMemo( + () => ({ render: () => Home Page } as unknown as RouterProps), + [], + ); return (
    @@ -57,8 +66,8 @@ describe('react router', () => { navigate('/apps')}>Application List
    - - Home Page} /> + + {breadcrumbItems}
    diff --git a/components/cascader/__tests__/__snapshots__/demo.test.js.snap b/components/cascader/__tests__/__snapshots__/demo.test.ts.snap similarity index 100% rename from components/cascader/__tests__/__snapshots__/demo.test.js.snap rename to components/cascader/__tests__/__snapshots__/demo.test.ts.snap diff --git a/components/cascader/__tests__/__snapshots__/index.test.js.snap b/components/cascader/__tests__/__snapshots__/index.test.tsx.snap similarity index 100% rename from components/cascader/__tests__/__snapshots__/index.test.js.snap rename to components/cascader/__tests__/__snapshots__/index.test.tsx.snap diff --git a/components/cascader/__tests__/demo.test.js b/components/cascader/__tests__/demo.test.ts similarity index 100% rename from components/cascader/__tests__/demo.test.js rename to components/cascader/__tests__/demo.test.ts diff --git a/components/cascader/__tests__/index.test.js b/components/cascader/__tests__/index.test.tsx similarity index 81% rename from components/cascader/__tests__/index.test.js rename to components/cascader/__tests__/index.test.tsx index 511392135a..e148c89263 100644 --- a/components/cascader/__tests__/index.test.js +++ b/components/cascader/__tests__/index.test.tsx @@ -1,4 +1,6 @@ import React from 'react'; +import type { SingleValueType } from 'rc-cascader/lib/Cascader'; +import type { BaseOptionType, DefaultOptionType } from '..'; import Cascader from '..'; import excludeAllWarning from '../../../tests/shared/excludeWarning'; import focusTest from '../../../tests/shared/focusTest'; @@ -9,22 +11,27 @@ import { fireEvent, render } from '../../../tests/utils'; const { SHOW_CHILD, SHOW_PARENT } = Cascader; -function toggleOpen(container) { - fireEvent.mouseDown(container.querySelector('.ant-select-selector')); +function toggleOpen(container: ReturnType['container']) { + fireEvent.mouseDown(container.querySelector('.ant-select-selector')!); } -function isOpen(container) { - return container.querySelector('.ant-cascader').className.includes('ant-select-open'); +function isOpen(container: ReturnType['container']) { + return container.querySelector('.ant-cascader')?.className.includes('ant-select-open'); } -function getDropdown(container) { +function getDropdown(container: ReturnType['container']) { return container.querySelector('.ant-select-dropdown'); } -function clickOption(container, menuIndex, itemIndex, type = 'click') { +function clickOption( + container: ReturnType['container'], + menuIndex: number, + itemIndex: number, + type = 'click', +) { const menu = container.querySelectorAll('ul.ant-cascader-menu')[menuIndex]; const itemList = menu.querySelectorAll('li.ant-cascader-menu-item'); - fireEvent[type](itemList[itemIndex]); + fireEvent?.[type as keyof typeof fireEvent]?.(itemList[itemIndex]); } const options = [ @@ -62,8 +69,11 @@ const options = [ }, ]; -function filter(inputValue, path) { - return path.some(option => option.label.toLowerCase().indexOf(inputValue.toLowerCase()) > -1); +function filter( + inputValue: string, + path: OptionType[], +): boolean { + return path.some(option => option.label.toLowerCase().includes(inputValue.toLowerCase())); } describe('Cascader', () => { @@ -133,31 +143,25 @@ describe('Cascader', () => { it('backspace should work with `Cascader[showSearch]`', () => { const { container } = render(); - fireEvent.change(container.querySelector('input'), { target: { value: '123' } }); + fireEvent.change(container.querySelector('input')!, { target: { value: '123' } }); expect(isOpen(container)).toBeTruthy(); - fireEvent.keyDown(container.querySelector('input'), { - key: 'Backspace', - keyCode: 8, - }); + fireEvent.keyDown(container.querySelector('input')!, { key: 'Backspace', keyCode: 8 }); expect(isOpen(container)).toBeTruthy(); - fireEvent.change(container.querySelector('input'), { target: { value: '' } }); + fireEvent.change(container.querySelector('input')!, { target: { value: '' } }); expect(isOpen(container)).toBeTruthy(); - fireEvent.keyDown(container.querySelector('input'), { - key: 'Backspace', - keyCode: 8, - }); + fireEvent.keyDown(container.querySelector('input')!, { key: 'Backspace', keyCode: 8 }); expect(isOpen(container)).toBeFalsy(); }); it('should highlight keyword and filter when search in Cascader', () => { const { container } = render(); - fireEvent.change(container.querySelector('input'), { target: { value: 'z' } }); + fireEvent.change(container.querySelector('input')!, { target: { value: 'z' } }); // React 18 with testing lib will have additional space. We have to compare innerHTML. Sad. - expect(getDropdown(container).innerHTML).toMatchSnapshot(); + expect(getDropdown(container)?.innerHTML).toMatchSnapshot(); }); it('should highlight keyword and filter when search in Cascader with same field name of label and value', () => { @@ -180,8 +184,11 @@ describe('Cascader', () => { ], }, ]; - function customFilter(inputValue, path) { - return path.some(option => option.name.toLowerCase().indexOf(inputValue.toLowerCase()) > -1); + function customFilter( + inputValue: string, + path: OptionType[], + ): boolean { + return path.some(option => option.name.toLowerCase().includes(inputValue.toLowerCase())); } const { container } = render( { showSearch={{ filter: customFilter }} />, ); - fireEvent.change(container.querySelector('input'), { target: { value: 'z' } }); + fireEvent.change(container.querySelector('input')!, { target: { value: 'z' } }); // React 18 with testing lib will have additional space. We have to compare innerHTML. Sad. - expect(getDropdown(container).innerHTML).toMatchSnapshot(); + expect(getDropdown(container)?.innerHTML).toMatchSnapshot(); }); it('should render not found content', () => { const { container } = render(); - fireEvent.change(container.querySelector('input'), { + fireEvent.change(container.querySelector('input')!, { target: { value: '__notfoundkeyword__' }, }); expect(getDropdown(container)).toMatchSnapshot(); @@ -208,10 +215,10 @@ describe('Cascader', () => { const { container } = render( , ); - expect(container.querySelector('.ant-select-selection-item').textContent).toEqual( + expect(container.querySelector('.ant-select-selection-item')?.textContent).toEqual( 'Zhejiang / Hangzhou', ); - fireEvent.mouseDown(container.querySelector('.ant-select-clear')); + fireEvent.mouseDown(container.querySelector('.ant-select-clear')!); expect(container.querySelector('.ant-select-selection-item')).toBeFalsy(); }); @@ -219,14 +226,14 @@ describe('Cascader', () => { const { container } = render( , ); - fireEvent.change(container.querySelector('input'), { target: { value: 'xxx' } }); - fireEvent.mouseDown(container.querySelector('.ant-select-clear')); - expect(container.querySelector('input').value).toEqual(''); + fireEvent.change(container.querySelector('input')!, { target: { value: 'xxx' } }); + fireEvent.mouseDown(container.querySelector('.ant-select-clear')!); + expect(container.querySelector('input')?.value).toEqual(''); }); it('should change filtered item when options are changed', () => { const { container, rerender } = render(); - fireEvent.change(container.querySelector('input'), { target: { value: 'a' } }); + fireEvent.change(container.querySelector('input')!, { target: { value: 'a' } }); expect(container.querySelectorAll('.ant-cascader-menu-item').length).toBe(2); rerender(); @@ -235,14 +242,11 @@ describe('Cascader', () => { it('should select item immediately when searching and pressing down arrow key', () => { const { container } = render(); - fireEvent.change(container.querySelector('input'), { target: { value: 'a' } }); + fireEvent.change(container.querySelector('input')!, { target: { value: 'a' } }); expect(container.querySelectorAll('.ant-cascader-menu-item').length).toBe(2); expect(container.querySelectorAll('.ant-cascader-menu-item-active').length).toBe(0); - fireEvent.keyDown(container.querySelector('input'), { - key: 'Down', - keyCode: 40, - }); + fireEvent.keyDown(container.querySelector('input')!, { key: 'Down', keyCode: 40 }); expect(container.querySelectorAll('.ant-cascader-menu-item-active').length).toBe(1); }); @@ -300,14 +304,14 @@ describe('Cascader', () => { clickOption(container, 0, 0); clickOption(container, 1, 0); clickOption(container, 2, 0); - expect(container.querySelector('.ant-select-selection-item').textContent).toEqual( + expect(container.querySelector('.ant-select-selection-item')?.textContent).toEqual( 'Zhejiang / Hangzhou / West Lake', ); expect(onChange).toHaveBeenCalledWith(['zhejiang', 'hangzhou', 'xihu'], expect.anything()); }); it('should show not found content when options.length is 0', () => { - const customerOptions = []; + const customerOptions: any[] = []; const { container } = render(); toggleOpen(container); expect(getDropdown(container)).toMatchSnapshot(); @@ -329,7 +333,7 @@ describe('Cascader', () => { const { container } = render( , ); - fireEvent.change(container.querySelector('input'), { target: { value: 'a' } }); + fireEvent.change(container.querySelector('input')!, { target: { value: 'a' } }); expect(container.querySelectorAll('.ant-cascader-menu-item')).toHaveLength(1); }); @@ -337,7 +341,7 @@ describe('Cascader', () => { const { container } = render( , ); - fireEvent.change(container.querySelector('input'), { target: { value: 'a' } }); + fireEvent.change(container.querySelector('input')!, { target: { value: 'a' } }); expect(container.querySelectorAll('.ant-cascader-menu-item')).toHaveLength(2); }); @@ -345,8 +349,8 @@ describe('Cascader', () => { const { container } = render( , ); - fireEvent.click(container.querySelector('input')); - fireEvent.change(container.querySelector('input'), { target: { value: 'a' } }); + fireEvent.click(container.querySelector('input')!); + fireEvent.change(container.querySelector('input')!, { target: { value: 'a' } }); expect(container.querySelectorAll('.ant-cascader-menu-item')).toHaveLength(2); }); }); @@ -384,11 +388,11 @@ describe('Cascader', () => { it('placeholder works correctly', () => { const { container, rerender } = render(); - expect(container.querySelector('.ant-select-selection-placeholder').textContent).toEqual(''); + expect(container.querySelector('.ant-select-selection-placeholder')?.textContent).toEqual(''); const customPlaceholder = 'Custom placeholder'; rerender(); - expect(container.querySelector('.ant-select-selection-placeholder').textContent).toEqual( + expect(container.querySelector('.ant-select-selection-placeholder')?.textContent).toEqual( customPlaceholder, ); }); @@ -410,7 +414,7 @@ describe('Cascader', () => { toggleOpen(container); // Inject in tests/__mocks__/rc-trigger.js - expect(global.triggerProps.popupPlacement).toEqual('topRight'); + expect((global as any)?.triggerProps.popupPlacement).toEqual('topRight'); }); it('popup correctly with defaultValue RTL', () => { @@ -489,7 +493,7 @@ describe('Cascader', () => { const { container } = render( , ); - expect(container.querySelector('.ant-select-selection-item').textContent).toEqual( + expect(container.querySelector('.ant-select-selection-item')?.textContent).toEqual( 'options1 / options2', ); }); @@ -497,7 +501,7 @@ describe('Cascader', () => { it('can be selected when showSearch', () => { const onChange = jest.fn(); const { container } = render(); - fireEvent.change(container.querySelector('input'), { target: { value: 'Zh' } }); + fireEvent.change(container.querySelector('input')!, { target: { value: 'Zh' } }); expect(container.querySelectorAll('.ant-cascader-menu').length).toBe(1); clickOption(container, 0, 0); @@ -506,14 +510,11 @@ describe('Cascader', () => { it('options should open after press esc and then search', () => { const { container } = render(); - fireEvent.change(container.querySelector('input'), { target: { value: 'jin' } }); + fireEvent.change(container.querySelector('input')!, { target: { value: 'jin' } }); expect(isOpen(container)).toBeTruthy(); - fireEvent.keyDown(container.querySelector('input'), { - key: 'Esc', - keyCode: 27, - }); + fireEvent.keyDown(container.querySelector('input')!, { key: 'Esc', keyCode: 27 }); expect(isOpen(container)).toBeFalsy(); - fireEvent.change(container.querySelector('input'), { target: { value: 'jin' } }); + fireEvent.change(container.querySelector('input')!, { target: { value: 'jin' } }); expect(isOpen(container)).toBeTruthy(); }); @@ -523,7 +524,7 @@ describe('Cascader', () => { const { container } = render( , ); - fireEvent.change(container.querySelector('input'), { target: { value: 'est' } }); + fireEvent.change(container.querySelector('input')!, { target: { value: 'est' } }); clickOption(container, 0, 0); expect(onChange).toHaveBeenCalledWith(['Zhejiang', 'Hangzhou', 'West Lake'], expect.anything()); }); @@ -533,14 +534,14 @@ describe('Cascader', () => { toggleOpen(container); // Inject in tests/__mocks__/rc-trigger.js - expect(global.triggerProps.popupPlacement).toEqual('bottomRight'); + expect((global as any).triggerProps.popupPlacement).toEqual('bottomRight'); }); describe('legacy props', () => { it('popupClassName', () => { render(); // Inject in tests/__mocks__/rc-trigger.js - expect(global.triggerProps.popupPlacement).toEqual('bottomLeft'); + expect((global as any).triggerProps.popupPlacement).toEqual('bottomLeft'); }); it('should support showCheckedStrategy child', () => { @@ -583,8 +584,8 @@ describe('Cascader', () => { }, ]; - let selectedValue; - const onChange = function onChange(value) { + let selectedValue: SingleValueType[]; + const onChange = function onChange(value: SingleValueType[]) { selectedValue = value; }; @@ -603,9 +604,9 @@ describe('Cascader', () => { clickOption(container, 1, 0); clickOption(container, 2, 0); clickOption(container, 2, 1); - expect(selectedValue[0].join(',')).toBe('zhejiang,hangzhou,xihu'); - expect(selectedValue[1].join(',')).toBe('zhejiang,hangzhou,donghu'); - expect(selectedValue.join(',')).toBe('zhejiang,hangzhou,xihu,zhejiang,hangzhou,donghu'); + expect(selectedValue![0].join(',')).toBe('zhejiang,hangzhou,xihu'); + expect(selectedValue![1].join(',')).toBe('zhejiang,hangzhou,donghu'); + expect(selectedValue!.join(',')).toBe('zhejiang,hangzhou,xihu,zhejiang,hangzhou,donghu'); }); it('should support showCheckedStrategy parent', () => { @@ -648,8 +649,8 @@ describe('Cascader', () => { }, ]; - let selectedValue; - const onChange = function onChange(value) { + let selectedValue: SingleValueType[]; + const onChange = function onChange(value: SingleValueType[]) { selectedValue = value; }; @@ -668,8 +669,8 @@ describe('Cascader', () => { clickOption(container, 2, 0); clickOption(container, 2, 1); - expect(selectedValue.length).toBe(1); - expect(selectedValue.join(',')).toBe('zhejiang'); + expect(selectedValue!.length).toBe(1); + expect(selectedValue!.join(',')).toBe('zhejiang'); }); }); }); diff --git a/components/checkbox/__tests__/__snapshots__/checkbox.test.js.snap b/components/checkbox/__tests__/__snapshots__/checkbox.test.tsx.snap similarity index 100% rename from components/checkbox/__tests__/__snapshots__/checkbox.test.js.snap rename to components/checkbox/__tests__/__snapshots__/checkbox.test.tsx.snap diff --git a/components/checkbox/__tests__/__snapshots__/demo.test.js.snap b/components/checkbox/__tests__/__snapshots__/demo.test.ts.snap similarity index 100% rename from components/checkbox/__tests__/__snapshots__/demo.test.js.snap rename to components/checkbox/__tests__/__snapshots__/demo.test.ts.snap diff --git a/components/checkbox/__tests__/__snapshots__/group.test.js.snap b/components/checkbox/__tests__/__snapshots__/group.test.tsx.snap similarity index 100% rename from components/checkbox/__tests__/__snapshots__/group.test.js.snap rename to components/checkbox/__tests__/__snapshots__/group.test.tsx.snap diff --git a/components/checkbox/__tests__/checkbox.test.js b/components/checkbox/__tests__/checkbox.test.tsx similarity index 90% rename from components/checkbox/__tests__/checkbox.test.js rename to components/checkbox/__tests__/checkbox.test.tsx index 6814d86505..8cd3d6dcde 100644 --- a/components/checkbox/__tests__/checkbox.test.js +++ b/components/checkbox/__tests__/checkbox.test.tsx @@ -19,10 +19,10 @@ describe('Checkbox', () => { , ); - fireEvent.mouseEnter(container.querySelector('label')); + fireEvent.mouseEnter(container.querySelector('label')!); expect(onMouseEnter).toHaveBeenCalled(); - fireEvent.mouseLeave(container.querySelector('label')); + fireEvent.mouseLeave(container.querySelector('label')!); expect(onMouseLeave).toHaveBeenCalled(); }); diff --git a/components/checkbox/__tests__/demo.test.js b/components/checkbox/__tests__/demo.test.ts similarity index 100% rename from components/checkbox/__tests__/demo.test.js rename to components/checkbox/__tests__/demo.test.ts diff --git a/components/checkbox/__tests__/group.test.js b/components/checkbox/__tests__/group.test.tsx similarity index 90% rename from components/checkbox/__tests__/group.test.js rename to components/checkbox/__tests__/group.test.tsx index 6ffa2be3e2..b22065d489 100644 --- a/components/checkbox/__tests__/group.test.js +++ b/components/checkbox/__tests__/group.test.tsx @@ -6,6 +6,8 @@ import Collapse from '../../collapse'; import Input from '../../input'; import Table from '../../table'; import Checkbox from '../index'; +import type { CheckboxValueType } from '../Group'; +import type { CheckboxGroupProps } from '../index'; describe('CheckboxGroup', () => { mountTest(Checkbox.Group); @@ -60,9 +62,11 @@ describe('CheckboxGroup', () => { it('all children should have a name property', () => { const { container } = render(); - [...container.querySelectorAll('input[type="checkbox"]')].forEach(el => { - expect(el.getAttribute('name')).toEqual('checkboxgroup'); - }); + Array.from(container.querySelectorAll('input[type="checkbox"]')).forEach( + el => { + expect(el.getAttribute('name')).toEqual('checkboxgroup'); + }, + ); }); it('passes prefixCls down to checkbox', () => { @@ -81,10 +85,10 @@ describe('CheckboxGroup', () => { { label: 'Apple', value: 'Apple' }, { label: 'Orange', value: 'Orange' }, ]; - const renderCheckbox = props => ; + const renderCheckbox = (props: CheckboxGroupProps) => ; const { container, rerender } = render(renderCheckbox({ options })); expect(container.querySelectorAll('.ant-checkbox-checked').length).toBe(0); - rerender(renderCheckbox({ options, value: 'Apple' })); + rerender(renderCheckbox({ options, value: 'Apple' as unknown as CheckboxValueType[] })); expect(container.querySelectorAll('.ant-checkbox-checked').length).toBe(1); }); @@ -116,7 +120,7 @@ describe('CheckboxGroup', () => { , ); - fireEvent.click(container.querySelector('.ant-checkbox-input')); + fireEvent.click(container.querySelector('.ant-checkbox-input')!); expect(onChange).toHaveBeenCalledWith([2]); }); @@ -164,7 +168,7 @@ describe('CheckboxGroup', () => { const { container } = render( - +
    item
    @@ -174,11 +178,11 @@ describe('CheckboxGroup', () => { ); fireEvent.click( - container.querySelector('.ant-collapse-item').querySelector('.ant-collapse-header'), + container.querySelector('.ant-collapse-item')?.querySelector('.ant-collapse-header')!, ); - fireEvent.click(container.querySelector('.ant-checkbox-input')); + fireEvent.click(container.querySelector('.ant-checkbox-input')!); expect(container.querySelectorAll('.ant-checkbox-checked').length).toBe(1); - fireEvent.click(container.querySelector('.ant-checkbox-input')); + fireEvent.click(container.querySelector('.ant-checkbox-input')!); expect(container.querySelectorAll('.ant-checkbox-checked').length).toBe(0); }); @@ -210,12 +214,12 @@ describe('CheckboxGroup', () => { }); it('should get div ref', () => { - const refCalls = []; + const refCalls: HTMLDivElement[] = []; render( { - refCalls.push(node); + refCalls.push(node!); }} />, ); @@ -230,18 +234,18 @@ describe('CheckboxGroup', () => { , ); - fireEvent.click(container.querySelector('.ant-checkbox-input')); + fireEvent.click(container.querySelector('.ant-checkbox-input')!); expect(onChange).toHaveBeenCalledWith([1]); }); it('should store latest checkbox value if changed', () => { const onChange = jest.fn(); - const Demo = () => { - const [v, setV] = useState(''); + const Demo: React.FC = () => { + const [v, setV] = useState(''); React.useEffect(() => { - setTimeout(setV('1'), 1000); + setTimeout(setV('1') as unknown as TimerHandler, 1000); }, []); return ( @@ -257,12 +261,12 @@ describe('CheckboxGroup', () => { }; const { container } = render(); - fireEvent.click(container.querySelector('.ant-checkbox-input')); + fireEvent.click(container.querySelector('.ant-checkbox-input')!); expect(onChange).toHaveBeenCalledWith([]); - fireEvent.click(container.querySelector('.ant-checkbox-input')); + fireEvent.click(container.querySelector('.ant-checkbox-input')!); expect(onChange).toHaveBeenCalledWith(['length1']); - fireEvent.change(container.querySelector('.ant-input'), { target: { value: '' } }); - fireEvent.click(container.querySelector('.ant-checkbox-input')); + fireEvent.change(container.querySelector('.ant-input')!, { target: { value: '' } }); + fireEvent.click(container.querySelector('.ant-checkbox-input')!); expect(onChange).toHaveBeenCalledWith(['A']); }); }); diff --git a/components/config-provider/__tests__/__snapshots__/components.test.tsx.snap b/components/config-provider/__tests__/__snapshots__/components.test.tsx.snap index fa2856b030..237741a587 100644 --- a/components/config-provider/__tests__/__snapshots__/components.test.tsx.snap +++ b/components/config-provider/__tests__/__snapshots__/components.test.tsx.snap @@ -15519,11 +15519,11 @@ exports[`ConfigProvider components Form configProvider 1`] = ` >