From 54912b63e6ab2db8b403f6807668f6702e53ab14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BA=8C=E8=B4=A7=E7=88=B1=E5=90=83=E7=99=BD=E8=90=9D?= =?UTF-8?q?=E5=8D=9C?= Date: Mon, 19 Dec 2022 15:04:25 +0800 Subject: [PATCH] refactor: upgrade to father 4 & dumi 2 (#626) * chore: bump father * part test * test: more test case * test: more test case * test: rest test * chore: doc dest --- .dumirc.ts | 8 + .fatherrc.js | 14 +- .gitignore | 1 + .umirc.ts | 22 --- docs/demo/animated.md | 9 +- docs/demo/basic.md | 9 +- docs/demo/editable.md | 9 +- docs/demo/extra.md | 9 +- docs/demo/mix.md | 9 +- docs/demo/overflow.md | 9 +- docs/demo/position.md | 9 +- docs/demo/renderTabBar-dragable.md | 9 +- docs/demo/renderTabBar-sticky.md | 9 +- docs/demo/renderTabBar-use-panes.md | 9 +- jest.config.js | 25 ++- package.json | 25 ++- src/TabNavList/OperationNode.tsx | 10 +- tests/common/util.tsx | 32 +++- tests/index.test.tsx | 215 ++++++++++++---------- tests/mobile.test.tsx | 74 +++----- tests/operation-overflow.test.tsx | 13 +- tests/overflow.test.tsx | 275 +++++++++++++++------------- tests/rtl.test.tsx | 18 +- tests/setup.js | 8 - tests/setupFilesAfterEnv.js | 1 - tsconfig.json | 19 +- vercel.json | 2 +- 27 files changed, 460 insertions(+), 392 deletions(-) create mode 100644 .dumirc.ts delete mode 100644 .umirc.ts delete mode 100644 tests/setup.js delete mode 100644 tests/setupFilesAfterEnv.js diff --git a/.dumirc.ts b/.dumirc.ts new file mode 100644 index 00000000..92fcf489 --- /dev/null +++ b/.dumirc.ts @@ -0,0 +1,8 @@ +import { defineConfig } from 'dumi'; + +export default defineConfig({ + themeConfig: { + name: 'Tabs', + }, + mfsu: false, +}); \ No newline at end of file diff --git a/.fatherrc.js b/.fatherrc.js index 912aa0aa..4ddbafd1 100644 --- a/.fatherrc.js +++ b/.fatherrc.js @@ -1,9 +1,5 @@ -export default { - cjs: 'babel', - esm: { type: 'babel', importLibToEs: true }, - preCommit: { - eslint: true, - prettier: true, - }, - runtimeHelpers: true, -}; +import { defineConfig } from 'father'; + +export default defineConfig({ + plugins: ['@rc-component/father-plugin'], +}); \ No newline at end of file diff --git a/.gitignore b/.gitignore index 1b0597ee..e62b6b58 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,4 @@ package-lock.json .umi-production .umi-test .env.local +.dumi \ No newline at end of file diff --git a/.umirc.ts b/.umirc.ts deleted file mode 100644 index ac85534a..00000000 --- a/.umirc.ts +++ /dev/null @@ -1,22 +0,0 @@ -// more config: https://d.umijs.org/config -import { defineConfig } from 'dumi'; - -export default defineConfig({ - title: 'rc-tabs', - favicon: 'https://avatars0.githubusercontent.com/u/9441414?s=200&v=4', - logo: 'https://avatars0.githubusercontent.com/u/9441414?s=200&v=4', - outputPath: '.doc', - exportStatic: {}, - styles: [ - ` - .markdown table { - width: auto !important; - } - `, - ], - - chainWebpack(memo) { - memo.resolve.alias.delete('rc-tabs'); - return memo; - }, -}); diff --git a/docs/demo/animated.md b/docs/demo/animated.md index 4848788e..24cde477 100644 --- a/docs/demo/animated.md +++ b/docs/demo/animated.md @@ -1,3 +1,8 @@ -## animated +--- +title: Animated +nav: + title: Demo + path: /demo +--- - \ No newline at end of file + \ No newline at end of file diff --git a/docs/demo/basic.md b/docs/demo/basic.md index d27d11d4..acad05fc 100644 --- a/docs/demo/basic.md +++ b/docs/demo/basic.md @@ -1,3 +1,8 @@ -## basic +--- +title: Basic +nav: + title: Demo + path: /demo +--- - \ No newline at end of file + diff --git a/docs/demo/editable.md b/docs/demo/editable.md index e0c725db..af8da863 100644 --- a/docs/demo/editable.md +++ b/docs/demo/editable.md @@ -1,3 +1,8 @@ -## editable +--- +title: Editable +nav: + title: Demo + path: /demo +--- - + diff --git a/docs/demo/extra.md b/docs/demo/extra.md index 18ede969..8b961634 100644 --- a/docs/demo/extra.md +++ b/docs/demo/extra.md @@ -1,3 +1,8 @@ -## extra +--- +title: Extra +nav: + title: Demo + path: /demo +--- - \ No newline at end of file + diff --git a/docs/demo/mix.md b/docs/demo/mix.md index 6f3e387e..9b33bfbf 100644 --- a/docs/demo/mix.md +++ b/docs/demo/mix.md @@ -1,3 +1,8 @@ -## mix +--- +title: Mix +nav: + title: Demo + path: /demo +--- - \ No newline at end of file + diff --git a/docs/demo/overflow.md b/docs/demo/overflow.md index aa4ee6d0..0081c637 100644 --- a/docs/demo/overflow.md +++ b/docs/demo/overflow.md @@ -1,3 +1,8 @@ -## overflow +--- +title: Overflow +nav: + title: Demo + path: /demo +--- - \ No newline at end of file + diff --git a/docs/demo/position.md b/docs/demo/position.md index db95550d..e4c81258 100644 --- a/docs/demo/position.md +++ b/docs/demo/position.md @@ -1,3 +1,8 @@ -## position +--- +title: Position +nav: + title: Demo + path: /demo +--- - \ No newline at end of file + diff --git a/docs/demo/renderTabBar-dragable.md b/docs/demo/renderTabBar-dragable.md index a0f4bb7d..0d3f38e9 100644 --- a/docs/demo/renderTabBar-dragable.md +++ b/docs/demo/renderTabBar-dragable.md @@ -1,3 +1,8 @@ -## renderTabBar-dragable +--- +title: renderTabBar-dragable +nav: + title: Demo + path: /demo +--- - \ No newline at end of file + diff --git a/docs/demo/renderTabBar-sticky.md b/docs/demo/renderTabBar-sticky.md index 96c88806..0b6c4994 100644 --- a/docs/demo/renderTabBar-sticky.md +++ b/docs/demo/renderTabBar-sticky.md @@ -1,3 +1,10 @@ +--- +title: renderTabBar-sticky +nav: + title: Demo + path: /demo +--- + ## renderTabBar-sticky - \ No newline at end of file + \ No newline at end of file diff --git a/docs/demo/renderTabBar-use-panes.md b/docs/demo/renderTabBar-use-panes.md index 4a94f500..616e1cfc 100644 --- a/docs/demo/renderTabBar-use-panes.md +++ b/docs/demo/renderTabBar-use-panes.md @@ -1,3 +1,8 @@ -## renderTabBar-use-panes +--- +title: enderTabBar-use-panes +nav: + title: Demo + path: /demo +--- - \ No newline at end of file + diff --git a/jest.config.js b/jest.config.js index ec5296ce..520a138f 100644 --- a/jest.config.js +++ b/jest.config.js @@ -1,5 +1,24 @@ +// Copy from antd jest config file. We need compile `rc-resize-observer` +const compileModules = [ + 'array-move', + 'react-dnd', + 'react-dnd-html5-backend', + '@react-dnd', + 'dnd-core', + 'tween-one', + '@babel', + '@ant-design', +]; + +const ignoreList = []; + +// cnpm use `_` as prefix +['', '_'].forEach((prefix) => { + compileModules.forEach((module) => { + ignoreList.push(`${prefix}${module}`); + }); +}); + module.exports = { - setupFiles: ['./tests/setup.js'], - snapshotSerializers: [require.resolve('enzyme-to-json/serializer')], - setupFilesAfterEnv: ['/tests/setupFilesAfterEnv.js'], + transformIgnorePatterns: [`/node_modules/(?!${ignoreList.join('|')})[^/]+?/(?!(es)/)`], }; diff --git a/package.json b/package.json index 79c57697..30d994fc 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "build": "dumi build", "docs:deploy": "gh-pages -d .doc", "compile": "father build && npm run compile:style", - "test": "father test", + "test": "rc-test", "coverage": "father test --coverage", "now-build": "npm run build", "lint": "eslint src/ docs/examples/ --ext .tsx,.ts,.jsx,.js", @@ -42,38 +42,35 @@ }, "devDependencies": { "@testing-library/jest-dom": "^5.16.4", - "@testing-library/react": "^12.0.0", + "@testing-library/react": "^13.0.0", "@types/classnames": "^2.2.10", "@types/enzyme": "^3.10.5", - "@types/keyv": "3.1.4", "@types/jest": "^25.2.3", + "@types/keyv": "3.1.4", "@types/react": "^17.0.14", "@types/react-dom": "^16.9.8", "@umijs/fabric": "^2.3.1", "coveralls": "^3.0.6", "cross-env": "^7.0.2", - "dumi": "^1.1.0", - "enzyme": "^3.7.0", - "enzyme-adapter-react-16": "^1.7.0", - "enzyme-to-json": "^3.3.4", + "dumi": "^2.0.0", "eslint": "^7.0.0", "fastclick": "~1.0.6", - "father": "^2.29.2", + "father": "^4.0.0", "gh-pages": "^3.1.0", "history": "^1.17.0", "immutability-helper": "^3.0.1", "less": "^3.11.1", "np": "^7.5.0", - "preact": "^8.2.1", "preact-compat": "^3.16.0", - "react": "^16.0.0", + "rc-test": "^7.0.14", + "react": "^18.0.0", "react-dnd": "^10.0.0", "react-dnd-html5-backend": "^10.0.0", - "react-dom": "^16.0.0", + "react-dom": "^18.0.0", "react-sticky": "^6.0.3", - "react-test-renderer": "^16.0.0", "sortablejs": "^1.7.0", - "typescript": "^4.0.5" + "typescript": "^4.0.5", + "@rc-component/father-plugin": "^1.0.0" }, "dependencies": { "@babel/runtime": "^7.11.2", @@ -88,4 +85,4 @@ "react": ">=16.9.0", "react-dom": ">=16.9.0" } -} +} \ No newline at end of file diff --git a/src/TabNavList/OperationNode.tsx b/src/TabNavList/OperationNode.tsx index fd461ca2..8422ef0c 100644 --- a/src/TabNavList/OperationNode.tsx +++ b/src/TabNavList/OperationNode.tsx @@ -1,10 +1,10 @@ -import * as React from 'react'; import classNames from 'classnames'; -import { useState, useEffect } from 'react'; -import KeyCode from 'rc-util/lib/KeyCode'; -import Menu, { MenuItem } from 'rc-menu'; import Dropdown from 'rc-dropdown'; -import type { Tab, TabsLocale, EditableConfig } from '../interface'; +import Menu, { MenuItem } from 'rc-menu'; +import KeyCode from 'rc-util/lib/KeyCode'; +import * as React from 'react'; +import { useEffect, useState } from 'react'; +import type { EditableConfig, Tab, TabsLocale } from '../interface'; import AddButton from './AddButton'; export interface OperationNodeProps { diff --git a/tests/common/util.tsx b/tests/common/util.tsx index 258655af..80d122b3 100644 --- a/tests/common/util.tsx +++ b/tests/common/util.tsx @@ -1,6 +1,9 @@ /* eslint-disable @typescript-eslint/no-invalid-this */ -import React from 'react'; +import { act } from '@testing-library/react'; import type { ReactWrapper } from 'enzyme'; +import { _rs as onEsResize } from 'rc-resize-observer/es/utils/observerUtil'; +import { _rs as onLibResize } from 'rc-resize-observer/lib/utils/observerUtil'; +import React from 'react'; import Tabs from '../../src'; import type { TabsProps } from '../../src/Tabs'; @@ -85,23 +88,23 @@ export function btnOffsetPosition() { return 20 * index; } -export function getTransformX(wrapper: ReactWrapper) { - const { transform } = wrapper.find('.rc-tabs-nav-list').props().style; +export function getTransformX(container: Element) { + const { transform } = container.querySelector('.rc-tabs-nav-list').style; const match = transform.match(/\(([-\d.]+)px/); if (!match) { // eslint-disable-next-line no-console - console.log(wrapper.find('.rc-tabs-nav-list').html()); + // console.log(container.querySelector('.rc-tabs-nav-list').innerHTML); throw new Error(`Not find transformX: ${transform}`); } return Number(match[1]); } -export function getTransformY(wrapper: ReactWrapper) { - const { transform } = wrapper.find('.rc-tabs-nav-list').props().style; +export function getTransformY(container: Element) { + const { transform } = container.querySelector('.rc-tabs-nav-list').style; const match = transform.match(/,\s*([-\d.]+)px/); if (!match) { // eslint-disable-next-line no-console - console.log(wrapper.find('.rc-tabs-nav-list').html()); + // console.log(wrapper.find('.rc-tabs-nav-list').html()); throw new Error(`Not find transformY: ${transform}`); } return Number(match[1]); @@ -143,6 +146,15 @@ export function getTabs(props: TabsProps = null) { ); } -export function triggerResize(wrapper: ReactWrapper) { - (wrapper.find('.rc-tabs-nav').find('ResizeObserver').first().props() as any).onResize(); -} +// export function triggerResize(wrapper: ReactWrapper) { +// (wrapper.find('.rc-tabs-nav').find('ResizeObserver').first().props() as any).onResize(); +// } + +export const triggerResize = (container: Element) => { + const target = container.querySelector('.rc-tabs-nav'); + + act(() => { + onLibResize([{ target } as ResizeObserverEntry]); + onEsResize([{ target } as ResizeObserverEntry]); + }); +}; diff --git a/tests/index.test.tsx b/tests/index.test.tsx index d3eea3b7..eb40fcca 100644 --- a/tests/index.test.tsx +++ b/tests/index.test.tsx @@ -1,18 +1,26 @@ -import React from 'react'; -import type { ReactWrapper } from 'enzyme'; -import { render, screen, fireEvent } from '@testing-library/react'; import '@testing-library/dom'; -import { mount } from 'enzyme'; -import { spyElementPrototypes } from 'rc-util/lib/test/domHook'; +import { fireEvent, render, screen } from '@testing-library/react'; import KeyCode from 'rc-util/lib/KeyCode'; +import { spyElementPrototypes } from 'rc-util/lib/test/domHook'; +import React from 'react'; import Tabs from '../src'; import type { TabsProps } from '../src/Tabs'; import type { HackInfo } from './common/util'; import { getOffsetSizeFunc } from './common/util'; +global.animated = null; + +jest.mock('../src/TabPanelList', () => { + const Origin = jest.requireActual('../src/TabPanelList').default; + + return (props: any) => { + global.animated = props.animated; + return ; + }; +}); + describe('Tabs.Basic', () => { let domSpy: ReturnType; - let holder: HTMLDivElement; const hackOffsetInfo: HackInfo = {}; @@ -20,12 +28,11 @@ describe('Tabs.Basic', () => { Object.keys(hackOffsetInfo).forEach(key => { delete hackOffsetInfo[key]; }); + + global.animated = null; }); beforeAll(() => { - holder = document.createElement('div'); - document.body.appendChild(holder); - domSpy = spyElementPrototypes(HTMLElement, { scrollIntoView: () => {}, offsetWidth: { @@ -36,7 +43,6 @@ describe('Tabs.Basic', () => { afterAll(() => { domSpy.mockRestore(); - document.body.removeChild(holder); }); function getTabs(props: TabsProps = null) { @@ -65,15 +71,15 @@ describe('Tabs.Basic', () => { } it('Normal', () => { - const wrapper = mount(getTabs({ defaultActiveKey: 'bamboo' })); + const { container } = render(getTabs({ defaultActiveKey: 'bamboo' })); - expect(wrapper.render()).toMatchSnapshot(); + expect(container.firstChild).toMatchSnapshot(); }); it('disabled not change', () => { const onChange = jest.fn(); - const wrapper = mount( + const { container } = render( getTabs({ defaultActiveKey: 'light', items: [ @@ -92,12 +98,12 @@ describe('Tabs.Basic', () => { }), ); - wrapper.find('.rc-tabs-tab-disabled').simulate('click'); + fireEvent.click(container.querySelector('.rc-tabs-tab-disabled')); expect(onChange).not.toHaveBeenCalled(); }); it('Skip invalidate children', () => { - const wrapper = mount( + const { container } = render( getTabs({ items: [ { @@ -109,13 +115,12 @@ describe('Tabs.Basic', () => { ], }), ); - wrapper.update(); - expect(wrapper.render()).toMatchSnapshot(); + expect(container.firstChild).toMatchSnapshot(); }); it('nothing for empty tabs', () => { - mount(getTabs({ items: null })); + render(getTabs({ items: null })); }); it('same width in windows call resize', async () => { @@ -173,20 +178,23 @@ describe('Tabs.Basic', () => { }); describe('onChange and onTabClick should work', () => { - const list: { name: string; trigger: (wrapper: ReactWrapper) => void }[] = [ + const list: { name: string; trigger: (container: HTMLElement) => void }[] = [ { name: 'outer div', - trigger: wrapper => wrapper.find('.rc-tabs-tab').at(2).simulate('click'), + trigger: container => fireEvent.click(container.querySelectorAll('.rc-tabs-tab')[2]), }, { name: 'inner button', - trigger: wrapper => wrapper.find('.rc-tabs-tab .rc-tabs-tab-btn').at(2).simulate('click'), + trigger: container => + fireEvent.click(container.querySelectorAll('.rc-tabs-tab .rc-tabs-tab-btn')[2]), }, { name: 'inner button key down', - trigger: wrapper => - wrapper.find('.rc-tabs-tab .rc-tabs-tab-btn').at(2).simulate('keydown', { + trigger: container => + fireEvent.keyDown(container.querySelectorAll('.rc-tabs-tab .rc-tabs-tab-btn')[2], { which: KeyCode.SPACE, + keyCode: KeyCode.SPACE, + charCode: KeyCode.SPACE, }), }, ]; @@ -195,9 +203,9 @@ describe('Tabs.Basic', () => { it(name, () => { const onChange = jest.fn(); const onTabClick = jest.fn(); - const wrapper = mount(getTabs({ onChange, onTabClick })); + const { container } = render(getTabs({ onChange, onTabClick })); - trigger(wrapper); + trigger(container); expect(onTabClick).toHaveBeenCalledWith('cute', expect.anything()); expect(onChange).toHaveBeenCalledWith('cute'); }); @@ -207,53 +215,66 @@ describe('Tabs.Basic', () => { it('should not trigger onChange when click current tab', () => { const onChange = jest.fn(); const onTabClick = jest.fn(); - const wrapper = mount(getTabs({ onChange, onTabClick })); + const { container } = render(getTabs({ onChange, onTabClick })); - wrapper.find('.rc-tabs-tab').at(0).simulate('click'); + fireEvent.click(container.querySelector('.rc-tabs-tab')); expect(onTabClick).toHaveBeenCalledWith('light', expect.anything()); expect(onChange).not.toHaveBeenCalled(); }); }); it('active first tab when children is changed', () => { - const wrapper = mount(getTabs()); - wrapper.setProps({ - items: [ - { - label: 'Yo', - key: '2333', - children: 'New', - }, - ], - }); - wrapper.update(); - expect(wrapper.find('.rc-tabs-tab-active').text()).toEqual('Yo'); + const { container, rerender } = render(getTabs()); + rerender( + getTabs({ + items: [ + { + label: 'Yo', + key: '2333', + children: 'New', + }, + ], + }), + ); + + expect(container.querySelector('.rc-tabs-tab-active').textContent).toEqual('Yo'); }); it('active first tab when children is not changed at controlled mode', () => { - const wrapper = mount(getTabs({ activeKey: 'light' })); - expect(wrapper.find('.rc-tabs-tab-active').text()).toEqual('light'); + const { container, rerender } = render(getTabs({ activeKey: 'light' })); + expect(container.querySelector('.rc-tabs-tab-active').textContent).toEqual('light'); - wrapper.setProps({ - items: [ - { - label: 'Yo', - key: '2333', - children: 'New', - }, - ], - }); - expect(wrapper.find('.rc-tabs-tab-active')).toHaveLength(0); + rerender( + getTabs({ + activeKey: 'light', + items: [ + { + label: 'Yo', + key: '2333', + children: 'New', + }, + ], + }), + ); + expect(container.querySelector('.rc-tabs-tab-active')).toBeFalsy(); }); it('tabBarGutter should work', () => { - const topTabs = mount(getTabs({ tabBarGutter: 23 })); - expect(topTabs.find('.rc-tabs-tab').at(0).props().style?.marginLeft).toBe(undefined); - expect(topTabs.find('.rc-tabs-tab').at(1).props().style?.marginLeft).toBe(23); + const topTabs = render(getTabs({ tabBarGutter: 23 })); + expect(topTabs.container.querySelectorAll('.rc-tabs-tab')[0]).toHaveStyle({ + marginLeft: undefined, + }); + expect(topTabs.container.querySelectorAll('.rc-tabs-tab')[1]).toHaveStyle({ + marginLeft: '23px', + }); - const rightTabs = mount(getTabs({ tabBarGutter: 33, tabPosition: 'right' })); - expect(rightTabs.find('.rc-tabs-tab').at(0).props().style?.marginTop).toEqual(undefined); - expect(rightTabs.find('.rc-tabs-tab').at(1).props().style?.marginTop).toEqual(33); + const rightTabs = render(getTabs({ tabBarGutter: 33, tabPosition: 'right' })); + expect(rightTabs.container.querySelectorAll('.rc-tabs-tab')[0]).toHaveStyle({ + marginTop: undefined, + }); + expect(rightTabs.container.querySelectorAll('.rc-tabs-tab')[1]).toHaveStyle({ + marginTop: '33px', + }); }); describe('renderTabBar', () => { @@ -265,9 +286,9 @@ describe('Tabs.Basic', () => { ); }); - const wrapper = mount(getTabs({ renderTabBar })); - expect(wrapper.find('.my-wrapper').length).toBeTruthy(); - expect(wrapper.find('.my-node').length).toBeTruthy(); + const { container } = render(getTabs({ renderTabBar })); + expect(container.querySelector('.my-wrapper')).toBeTruthy(); + expect(container.querySelector('.my-node')).toBeTruthy(); expect(renderTabBar).toHaveBeenCalled(); }); it('has panes property in props', () => { @@ -282,10 +303,10 @@ describe('Tabs.Basic', () => { ); }; - const wrapper = mount(getTabs({ renderTabBar })); - expect(wrapper.find('[data-key="light"]').length).toBeTruthy(); - expect(wrapper.find('[data-key="bamboo"]').length).toBeTruthy(); - expect(wrapper.find('[data-key="cute"]').length).toBeTruthy(); + const { container } = render(getTabs({ renderTabBar })); + expect(container.querySelector('[data-key="light"]')).toBeTruthy(); + expect(container.querySelector('[data-key="bamboo"]')).toBeTruthy(); + expect(container.querySelector('[data-key="cute"]')).toBeTruthy(); }); }); @@ -326,25 +347,25 @@ describe('Tabs.Basic', () => { describe('editable', () => { it('no and', () => { const onEdit = jest.fn(); - const wrapper = mount(getTabs({ editable: { onEdit, showAdd: false } })); - expect(wrapper.find('.rc-tabs-nav-add')).toHaveLength(0); + const { container } = render(getTabs({ editable: { onEdit, showAdd: false } })); + expect(container.querySelector('.rc-tabs-nav-add')).toBeFalsy(); }); it('add', () => { const onEdit = jest.fn(); - const wrapper = mount(getTabs({ editable: { onEdit } })); - wrapper.find('.rc-tabs-nav-add').first().simulate('click'); + const { container } = render(getTabs({ editable: { onEdit } })); + fireEvent.click(container.querySelector('.rc-tabs-nav-add')); expect(onEdit).toHaveBeenCalledWith('add', { key: undefined, event: expect.anything(), }); }); - const list: { name: string; trigger: (node: ReactWrapper) => void }[] = [ + const list: { name: string; trigger: (node: Element) => void }[] = [ { name: 'click', trigger: node => { - node.simulate('click'); + fireEvent.click(node); }, }, ]; @@ -352,13 +373,13 @@ describe('Tabs.Basic', () => { list.forEach(({ name, trigger }) => { it(`remove by ${name}`, () => { const onEdit = jest.fn(); - const wrapper = mount(getTabs({ editable: { onEdit } })); + const { container } = render(getTabs({ editable: { onEdit } })); - const first = wrapper.find('.rc-tabs-tab-remove').first(); + const first = container.querySelector('.rc-tabs-tab-remove'); trigger(first); // Should be button to enable press SPACE key to trigger - expect(first.instance() instanceof HTMLButtonElement).toBeTruthy(); + expect(first instanceof HTMLButtonElement).toBeTruthy(); expect(onEdit).toHaveBeenCalledWith('remove', { key: 'light', @@ -369,7 +390,7 @@ describe('Tabs.Basic', () => { it('customize closeIcon', () => { const onEdit = jest.fn(); - const wrapper = mount( + const { container } = render( getTabs({ editable: { onEdit }, items: [ @@ -382,40 +403,44 @@ describe('Tabs.Basic', () => { }), ); - expect(wrapper.find('.rc-tabs-tab-remove').find('.close-light').length).toBeTruthy(); + expect( + container.querySelector('.rc-tabs-tab-remove').querySelector('.close-light'), + ).toBeTruthy(); }); }); it('extra', () => { - const wrapper = mount(getTabs({ tabBarExtraContent: 'Bamboo' })); - expect(wrapper.find('.rc-tabs-extra-content').text()).toEqual('Bamboo'); + const { container } = render(getTabs({ tabBarExtraContent: 'Bamboo' })); + expect(container.querySelector('.rc-tabs-extra-content').textContent).toEqual('Bamboo'); }); it('extra position', () => { - const wrapper = mount( + const { container } = render( getTabs({ tabBarExtraContent: { left: 'Left Bamboo', right: 'Right Bamboo' } }), ); - expect(wrapper.find('.rc-tabs-extra-content').first().text()).toEqual('Left Bamboo'); + expect(container.querySelector('.rc-tabs-extra-content').textContent).toEqual('Left Bamboo'); - expect(wrapper.find('.rc-tabs-extra-content').at(1).text()).toEqual('Right Bamboo'); + expect(container.querySelectorAll('.rc-tabs-extra-content')[1].textContent).toEqual( + 'Right Bamboo', + ); }); it('no break of empty object', () => { - mount(getTabs({ tabBarExtraContent: {} })); + render(getTabs({ tabBarExtraContent: {} })); }); describe('animated', () => { it('false', () => { - const wrapper = mount(getTabs({ animated: false })); - expect(wrapper.find('TabPanelList').prop('animated')).toEqual({ + render(getTabs({ animated: false })); + expect(global.animated).toEqual({ inkBar: false, tabPane: false, }); }); it('true', () => { - const wrapper = mount(getTabs({ animated: true })); - expect(wrapper.find('TabPanelList').prop('animated')).toEqual({ + render(getTabs({ animated: true })); + expect(global.animated).toEqual({ inkBar: true, tabPane: false, }); @@ -424,8 +449,8 @@ describe('Tabs.Basic', () => { it('customize but !tabPaneMotion', () => { const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {}); - const wrapper = mount(getTabs({ animated: { inkBar: false, tabPane: true } })); - expect(wrapper.find('TabPanelList').prop('animated')).toEqual({ + render(getTabs({ animated: { inkBar: false, tabPane: true } })); + expect(global.animated).toEqual({ inkBar: false, tabPane: false, }); @@ -437,10 +462,8 @@ describe('Tabs.Basic', () => { }); it('customize', () => { - const wrapper = mount( - getTabs({ animated: { inkBar: true, tabPane: true, tabPaneMotion: {} } }), - ); - expect(wrapper.find('TabPanelList').prop('animated')).toEqual( + render(getTabs({ animated: { inkBar: true, tabPane: true, tabPaneMotion: {} } })); + expect(global.animated).toEqual( expect.objectContaining({ inkBar: true, tabPane: true, @@ -450,13 +473,13 @@ describe('Tabs.Basic', () => { }); it('focus to scroll', () => { - const wrapper = mount(getTabs()); - wrapper.find('.rc-tabs-tab-btn').first().simulate('focus'); - wrapper.unmount(); + const { container, unmount } = render(getTabs()); + fireEvent.focus(container.querySelector('.rc-tabs-tab')); + unmount(); }); it('tabBarStyle', () => { - const wrapper = mount(getTabs({ tabBarStyle: { background: 'red' } })); - expect(wrapper.find('.rc-tabs-nav').prop('style').background).toEqual('red'); + const { container } = render(getTabs({ tabBarStyle: { background: 'red' } })); + expect(container.querySelector('.rc-tabs-nav')).toHaveStyle({ background: 'red' }); }); }); diff --git a/tests/mobile.test.tsx b/tests/mobile.test.tsx index 538a3b5a..5e0a2130 100644 --- a/tests/mobile.test.tsx +++ b/tests/mobile.test.tsx @@ -1,28 +1,14 @@ -import React from 'react'; -import { mount } from 'enzyme'; -import type { ReactWrapper } from 'enzyme'; +import { render } from '@testing-library/react'; import { spyElementPrototypes } from 'rc-util/lib/test/domHook'; +import React from 'react'; import { act } from 'react-dom/test-utils'; -import Tabs from '../src'; import type { TabsProps } from '../src'; +import Tabs from '../src'; import { btnOffsetPosition, getOffsetSizeFunc, getTransformX } from './common/util'; -describe('Tabs.Mobile', () => { - const originAgent = navigator.userAgent; - - beforeAll(() => { - Object.defineProperty(window.navigator, 'userAgent', { - value: - 'Mozilla/5.0 (Linux; Android 6.0; Nexus 5 Build/MRA58N) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/81.0.4044.138 Mobile Safari/537.36', - }); - }); - - afterAll(() => { - Object.defineProperty(window.navigator, 'userAgent', { - value: originAgent, - }); - }); +jest.mock('rc-util/lib/isMobile', () => () => true); +describe('Tabs.Mobile', () => { const tabCount = 100; function getTabs(props: TabsProps = null) { @@ -40,13 +26,8 @@ describe('Tabs.Mobile', () => { describe('mobile is scrollable', () => { let domSpy: ReturnType; - let btnSpy: ReturnType; - let dateSpy: ReturnType; - let timestamp: number = 0; beforeAll(() => { - dateSpy = jest.spyOn(Date, 'now').mockImplementation(() => timestamp); - domSpy = spyElementPrototypes(HTMLElement, { scrollIntoView: () => {}, offsetWidth: { @@ -65,19 +46,16 @@ describe('Tabs.Mobile', () => { }); afterAll(() => { - btnSpy.mockRestore(); domSpy.mockRestore(); - dateSpy.mockRestore(); }); - function touchMove(wrapper: ReactWrapper, jest: any, offsetX: number[] | number) { + function touchMove(container: HTMLElement, jest: any, offsetX: number[] | number) { act(() => { jest.runAllTimers(); - wrapper.update(); }); // Touch to move - const node = wrapper.find('.rc-tabs-nav-wrap').instance() as unknown as HTMLElement; + const node = container.querySelector('.rc-tabs-nav-wrap'); act(() => { const touchStart = new TouchEvent('touchstart', { @@ -101,12 +79,11 @@ describe('Tabs.Mobile', () => { document.dispatchEvent(moveEvent1); }); - timestamp += 10; + act(() => { + jest.advanceTimersByTime(10); + }); } - // Init - timestamp = 0; - // First move trigger(); @@ -123,49 +100,45 @@ describe('Tabs.Mobile', () => { // Execution swipe act(() => { jest.runAllTimers(); - wrapper.update(); }); } describe('LTR', () => { it('slow move', () => { jest.useFakeTimers(); - const wrapper = mount(getTabs({ tabPosition: 'top' })); + const { container } = render(getTabs({ tabPosition: 'top' })); // Last touch is slow move - touchMove(wrapper, jest, [-100, 0.05]); + touchMove(container, jest, [-100, 0.05]); - expect(getTransformX(wrapper)).toEqual(-99.95); + expect(getTransformX(container)).toEqual(-99.95); jest.useRealTimers(); }); it('swipe', () => { jest.useFakeTimers(); - const wrapper = mount(getTabs({ tabPosition: 'top' })); + const { container } = render(getTabs({ tabPosition: 'top' })); act(() => { jest.runAllTimers(); - wrapper.update(); }); - expect(wrapper.find('.rc-tabs-nav-more')).toHaveLength(0); + expect(container.querySelector('.rc-tabs-nav-more')).toBeFalsy(); - touchMove(wrapper, jest, -200); + touchMove(container, jest, -200); - wrapper.update(); - expect(getTransformX(wrapper) < -200).toBeTruthy(); + expect(getTransformX(container) < -200).toBeTruthy(); jest.useRealTimers(); }); it('not out of the edge', () => { jest.useFakeTimers(); - const wrapper = mount(getTabs({ tabPosition: 'top' })); + const { container } = render(getTabs({ tabPosition: 'top' })); - touchMove(wrapper, jest, 100); + touchMove(container, jest, 100); - wrapper.update(); - expect(getTransformX(wrapper)).toEqual(0); + expect(getTransformX(container)).toEqual(0); jest.useRealTimers(); }); @@ -174,12 +147,11 @@ describe('Tabs.Mobile', () => { describe('RTL', () => { it('not out of the edge', () => { jest.useFakeTimers(); - const wrapper = mount(getTabs({ direction: 'rtl' })); + const { container } = render(getTabs({ direction: 'rtl' })); - touchMove(wrapper, jest, -100); + touchMove(container, jest, -100); - wrapper.update(); - expect(getTransformX(wrapper)).toEqual(0); + expect(getTransformX(container)).toEqual(0); jest.useRealTimers(); }); diff --git a/tests/operation-overflow.test.tsx b/tests/operation-overflow.test.tsx index dd347d5d..a5b87eed 100644 --- a/tests/operation-overflow.test.tsx +++ b/tests/operation-overflow.test.tsx @@ -1,4 +1,4 @@ -import { mount } from 'enzyme'; +import { render } from '@testing-library/react'; import { spyElementPrototypes } from 'rc-util/lib/test/domHook'; import { act } from 'react-dom/test-utils'; import { getOffsetSizeFunc, getTabs, triggerResize } from './common/util'; @@ -47,18 +47,17 @@ describe('Tabs.Operation-Overflow', () => { it('should collapse', () => { jest.useFakeTimers(); const onEdit = jest.fn(); - const wrapper = mount(getTabs({ editable: { onEdit } })); + const { container, unmount } = render(getTabs({ editable: { onEdit } })); - triggerResize(wrapper); + triggerResize(container); act(() => { jest.runAllTimers(); - wrapper.update(); }); expect( - wrapper.find('.rc-tabs-nav-operations').hasClass('rc-tabs-nav-operations-hidden'), - ).toBeFalsy(); + container.querySelector('.rc-tabs-nav-operations'), + ).not.toHaveClass('rc-tabs-nav-operations-hidden'); - wrapper.unmount(); + unmount(); jest.useRealTimers(); }); diff --git a/tests/overflow.test.tsx b/tests/overflow.test.tsx index 5eec2c1f..3a1c9727 100644 --- a/tests/overflow.test.tsx +++ b/tests/overflow.test.tsx @@ -1,8 +1,10 @@ -import type { ReactWrapper } from 'enzyme'; -import { mount } from 'enzyme'; +import { act, fireEvent, render } from '@testing-library/react'; import KeyCode from 'rc-util/lib/KeyCode'; import { spyElementPrototypes } from 'rc-util/lib/test/domHook'; -import { act } from 'react-dom/test-utils'; +import React from 'react'; +import type { TabsProps } from '../src'; +import Tabs from '../src'; +import type { HackInfo } from './common/util'; import { btnOffsetPosition, getOffsetSizeFunc, @@ -11,13 +13,9 @@ import { getTransformY, triggerResize, } from './common/util'; -import type { HackInfo } from './common/util'; -import type { TabsProps } from '../src'; -import Tabs from '../src'; describe('Tabs.Overflow', () => { let domSpy: ReturnType; - let holder: HTMLDivElement; const hackOffsetInfo: HackInfo = {}; @@ -28,9 +26,6 @@ describe('Tabs.Overflow', () => { }); beforeAll(() => { - holder = document.createElement('div'); - document.body.appendChild(holder); - domSpy = spyElementPrototypes(HTMLElement, { scrollIntoView: () => {}, offsetWidth: { @@ -50,32 +45,33 @@ describe('Tabs.Overflow', () => { afterAll(() => { domSpy.mockRestore(); - document.body.removeChild(holder); }); it('should collapse', () => { jest.useFakeTimers(); const onChange = jest.fn(); - const wrapper = mount(getTabs({ onChange })); + const { container, unmount } = render(getTabs({ onChange })); - triggerResize(wrapper); + triggerResize(container); act(() => { jest.runAllTimers(); - wrapper.update(); }); - expect(wrapper.find('.rc-tabs-nav-more').render()).toMatchSnapshot(); + expect(container.querySelector('.rc-tabs-nav-more')).toMatchSnapshot(); // Click to open - wrapper.find('.rc-tabs-nav-more').simulate('mouseenter'); - jest.runAllTimers(); - wrapper.update(); - expect(wrapper.find('.rc-tabs-dropdown li').first().text()).toEqual('cute'); + fireEvent.mouseEnter(container.querySelector('.rc-tabs-nav-more')); + + act(() => { + jest.runAllTimers(); + }); + + expect(document.querySelector('.rc-tabs-dropdown li').textContent).toEqual('cute'); // Click to select - wrapper.find('.rc-tabs-dropdown-menu-item').first().simulate('click'); + fireEvent.click(document.querySelector('.rc-tabs-dropdown-menu-item')); expect(onChange).toHaveBeenCalledWith('cute'); - wrapper.unmount(); + unmount(); jest.useRealTimers(); }); @@ -84,25 +80,31 @@ describe('Tabs.Overflow', () => { it(`keyboard with select keycode: ${code}`, () => { jest.useFakeTimers(); const onChange = jest.fn(); - const wrapper = mount(getTabs({ onChange }), { attachTo: holder }); + const { container, unmount } = render(getTabs({ onChange })); - triggerResize(wrapper); + triggerResize(container); act(() => { jest.runAllTimers(); - wrapper.update(); }); // Open - wrapper.find('.rc-tabs-nav-more').simulate('keydown', { + fireEvent.keyDown(container.querySelector('.rc-tabs-nav-more'), { which: KeyCode.DOWN, + keyCode: KeyCode.DOWN, + charCode: KeyCode.DOWN, }); // key selection function keyMatch(which: number, match: string) { - wrapper.find('.rc-tabs-nav-more').simulate('keydown', { + fireEvent.keyDown(container.querySelector('.rc-tabs-nav-more'), { which, + keyCode: which, + charCode: which, }); - expect(wrapper.find('li.rc-tabs-dropdown-menu-item-selected').text()).toEqual(match); + + expect( + document.querySelector('li.rc-tabs-dropdown-menu-item-selected').textContent, + ).toEqual(match); } keyMatch(KeyCode.DOWN, 'cute'); @@ -110,30 +112,34 @@ describe('Tabs.Overflow', () => { keyMatch(KeyCode.UP, 'cute'); // Select - wrapper.find('.rc-tabs-nav-more').simulate('keydown', { + fireEvent.keyDown(container.querySelector('.rc-tabs-nav-more'), { which: code, + keyCode: code, + charCode: code, }); expect(onChange).toHaveBeenCalledWith('cute'); // Open - wrapper.find('.rc-tabs-nav-more').simulate('keydown', { + fireEvent.keyDown(container.querySelector('.rc-tabs-nav-more'), { which: KeyCode.DOWN, + keyCode: KeyCode.DOWN, + charCode: KeyCode.DOWN, }); - wrapper.update(); - expect( - wrapper.find('.rc-tabs-dropdown').last().hasClass('rc-tabs-dropdown-hidden'), - ).toBeFalsy(); + + expect(document.querySelector('.rc-tabs-dropdown')).not.toHaveClass( + 'rc-tabs-dropdown-hidden', + ); // ESC - wrapper.find('.rc-tabs-nav-more').simulate('keydown', { + fireEvent.keyDown(container.querySelector('.rc-tabs-nav-more'), { which: KeyCode.ESC, + keyCode: KeyCode.ESC, + charCode: KeyCode.ESC, }); - wrapper.update(); - expect( - wrapper.find('.rc-tabs-dropdown').last().hasClass('rc-tabs-dropdown-hidden'), - ).toBeTruthy(); - wrapper.unmount(); + expect(document.querySelector('.rc-tabs-dropdown')).toHaveClass('rc-tabs-dropdown-hidden'); + + unmount(); jest.useRealTimers(); }); @@ -161,16 +167,15 @@ describe('Tabs.Overflow', () => { list.forEach(({ name, x1, y1, x2, y2 }) => { it(`should tab pos '${tabPosition}' work for ${name}`, () => { jest.useFakeTimers(); - const wrapper = mount(getTabs({ tabPosition }), { attachTo: holder }); + const { container, unmount } = render(getTabs({ tabPosition })); - triggerResize(wrapper); + triggerResize(container); act(() => { jest.runAllTimers(); - wrapper.update(); }); // Wheel to move - const node = wrapper.find('.rc-tabs-nav-wrap').instance() as unknown as HTMLElement; + const node = container.querySelector('.rc-tabs-nav-wrap'); act(() => { const wheel = new WheelEvent('wheel', { @@ -190,14 +195,13 @@ describe('Tabs.Overflow', () => { jest.runAllTimers(); }); - wrapper.update(); if (tabPosition === 'top') { - expect(getTransformX(wrapper)).toEqual(-23); + expect(getTransformX(container)).toEqual(-23); } else { - expect(getTransformY(wrapper)).toEqual(-23); + expect(getTransformY(container)).toEqual(-23); } - wrapper.unmount(); + unmount(); jest.useRealTimers(); }); }); @@ -206,7 +210,7 @@ describe('Tabs.Overflow', () => { ['top', 'left'].forEach((tabPosition: any) => { it(`no need if place is enough: ${tabPosition}`, () => { jest.useFakeTimers(); - const wrapper = mount( + const { container } = render( getTabs({ items: [ { @@ -218,14 +222,13 @@ describe('Tabs.Overflow', () => { }), ); - triggerResize(wrapper); + triggerResize(container); act(() => { jest.runAllTimers(); - wrapper.update(); }); // Wheel to move - const node = wrapper.find('.rc-tabs-nav-wrap').instance() as unknown as HTMLElement; + const node = container.querySelector('.rc-tabs-nav-wrap'); const wheel = new WheelEvent('wheel', { deltaX: 20, deltaY: 20, @@ -238,7 +241,7 @@ describe('Tabs.Overflow', () => { }); expect(wheel.preventDefault).not.toHaveBeenCalled(); - expect(getTransformX(wrapper)).toEqual(0); + expect(getTransformX(container)).toEqual(0); jest.useRealTimers(); }); @@ -250,33 +253,32 @@ describe('Tabs.Overflow', () => { jest.useFakeTimers(); const onTabScroll = jest.fn(); // light bamboo [cute disabled] miu - const wrapper = mount(getTabs({ activeKey: 'disabled', onTabScroll })); + const { container, rerender } = render(getTabs({ activeKey: 'disabled', onTabScroll })); - triggerResize(wrapper); + triggerResize(container); act(() => { jest.runAllTimers(); - wrapper.update(); }); - expect(getTransformX(wrapper)).toEqual(-40); + expect(getTransformX(container)).toEqual(-40); // light [bamboo cute] disabled miu onTabScroll.mockReset(); - wrapper.setProps({ activeKey: 'bamboo' }); + // wrapper.setProps({ activeKey: 'bamboo' }); + rerender(getTabs({ activeKey: 'bamboo', onTabScroll })); act(() => { jest.runAllTimers(); - wrapper.update(); }); - expect(getTransformX(wrapper)).toEqual(-20); + expect(getTransformX(container)).toEqual(-20); expect(onTabScroll).toHaveBeenCalledWith({ direction: 'left' }); // scroll to 0 when activeKey is null onTabScroll.mockReset(); - wrapper.setProps({ activeKey: null }); + // wrapper.setProps({ activeKey: null }); + rerender(getTabs({ activeKey: null, onTabScroll })); act(() => { jest.runAllTimers(); - wrapper.update(); }); - expect(getTransformX(wrapper)).toEqual(0); + expect(getTransformX(container)).toEqual(0); jest.useRealTimers(); }); @@ -293,23 +295,23 @@ describe('Tabs.Overflow', () => { * -------- disabled * miu miu */ - const wrapper = mount(getTabs({ activeKey: 'disabled', tabPosition: 'left', onTabScroll })); + const { container, rerender } = render( + getTabs({ activeKey: 'disabled', tabPosition: 'left', onTabScroll }), + ); - triggerResize(wrapper); + triggerResize(container); act(() => { jest.runAllTimers(); - wrapper.update(); }); - expect(getTransformY(wrapper)).toEqual(-40); + expect(getTransformY(container)).toEqual(-40); // light [bamboo cute] disabled miu onTabScroll.mockReset(); - wrapper.setProps({ activeKey: 'bamboo' }); + rerender(getTabs({ activeKey: 'bamboo', tabPosition: 'left', onTabScroll })); act(() => { jest.runAllTimers(); - wrapper.update(); }); - expect(getTransformY(wrapper)).toEqual(-20); + expect(getTransformY(container)).toEqual(-20); expect(onTabScroll).toHaveBeenCalledWith({ direction: 'top' }); jest.useRealTimers(); @@ -317,11 +319,11 @@ describe('Tabs.Overflow', () => { }); describe('editable dropdown menu', () => { - const list: { name: string; trigger: (node: ReactWrapper) => void }[] = [ + const list: { name: string; trigger: (node: HTMLElement) => void }[] = [ { name: 'click', trigger: node => { - node.simulate('click'); + fireEvent.click(node); }, }, ]; @@ -330,26 +332,24 @@ describe('Tabs.Overflow', () => { it(`remove by ${name} in dropdown menu`, () => { jest.useFakeTimers(); const onEdit = jest.fn(); - const wrapper = mount(getTabs({ editable: { onEdit } })); + const { container, unmount } = render(getTabs({ editable: { onEdit } })); - triggerResize(wrapper); + triggerResize(container); act(() => { jest.runAllTimers(); - wrapper.update(); }); // Click to open - wrapper.find('.rc-tabs-nav-more').simulate('mouseenter'); + fireEvent.mouseEnter(container.querySelector('.rc-tabs-nav-more')); act(() => { jest.runAllTimers(); - wrapper.update(); }); - const first = wrapper.find('.rc-tabs-dropdown-menu-item-remove').first(); + const first = document.querySelector('.rc-tabs-dropdown-menu-item-remove'); trigger(first); // Should be button to enable press SPACE key to trigger - expect(first.instance() instanceof HTMLButtonElement).toBeTruthy(); + expect(first instanceof HTMLButtonElement).toBeTruthy(); expect(onEdit).toHaveBeenCalledWith( 'remove', @@ -358,111 +358,122 @@ describe('Tabs.Overflow', () => { }), ); - wrapper.unmount(); + unmount(); jest.useRealTimers(); }); }); it('auto hidden Dropdown', () => { - console.log('run here'); jest.useFakeTimers(); - let items: TabsProps['items'] = new Array(8).fill(0).map((_, index) => ({ + const originItems: TabsProps['items'] = new Array(8).fill(0).map((_, index) => ({ key: `${index}`, label: `Tab ${index + 1}`, children: `Tab Content${index + 1}`, })); - const wrapper = mount( - { - return ele.key !== key.toString(); - }); - wrapper.setProps({ - items, - }); - } - }, - }} - items={items} - />, - ); + const Demo = () => { + const [items, setItems] = React.useState(originItems); + + return ( + { + return ele.key !== key.toString(); + }); + setItems(nextItems); + } + }, + }} + items={items} + /> + ); + }; + + const { container, unmount } = render(); - triggerResize(wrapper); + triggerResize(container); act(() => { jest.runAllTimers(); - wrapper.update(); }); // Click to open - wrapper.find('.rc-tabs-nav-more').simulate('mouseenter'); - jest.runAllTimers(); - wrapper.update(); - + fireEvent.mouseEnter(container.querySelector('.rc-tabs-nav-more')); act(() => { - while (true) { - const remove = wrapper.find('.rc-tabs-dropdown-menu-item-remove'); - if (!remove.exists()) return; - act(() => { - remove.first().simulate('click'); - }); - jest.runAllTimers(); - wrapper.update(); - } + jest.runAllTimers(); }); - expect(wrapper.find('.rc-tabs-dropdown-hidden').exists()).toBeTruthy(); + while (true) { + const remove = document.querySelector('.rc-tabs-dropdown-menu-item-remove'); + if (!remove) { + break; + } - wrapper.unmount(); + act(() => { + fireEvent.click(remove); + }); + + act(() => { + jest.runAllTimers(); + }); + } + + expect(document.querySelector('.rc-tabs-dropdown-hidden')).toBeTruthy(); + + unmount(); }); }); it('should calculate hidden tabs correctly', () => { jest.useFakeTimers(); const onEdit = jest.fn(); - const wrapper = mount(getTabs({ editable: { onEdit }, activeKey: 'miu' })); + const { container } = render(getTabs({ editable: { onEdit }, activeKey: 'miu' })); - triggerResize(wrapper); + triggerResize(container); act(() => { jest.runAllTimers(); - wrapper.update(); }); - wrapper.find('.rc-tabs-nav-more').simulate('mouseenter'); + fireEvent.mouseEnter(container.querySelector('.rc-tabs-nav-more')); act(() => { jest.runAllTimers(); - wrapper.update(); }); - expect(wrapper.find('.rc-tabs-dropdown-menu').first().text()).not.toContain('miu'); + expect(document.querySelector('.rc-tabs-dropdown-menu').textContent).not.toContain('miu'); }); it('should support getPopupContainer', () => { - const getPopupContainer = trigger => trigger.parentNode; - const wrapper = mount(getTabs({ getPopupContainer })); - expect(wrapper.find('Trigger').first().prop('getPopupContainer')).toBe(getPopupContainer); + const div = document.createElement('div'); + document.body.appendChild(div); + expect(div.childNodes.length).toBeFalsy(); + + const getPopupContainer = () => div; + const { container } = render(getTabs({ getPopupContainer })); + fireEvent.mouseEnter(container.querySelector('.rc-tabs-nav-more')); + act(() => { + jest.runAllTimers(); + }); + + expect(div.childNodes.length).toBeTruthy(); + + document.body.removeChild(div); }); it('should support popupClassName', () => { jest.useFakeTimers(); - const wrapper = mount(getTabs({ popupClassName: 'custom-popup' })); + const { container } = render(getTabs({ popupClassName: 'custom-popup' })); - triggerResize(wrapper); + triggerResize(container); act(() => { jest.runAllTimers(); - wrapper.update(); }); - wrapper.find('.rc-tabs-nav-more').simulate('mouseenter'); + fireEvent.mouseEnter(container.querySelector('.rc-tabs-nav-more')); act(() => { jest.runAllTimers(); - wrapper.update(); }); - expect(wrapper.find('.rc-tabs-dropdown').first().getDOMNode().className).toContain( - 'custom-popup', - ); + expect(document.querySelector('.rc-tabs-dropdown')).toHaveClass('custom-popup'); }); }); diff --git a/tests/rtl.test.tsx b/tests/rtl.test.tsx index 83b9a378..04277169 100644 --- a/tests/rtl.test.tsx +++ b/tests/rtl.test.tsx @@ -1,7 +1,7 @@ -import { mount } from 'enzyme'; +import { render } from '@testing-library/react'; import { spyElementPrototypes } from 'rc-util/lib/test/domHook'; import { act } from 'react-dom/test-utils'; -import { getOffsetSizeFunc, getTabs, triggerResize, getTransformX } from './common/util'; +import { getOffsetSizeFunc, getTabs, getTransformX, triggerResize } from './common/util'; // Same as `overflow.test.tsx` but use in RTL @@ -46,23 +46,23 @@ describe('Tabs.RTL', () => { it('overflow to scroll', () => { // Miu [Disabled Cute] Bamboo Light jest.useFakeTimers(); - const wrapper = mount(getTabs({ direction: 'rtl', defaultActiveKey: 'disabled' })); + const { container, rerender } = render( + getTabs({ direction: 'rtl', defaultActiveKey: 'disabled' }), + ); - triggerResize(wrapper); + triggerResize(container); act(() => { jest.runAllTimers(); - wrapper.update(); }); - expect(getTransformX(wrapper)).toEqual(40); + expect(getTransformX(container)).toEqual(40); // Miu Disabled [Cute Bamboo] Light - wrapper.setProps({ activeKey: 'bamboo' }); + rerender(getTabs({ direction: 'rtl', defaultActiveKey: 'disabled', activeKey: 'bamboo' })); act(() => { jest.runAllTimers(); - wrapper.update(); }); - expect(getTransformX(wrapper)).toEqual(20); + expect(getTransformX(container)).toEqual(20); jest.useRealTimers(); }); diff --git a/tests/setup.js b/tests/setup.js deleted file mode 100644 index 6cced84f..00000000 --- a/tests/setup.js +++ /dev/null @@ -1,8 +0,0 @@ -global.requestAnimationFrame = function requestAnimationFrame(cb) { - return setTimeout(cb, 0); -}; - -const Enzyme = require('enzyme'); -const Adapter = require('enzyme-adapter-react-16'); - -Enzyme.configure({ adapter: new Adapter() }); diff --git a/tests/setupFilesAfterEnv.js b/tests/setupFilesAfterEnv.js deleted file mode 100644 index 7b0828bf..00000000 --- a/tests/setupFilesAfterEnv.js +++ /dev/null @@ -1 +0,0 @@ -import '@testing-library/jest-dom'; diff --git a/tsconfig.json b/tsconfig.json index 78fcb71e..b85ad9c3 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -3,15 +3,24 @@ "target": "esnext", "moduleResolution": "node", "baseUrl": "./", - "lib": ["dom", "es2017"], - "jsx": "preserve", + "lib": [ + "dom", + "es2017" + ], + "jsx": "react", "declaration": true, "skipLibCheck": true, "esModuleInterop": true, "paths": { - "@/*": ["src/*"], - "@@/*": ["src/.umi/*"], - "rc-tabs": ["src/"] + "@/*": [ + "src/*" + ], + "@@/*": [ + "src/.umi/*" + ], + "rc-tabs": [ + "src/" + ] } } } \ No newline at end of file diff --git a/vercel.json b/vercel.json index 09eab0de..4cb7d015 100644 --- a/vercel.json +++ b/vercel.json @@ -5,7 +5,7 @@ { "src": "package.json", "use": "@now/static-build", - "config": { "distDir": ".doc" } + "config": { "distDir": "dist" } } ] }