mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-24 02:59:58 +08:00
fix: react 18 test fixing (#34787)
* fix: try fix * chore: ci * test: recover * test: more test case * test: more and mote * test: btn test * fix: react 18 compitable * chore: more test * test: all confirm test * chore: tmp * chore: test lib * chore: tmp * chore: tmp * test: back of part * test: back of menu index test * test: more test * test: form test * test: rm IE11 test case * chore: fix compatible * chore: clean up * chore: back of all test case * test: ignore 18 lines * chore: remove render test of enzyme in upload * test: back of IE11 test case to fit 100% coverage * chore: fix pkg deps
This commit is contained in:
parent
08e962db4e
commit
a67c0d28d3
6
.github/workflows/test.yml
vendored
6
.github/workflows/test.yml
vendored
@ -231,8 +231,7 @@ jobs:
|
||||
name: test
|
||||
strategy:
|
||||
matrix:
|
||||
react: ['16', '17']
|
||||
# react: ['17', '18']
|
||||
react: ['16', '17', '18']
|
||||
module: ['dom', 'node', 'dist']
|
||||
env:
|
||||
REACT: ${{ matrix.react }}
|
||||
@ -349,8 +348,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
matrix:
|
||||
react: ['16', '17']
|
||||
# react: ['17', '18']
|
||||
react: ['16', '17', '18']
|
||||
module: [lib, es]
|
||||
env:
|
||||
REACT: ${{ matrix.react }}
|
||||
|
50
components/_util/compatible.ts
Normal file
50
components/_util/compatible.ts
Normal file
@ -0,0 +1,50 @@
|
||||
/* eslint-disable import/prefer-default-export */
|
||||
import * as React from 'react';
|
||||
import { render, unmountComponentAtNode } from 'react-dom';
|
||||
import type { Root } from 'react-dom/client';
|
||||
// import * as reactDomClient from 'react-dom/client';
|
||||
|
||||
let createRoot: (container: ContainerType) => Root;
|
||||
try {
|
||||
// eslint-disable-next-line global-require, import/no-unresolved
|
||||
createRoot = require('react-dom/client').createRoot;
|
||||
} catch (e) {
|
||||
// Do nothing;
|
||||
}
|
||||
|
||||
const MARK = '__antd_react_root__';
|
||||
|
||||
type ContainerType = (Element | DocumentFragment) & {
|
||||
[MARK]?: Root;
|
||||
};
|
||||
|
||||
export function reactRender(node: React.ReactElement, container: ContainerType) {
|
||||
// React 17 test will not reach here
|
||||
/* istanbul ignore next */
|
||||
if (createRoot !== undefined) {
|
||||
const root = container[MARK] || createRoot(container);
|
||||
root.render(node);
|
||||
|
||||
container[MARK] = root;
|
||||
return;
|
||||
}
|
||||
|
||||
render(node, container);
|
||||
}
|
||||
|
||||
export function reactUnmount(container: ContainerType) {
|
||||
// React 17 test will not reach here
|
||||
/* istanbul ignore next */
|
||||
if (createRoot !== undefined) {
|
||||
// Delay to unmount to avoid React 18 sync warning
|
||||
Promise.resolve().then(() => {
|
||||
container[MARK]?.unmount();
|
||||
|
||||
delete container[MARK];
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
unmountComponentAtNode(container);
|
||||
}
|
@ -2,6 +2,8 @@ import React from 'react';
|
||||
import ReactDOM from 'react-dom';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { mount } from 'enzyme';
|
||||
import { render } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import Avatar from '..';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
@ -144,9 +146,10 @@ describe('Avatar Render', () => {
|
||||
|
||||
it('should warning when pass a string as icon props', () => {
|
||||
const warnSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
mount(<Avatar size={64} icon="aa" />);
|
||||
render(<Avatar size={64} icon="aa" />);
|
||||
expect(warnSpy).not.toHaveBeenCalled();
|
||||
mount(<Avatar size={64} icon="user" />);
|
||||
|
||||
render(<Avatar size={64} icon="user" />);
|
||||
expect(warnSpy).toHaveBeenCalledWith(
|
||||
`Warning: [antd: Avatar] \`icon\` is using ReactNode instead of string naming in v4. Please check \`user\` at https://ant.design/components/icon`,
|
||||
);
|
||||
|
@ -1,5 +1,7 @@
|
||||
import React from 'react';
|
||||
import { mount, render } from 'enzyme';
|
||||
import { mount } from 'enzyme';
|
||||
import { render } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import Breadcrumb from '../index';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
@ -21,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 = () => <div>foo</div>;
|
||||
mount(
|
||||
render(
|
||||
<Breadcrumb>
|
||||
<MyCom />
|
||||
</Breadcrumb>,
|
||||
@ -34,7 +36,7 @@ describe('Breadcrumb', () => {
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/5015
|
||||
it('should allow Breadcrumb.Item is null or undefined', () => {
|
||||
const wrapper = render(
|
||||
const { asFragment } = render(
|
||||
<Breadcrumb>
|
||||
{null}
|
||||
<Breadcrumb.Item>Home</Breadcrumb.Item>
|
||||
@ -42,24 +44,24 @@ describe('Breadcrumb', () => {
|
||||
</Breadcrumb>,
|
||||
);
|
||||
expect(errorSpy).not.toHaveBeenCalled();
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
expect(asFragment().firstChild).toMatchSnapshot();
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/5542
|
||||
it('should not display Breadcrumb Item when its children is falsy', () => {
|
||||
const wrapper = render(
|
||||
const wrapper = mount(
|
||||
<Breadcrumb>
|
||||
<Breadcrumb.Item />
|
||||
<Breadcrumb.Item>xxx</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>yyy</Breadcrumb.Item>
|
||||
</Breadcrumb>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/18260
|
||||
it('filter React.Fragment', () => {
|
||||
const wrapper = render(
|
||||
const wrapper = mount(
|
||||
<Breadcrumb separator="">
|
||||
<Breadcrumb.Item>Location</Breadcrumb.Item>
|
||||
<Breadcrumb.Separator>:</Breadcrumb.Separator>
|
||||
@ -69,7 +71,7 @@ describe('Breadcrumb', () => {
|
||||
</>
|
||||
</Breadcrumb>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should render a menu', () => {
|
||||
@ -104,27 +106,27 @@ describe('Breadcrumb', () => {
|
||||
path: 'third',
|
||||
},
|
||||
];
|
||||
const wrapper = render(<Breadcrumb routes={routes} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
const wrapper = mount(<Breadcrumb routes={routes} />);
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should accept undefined routes', () => {
|
||||
const wrapper = render(<Breadcrumb routes={undefined} />);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
const wrapper = mount(<Breadcrumb routes={undefined} />);
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should support custom attribute', () => {
|
||||
const wrapper = render(
|
||||
const wrapper = mount(
|
||||
<Breadcrumb data-custom="custom">
|
||||
<Breadcrumb.Item data-custom="custom-item">xxx</Breadcrumb.Item>
|
||||
<Breadcrumb.Item>yyy</Breadcrumb.Item>
|
||||
</Breadcrumb>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('should support React.Fragment and falsy children', () => {
|
||||
const wrapper = render(
|
||||
const wrapper = mount(
|
||||
<Breadcrumb>
|
||||
<>
|
||||
<Breadcrumb.Item>yyy</Breadcrumb.Item>
|
||||
@ -136,7 +138,7 @@ describe('Breadcrumb', () => {
|
||||
{undefined}
|
||||
</Breadcrumb>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/25975
|
||||
@ -146,13 +148,13 @@ describe('Breadcrumb', () => {
|
||||
<Breadcrumb.Item>Mock Node</Breadcrumb.Item>
|
||||
</span>
|
||||
);
|
||||
const wrapper = render(
|
||||
const wrapper = mount(
|
||||
<Breadcrumb>
|
||||
<Breadcrumb.Item>Location</Breadcrumb.Item>
|
||||
<MockComponent />
|
||||
<Breadcrumb.Item>Application Center</Breadcrumb.Item>
|
||||
</Breadcrumb>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
@ -1,5 +1,7 @@
|
||||
import React, { Component } from 'react';
|
||||
import { mount, render } from 'enzyme';
|
||||
import { mount } from 'enzyme';
|
||||
import { render } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { SearchOutlined } from '@ant-design/icons';
|
||||
import { resetWarned } from 'rc-util/lib/warning';
|
||||
@ -39,7 +41,7 @@ describe('Button', () => {
|
||||
const mockWarn = jest.fn();
|
||||
jest.spyOn(console, 'warn').mockImplementation(mockWarn);
|
||||
const size = 'who am I' as any as SizeType;
|
||||
render(<Button.Group size={size} />);
|
||||
mount(<Button.Group size={size} />);
|
||||
expect(mockWarn).toHaveBeenCalledTimes(1);
|
||||
expect(mockWarn.mock.calls[0][0]).toMatchObject({
|
||||
message: 'unreachable case: "who am I"',
|
||||
@ -51,12 +53,14 @@ describe('Button', () => {
|
||||
// should not insert space when there is icon
|
||||
expect(mount(<Button icon={<SearchOutlined />}>按钮</Button>).render()).toMatchSnapshot();
|
||||
// should not insert space when there is icon
|
||||
expect(mount(
|
||||
<Button>
|
||||
<SearchOutlined />
|
||||
按钮
|
||||
</Button>,
|
||||
).render()).toMatchSnapshot();
|
||||
expect(
|
||||
mount(
|
||||
<Button>
|
||||
<SearchOutlined />
|
||||
按钮
|
||||
</Button>,
|
||||
).render(),
|
||||
).toMatchSnapshot();
|
||||
// should not insert space when there is icon
|
||||
expect(mount(<Button icon={<SearchOutlined />}>按钮</Button>).render()).toMatchSnapshot();
|
||||
// should not insert space when there is icon while loading
|
||||
@ -261,12 +265,15 @@ describe('Button', () => {
|
||||
it('should warning when pass a string as icon props', () => {
|
||||
resetWarned();
|
||||
const warnSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
mount(<Button type="primary" icon="ab" />);
|
||||
|
||||
render(<Button type="primary" icon="ab" />);
|
||||
expect(warnSpy).not.toHaveBeenCalled();
|
||||
mount(<Button type="primary" icon="search" />);
|
||||
|
||||
render(<Button type="primary" icon="search" />);
|
||||
expect(warnSpy).toHaveBeenCalledWith(
|
||||
`Warning: [antd: Button] \`icon\` is using ReactNode instead of string naming in v4. Please check \`search\` at https://ant.design/components/icon`,
|
||||
);
|
||||
|
||||
warnSpy.mockRestore();
|
||||
});
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { render } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import ConfigProvider from '..';
|
||||
import zhCN from '../../locale/zh_CN';
|
||||
@ -15,10 +17,10 @@ describe('ConfigProvider.Form', () => {
|
||||
});
|
||||
|
||||
describe('form validateMessages', () => {
|
||||
const wrapperComponent = ({ validateMessages }) => {
|
||||
const renderComponent = ({ validateMessages }) => {
|
||||
const formRef = React.createRef();
|
||||
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<ConfigProvider locale={zhCN} form={{ validateMessages }}>
|
||||
<Form ref={formRef} initialValues={{ age: 18 }}>
|
||||
<Form.Item name="test" label="姓名" rules={[{ required: true }]}>
|
||||
@ -31,11 +33,11 @@ describe('ConfigProvider.Form', () => {
|
||||
</ConfigProvider>,
|
||||
);
|
||||
|
||||
return [wrapper, formRef];
|
||||
return [container, formRef];
|
||||
};
|
||||
|
||||
it('set locale zhCN', async () => {
|
||||
const [wrapper, formRef] = wrapperComponent({});
|
||||
const [container, formRef] = renderComponent({});
|
||||
|
||||
await act(async () => {
|
||||
try {
|
||||
@ -47,15 +49,14 @@ describe('ConfigProvider.Form', () => {
|
||||
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
wrapper.update();
|
||||
await Promise.resolve();
|
||||
});
|
||||
|
||||
expect(wrapper.find('.ant-form-item-explain').first().text()).toEqual('请输入姓名');
|
||||
expect(container.querySelector('.ant-form-item-explain')).toHaveTextContent('请输入姓名');
|
||||
});
|
||||
|
||||
it('set locale zhCN and set form validateMessages one item, other use default message', async () => {
|
||||
const [wrapper, formRef] = wrapperComponent({ validateMessages: { required: '必须' } });
|
||||
const [container, formRef] = renderComponent({ validateMessages: { required: '必须' } });
|
||||
|
||||
await act(async () => {
|
||||
try {
|
||||
@ -67,12 +68,13 @@ describe('ConfigProvider.Form', () => {
|
||||
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
wrapper.update();
|
||||
await Promise.resolve();
|
||||
});
|
||||
|
||||
expect(wrapper.find('.ant-form-item-explain').first().text()).toEqual('必须');
|
||||
expect(wrapper.find('.ant-form-item-explain').last().text()).toEqual('年龄必须等于17');
|
||||
const explains = Array.from(container.querySelectorAll('.ant-form-item-explain'));
|
||||
|
||||
expect(explains[0]).toHaveTextContent('必须');
|
||||
expect(explains[explains.length - 1]).toHaveTextContent('年龄必须等于17');
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
import React from 'react';
|
||||
import { render, mount } from 'enzyme';
|
||||
import { mount } from 'enzyme';
|
||||
import { render } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import Drawer from '..';
|
||||
import ConfigProvider from '../../config-provider';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
@ -18,12 +20,12 @@ describe('Drawer', () => {
|
||||
rtlTest(Drawer);
|
||||
|
||||
it('render correctly', () => {
|
||||
const wrapper = render(
|
||||
const wrapper = mount(
|
||||
<Drawer visible width={400} getContainer={false}>
|
||||
Here is content of Drawer
|
||||
</Drawer>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('getContainer return undefined', () => {
|
||||
@ -34,55 +36,55 @@ describe('Drawer', () => {
|
||||
});
|
||||
|
||||
it('render top drawer', () => {
|
||||
const wrapper = render(
|
||||
const wrapper = mount(
|
||||
<Drawer visible height={400} placement="top" getContainer={false}>
|
||||
Here is content of Drawer
|
||||
</Drawer>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('have a title', () => {
|
||||
const wrapper = render(
|
||||
const wrapper = mount(
|
||||
<Drawer visible title="Test Title" getContainer={false}>
|
||||
Here is content of Drawer
|
||||
</Drawer>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('closable is false', () => {
|
||||
const wrapper = render(
|
||||
const wrapper = mount(
|
||||
<Drawer visible closable={false} getContainer={false}>
|
||||
Here is content of Drawer
|
||||
</Drawer>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('destroyOnClose is true', () => {
|
||||
const wrapper = render(
|
||||
const wrapper = mount(
|
||||
<Drawer destroyOnClose visible={false} getContainer={false}>
|
||||
Here is content of Drawer
|
||||
</Drawer>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('className is test_drawer', () => {
|
||||
const wrapper = render(
|
||||
const wrapper = mount(
|
||||
<Drawer destroyOnClose visible={false} className="test_drawer" getContainer={false}>
|
||||
Here is content of Drawer
|
||||
</Drawer>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('style/drawerStyle/headerStyle/bodyStyle should work', () => {
|
||||
const style = {
|
||||
backgroundColor: '#08c',
|
||||
};
|
||||
const wrapper = render(
|
||||
const wrapper = mount(
|
||||
<Drawer
|
||||
visible
|
||||
style={style}
|
||||
@ -94,16 +96,16 @@ describe('Drawer', () => {
|
||||
Here is content of Drawer
|
||||
</Drawer>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('have a footer', () => {
|
||||
const wrapper = render(
|
||||
const wrapper = mount(
|
||||
<Drawer visible footer="Test Footer" getContainer={false}>
|
||||
Here is content of Drawer
|
||||
</Drawer>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('forceRender works', () => {
|
||||
@ -126,18 +128,18 @@ describe('Drawer', () => {
|
||||
});
|
||||
|
||||
it('support closeIcon', () => {
|
||||
const wrapper = render(
|
||||
const wrapper = mount(
|
||||
<Drawer visible closable closeIcon={<span>close</span>} width={400} getContainer={false}>
|
||||
Here is content of Drawer
|
||||
</Drawer>,
|
||||
);
|
||||
expect(wrapper).toMatchSnapshot();
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it('ConfigProvider should not warning', () => {
|
||||
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
|
||||
mount(
|
||||
render(
|
||||
<ConfigProvider virtual>
|
||||
<Drawer visible>Bamboo is Light</Drawer>
|
||||
</ConfigProvider>,
|
||||
|
@ -13,14 +13,14 @@ exports[`Drawer className is test_drawer 1`] = `
|
||||
/>
|
||||
<div
|
||||
class="ant-drawer-content-wrapper"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:378px"
|
||||
style="transform: translateX(100%); width: 378px;"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-content"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-wrapper-body"
|
||||
style="opacity:0;transition:opacity .3s"
|
||||
style="opacity: 0; transition: opacity .3s;"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-header ant-drawer-header-close-only"
|
||||
@ -72,7 +72,7 @@ exports[`Drawer closable is false 1`] = `
|
||||
class=""
|
||||
>
|
||||
<div
|
||||
class="ant-drawer ant-drawer-right"
|
||||
class="ant-drawer ant-drawer-right ant-drawer-open"
|
||||
tabindex="-1"
|
||||
>
|
||||
<div
|
||||
@ -80,7 +80,7 @@ exports[`Drawer closable is false 1`] = `
|
||||
/>
|
||||
<div
|
||||
class="ant-drawer-content-wrapper"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:378px"
|
||||
style="width: 378px;"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-content"
|
||||
@ -113,14 +113,14 @@ exports[`Drawer destroyOnClose is true 1`] = `
|
||||
/>
|
||||
<div
|
||||
class="ant-drawer-content-wrapper"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:378px"
|
||||
style="transform: translateX(100%); width: 378px;"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-content"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-wrapper-body"
|
||||
style="opacity:0;transition:opacity .3s"
|
||||
style="opacity: 0; transition: opacity .3s;"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-header ant-drawer-header-close-only"
|
||||
@ -242,7 +242,7 @@ exports[`Drawer have a footer 1`] = `
|
||||
class=""
|
||||
>
|
||||
<div
|
||||
class="ant-drawer ant-drawer-right"
|
||||
class="ant-drawer ant-drawer-right ant-drawer-open"
|
||||
tabindex="-1"
|
||||
>
|
||||
<div
|
||||
@ -250,7 +250,7 @@ exports[`Drawer have a footer 1`] = `
|
||||
/>
|
||||
<div
|
||||
class="ant-drawer-content-wrapper"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:378px"
|
||||
style="width: 378px;"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-content"
|
||||
@ -313,7 +313,7 @@ exports[`Drawer have a title 1`] = `
|
||||
class=""
|
||||
>
|
||||
<div
|
||||
class="ant-drawer ant-drawer-right"
|
||||
class="ant-drawer ant-drawer-right ant-drawer-open"
|
||||
tabindex="-1"
|
||||
>
|
||||
<div
|
||||
@ -321,7 +321,7 @@ exports[`Drawer have a title 1`] = `
|
||||
/>
|
||||
<div
|
||||
class="ant-drawer-content-wrapper"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:378px"
|
||||
style="width: 378px;"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-content"
|
||||
@ -384,7 +384,7 @@ exports[`Drawer render correctly 1`] = `
|
||||
class=""
|
||||
>
|
||||
<div
|
||||
class="ant-drawer ant-drawer-right"
|
||||
class="ant-drawer ant-drawer-right ant-drawer-open"
|
||||
tabindex="-1"
|
||||
>
|
||||
<div
|
||||
@ -392,7 +392,7 @@ exports[`Drawer render correctly 1`] = `
|
||||
/>
|
||||
<div
|
||||
class="ant-drawer-content-wrapper"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:400px"
|
||||
style="width: 400px;"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-content"
|
||||
@ -450,7 +450,7 @@ exports[`Drawer render top drawer 1`] = `
|
||||
class=""
|
||||
>
|
||||
<div
|
||||
class="ant-drawer ant-drawer-top"
|
||||
class="ant-drawer ant-drawer-top ant-drawer-open"
|
||||
tabindex="-1"
|
||||
>
|
||||
<div
|
||||
@ -458,7 +458,7 @@ exports[`Drawer render top drawer 1`] = `
|
||||
/>
|
||||
<div
|
||||
class="ant-drawer-content-wrapper"
|
||||
style="transform:translateY(-100%);-ms-transform:translateY(-100%);height:400px"
|
||||
style="height: 400px;"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-content"
|
||||
@ -518,8 +518,8 @@ exports[`Drawer style/drawerStyle/headerStyle/bodyStyle should work 1`] = `
|
||||
class=""
|
||||
>
|
||||
<div
|
||||
class="ant-drawer ant-drawer-right"
|
||||
style="background-color:#08c"
|
||||
class="ant-drawer ant-drawer-right ant-drawer-open"
|
||||
style="background-color: rgb(0, 136, 204);"
|
||||
tabindex="-1"
|
||||
>
|
||||
<div
|
||||
@ -527,18 +527,18 @@ exports[`Drawer style/drawerStyle/headerStyle/bodyStyle should work 1`] = `
|
||||
/>
|
||||
<div
|
||||
class="ant-drawer-content-wrapper"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:378px"
|
||||
style="width: 378px;"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-content"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-wrapper-body"
|
||||
style="background-color:#08c"
|
||||
style="background-color: rgb(0, 136, 204);"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-header ant-drawer-header-close-only"
|
||||
style="background-color:#08c"
|
||||
style="background-color: rgb(0, 136, 204);"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-header-title"
|
||||
@ -572,7 +572,7 @@ exports[`Drawer style/drawerStyle/headerStyle/bodyStyle should work 1`] = `
|
||||
</div>
|
||||
<div
|
||||
class="ant-drawer-body"
|
||||
style="background-color:#08c"
|
||||
style="background-color: rgb(0, 136, 204);"
|
||||
>
|
||||
Here is content of Drawer
|
||||
</div>
|
||||
@ -588,7 +588,7 @@ exports[`Drawer support closeIcon 1`] = `
|
||||
class=""
|
||||
>
|
||||
<div
|
||||
class="ant-drawer ant-drawer-right"
|
||||
class="ant-drawer ant-drawer-right ant-drawer-open"
|
||||
tabindex="-1"
|
||||
>
|
||||
<div
|
||||
@ -596,7 +596,7 @@ exports[`Drawer support closeIcon 1`] = `
|
||||
/>
|
||||
<div
|
||||
class="ant-drawer-content-wrapper"
|
||||
style="transform:translateX(100%);-ms-transform:translateX(100%);width:400px"
|
||||
style="width: 400px;"
|
||||
>
|
||||
<div
|
||||
class="ant-drawer-content"
|
||||
|
@ -1,5 +1,7 @@
|
||||
import React, { Component, useState } from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { render, fireEvent } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import scrollIntoView from 'scroll-into-view-if-needed';
|
||||
import Form from '..';
|
||||
@ -27,15 +29,18 @@ describe('Form', () => {
|
||||
scrollIntoView.mockImplementation(() => {});
|
||||
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
|
||||
async function change(wrapper, index, value, executeMockTimer) {
|
||||
wrapper.find(Input).at(index).simulate('change', { target: { value } });
|
||||
async function change(container, index, value, executeMockTimer) {
|
||||
fireEvent.change(container.querySelectorAll('input')[index], {
|
||||
target: { value },
|
||||
});
|
||||
await sleep(200);
|
||||
|
||||
if (executeMockTimer) {
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
wrapper.update();
|
||||
});
|
||||
for (let i = 0; i < 10; i += 1) {
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
}
|
||||
await sleep(1);
|
||||
}
|
||||
}
|
||||
@ -60,19 +65,19 @@ describe('Form', () => {
|
||||
|
||||
const onChange = jest.fn();
|
||||
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<Form>
|
||||
<Form.Item>
|
||||
<Form.Item name="test" rules={[{ required: true }]}>
|
||||
<Form.Item name="test" initialValue="bamboo" rules={[{ required: true }]}>
|
||||
<Input onChange={onChange} />
|
||||
</Form.Item>
|
||||
</Form.Item>
|
||||
</Form>,
|
||||
);
|
||||
|
||||
await change(wrapper, 0, '', true);
|
||||
expect(wrapper.find('.ant-form-item-with-help').length).toBeTruthy();
|
||||
expect(wrapper.find('.ant-form-item-has-error').length).toBeTruthy();
|
||||
await change(container, 0, '', true);
|
||||
expect(container.querySelectorAll('.ant-form-item-with-help').length).toBeTruthy();
|
||||
expect(container.querySelectorAll('.ant-form-item-has-error').length).toBeTruthy();
|
||||
|
||||
expect(onChange).toHaveBeenCalled();
|
||||
|
||||
@ -124,13 +129,13 @@ describe('Form', () => {
|
||||
);
|
||||
};
|
||||
|
||||
const wrapper = mount(<Demo />);
|
||||
await change(wrapper, 0, '1', true);
|
||||
expect(wrapper.find('.ant-form-item-explain').text()).toEqual('aaa');
|
||||
await change(wrapper, 0, '2', true);
|
||||
expect(wrapper.find('.ant-form-item-explain').text()).toEqual('ccc');
|
||||
await change(wrapper, 0, '1', true);
|
||||
expect(wrapper.find('.ant-form-item-explain').text()).toEqual('aaa');
|
||||
const { container } = render(<Demo />);
|
||||
await change(container, 0, '1', true);
|
||||
expect(container.querySelector('.ant-form-item-explain').textContent).toEqual('aaa');
|
||||
await change(container, 0, '2', true);
|
||||
expect(container.querySelector('.ant-form-item-explain').textContent).toEqual('ccc');
|
||||
await change(container, 0, '1', true);
|
||||
expect(container.querySelector('.ant-form-item-explain').textContent).toEqual('aaa');
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
@ -353,7 +358,7 @@ describe('Form', () => {
|
||||
it('Error change should work', async () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<Form>
|
||||
<Form.Item
|
||||
name="name"
|
||||
@ -376,13 +381,15 @@ describe('Form', () => {
|
||||
|
||||
/* eslint-disable no-await-in-loop */
|
||||
for (let i = 0; i < 3; i += 1) {
|
||||
await change(wrapper, 0, '', true);
|
||||
expect(wrapper.find('.ant-form-item-explain').first().text()).toEqual("'name' is required");
|
||||
await change(container, 0, 'bamboo', true);
|
||||
await change(container, 0, '', true);
|
||||
expect(container.querySelector('.ant-form-item-explain').textContent).toEqual(
|
||||
"'name' is required",
|
||||
);
|
||||
|
||||
await change(wrapper, 0, 'p', true);
|
||||
await change(container, 0, 'p', true);
|
||||
await sleep(100);
|
||||
wrapper.update();
|
||||
expect(wrapper.find('.ant-form-item-explain').first().text()).toEqual('not a p');
|
||||
expect(container.querySelector('.ant-form-item-explain').textContent).toEqual('not a p');
|
||||
}
|
||||
/* eslint-enable */
|
||||
|
||||
@ -470,17 +477,22 @@ describe('Form', () => {
|
||||
it('Form.Item with `help` should display error style when validate failed', async () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<Form>
|
||||
<Form.Item name="test" help="help" rules={[{ required: true, message: 'message' }]}>
|
||||
<Form.Item
|
||||
name="test"
|
||||
help="help"
|
||||
initialValue="bamboo"
|
||||
rules={[{ required: true, message: 'message' }]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</Form>,
|
||||
);
|
||||
|
||||
await change(wrapper, 0, '', true);
|
||||
expect(wrapper.find('.ant-form-item').first().hasClass('ant-form-item-has-error')).toBeTruthy();
|
||||
expect(wrapper.find('.ant-form-item-explain').text()).toEqual('help');
|
||||
await change(container, 0, '', true);
|
||||
expect(container.querySelector('.ant-form-item')).toHaveClass('ant-form-item-has-error');
|
||||
expect(container.querySelector('.ant-form-item-explain').textContent).toEqual('help');
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
@ -488,23 +500,22 @@ describe('Form', () => {
|
||||
it('clear validation message when ', async () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<Form>
|
||||
<Form.Item name="username" rules={[{ required: true, message: 'message' }]}>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</Form>,
|
||||
);
|
||||
await change(wrapper, 0, '1', true);
|
||||
expect(wrapper.find('.ant-form-item-explain').length).toBeFalsy();
|
||||
await change(container, 0, '1', true);
|
||||
expect(container.querySelectorAll('.ant-form-item-explain').length).toBeFalsy();
|
||||
|
||||
await change(wrapper, 0, '', true);
|
||||
expect(wrapper.find('.ant-form-item-explain').length).toBeTruthy();
|
||||
await change(container, 0, '', true);
|
||||
expect(container.querySelectorAll('.ant-form-item-explain').length).toBeTruthy();
|
||||
|
||||
await change(wrapper, 0, '123', true);
|
||||
await change(container, 0, '123', true);
|
||||
await sleep(800);
|
||||
wrapper.update();
|
||||
expect(wrapper.find('.ant-form-item-explain').length).toBeFalsy();
|
||||
expect(container.querySelectorAll('.ant-form-item-explain').length).toBeFalsy();
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
@ -591,8 +602,8 @@ describe('Form', () => {
|
||||
);
|
||||
};
|
||||
|
||||
const wrapper = mount(<Demo />);
|
||||
wrapper.find('button').simulate('click');
|
||||
const { container } = render(<Demo />);
|
||||
fireEvent.click(container.querySelector('button'));
|
||||
|
||||
expect(errorSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
@ -794,7 +805,7 @@ describe('Form', () => {
|
||||
});
|
||||
|
||||
it('no warning of initialValue & getValueProps & preserve', () => {
|
||||
mount(
|
||||
render(
|
||||
<Form>
|
||||
<Form.Item initialValue="bamboo" getValueProps={() => null} preserve={false}>
|
||||
<Input />
|
||||
@ -973,19 +984,23 @@ describe('Form', () => {
|
||||
it('warningOnly validate', async () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<Form>
|
||||
<Form.Item>
|
||||
<Form.Item name="test" rules={[{ required: true, warningOnly: true }]}>
|
||||
<Form.Item
|
||||
name="test"
|
||||
initialValue="bamboo"
|
||||
rules={[{ required: true, warningOnly: true }]}
|
||||
>
|
||||
<Input />
|
||||
</Form.Item>
|
||||
</Form.Item>
|
||||
</Form>,
|
||||
);
|
||||
|
||||
await change(wrapper, 0, '', true);
|
||||
expect(wrapper.find('.ant-form-item-with-help').length).toBeTruthy();
|
||||
expect(wrapper.find('.ant-form-item-has-warning').length).toBeTruthy();
|
||||
await change(container, 0, '', true);
|
||||
expect(container.querySelectorAll('.ant-form-item-with-help').length).toBeTruthy();
|
||||
expect(container.querySelectorAll('.ant-form-item-has-warning').length).toBeTruthy();
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
@ -994,12 +1009,13 @@ describe('Form', () => {
|
||||
jest.useFakeTimers();
|
||||
let rejectFn = null;
|
||||
|
||||
const wrapper = mount(
|
||||
const { container, unmount } = render(
|
||||
<Form>
|
||||
<Form.Item>
|
||||
<Form.Item
|
||||
noStyle
|
||||
name="test"
|
||||
initialValue="bamboo"
|
||||
rules={[
|
||||
{
|
||||
validator: () =>
|
||||
@ -1015,9 +1031,9 @@ describe('Form', () => {
|
||||
</Form>,
|
||||
);
|
||||
|
||||
await change(wrapper, 0, '', true);
|
||||
await change(container, 0, '', true);
|
||||
|
||||
wrapper.unmount();
|
||||
unmount();
|
||||
|
||||
// Delay validate failed
|
||||
rejectFn(new Error('delay failed'));
|
||||
|
@ -64,9 +64,11 @@ describe('Form.List', () => {
|
||||
expect(wrapper.find(Input).length).toBe(3);
|
||||
|
||||
await change(wrapper, 2, '');
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
for (let i = 0; i < 10; i += 1) {
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
}
|
||||
wrapper.update();
|
||||
expect(wrapper.find('.ant-form-item-explain div').length).toBe(1);
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
import React from 'react';
|
||||
import ReactDOMServer from 'react-dom/server';
|
||||
import { render } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import { mount } from 'enzyme';
|
||||
import { Col, Row } from '..';
|
||||
// eslint-disable-next-line no-unused-vars
|
||||
@ -42,12 +44,12 @@ describe('Grid.Gap', () => {
|
||||
const ssrTxt = ReactDOMServer.renderToString(<Demo />);
|
||||
div.innerHTML = ssrTxt;
|
||||
|
||||
const wrapper = mount(<Demo />, { hydrateIn: div });
|
||||
const { unmount } = render(<Demo />, { container: div, hydrate: true });
|
||||
|
||||
expect(warnSpy).not.toHaveBeenCalled();
|
||||
|
||||
warnSpy.mockRestore();
|
||||
|
||||
wrapper.unmount();
|
||||
unmount();
|
||||
});
|
||||
});
|
||||
|
@ -1,5 +1,7 @@
|
||||
import React, { useState } from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { render, fireEvent } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
// eslint-disable-next-line import/no-unresolved
|
||||
import Form from '../../form';
|
||||
import Input, { InputProps, InputRef } from '..';
|
||||
@ -54,11 +56,11 @@ describe('Input', () => {
|
||||
|
||||
describe('focus trigger warning', () => {
|
||||
it('not trigger', () => {
|
||||
const wrapper = mount(<Input suffix="bamboo" />);
|
||||
(wrapper.find('input').instance() as any).focus();
|
||||
wrapper.setProps({
|
||||
suffix: 'light',
|
||||
});
|
||||
const { container, rerender } = render(<Input suffix="bamboo" />);
|
||||
|
||||
fireEvent.focus(container.querySelector('input')!);
|
||||
|
||||
rerender(<Input suffix="light" />);
|
||||
expect(errorSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
it('trigger warning', () => {
|
||||
|
@ -1,5 +1,7 @@
|
||||
import React, { useState } from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { render } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import RcTextArea from 'rc-textarea';
|
||||
import Input from '..';
|
||||
import focusTest from '../../../tests/shared/focusTest';
|
||||
@ -35,18 +37,32 @@ describe('TextArea', () => {
|
||||
|
||||
const ref = React.createRef();
|
||||
|
||||
const wrapper = mount(
|
||||
<TextArea value="" readOnly autoSize={{ minRows: 2, maxRows: 6 }} wrap="off" ref={ref} />,
|
||||
const genTextArea = (props = {}) => (
|
||||
<TextArea
|
||||
value=""
|
||||
readOnly
|
||||
autoSize={{ minRows: 2, maxRows: 6 }}
|
||||
wrap="off"
|
||||
ref={ref}
|
||||
{...props}
|
||||
/>
|
||||
);
|
||||
|
||||
const { container, rerender } = render(genTextArea());
|
||||
|
||||
const mockFunc = jest.spyOn(ref.current.resizableTextArea, 'resizeTextarea');
|
||||
wrapper.setProps({ value: '1111\n2222\n3333' });
|
||||
|
||||
rerender(genTextArea({ value: '1111\n2222\n3333' }));
|
||||
// wrapper.setProps({ value: '1111\n2222\n3333' });
|
||||
await sleep(0);
|
||||
expect(mockFunc).toHaveBeenCalledTimes(1);
|
||||
wrapper.setProps({ value: '1111' });
|
||||
|
||||
rerender(genTextArea({ value: '1111' }));
|
||||
// wrapper.setProps({ value: '1111' });
|
||||
await sleep(0);
|
||||
expect(mockFunc).toHaveBeenCalledTimes(2);
|
||||
wrapper.update();
|
||||
expect(wrapper.find('textarea').props().style.overflow).toBeFalsy();
|
||||
|
||||
expect(container.querySelector('textarea').style.overflow).toBeFalsy();
|
||||
|
||||
expect(errorSpy).not.toHaveBeenCalled();
|
||||
errorSpy.mockRestore();
|
||||
|
@ -1,7 +1,9 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import ConfigProvider from '../../config-provider';
|
||||
import { Modal } from '../..';
|
||||
import { sleep } from '../../../tests/utils';
|
||||
import zhCN from '../zh_CN';
|
||||
|
||||
class Demo extends React.Component {
|
||||
@ -19,7 +21,7 @@ class Demo extends React.Component {
|
||||
}
|
||||
|
||||
describe('Locale Provider demo', () => {
|
||||
it('change type', () => {
|
||||
it('change type', async () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
const BasicExample = () => {
|
||||
@ -48,10 +50,19 @@ describe('Locale Provider demo', () => {
|
||||
);
|
||||
};
|
||||
const wrapper = mount(<BasicExample />);
|
||||
|
||||
wrapper.find('.about').at(0).simulate('click');
|
||||
jest.runAllTimers();
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
await sleep();
|
||||
});
|
||||
|
||||
wrapper.find('.dashboard').at(0).simulate('click');
|
||||
jest.runAllTimers();
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
await sleep();
|
||||
});
|
||||
|
||||
expect(document.body.querySelectorAll('.ant-btn-primary span')[0].textContent).toBe('确 定');
|
||||
Modal.destroyAll();
|
||||
jest.useRealTimers();
|
||||
|
@ -7,6 +7,8 @@ import {
|
||||
PieChartOutlined,
|
||||
UserOutlined,
|
||||
} from '@ant-design/icons';
|
||||
import { render, fireEvent } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import Menu from '..';
|
||||
import Layout from '../../layout';
|
||||
@ -15,62 +17,75 @@ import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
import collapseMotion from '../../_util/motion';
|
||||
|
||||
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
|
||||
|
||||
const { SubMenu } = Menu;
|
||||
|
||||
const noop = () => {};
|
||||
|
||||
const expectSubMenuBehavior = (menu, enter = noop, leave = noop) => {
|
||||
if (!menu.prop('openKeys') && !menu.prop('defaultOpenKeys')) {
|
||||
expect(menu.find('ul.ant-menu-sub').length).toBe(0);
|
||||
}
|
||||
menu.update();
|
||||
expect(menu.find('ul.ant-menu-sub').length).toBe(0);
|
||||
const AnimationClassNames = {
|
||||
horizontal: 'ant-slide-up-leave',
|
||||
inline: 'ant-motion-collapse-leave',
|
||||
vertical: 'ant-zoom-big-leave',
|
||||
};
|
||||
const mode = menu.prop('mode') || 'horizontal';
|
||||
|
||||
act(() => {
|
||||
enter();
|
||||
jest.runAllTimers();
|
||||
menu.update();
|
||||
});
|
||||
|
||||
function getSubMenu() {
|
||||
if (mode === 'inline') {
|
||||
return menu.find('ul.ant-menu-sub.ant-menu-inline').hostNodes().at(0);
|
||||
}
|
||||
return menu.find('div.ant-menu-submenu-popup').hostNodes().at(0);
|
||||
}
|
||||
|
||||
expect(
|
||||
getSubMenu().hasClass('ant-menu-hidden') || getSubMenu().hasClass(AnimationClassNames[mode]),
|
||||
).toBeFalsy();
|
||||
|
||||
act(() => {
|
||||
leave();
|
||||
jest.runAllTimers();
|
||||
menu.update();
|
||||
});
|
||||
|
||||
if (getSubMenu().length) {
|
||||
expect(
|
||||
getSubMenu().hasClass('ant-menu-hidden') || getSubMenu().hasClass(AnimationClassNames[mode]),
|
||||
).toBeTruthy();
|
||||
}
|
||||
};
|
||||
|
||||
describe('Menu', () => {
|
||||
window.requestAnimationFrame = callback => window.setTimeout(callback, 16);
|
||||
window.cancelAnimationFrame = window.clearTimeout;
|
||||
function triggerAllTimer() {
|
||||
for (let i = 0; i < 10; i += 1) {
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
beforeAll(() => {
|
||||
const expectSubMenuBehavior = (defaultProps, instance, enter = noop, leave = noop) => {
|
||||
const { container } = instance;
|
||||
|
||||
expect(container.querySelectorAll('ul.ant-menu-sub')).toHaveLength(0);
|
||||
const AnimationClassNames = {
|
||||
horizontal: 'ant-slide-up-leave',
|
||||
inline: 'ant-motion-collapse-leave',
|
||||
vertical: 'ant-zoom-big-leave',
|
||||
};
|
||||
const mode = defaultProps.mode || 'horizontal';
|
||||
|
||||
act(() => {
|
||||
enter();
|
||||
});
|
||||
|
||||
// React concurrent may delay creat this
|
||||
triggerAllTimer();
|
||||
|
||||
function getSubMenu() {
|
||||
if (mode === 'inline') {
|
||||
return container.querySelector('ul.ant-menu-sub.ant-menu-inline');
|
||||
}
|
||||
return container.querySelector('div.ant-menu-submenu-popup');
|
||||
}
|
||||
|
||||
expect(
|
||||
getSubMenu().classList.contains('ant-menu-hidden') ||
|
||||
getSubMenu().classList.contains(AnimationClassNames[mode]),
|
||||
).toBeFalsy();
|
||||
|
||||
act(() => {
|
||||
leave();
|
||||
});
|
||||
|
||||
// React concurrent may delay creat this
|
||||
triggerAllTimer();
|
||||
|
||||
if (getSubMenu()) {
|
||||
expect(
|
||||
getSubMenu().classList.contains('ant-menu-hidden') ||
|
||||
getSubMenu().classList.contains(AnimationClassNames[mode]),
|
||||
).toBeTruthy();
|
||||
}
|
||||
};
|
||||
|
||||
// window.requestAnimationFrame = callback => window.setTimeout(callback, 16);
|
||||
// window.cancelAnimationFrame = window.clearTimeout;
|
||||
|
||||
beforeEach(() => {
|
||||
jest.useFakeTimers();
|
||||
jest.clearAllTimers();
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
afterEach(() => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
@ -236,54 +251,73 @@ describe('Menu', () => {
|
||||
expect(wrapper.find('PopupTrigger').first().prop('visible')).toBeTruthy();
|
||||
});
|
||||
|
||||
it('test submenu in mode horizontal', () => {
|
||||
const wrapper = mount(
|
||||
<Menu mode="horizontal">
|
||||
it('test submenu in mode horizontal', async () => {
|
||||
const defaultProps = {
|
||||
mode: 'horizontal',
|
||||
};
|
||||
|
||||
const Demo = props => (
|
||||
<Menu {...defaultProps} {...props}>
|
||||
<SubMenu key="1" title="submenu1">
|
||||
<Menu.Item key="submenu1">Option 1</Menu.Item>
|
||||
<Menu.Item key="submenu2">Option 2</Menu.Item>
|
||||
</SubMenu>
|
||||
<Menu.Item key="2">menu2</Menu.Item>
|
||||
</Menu>,
|
||||
</Menu>
|
||||
);
|
||||
|
||||
const instance = render(<Demo />);
|
||||
|
||||
expectSubMenuBehavior(
|
||||
wrapper,
|
||||
() => wrapper.setProps({ openKeys: ['1'] }),
|
||||
() => wrapper.setProps({ openKeys: [] }),
|
||||
defaultProps,
|
||||
instance,
|
||||
() => instance.rerender(<Demo openKeys={['1']} />),
|
||||
() => instance.rerender(<Demo openKeys={[]} />),
|
||||
);
|
||||
|
||||
instance.rerender(<Demo openKeys={['1']} />);
|
||||
});
|
||||
|
||||
it('test submenu in mode inline', () => {
|
||||
const wrapper = mount(
|
||||
<Menu mode="inline">
|
||||
const defaultProps = { mode: 'inline' };
|
||||
|
||||
const Demo = props => (
|
||||
<Menu {...defaultProps} {...props}>
|
||||
<SubMenu key="1" title="submenu1">
|
||||
<Menu.Item key="submenu1">Option 1</Menu.Item>
|
||||
<Menu.Item key="submenu2">Option 2</Menu.Item>
|
||||
</SubMenu>
|
||||
<Menu.Item key="2">menu2</Menu.Item>
|
||||
</Menu>,
|
||||
</Menu>
|
||||
);
|
||||
const instance = render(<Demo />);
|
||||
expectSubMenuBehavior(
|
||||
wrapper,
|
||||
() => wrapper.setProps({ openKeys: ['1'] }),
|
||||
() => wrapper.setProps({ openKeys: [] }),
|
||||
defaultProps,
|
||||
instance,
|
||||
() => instance.rerender(<Demo openKeys={['1']} />),
|
||||
() => instance.rerender(<Demo openKeys={[]} />),
|
||||
);
|
||||
});
|
||||
|
||||
it('test submenu in mode vertical', () => {
|
||||
const wrapper = mount(
|
||||
<Menu mode="vertical" openTransitionName="">
|
||||
const defaultProps = { mode: 'vertical', openTransitionName: '' };
|
||||
|
||||
const Demo = props => (
|
||||
<Menu {...defaultProps} {...props}>
|
||||
<SubMenu key="1" title="submenu1">
|
||||
<Menu.Item key="submenu1">Option 1</Menu.Item>
|
||||
<Menu.Item key="submenu2">Option 2</Menu.Item>
|
||||
</SubMenu>
|
||||
<Menu.Item key="2">menu2</Menu.Item>
|
||||
</Menu>,
|
||||
</Menu>
|
||||
);
|
||||
|
||||
const instance = render(<Demo />);
|
||||
expectSubMenuBehavior(
|
||||
wrapper,
|
||||
() => wrapper.setProps({ openKeys: ['1'] }),
|
||||
() => wrapper.setProps({ openKeys: [] }),
|
||||
defaultProps,
|
||||
instance,
|
||||
() => instance.rerender(<Demo openKeys={['1']} />),
|
||||
() => instance.rerender(<Demo openKeys={[]} />),
|
||||
);
|
||||
});
|
||||
|
||||
@ -292,7 +326,7 @@ describe('Menu', () => {
|
||||
|
||||
menuModesWithPopupSubMenu.forEach(menuMode => {
|
||||
it(`when menu is mode ${menuMode}`, () => {
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<Menu mode={menuMode} openKeys={['1']} theme="dark">
|
||||
<SubMenu key="1" title="submenu1" theme="light">
|
||||
<Menu.Item key="submenu1">Option 1</Menu.Item>
|
||||
@ -304,11 +338,10 @@ describe('Menu', () => {
|
||||
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
wrapper.update();
|
||||
});
|
||||
|
||||
expect(wrapper.find('ul.ant-menu-root').hasClass('ant-menu-dark')).toBeTruthy();
|
||||
expect(wrapper.find('div.ant-menu-submenu-popup').hasClass('ant-menu-light')).toBeTruthy();
|
||||
expect(container.querySelector('ul.ant-menu-root')).toHaveClass('ant-menu-dark');
|
||||
expect(container.querySelector('div.ant-menu-submenu-popup')).toHaveClass('ant-menu-light');
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -317,7 +350,7 @@ describe('Menu', () => {
|
||||
// https://github.com/ant-design/ant-design/issues/4692
|
||||
// TypeError: Cannot read property 'indexOf' of undefined
|
||||
it('pr #4677 and issue #4692', () => {
|
||||
const wrapper = mount(
|
||||
render(
|
||||
<Menu mode="horizontal">
|
||||
<SubMenu title="submenu">
|
||||
<Menu.Item key="1">menu1</Menu.Item>
|
||||
@ -325,25 +358,32 @@ describe('Menu', () => {
|
||||
</SubMenu>
|
||||
</Menu>,
|
||||
);
|
||||
wrapper.update();
|
||||
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
// just expect no error emit
|
||||
});
|
||||
|
||||
it('should always follow openKeys when mode is switched', () => {
|
||||
const wrapper = mount(
|
||||
<Menu openKeys={['1']} mode="inline">
|
||||
const Demo = props => (
|
||||
<Menu openKeys={['1']} mode="inline" {...props}>
|
||||
<SubMenu key="1" title="submenu1">
|
||||
<Menu.Item key="submenu1">Option 1</Menu.Item>
|
||||
<Menu.Item key="submenu2">Option 2</Menu.Item>
|
||||
</SubMenu>
|
||||
<Menu.Item key="2">menu2</Menu.Item>
|
||||
</Menu>,
|
||||
</Menu>
|
||||
);
|
||||
expect(wrapper.find('ul.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).toBe(false);
|
||||
wrapper.setProps({ mode: 'vertical' });
|
||||
expect(wrapper.find('ul.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).toBe(false);
|
||||
wrapper.setProps({ mode: 'inline' });
|
||||
expect(wrapper.find('ul.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).toBe(false);
|
||||
|
||||
const { container, rerender } = render(<Demo />);
|
||||
expect(container.querySelector('ul.ant-menu-sub')).not.toHaveClass('ant-menu-hidden');
|
||||
|
||||
rerender(<Demo mode="vertical" />);
|
||||
expect(container.querySelector('ul.ant-menu-sub')).not.toHaveClass('ant-menu-hidden');
|
||||
|
||||
rerender(<Demo mode="inline" />);
|
||||
expect(container.querySelector('ul.ant-menu-sub')).not.toHaveClass('ant-menu-hidden');
|
||||
});
|
||||
|
||||
it('should always follow openKeys when inlineCollapsed is switched', () => {
|
||||
@ -383,8 +423,8 @@ describe('Menu', () => {
|
||||
});
|
||||
|
||||
it('inlineCollapsed should works well when specify a not existed default openKeys', () => {
|
||||
const wrapper = mount(
|
||||
<Menu defaultOpenKeys={['not-existed']} mode="inline">
|
||||
const Demo = props => (
|
||||
<Menu defaultOpenKeys={['not-existed']} mode="inline" {...props}>
|
||||
<Menu.Item key="menu1" icon={<InboxOutlined />}>
|
||||
Option
|
||||
</Menu.Item>
|
||||
@ -392,28 +432,30 @@ describe('Menu', () => {
|
||||
<Menu.Item key="submenu1">Option</Menu.Item>
|
||||
<Menu.Item key="submenu2">Option</Menu.Item>
|
||||
</SubMenu>
|
||||
</Menu>,
|
||||
</Menu>
|
||||
);
|
||||
expect(wrapper.find('.ant-menu-sub').length).toBe(0);
|
||||
wrapper.setProps({ inlineCollapsed: true });
|
||||
jest.runAllTimers();
|
||||
wrapper.update();
|
||||
wrapper.simulate('transitionEnd', { propertyName: 'width' });
|
||||
const { container, rerender } = render(<Demo />);
|
||||
|
||||
expect(container.querySelectorAll('.ant-menu-sub')).toHaveLength(0);
|
||||
|
||||
rerender(<Demo inlineCollapsed />);
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
wrapper.update();
|
||||
});
|
||||
|
||||
wrapper.find('.ant-menu-submenu-title').at(0).simulate('mouseEnter');
|
||||
jest.runAllTimers();
|
||||
wrapper.update();
|
||||
expect(wrapper.find('.ant-menu-submenu').at(0).hasClass('ant-menu-submenu-vertical')).toBe(
|
||||
true,
|
||||
);
|
||||
expect(wrapper.find('.ant-menu-submenu').at(0).hasClass('ant-menu-submenu-open')).toBe(true);
|
||||
expect(wrapper.find('ul.ant-menu-sub').at(0).hasClass('ant-menu-vertical')).toBe(true);
|
||||
expect(wrapper.find('ul.ant-menu-sub').at(0).hasClass('ant-menu-hidden')).toBe(false);
|
||||
const transitionEndEvent = new Event('transitionend');
|
||||
fireEvent(container.querySelector('ul'), transitionEndEvent);
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
|
||||
fireEvent.mouseEnter(container.querySelector('.ant-menu-submenu-title'));
|
||||
triggerAllTimer();
|
||||
|
||||
expect(container.querySelector('.ant-menu-submenu')).toHaveClass('ant-menu-submenu-vertical');
|
||||
expect(container.querySelector('.ant-menu-submenu')).toHaveClass('ant-menu-submenu-open');
|
||||
expect(container.querySelector('ul.ant-menu-sub')).toHaveClass('ant-menu-vertical');
|
||||
expect(container.querySelector('ul.ant-menu-sub')).not.toHaveClass('ant-menu-hidden');
|
||||
});
|
||||
|
||||
it('inlineCollapsed Menu.Item Tooltip can be removed', () => {
|
||||
@ -451,26 +493,32 @@ describe('Menu', () => {
|
||||
});
|
||||
|
||||
describe('open submenu when click submenu title', () => {
|
||||
const toggleMenu = (wrapper, index, event) => {
|
||||
wrapper.find('.ant-menu-submenu-title').at(index).simulate(event);
|
||||
jest.runAllTimers();
|
||||
wrapper.update();
|
||||
const toggleMenu = (instance, index, event) => {
|
||||
fireEvent[event](instance.container.querySelectorAll('.ant-menu-submenu-title')[index]);
|
||||
|
||||
triggerAllTimer();
|
||||
};
|
||||
|
||||
it('inline', () => {
|
||||
const wrapper = mount(
|
||||
<Menu mode="inline">
|
||||
const defaultProps = { mode: 'inline' };
|
||||
|
||||
const Demo = props => (
|
||||
<Menu {...defaultProps} {...props}>
|
||||
<SubMenu key="1" title="submenu1">
|
||||
<Menu.Item key="submenu1">Option 1</Menu.Item>
|
||||
<Menu.Item key="submenu2">Option 2</Menu.Item>
|
||||
</SubMenu>
|
||||
<Menu.Item key="2">menu2</Menu.Item>
|
||||
</Menu>,
|
||||
</Menu>
|
||||
);
|
||||
|
||||
const instance = render(<Demo />);
|
||||
|
||||
expectSubMenuBehavior(
|
||||
wrapper,
|
||||
() => toggleMenu(wrapper, 0, 'click'),
|
||||
() => toggleMenu(wrapper, 0, 'click'),
|
||||
defaultProps,
|
||||
instance,
|
||||
() => toggleMenu(instance, 0, 'click'),
|
||||
() => toggleMenu(instance, 0, 'click'),
|
||||
);
|
||||
});
|
||||
|
||||
@ -483,7 +531,7 @@ describe('Menu', () => {
|
||||
const onOpenChange = jest.fn();
|
||||
const onEnterEnd = jest.spyOn(cloneMotion, 'onEnterEnd');
|
||||
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<Menu mode="inline" motion={cloneMotion} onOpenChange={onOpenChange}>
|
||||
<SubMenu key="1" title="submenu1">
|
||||
<Menu.Item key="submenu1">Option 1</Menu.Item>
|
||||
@ -493,90 +541,105 @@ describe('Menu', () => {
|
||||
</Menu>,
|
||||
);
|
||||
|
||||
wrapper.find('div.ant-menu-submenu-title').simulate('click');
|
||||
fireEvent.click(container.querySelector('.ant-menu-submenu-title'));
|
||||
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
wrapper.update();
|
||||
});
|
||||
triggerAllTimer();
|
||||
|
||||
expect(onOpenChange).toHaveBeenCalled();
|
||||
expect(onEnterEnd).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('vertical with hover(default)', () => {
|
||||
const wrapper = mount(
|
||||
<Menu mode="vertical">
|
||||
const defaultProps = { mode: 'vertical' };
|
||||
|
||||
const Demo = () => (
|
||||
<Menu {...defaultProps}>
|
||||
<SubMenu key="1" title="submenu1">
|
||||
<Menu.Item key="submenu1">Option 1</Menu.Item>
|
||||
<Menu.Item key="submenu2">Option 2</Menu.Item>
|
||||
</SubMenu>
|
||||
<Menu.Item key="2">menu2</Menu.Item>
|
||||
</Menu>,
|
||||
</Menu>
|
||||
);
|
||||
|
||||
const instance = render(<Demo />);
|
||||
|
||||
expectSubMenuBehavior(
|
||||
wrapper,
|
||||
() => toggleMenu(wrapper, 0, 'mouseenter'),
|
||||
() => toggleMenu(wrapper, 0, 'mouseleave'),
|
||||
defaultProps,
|
||||
instance,
|
||||
() => toggleMenu(instance, 0, 'mouseEnter'),
|
||||
() => toggleMenu(instance, 0, 'mouseLeave'),
|
||||
);
|
||||
});
|
||||
|
||||
it('vertical with click', () => {
|
||||
const wrapper = mount(
|
||||
<Menu mode="vertical" triggerSubMenuAction="click">
|
||||
const defaultProps = { mode: 'vertical', triggerSubMenuAction: 'click' };
|
||||
const Demo = () => (
|
||||
<Menu {...defaultProps}>
|
||||
<SubMenu key="1" title="submenu1">
|
||||
<Menu.Item key="submenu1">Option 1</Menu.Item>
|
||||
<Menu.Item key="submenu2">Option 2</Menu.Item>
|
||||
</SubMenu>
|
||||
<Menu.Item key="2">menu2</Menu.Item>
|
||||
</Menu>,
|
||||
</Menu>
|
||||
);
|
||||
|
||||
const instance = render(<Demo />);
|
||||
|
||||
expectSubMenuBehavior(
|
||||
wrapper,
|
||||
() => toggleMenu(wrapper, 0, 'click'),
|
||||
() => toggleMenu(wrapper, 0, 'click'),
|
||||
defaultProps,
|
||||
instance,
|
||||
() => toggleMenu(instance, 0, 'click'),
|
||||
() => toggleMenu(instance, 0, 'click'),
|
||||
);
|
||||
});
|
||||
|
||||
it('horizontal with hover(default)', () => {
|
||||
jest.useFakeTimers();
|
||||
const wrapper = mount(
|
||||
<Menu mode="horizontal">
|
||||
const defaultProps = { mode: 'horizontal' };
|
||||
const Demo = () => (
|
||||
<Menu {...defaultProps}>
|
||||
<SubMenu key="1" title="submenu1">
|
||||
<Menu.Item key="submenu1">Option 1</Menu.Item>
|
||||
<Menu.Item key="submenu2">Option 2</Menu.Item>
|
||||
</SubMenu>
|
||||
<Menu.Item key="2">menu2</Menu.Item>
|
||||
</Menu>,
|
||||
</Menu>
|
||||
);
|
||||
|
||||
const instance = render(<Demo />);
|
||||
|
||||
expectSubMenuBehavior(
|
||||
wrapper,
|
||||
() => toggleMenu(wrapper, 0, 'mouseenter'),
|
||||
() => toggleMenu(wrapper, 0, 'mouseleave'),
|
||||
defaultProps,
|
||||
instance,
|
||||
() => toggleMenu(instance, 0, 'mouseEnter'),
|
||||
() => toggleMenu(instance, 0, 'mouseLeave'),
|
||||
);
|
||||
});
|
||||
|
||||
it('horizontal with click', () => {
|
||||
jest.useFakeTimers();
|
||||
const wrapper = mount(
|
||||
<Menu mode="horizontal" triggerSubMenuAction="click">
|
||||
const defaultProps = { mode: 'horizontal', triggerSubMenuAction: 'click' };
|
||||
const Demo = () => (
|
||||
<Menu {...defaultProps}>
|
||||
<SubMenu key="1" title="submenu1">
|
||||
<Menu.Item key="submenu1">Option 1</Menu.Item>
|
||||
<Menu.Item key="submenu2">Option 2</Menu.Item>
|
||||
</SubMenu>
|
||||
<Menu.Item key="2">menu2</Menu.Item>
|
||||
</Menu>,
|
||||
</Menu>
|
||||
);
|
||||
|
||||
const instance = render(<Demo />);
|
||||
|
||||
expectSubMenuBehavior(
|
||||
wrapper,
|
||||
() => toggleMenu(wrapper, 0, 'click'),
|
||||
() => toggleMenu(wrapper, 0, 'click'),
|
||||
defaultProps,
|
||||
instance,
|
||||
() => toggleMenu(instance, 0, 'click'),
|
||||
() => toggleMenu(instance, 0, 'click'),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
it('inline title', () => {
|
||||
jest.useFakeTimers();
|
||||
const wrapper = mount(
|
||||
<Menu mode="inline" inlineCollapsed>
|
||||
<Menu.Item key="1" title="bamboo lucky" icon={<PieChartOutlined />}>
|
||||
@ -591,15 +654,11 @@ describe('Menu', () => {
|
||||
);
|
||||
|
||||
wrapper.find('.ant-menu-item').hostNodes().simulate('mouseenter');
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
triggerAllTimer();
|
||||
wrapper.update();
|
||||
|
||||
const text = wrapper.find('.ant-tooltip-inner').text();
|
||||
expect(text).toBe('bamboo lucky');
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('render correctly when using with Layout.Sider', () => {
|
||||
@ -632,9 +691,7 @@ describe('Menu', () => {
|
||||
expect(wrapper.find(Menu).at(0).getDOMNode().classList.contains('ant-menu-inline')).toBe(true);
|
||||
wrapper.find('.ant-menu-submenu-title').simulate('click');
|
||||
wrapper.find('.ant-layout-sider-trigger').simulate('click');
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
triggerAllTimer();
|
||||
wrapper.update();
|
||||
expect(wrapper.find(Menu).getDOMNode().classList.contains('ant-menu-inline-collapsed')).toBe(
|
||||
true,
|
||||
@ -735,7 +792,7 @@ describe('Menu', () => {
|
||||
|
||||
const onOpen = jest.fn();
|
||||
const onClose = jest.fn();
|
||||
mount(
|
||||
render(
|
||||
<Menu defaultOpenKeys={['1']} mode="inline" onOpen={onOpen} onClose={onClose}>
|
||||
<SubMenu key="1" title="submenu1">
|
||||
<Menu.Item key="submenu1">Option 1</Menu.Item>
|
||||
|
@ -10,6 +10,8 @@ import destroyFns from '../destroyFns';
|
||||
import { sleep } from '../../../tests/utils';
|
||||
import ConfigProvider from '../../config-provider';
|
||||
|
||||
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
|
||||
|
||||
const { confirm } = Modal;
|
||||
|
||||
jest.mock('rc-motion');
|
||||
@ -21,13 +23,23 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
CSSMotion[key] = MockCSSMotion[key];
|
||||
});
|
||||
|
||||
// Mock for rc-util raf
|
||||
window.requestAnimationFrame = callback => window.setTimeout(callback, 16);
|
||||
window.cancelAnimationFrame = id => {
|
||||
window.clearTimeout(id);
|
||||
};
|
||||
// // Mock for rc-util raf
|
||||
// window.requestAnimationFrame = callback => {
|
||||
// const ret = window.setTimeout(callback, 16);
|
||||
// return ret;
|
||||
// };
|
||||
// window.cancelAnimationFrame = id => {
|
||||
// window.clearTimeout(id);
|
||||
// };
|
||||
|
||||
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
// jest.spyOn(window, 'requestAnimationFrame').mockImplementation(callback => {
|
||||
// const id = window.setTimeout(callback);
|
||||
// console.log('Mock Raf:', id);
|
||||
// return id;
|
||||
// });
|
||||
// jest.spyOn(window, 'cancelAnimationFrame').mockImplementation(id => window.clearTimeout(id));
|
||||
|
||||
const errorSpy = jest.spyOn(console, 'error');
|
||||
|
||||
/* eslint-disable no-console */
|
||||
// Hack error to remove act warning
|
||||
@ -42,10 +54,13 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
};
|
||||
/* eslint-enable */
|
||||
|
||||
afterEach(() => {
|
||||
afterEach(async () => {
|
||||
jest.clearAllTimers();
|
||||
errorSpy.mockReset();
|
||||
document.body.innerHTML = '';
|
||||
Modal.destroyAll();
|
||||
|
||||
await sleep();
|
||||
document.body.innerHTML = '';
|
||||
});
|
||||
|
||||
afterAll(() => {
|
||||
@ -77,69 +92,88 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('trigger onCancel once when click on cancel button', () => {
|
||||
it('trigger onCancel once when click on cancel button', async () => {
|
||||
const onCancel = jest.fn();
|
||||
const onOk = jest.fn();
|
||||
open({
|
||||
onCancel,
|
||||
onOk,
|
||||
});
|
||||
|
||||
// first Modal
|
||||
await sleep();
|
||||
$$('.ant-btn')[0].click();
|
||||
expect(onCancel.mock.calls.length).toBe(1);
|
||||
expect(onOk.mock.calls.length).toBe(0);
|
||||
});
|
||||
|
||||
it('trigger onOk once when click on ok button', () => {
|
||||
it('trigger onOk once when click on ok button', async () => {
|
||||
const onCancel = jest.fn();
|
||||
const onOk = jest.fn();
|
||||
open({
|
||||
onCancel,
|
||||
onOk,
|
||||
});
|
||||
|
||||
// second Modal
|
||||
await sleep();
|
||||
$$('.ant-btn-primary')[0].click();
|
||||
expect(onCancel.mock.calls.length).toBe(0);
|
||||
expect(onOk.mock.calls.length).toBe(1);
|
||||
});
|
||||
|
||||
it('should allow Modal.confirm without onCancel been set', () => {
|
||||
it('should allow Modal.confirm without onCancel been set', async () => {
|
||||
open();
|
||||
await sleep();
|
||||
|
||||
// Third Modal
|
||||
$$('.ant-btn')[0].click();
|
||||
expect(errorSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should allow Modal.confirm without onOk been set', () => {
|
||||
it('should allow Modal.confirm without onOk been set', async () => {
|
||||
open();
|
||||
|
||||
// Fourth Modal
|
||||
await sleep();
|
||||
$$('.ant-btn-primary')[0].click();
|
||||
expect(errorSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should close confirm modal when press ESC', () => {
|
||||
it('should close confirm modal when press ESC', async () => {
|
||||
jest.useFakeTimers();
|
||||
jest.clearAllTimers();
|
||||
const onCancel = jest.fn();
|
||||
Modal.confirm({
|
||||
title: 'title',
|
||||
content: 'content',
|
||||
onCancel,
|
||||
});
|
||||
|
||||
jest.runAllTimers();
|
||||
await sleep();
|
||||
jest.runAllTimers();
|
||||
|
||||
expect($$(`.ant-modal-confirm-confirm`)).toHaveLength(1);
|
||||
TestUtils.Simulate.keyDown($$('.ant-modal')[0], {
|
||||
keyCode: KeyCode.ESC,
|
||||
});
|
||||
|
||||
jest.runAllTimers();
|
||||
await sleep(0);
|
||||
jest.runAllTimers();
|
||||
|
||||
expect($$(`.ant-modal-confirm-confirm`)).toHaveLength(0);
|
||||
expect(onCancel).toHaveBeenCalledTimes(1);
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('should not hide confirm when onOk return Promise.resolve', () => {
|
||||
it('should not hide confirm when onOk return Promise.resolve', async () => {
|
||||
open({
|
||||
onOk: () => Promise.resolve(''),
|
||||
});
|
||||
|
||||
await sleep();
|
||||
$$('.ant-btn-primary')[0].click();
|
||||
expect($$('.ant-modal-confirm')).toHaveLength(1);
|
||||
});
|
||||
@ -149,6 +183,8 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
open({
|
||||
onOk: () => Promise.reject(error),
|
||||
});
|
||||
|
||||
await sleep();
|
||||
$$('.ant-btn-primary')[0].click();
|
||||
|
||||
// wait promise
|
||||
@ -157,52 +193,72 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
expect(errorSpy).toHaveBeenCalledWith(error);
|
||||
});
|
||||
|
||||
it('shows animation when close', () => {
|
||||
it('shows animation when close', async () => {
|
||||
open();
|
||||
|
||||
jest.useFakeTimers();
|
||||
jest.runAllTimers();
|
||||
await sleep();
|
||||
jest.runAllTimers();
|
||||
|
||||
expect($$('.ant-modal-confirm')).toHaveLength(1);
|
||||
|
||||
await sleep();
|
||||
$$('.ant-btn')[0].click();
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
|
||||
jest.runAllTimers();
|
||||
await sleep();
|
||||
jest.runAllTimers();
|
||||
|
||||
expect($$('.ant-modal-confirm')).toHaveLength(0);
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('ok only', () => {
|
||||
it('ok only', async () => {
|
||||
open({ okCancel: false });
|
||||
await sleep();
|
||||
expect($$('.ant-btn')).toHaveLength(1);
|
||||
expect($$('.ant-btn')[0].innerHTML).toContain('OK');
|
||||
});
|
||||
|
||||
it('allows extra props on buttons', () => {
|
||||
it('allows extra props on buttons', async () => {
|
||||
open({ okButtonProps: { disabled: true }, cancelButtonProps: { 'data-test': 'baz' } });
|
||||
|
||||
await sleep();
|
||||
expect($$('.ant-btn')).toHaveLength(2);
|
||||
expect($$('.ant-btn')[0].attributes['data-test'].value).toBe('baz');
|
||||
expect($$('.ant-btn')[1].disabled).toBe(true);
|
||||
});
|
||||
|
||||
it('should close modals when click confirm button', () => {
|
||||
jest.useFakeTimers();
|
||||
describe('should close modals when click confirm button', () => {
|
||||
['info', 'success', 'warning', 'error'].forEach(type => {
|
||||
Modal[type]({
|
||||
title: 'title',
|
||||
content: 'content',
|
||||
it(type, async () => {
|
||||
jest.useFakeTimers();
|
||||
Modal[type]({
|
||||
title: 'title',
|
||||
content: 'content',
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
await sleep();
|
||||
jest.runAllTimers();
|
||||
});
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1);
|
||||
|
||||
$$('.ant-btn')[0].click();
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
await sleep();
|
||||
jest.runAllTimers();
|
||||
});
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(0);
|
||||
jest.useRealTimers();
|
||||
});
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1);
|
||||
$$('.ant-btn')[0].click();
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(0);
|
||||
});
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('should close confirm modal when click cancel button', () => {
|
||||
it('should close confirm modal when click cancel button', async () => {
|
||||
jest.useFakeTimers();
|
||||
const onCancel = jest.fn();
|
||||
Modal.confirm({
|
||||
@ -215,15 +271,16 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
});
|
||||
expect($$(`.ant-modal-confirm-confirm`)).toHaveLength(1);
|
||||
$$('.ant-btn')[0].click();
|
||||
act(() => {
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
await sleep();
|
||||
});
|
||||
expect($$(`.ant-modal-confirm-confirm`)).toHaveLength(0);
|
||||
expect(onCancel).toHaveBeenCalledTimes(1);
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('should close confirm modal when click close button', () => {
|
||||
it('should close confirm modal when click close button', async () => {
|
||||
jest.useFakeTimers();
|
||||
const onCancel = jest.fn();
|
||||
Modal.confirm({
|
||||
@ -238,151 +295,183 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
});
|
||||
expect($$(`.ant-modal-close`)).toHaveLength(1);
|
||||
$$('.ant-btn')[0].click();
|
||||
act(() => {
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
await sleep();
|
||||
});
|
||||
expect($$(`.ant-modal-close`)).toHaveLength(0);
|
||||
expect(onCancel).toHaveBeenCalledTimes(1);
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('should not close modals when click confirm button when onOk has argument', () => {
|
||||
jest.useFakeTimers();
|
||||
describe('should not close modals when click confirm button when onOk has argument', () => {
|
||||
['info', 'success', 'warning', 'error'].forEach(type => {
|
||||
Modal[type]({
|
||||
title: 'title',
|
||||
content: 'content',
|
||||
onOk: close => null, // eslint-disable-line no-unused-vars
|
||||
it(type, async () => {
|
||||
jest.useFakeTimers();
|
||||
Modal[type]({
|
||||
title: 'title',
|
||||
content: 'content',
|
||||
onOk: close => null, // eslint-disable-line no-unused-vars
|
||||
});
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
await sleep();
|
||||
});
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1);
|
||||
$$('.ant-btn')[0].click();
|
||||
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
await sleep();
|
||||
});
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1);
|
||||
jest.useRealTimers();
|
||||
});
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1);
|
||||
$$('.ant-btn')[0].click();
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1);
|
||||
});
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('could be update by new config', () => {
|
||||
jest.useFakeTimers();
|
||||
describe('could be update by new config', () => {
|
||||
['info', 'success', 'warning', 'error'].forEach(type => {
|
||||
const instance = Modal[type]({
|
||||
title: 'title',
|
||||
content: 'content',
|
||||
});
|
||||
act(() => {
|
||||
it(type, async () => {
|
||||
jest.useFakeTimers();
|
||||
const instance = Modal[type]({
|
||||
title: 'title',
|
||||
content: 'content',
|
||||
});
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
await sleep();
|
||||
});
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1);
|
||||
expect($$('.ant-modal-confirm-title')[0].innerHTML).toBe('title');
|
||||
expect($$('.ant-modal-confirm-content')[0].innerHTML).toBe('content');
|
||||
instance.update({
|
||||
title: 'new title',
|
||||
content: 'new content',
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
await sleep();
|
||||
});
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1);
|
||||
expect($$('.ant-modal-confirm-title')[0].innerHTML).toBe('new title');
|
||||
expect($$('.ant-modal-confirm-content')[0].innerHTML).toBe('new content');
|
||||
instance.destroy();
|
||||
jest.runAllTimers();
|
||||
jest.useRealTimers();
|
||||
});
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1);
|
||||
expect($$('.ant-modal-confirm-title')[0].innerHTML).toBe('title');
|
||||
expect($$('.ant-modal-confirm-content')[0].innerHTML).toBe('content');
|
||||
instance.update({
|
||||
title: 'new title',
|
||||
content: 'new content',
|
||||
});
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1);
|
||||
expect($$('.ant-modal-confirm-title')[0].innerHTML).toBe('new title');
|
||||
expect($$('.ant-modal-confirm-content')[0].innerHTML).toBe('new content');
|
||||
instance.destroy();
|
||||
jest.runAllTimers();
|
||||
});
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('could be update by call function', () => {
|
||||
jest.useFakeTimers();
|
||||
describe('could be update by call function', () => {
|
||||
['info', 'success', 'warning', 'error'].forEach(type => {
|
||||
const instance = Modal[type]({
|
||||
title: 'title',
|
||||
okButtonProps: {
|
||||
loading: true,
|
||||
style: {
|
||||
color: 'red',
|
||||
it(type, () => {
|
||||
jest.useFakeTimers();
|
||||
const instance = Modal[type]({
|
||||
title: 'title',
|
||||
okButtonProps: {
|
||||
loading: true,
|
||||
style: {
|
||||
color: 'red',
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
act(() => {
|
||||
});
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1);
|
||||
expect($$('.ant-modal-confirm-title')[0].innerHTML).toBe('title');
|
||||
expect($$('.ant-modal-confirm-btns .ant-btn-primary')[0].classList).toContain(
|
||||
'ant-btn-loading',
|
||||
);
|
||||
expect($$('.ant-modal-confirm-btns .ant-btn-primary')[0].style.color).toBe('red');
|
||||
instance.update(prevConfig => ({
|
||||
...prevConfig,
|
||||
okButtonProps: {
|
||||
...prevConfig.okButtonProps,
|
||||
loading: false,
|
||||
},
|
||||
}));
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1);
|
||||
expect($$('.ant-modal-confirm-title')[0].innerHTML).toBe('title');
|
||||
expect($$('.ant-modal-confirm-btns .ant-btn-primary')[0].classList).not.toContain(
|
||||
'ant-btn-loading',
|
||||
);
|
||||
expect($$('.ant-modal-confirm-btns .ant-btn-primary')[0].style.color).toBe('red');
|
||||
instance.destroy();
|
||||
jest.runAllTimers();
|
||||
jest.useRealTimers();
|
||||
});
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1);
|
||||
expect($$('.ant-modal-confirm-title')[0].innerHTML).toBe('title');
|
||||
expect($$('.ant-modal-confirm-btns .ant-btn-primary')[0].classList).toContain(
|
||||
'ant-btn-loading',
|
||||
);
|
||||
expect($$('.ant-modal-confirm-btns .ant-btn-primary')[0].style.color).toBe('red');
|
||||
instance.update(prevConfig => ({
|
||||
...prevConfig,
|
||||
okButtonProps: {
|
||||
...prevConfig.okButtonProps,
|
||||
loading: false,
|
||||
},
|
||||
}));
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1);
|
||||
expect($$('.ant-modal-confirm-title')[0].innerHTML).toBe('title');
|
||||
expect($$('.ant-modal-confirm-btns .ant-btn-primary')[0].classList).not.toContain(
|
||||
'ant-btn-loading',
|
||||
);
|
||||
expect($$('.ant-modal-confirm-btns .ant-btn-primary')[0].style.color).toBe('red');
|
||||
instance.destroy();
|
||||
jest.runAllTimers();
|
||||
});
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('could be destroy', () => {
|
||||
jest.useFakeTimers();
|
||||
describe('could be destroy', () => {
|
||||
['info', 'success', 'warning', 'error'].forEach(type => {
|
||||
const instance = Modal[type]({
|
||||
title: 'title',
|
||||
content: 'content',
|
||||
jest.useFakeTimers();
|
||||
it(type, async () => {
|
||||
const instance = Modal[type]({
|
||||
title: 'title',
|
||||
content: 'content',
|
||||
});
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
await sleep();
|
||||
});
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1);
|
||||
|
||||
instance.destroy();
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
await sleep();
|
||||
});
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(0);
|
||||
});
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1);
|
||||
instance.destroy();
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(0);
|
||||
jest.useRealTimers();
|
||||
});
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('could be Modal.destroyAll', () => {
|
||||
it('could be Modal.destroyAll', async () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
// Show
|
||||
['info', 'success', 'warning', 'error'].forEach(type => {
|
||||
Modal[type]({
|
||||
title: 'title',
|
||||
content: 'content',
|
||||
});
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
});
|
||||
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
await sleep();
|
||||
});
|
||||
|
||||
['info', 'success', 'warning', 'error'].forEach(type => {
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1);
|
||||
});
|
||||
|
||||
// Destroy
|
||||
Modal.destroyAll();
|
||||
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
await sleep();
|
||||
});
|
||||
|
||||
['info', 'success', 'warning', 'error'].forEach(type => {
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
});
|
||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(0);
|
||||
});
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('prefixCls', () => {
|
||||
it('prefixCls', async () => {
|
||||
open({ prefixCls: 'custom-modal' });
|
||||
|
||||
await sleep();
|
||||
expect($$('.custom-modal-mask')).toHaveLength(1);
|
||||
expect($$('.custom-modal-wrap')).toHaveLength(1);
|
||||
expect($$('.custom-modal-confirm')).toHaveLength(1);
|
||||
@ -428,20 +517,30 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('should warning when pass a string as icon props', () => {
|
||||
it('should warning when pass a string as icon props', async () => {
|
||||
jest.useFakeTimers();
|
||||
const warnSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
confirm({
|
||||
content: 'some descriptions',
|
||||
icon: 'ab',
|
||||
});
|
||||
jest.runAllTimers();
|
||||
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
await sleep();
|
||||
});
|
||||
|
||||
expect(warnSpy).not.toHaveBeenCalled();
|
||||
confirm({
|
||||
content: 'some descriptions',
|
||||
icon: 'question',
|
||||
});
|
||||
jest.runAllTimers();
|
||||
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
await sleep();
|
||||
});
|
||||
|
||||
expect(warnSpy).toHaveBeenCalledWith(
|
||||
`Warning: [antd: Modal] \`icon\` is using ReactNode instead of string naming in v4. Please check \`question\` at https://ant.design/components/icon`,
|
||||
);
|
||||
@ -449,16 +548,18 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('ok button should trigger onOk once when click it many times quickly', () => {
|
||||
it('ok button should trigger onOk once when click it many times quickly', async () => {
|
||||
const onOk = jest.fn();
|
||||
open({ onOk });
|
||||
|
||||
await sleep();
|
||||
$$('.ant-btn-primary')[0].click();
|
||||
$$('.ant-btn-primary')[0].click();
|
||||
expect(onOk).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
// https://github.com/ant-design/ant-design/issues/23358
|
||||
it('ok button should trigger onOk multiple times when onOk has close argument', () => {
|
||||
it('ok button should trigger onOk multiple times when onOk has close argument', async () => {
|
||||
const onOk = jest.fn();
|
||||
open({
|
||||
onOk: close => {
|
||||
@ -466,17 +567,24 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
(() => {})(close); // do nothing
|
||||
},
|
||||
});
|
||||
|
||||
await sleep();
|
||||
$$('.ant-btn-primary')[0].click();
|
||||
$$('.ant-btn-primary')[0].click();
|
||||
$$('.ant-btn-primary')[0].click();
|
||||
expect(onOk).toHaveBeenCalledTimes(3);
|
||||
});
|
||||
|
||||
it('should be able to global config rootPrefixCls', () => {
|
||||
it('should be able to global config rootPrefixCls', async () => {
|
||||
jest.useFakeTimers();
|
||||
ConfigProvider.config({ prefixCls: 'my', iconPrefixCls: 'bamboo' });
|
||||
confirm({ title: 'title', icon: <SmileOutlined /> });
|
||||
jest.runAllTimers();
|
||||
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
await sleep();
|
||||
});
|
||||
|
||||
expect(document.querySelectorAll('.ant-btn').length).toBe(0);
|
||||
expect(document.querySelectorAll('.my-btn').length).toBe(2);
|
||||
expect(document.querySelectorAll('.bamboo-smile').length).toBe(1);
|
||||
@ -485,7 +593,7 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
jest.useRealTimers();
|
||||
});
|
||||
|
||||
it('should be able to config rootPrefixCls', () => {
|
||||
it('should be able to config rootPrefixCls', async () => {
|
||||
resetWarned();
|
||||
|
||||
jest.useFakeTimers();
|
||||
@ -500,7 +608,12 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
confirm({
|
||||
title: 'title',
|
||||
});
|
||||
jest.runAllTimers();
|
||||
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
await sleep();
|
||||
});
|
||||
|
||||
expect(document.querySelectorAll('.ant-btn').length).toBe(0);
|
||||
expect(document.querySelectorAll('.my-btn').length).toBe(2);
|
||||
expect(document.querySelectorAll('.my-modal-confirm').length).toBe(1);
|
||||
@ -510,7 +623,12 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
confirm({
|
||||
title: 'title',
|
||||
});
|
||||
jest.runAllTimers();
|
||||
|
||||
await act(async () => {
|
||||
jest.runAllTimers();
|
||||
await sleep();
|
||||
});
|
||||
|
||||
expect(document.querySelectorAll('.ant-btn').length).toBe(0);
|
||||
expect(document.querySelectorAll('.my-btn').length).toBe(2);
|
||||
expect(document.querySelectorAll('.my-modal-confirm').length).toBe(1);
|
||||
@ -528,6 +646,7 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
afterClose,
|
||||
});
|
||||
// first Modal
|
||||
await sleep();
|
||||
$$('.ant-btn')[0].click();
|
||||
expect(afterClose).not.toHaveBeenCalled();
|
||||
await sleep(500);
|
||||
@ -539,7 +658,9 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
open({
|
||||
afterClose,
|
||||
});
|
||||
|
||||
// second Modal
|
||||
await sleep();
|
||||
$$('.ant-btn-primary')[0].click();
|
||||
expect(afterClose).not.toHaveBeenCalled();
|
||||
await sleep(500);
|
||||
@ -548,6 +669,8 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
|
||||
it('bodyStyle', async () => {
|
||||
open({ bodyStyle: { width: 500 } });
|
||||
|
||||
await sleep();
|
||||
const { width } = $$('.ant-modal-body')[0].style;
|
||||
expect(width).toBe('500px');
|
||||
});
|
||||
|
@ -1,5 +1,4 @@
|
||||
import * as React from 'react';
|
||||
import * as ReactDOM from 'react-dom';
|
||||
import InfoCircleOutlined from '@ant-design/icons/InfoCircleOutlined';
|
||||
import CheckCircleOutlined from '@ant-design/icons/CheckCircleOutlined';
|
||||
import CloseCircleOutlined from '@ant-design/icons/CloseCircleOutlined';
|
||||
@ -9,6 +8,7 @@ import type { ModalFuncProps } from './Modal';
|
||||
import ConfirmDialog from './ConfirmDialog';
|
||||
import { globalConfig } from '../config-provider';
|
||||
import devWarning from '../_util/devWarning';
|
||||
import { reactRender, reactUnmount } from '../_util/compatible';
|
||||
import destroyFns from './destroyFns';
|
||||
|
||||
let defaultRootPrefixCls = '';
|
||||
@ -32,7 +32,6 @@ export default function confirm(config: ModalFuncProps) {
|
||||
let currentConfig = { ...config, close, visible: true } as any;
|
||||
|
||||
function destroy(...args: any[]) {
|
||||
ReactDOM.unmountComponentAtNode(container);
|
||||
const triggerCancel = args.some(param => param && param.triggerCancel);
|
||||
if (config.onCancel && triggerCancel) {
|
||||
config.onCancel(...args);
|
||||
@ -45,6 +44,8 @@ export default function confirm(config: ModalFuncProps) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
reactUnmount(container);
|
||||
}
|
||||
|
||||
function render({ okText, cancelText, prefixCls: customizePrefixCls, ...props }: any) {
|
||||
@ -61,7 +62,7 @@ export default function confirm(config: ModalFuncProps) {
|
||||
const prefixCls = customizePrefixCls || `${rootPrefixCls}-modal`;
|
||||
const iconPrefixCls = getIconPrefixCls();
|
||||
|
||||
ReactDOM.render(
|
||||
reactRender(
|
||||
<ConfirmDialog
|
||||
{...props}
|
||||
prefixCls={prefixCls}
|
||||
@ -83,6 +84,7 @@ export default function confirm(config: ModalFuncProps) {
|
||||
if (typeof config.afterClose === 'function') {
|
||||
config.afterClose();
|
||||
}
|
||||
|
||||
destroy.apply(this, args);
|
||||
},
|
||||
};
|
||||
|
@ -1,6 +1,8 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { spyElementPrototype } from 'rc-util/lib/test/domHook';
|
||||
import { render, fireEvent } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import Popconfirm from '..';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import { sleep } from '../../../tests/utils';
|
||||
@ -251,18 +253,19 @@ describe('Popconfirm', () => {
|
||||
return <Button>Unmounted</Button>;
|
||||
};
|
||||
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<div>
|
||||
<Test />
|
||||
</div>,
|
||||
);
|
||||
|
||||
expect(wrapper.text()).toEqual('Test');
|
||||
const triggerNode = wrapper.find('.clickTarget').at(0);
|
||||
triggerNode.simulate('click');
|
||||
wrapper.find('.ant-btn-primary').simulate('click');
|
||||
expect(container.textContent).toEqual('Test');
|
||||
|
||||
fireEvent.click(container.querySelector('.clickTarget'));
|
||||
fireEvent.click(container.querySelector('.ant-btn-primary'));
|
||||
|
||||
await sleep(500);
|
||||
expect(wrapper.text()).toEqual('Unmounted');
|
||||
expect(container.textContent).toEqual('Unmounted');
|
||||
expect(error).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
@ -9,8 +9,8 @@ Array [
|
||||
</span>,
|
||||
<div>
|
||||
<div
|
||||
class="ant-popover ant-popover-rtl"
|
||||
style="opacity:0;pointer-events:none"
|
||||
class="ant-popover ant-popover-rtl ant-zoom-big-appear ant-zoom-big-appear-prepare ant-zoom-big"
|
||||
style="opacity: 0; pointer-events: none;"
|
||||
>
|
||||
<div
|
||||
class="ant-popover-content"
|
||||
|
@ -1,5 +1,7 @@
|
||||
import React from 'react';
|
||||
import { render, mount } from 'enzyme';
|
||||
import { mount } from 'enzyme';
|
||||
import { render } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import Popover from '..';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import ConfigProvider from '../../config-provider';
|
||||
@ -76,13 +78,13 @@ describe('Popover', () => {
|
||||
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
|
||||
const overlay = jest.fn();
|
||||
mount(
|
||||
render(
|
||||
<Popover content="console.log('hello world')" title="code" trigger="click">
|
||||
<span>show me your code</span>
|
||||
</Popover>,
|
||||
);
|
||||
|
||||
expect(errorSpy.mock.calls.length).toBe(0);
|
||||
expect(errorSpy).not.toHaveBeenCalled();
|
||||
expect(overlay).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
@ -94,6 +96,6 @@ describe('Popover', () => {
|
||||
</Popover>
|
||||
</ConfigProvider>,
|
||||
);
|
||||
expect(render(wrapper)).toMatchSnapshot();
|
||||
expect(wrapper.render()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
@ -1,5 +1,7 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { render } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import Result from '..';
|
||||
import Button from '../../button';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
@ -60,12 +62,15 @@ describe('Result', () => {
|
||||
|
||||
it('should warning when pass a string as icon props', () => {
|
||||
const warnSpy = jest.spyOn(console, 'error').mockImplementation(() => {});
|
||||
mount(<Result title="404" icon="ab" />);
|
||||
|
||||
render(<Result title="404" icon="ab" />);
|
||||
expect(warnSpy).not.toHaveBeenCalled();
|
||||
mount(<Result title="404" icon="smile" />);
|
||||
|
||||
render(<Result title="404" icon="smile" />);
|
||||
expect(warnSpy).toHaveBeenCalledWith(
|
||||
`Warning: [antd: Result] \`icon\` is using ReactNode instead of string naming in v4. Please check \`smile\` at https://ant.design/components/icon`,
|
||||
);
|
||||
|
||||
warnSpy.mockRestore();
|
||||
});
|
||||
});
|
||||
|
@ -2,6 +2,8 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import { render, fireEvent } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import Table from '..';
|
||||
import Input from '../../input';
|
||||
import Tooltip from '../../tooltip';
|
||||
@ -101,8 +103,8 @@ describe('Table.filter', () => {
|
||||
it('renders empty menu correctly', () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
jest.spyOn(console, 'error').mockImplementation(() => undefined);
|
||||
const wrapper = mount(
|
||||
const errorSpy = jest.spyOn(console, 'error').mockImplementation(() => undefined);
|
||||
const { container } = render(
|
||||
createTable({
|
||||
columns: [
|
||||
{
|
||||
@ -112,17 +114,16 @@ describe('Table.filter', () => {
|
||||
],
|
||||
}),
|
||||
);
|
||||
wrapper.find('span.ant-dropdown-trigger').simulate('click', nativeEvent);
|
||||
|
||||
fireEvent.click(container.querySelector('span.ant-dropdown-trigger'), nativeEvent);
|
||||
|
||||
act(() => {
|
||||
jest.runAllTimers();
|
||||
wrapper.update();
|
||||
});
|
||||
|
||||
expect(wrapper.find('Empty').length).toBeTruthy();
|
||||
// eslint-disable-next-line no-console
|
||||
expect(console.error).not.toHaveBeenCalled();
|
||||
// eslint-disable-next-line no-console
|
||||
console.error.mockRestore();
|
||||
expect(container.querySelector('.ant-empty')).toBeTruthy();
|
||||
expect(errorSpy).not.toHaveBeenCalled();
|
||||
errorSpy.mockRestore();
|
||||
|
||||
jest.useRealTimers();
|
||||
});
|
||||
@ -1964,7 +1965,11 @@ describe('Table.filter', () => {
|
||||
expect(wrapper.find('.ant-tree-checkbox').at(0).hasClass('ant-tree-checkbox-checked')).toBe(
|
||||
true,
|
||||
);
|
||||
expect(wrapper.find('.ant-table-filter-dropdown-checkall .ant-checkbox').hasClass('ant-checkbox-indeterminate')).toBe(true);
|
||||
expect(
|
||||
wrapper
|
||||
.find('.ant-table-filter-dropdown-checkall .ant-checkbox')
|
||||
.hasClass('ant-checkbox-indeterminate'),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it('select-all checkbox should change when all items are selected', () => {
|
||||
@ -1991,7 +1996,11 @@ describe('Table.filter', () => {
|
||||
});
|
||||
wrapper.find('.ant-tree-node-content-wrapper').at(0).simulate('click');
|
||||
wrapper.find('.ant-tree-node-content-wrapper').at(1).simulate('click');
|
||||
expect(wrapper.find('.ant-table-filter-dropdown-checkall .ant-checkbox').hasClass('ant-checkbox-checked')).toBe(true);
|
||||
expect(
|
||||
wrapper
|
||||
.find('.ant-table-filter-dropdown-checkall .ant-checkbox')
|
||||
.hasClass('ant-checkbox-checked'),
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { render } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import Table from '..';
|
||||
import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
@ -258,7 +260,7 @@ describe('Table', () => {
|
||||
dataIndex: 'name',
|
||||
},
|
||||
];
|
||||
mount(<Table columns={columns} rowKey={record => record.key} />);
|
||||
render(<Table columns={columns} rowKey={record => record.key} />);
|
||||
expect(warnSpy).not.toBeCalled();
|
||||
});
|
||||
|
||||
@ -275,7 +277,7 @@ describe('Table', () => {
|
||||
const ref = React.useRef();
|
||||
return <Table ref={ref} columns={columns} />;
|
||||
};
|
||||
mount(<Wrapper />);
|
||||
render(<Wrapper />);
|
||||
expect(warnSpy).not.toBeCalled();
|
||||
});
|
||||
});
|
||||
|
@ -1,5 +1,7 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { render } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import Transfer from '../index';
|
||||
|
||||
describe('Transfer.Customize', () => {
|
||||
@ -15,9 +17,9 @@ describe('Transfer.Customize', () => {
|
||||
|
||||
it('props#body does not work anymore', () => {
|
||||
const body = jest.fn();
|
||||
mount(<Transfer body={body} />);
|
||||
render(<Transfer body={body} />);
|
||||
|
||||
expect(errorSpy.mock.calls.length).toBe(0);
|
||||
expect(errorSpy).not.toHaveBeenCalled();
|
||||
expect(body).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { render, fireEvent } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import Search from '../search';
|
||||
import Transfer from '../index';
|
||||
|
||||
@ -66,14 +68,14 @@ describe('Transfer.Search', () => {
|
||||
|
||||
it('legacy props#onSearchChange doesnot work anymore', () => {
|
||||
const onSearchChange = jest.fn();
|
||||
const wrapper = mount(
|
||||
const { container } = render(
|
||||
<Transfer render={item => item.title} onSearchChange={onSearchChange} showSearch />,
|
||||
);
|
||||
wrapper
|
||||
.find('.ant-input')
|
||||
.at(0)
|
||||
.simulate('change', { target: { value: 'a' } });
|
||||
expect(errorSpy.mock.calls.length).toBe(0);
|
||||
|
||||
fireEvent.change(container.querySelector('.ant-input'), {
|
||||
target: { value: 'a' },
|
||||
});
|
||||
expect(errorSpy).not.toHaveBeenCalled();
|
||||
expect(onSearchChange).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
|
@ -1,5 +1,7 @@
|
||||
import React from 'react';
|
||||
import { mount } from 'enzyme';
|
||||
import { render } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import { SmileOutlined, LikeOutlined, HighlightOutlined, CheckOutlined } from '@ant-design/icons';
|
||||
import KeyCode from 'rc-util/lib/KeyCode';
|
||||
import { resetWarned } from 'rc-util/lib/warning';
|
||||
@ -398,7 +400,7 @@ describe('Typography', () => {
|
||||
|
||||
it('no italic warning', () => {
|
||||
resetWarned();
|
||||
mount(<Text italic>Little</Text>);
|
||||
render(<Text italic>Little</Text>);
|
||||
|
||||
expect(errorSpy).not.toHaveBeenCalled();
|
||||
});
|
||||
|
@ -1,6 +1,8 @@
|
||||
/* eslint-disable react/no-string-refs, react/prefer-es6-class */
|
||||
import React from 'react';
|
||||
import { mount, render } from 'enzyme';
|
||||
import { mount } from 'enzyme';
|
||||
import { render, fireEvent } from '@testing-library/react';
|
||||
import '@testing-library/jest-dom';
|
||||
import { act } from 'react-dom/test-utils';
|
||||
import produce from 'immer';
|
||||
import { cloneDeep } from 'lodash';
|
||||
@ -13,6 +15,8 @@ import mountTest from '../../../tests/shared/mountTest';
|
||||
import rtlTest from '../../../tests/shared/rtlTest';
|
||||
import { sleep } from '../../../tests/utils';
|
||||
|
||||
globalThis.IS_REACT_ACT_ENVIRONMENT = true;
|
||||
|
||||
describe('Upload', () => {
|
||||
mountTest(Upload);
|
||||
rtlTest(Upload);
|
||||
@ -296,7 +300,7 @@ describe('Upload', () => {
|
||||
url: 'http://www.baidu.com/xxx.png',
|
||||
},
|
||||
];
|
||||
render(<Upload fileList={fileList} />);
|
||||
mount(<Upload fileList={fileList} />);
|
||||
fileList.forEach(file => {
|
||||
expect(file.uid).toBeDefined();
|
||||
});
|
||||
@ -851,19 +855,22 @@ describe('Upload', () => {
|
||||
// IE11 Does not support the File constructor
|
||||
it('should not break in IE if beforeUpload returns false', async () => {
|
||||
const onChange = jest.fn();
|
||||
const wrapper = mount(<Upload beforeUpload={() => false} fileList={[]} onChange={onChange} />);
|
||||
const { container } = render(
|
||||
<Upload beforeUpload={() => false} fileList={[]} onChange={onChange} />,
|
||||
);
|
||||
const fileConstructor = () => {
|
||||
throw new TypeError("Object doesn't support this action");
|
||||
};
|
||||
global.File = jest.fn().mockImplementationOnce(fileConstructor);
|
||||
|
||||
await act(async () =>
|
||||
wrapper.find('input').simulate('change', {
|
||||
target: {
|
||||
files: [{ file: 'foo.png' }],
|
||||
},
|
||||
}),
|
||||
);
|
||||
jest.spyOn(global, 'File').mockImplementationOnce(fileConstructor);
|
||||
fireEvent.change(container.querySelector('input'), {
|
||||
target: {
|
||||
files: [{ file: 'foo.png' }],
|
||||
},
|
||||
});
|
||||
|
||||
// React 18 is async now
|
||||
await sleep();
|
||||
|
||||
expect(onChange.mock.calls[0][0].fileList).toHaveLength(1);
|
||||
});
|
||||
|
@ -101,7 +101,7 @@
|
||||
"version": "node ./scripts/generate-version",
|
||||
"install-react-16": "npm i --no-save --legacy-peer-deps react@16 react-dom@16 enzyme-adapter-react-16",
|
||||
"install-react-17": "npm i --no-save --legacy-peer-deps react@17 react-dom@17",
|
||||
"install-react-18": "npm i --no-save --legacy-peer-deps react@18 react-dom@18",
|
||||
"install-react-18": "npm i --no-save --legacy-peer-deps react@18 react-dom@18 @testing-library/react@13",
|
||||
"argos": "argos upload imageSnapshots"
|
||||
},
|
||||
"browserslist": [
|
||||
@ -165,8 +165,8 @@
|
||||
"@docsearch/react": "^3.0.0-alpha.39",
|
||||
"@qixian.cs/github-contributors-list": "^1.0.3",
|
||||
"@stackblitz/sdk": "^1.3.0",
|
||||
"@testing-library/jest-dom": "^5.16.2",
|
||||
"@testing-library/react": "^12.1.4",
|
||||
"@testing-library/jest-dom": "^5.16.3",
|
||||
"@testing-library/react": "^12.0.0",
|
||||
"@types/enzyme": "^3.10.5",
|
||||
"@types/gtag.js": "^0.0.10",
|
||||
"@types/jest": "^27.0.0",
|
||||
|
Loading…
Reference in New Issue
Block a user