mirror of
https://github.com/ant-design/ant-design.git
synced 2025-06-12 20:43:11 +08:00
fix(modal): Modal.xxx onCancel close argument is not a function (#36600)
* fix(modal): fix the error of `onCancel` parameter of modal returned by `useModal` resolve: 36581 ref: https://github.com/ant-design/ant-design/issues/36581#issuecomment-1189396007 * test(confirm): 补充 modal 测试用例 * test(modal): 添加测试用例 * Revert "fix(modal): fix the error of `onCancel` parameter of modal returned by `useModal`" This reverts commit e4fcb3e62add63193ec9081b2c21e657379bebfb. * fix(modal): fix modal onOk/onCancel method is not a valid function when there is a close parameter closed: #36581 * chore: cancel the introduction of `noop` from third-party library
This commit is contained in:
parent
09de419253
commit
16ecdbb58d
@ -305,7 +305,7 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
describe('should not close modals when click confirm button when onOk has argument', () => {
|
describe('should not close modals when click confirm button when onOk has argument', () => {
|
||||||
['info', 'success', 'warning', 'error'].forEach(type => {
|
['confirm', 'info', 'success', 'warning', 'error'].forEach(type => {
|
||||||
it(type, async () => {
|
it(type, async () => {
|
||||||
jest.useFakeTimers();
|
jest.useFakeTimers();
|
||||||
Modal[type]({
|
Modal[type]({
|
||||||
@ -318,7 +318,7 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
|||||||
await sleep();
|
await sleep();
|
||||||
});
|
});
|
||||||
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1);
|
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1);
|
||||||
$$('.ant-btn')[0].click();
|
$$('.ant-btn-primary')[0].click();
|
||||||
|
|
||||||
await act(async () => {
|
await act(async () => {
|
||||||
jest.runAllTimers();
|
jest.runAllTimers();
|
||||||
@ -674,4 +674,149 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
|||||||
const { width } = $$('.ant-modal-body')[0].style;
|
const { width } = $$('.ant-modal-body')[0].style;
|
||||||
expect(width).toBe('500px');
|
expect(width).toBe('500px');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
describe('the callback close should be a method when onCancel has a close parameter', () => {
|
||||||
|
['confirm', 'info', 'success', 'warning', 'error'].forEach(type => {
|
||||||
|
it(`click the close icon to trigger ${type} onCancel`, async () => {
|
||||||
|
jest.useFakeTimers();
|
||||||
|
const mock = jest.fn();
|
||||||
|
|
||||||
|
Modal[type]({
|
||||||
|
closable: true,
|
||||||
|
onCancel: close => mock(close),
|
||||||
|
});
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
jest.runAllTimers();
|
||||||
|
await sleep();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1);
|
||||||
|
$$('.ant-modal-close')[0].click();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
jest.runAllTimers();
|
||||||
|
await sleep();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(0);
|
||||||
|
expect(mock).toBeCalledWith(expect.any(Function));
|
||||||
|
|
||||||
|
jest.useRealTimers();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
['confirm', 'info', 'success', 'warning', 'error'].forEach(type => {
|
||||||
|
it(`press ESC to trigger ${type} onCancel`, async () => {
|
||||||
|
jest.useFakeTimers();
|
||||||
|
const mock = jest.fn();
|
||||||
|
|
||||||
|
Modal[type]({
|
||||||
|
keyboard: true,
|
||||||
|
onCancel: close => mock(close),
|
||||||
|
});
|
||||||
|
|
||||||
|
jest.runAllTimers();
|
||||||
|
await sleep();
|
||||||
|
jest.runAllTimers();
|
||||||
|
|
||||||
|
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1);
|
||||||
|
TestUtils.Simulate.keyDown($$('.ant-modal')[0], {
|
||||||
|
keyCode: KeyCode.ESC,
|
||||||
|
});
|
||||||
|
|
||||||
|
jest.runAllTimers();
|
||||||
|
await sleep(0);
|
||||||
|
jest.runAllTimers();
|
||||||
|
|
||||||
|
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(0);
|
||||||
|
expect(mock).toBeCalledWith(expect.any(Function));
|
||||||
|
|
||||||
|
jest.useRealTimers();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
['confirm', 'info', 'success', 'warning', 'error'].forEach(type => {
|
||||||
|
it(`click the mask to trigger ${type} onCancel`, async () => {
|
||||||
|
jest.useFakeTimers();
|
||||||
|
const mock = jest.fn();
|
||||||
|
|
||||||
|
Modal[type]({
|
||||||
|
maskClosable: true,
|
||||||
|
onCancel: close => mock(close),
|
||||||
|
});
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
jest.runAllTimers();
|
||||||
|
await sleep();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect($$('.ant-modal-mask')).toHaveLength(1);
|
||||||
|
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(1);
|
||||||
|
|
||||||
|
$$('.ant-modal-wrap')[0].click();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
jest.runAllTimers();
|
||||||
|
await sleep();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect($$(`.ant-modal-confirm-${type}`)).toHaveLength(0);
|
||||||
|
expect(mock).toBeCalledWith(expect.any(Function));
|
||||||
|
|
||||||
|
jest.useRealTimers();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('confirm modal click Cancel button close callback is a function', async () => {
|
||||||
|
jest.useFakeTimers();
|
||||||
|
const mock = jest.fn();
|
||||||
|
|
||||||
|
Modal.confirm({
|
||||||
|
onCancel: close => mock(close),
|
||||||
|
});
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
jest.runAllTimers();
|
||||||
|
await sleep();
|
||||||
|
});
|
||||||
|
|
||||||
|
$$('.ant-modal-confirm-btns > .ant-btn')[0].click();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
jest.runAllTimers();
|
||||||
|
await sleep();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect(mock).toBeCalledWith(expect.any(Function));
|
||||||
|
|
||||||
|
jest.useRealTimers();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('close can close modal when onCancel has a close parameter', async () => {
|
||||||
|
jest.useFakeTimers();
|
||||||
|
|
||||||
|
Modal.confirm({
|
||||||
|
onCancel: close => close(),
|
||||||
|
});
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
jest.runAllTimers();
|
||||||
|
await sleep();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect($$('.ant-modal-confirm-confirm')).toHaveLength(1);
|
||||||
|
|
||||||
|
$$('.ant-modal-confirm-btns > .ant-btn')[0].click();
|
||||||
|
|
||||||
|
await act(async () => {
|
||||||
|
jest.runAllTimers();
|
||||||
|
await sleep();
|
||||||
|
});
|
||||||
|
|
||||||
|
expect($$('.ant-modal-confirm-confirm')).toHaveLength(0);
|
||||||
|
|
||||||
|
jest.useRealTimers();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -1,9 +1,11 @@
|
|||||||
import CSSMotion from 'rc-motion';
|
import CSSMotion from 'rc-motion';
|
||||||
import { genCSSMotion } from 'rc-motion/lib/CSSMotion';
|
import { genCSSMotion } from 'rc-motion/lib/CSSMotion';
|
||||||
|
import KeyCode from 'rc-util/lib/KeyCode';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import { act } from 'react-dom/test-utils';
|
import TestUtils, { act } from 'react-dom/test-utils';
|
||||||
|
|
||||||
import Modal from '..';
|
import Modal from '..';
|
||||||
import { fireEvent, render } from '../../../tests/utils';
|
import { fireEvent, render, sleep } from '../../../tests/utils';
|
||||||
import Button from '../../button';
|
import Button from '../../button';
|
||||||
import ConfigProvider from '../../config-provider';
|
import ConfigProvider from '../../config-provider';
|
||||||
import Input from '../../input';
|
import Input from '../../input';
|
||||||
@ -193,4 +195,110 @@ describe('Modal.hook', () => {
|
|||||||
fireEvent.click(container.querySelectorAll('.open-hook-modal-btn')[0]);
|
fireEvent.click(container.querySelectorAll('.open-hook-modal-btn')[0]);
|
||||||
expect(document.body.classList.contains('ant-modal-confirm-title')).toBeFalsy();
|
expect(document.body.classList.contains('ant-modal-confirm-title')).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('the callback close should be a method when onCancel has a close parameter', async () => {
|
||||||
|
jest.useFakeTimers();
|
||||||
|
|
||||||
|
const clear = async function clear() {
|
||||||
|
await act(async () => {
|
||||||
|
jest.runAllTimers();
|
||||||
|
await sleep();
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const mockFn = jest.fn();
|
||||||
|
const Demo = () => {
|
||||||
|
const [modal, contextHolder] = Modal.useModal();
|
||||||
|
|
||||||
|
const openBrokenModal = React.useCallback(() => {
|
||||||
|
modal.confirm({
|
||||||
|
closable: true,
|
||||||
|
keyboard: true,
|
||||||
|
maskClosable: true,
|
||||||
|
onCancel: close => mockFn(close),
|
||||||
|
});
|
||||||
|
}, [modal]);
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className="App">
|
||||||
|
{contextHolder}
|
||||||
|
<div className="open-hook-modal-btn" onClick={openBrokenModal}>
|
||||||
|
Test hook modal
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
const { container } = render(<Demo />);
|
||||||
|
|
||||||
|
await clear();
|
||||||
|
|
||||||
|
expect(document.body.querySelectorAll('.ant-modal-confirm-confirm')).toHaveLength(0);
|
||||||
|
// First open
|
||||||
|
fireEvent.click(container.querySelectorAll('.open-hook-modal-btn')[0]);
|
||||||
|
await clear();
|
||||||
|
|
||||||
|
expect(document.body.querySelectorAll('.ant-modal-confirm-confirm')).toHaveLength(1);
|
||||||
|
// Click mask to close
|
||||||
|
fireEvent.click(document.body.querySelectorAll('.ant-modal-wrap')[0]);
|
||||||
|
|
||||||
|
await clear();
|
||||||
|
|
||||||
|
expect(document.body.querySelectorAll('.ant-modal-confirm-confirm')).toHaveLength(0);
|
||||||
|
// Second open
|
||||||
|
fireEvent.click(container.querySelectorAll('.open-hook-modal-btn')[0]);
|
||||||
|
|
||||||
|
await clear();
|
||||||
|
|
||||||
|
expect(document.body.querySelectorAll('.ant-modal-confirm-confirm')).toHaveLength(1);
|
||||||
|
// Press ESC to turn off
|
||||||
|
TestUtils.Simulate.keyDown(document.body.querySelectorAll('.ant-modal')[0], {
|
||||||
|
keyCode: KeyCode.ESC,
|
||||||
|
});
|
||||||
|
|
||||||
|
await clear();
|
||||||
|
|
||||||
|
expect(document.body.querySelectorAll('.ant-modal-confirm-confirm')).toHaveLength(0);
|
||||||
|
// Third open
|
||||||
|
fireEvent.click(container.querySelectorAll('.open-hook-modal-btn')[0]);
|
||||||
|
|
||||||
|
await clear();
|
||||||
|
|
||||||
|
expect(document.body.querySelectorAll('.ant-modal-confirm-confirm')).toHaveLength(1);
|
||||||
|
// Click the close icon to close
|
||||||
|
fireEvent.click(document.body.querySelectorAll('.ant-modal-close')[0]);
|
||||||
|
|
||||||
|
await clear();
|
||||||
|
|
||||||
|
expect(document.body.querySelectorAll('.ant-modal-confirm-confirm')).toHaveLength(0);
|
||||||
|
// Last open
|
||||||
|
fireEvent.click(container.querySelectorAll('.open-hook-modal-btn')[0]);
|
||||||
|
|
||||||
|
await clear();
|
||||||
|
|
||||||
|
expect(document.body.querySelectorAll('.ant-modal-confirm-confirm')).toHaveLength(1);
|
||||||
|
|
||||||
|
// Click the Cancel button to close (invalid)
|
||||||
|
fireEvent.click(document.body.querySelectorAll('.ant-modal-confirm-btns > .ant-btn')[0]);
|
||||||
|
|
||||||
|
await clear();
|
||||||
|
|
||||||
|
expect(document.body.querySelectorAll('.ant-modal-confirm-confirm')).toHaveLength(1);
|
||||||
|
|
||||||
|
mockFn.mockImplementation(close => close());
|
||||||
|
|
||||||
|
// Click the Cancel button to close (valid)
|
||||||
|
fireEvent.click(document.body.querySelectorAll('.ant-modal-confirm-btns > .ant-btn')[0]);
|
||||||
|
|
||||||
|
await clear();
|
||||||
|
|
||||||
|
expect(document.body.querySelectorAll('.ant-modal-confirm-confirm')).toHaveLength(0);
|
||||||
|
|
||||||
|
// Close called 5 times
|
||||||
|
expect(mockFn).toHaveBeenCalledTimes(5);
|
||||||
|
|
||||||
|
expect(mockFn.mock.calls).toEqual(Array.from({ length: 5 }, () => [expect.any(Function)]));
|
||||||
|
|
||||||
|
jest.useRealTimers();
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
@ -34,7 +34,7 @@ export default function confirm(config: ModalFuncProps) {
|
|||||||
function destroy(...args: any[]) {
|
function destroy(...args: any[]) {
|
||||||
const triggerCancel = args.some(param => param && param.triggerCancel);
|
const triggerCancel = args.some(param => param && param.triggerCancel);
|
||||||
if (config.onCancel && triggerCancel) {
|
if (config.onCancel && triggerCancel) {
|
||||||
config.onCancel(...args);
|
config.onCancel(() => {}, ...args.slice(1));
|
||||||
}
|
}
|
||||||
for (let i = 0; i < destroyFns.length; i++) {
|
for (let i = 0; i < destroyFns.length; i++) {
|
||||||
const fn = destroyFns[i];
|
const fn = destroyFns[i];
|
||||||
|
@ -36,7 +36,7 @@ const HookModal: React.ForwardRefRenderFunction<HookModalRef, HookModalProps> =
|
|||||||
setVisible(false);
|
setVisible(false);
|
||||||
const triggerCancel = args.some(param => param && param.triggerCancel);
|
const triggerCancel = args.some(param => param && param.triggerCancel);
|
||||||
if (innerConfig.onCancel && triggerCancel) {
|
if (innerConfig.onCancel && triggerCancel) {
|
||||||
innerConfig.onCancel();
|
innerConfig.onCancel(() => {}, ...args.slice(1));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user