mirror of
https://github.com/ant-design/ant-design.git
synced 2024-11-27 20:49:53 +08:00
fix: Allow users to handle promise rejections in ActionButton's onOk callback (#40018)
* fix: Allow users to handle promise rejections in onOk callback Components that rely on ActionButton swallow rejected promises. This makes it impossible for userland code to handle them. * polish: Fix linting problems * polish: Return rejected promise instead of throwing * refact: Remove test for unhandled promise rejection This test breaks when run in parallel by Jest. At the moment we have no way of changing the way Jest works and it prohibits us from testing for "unhandledRejection" events. See: https://github.com/ant-design/ant-design/pull/40018#issuecomment-1373590259 * test: hack for rejection Co-authored-by: 二货机器人 <smith3816@gmail.com>
This commit is contained in:
parent
c35787696b
commit
25ea3a7202
@ -55,12 +55,10 @@ const ActionButton: React.FC<ActionButtonProps> = (props) => {
|
||||
clickedRef.current = false;
|
||||
},
|
||||
(e: Error) => {
|
||||
// Emit error when catch promise reject
|
||||
// eslint-disable-next-line no-console
|
||||
console.error(e);
|
||||
// See: https://github.com/ant-design/ant-design/issues/6183
|
||||
setLoading(false, true);
|
||||
clickedRef.current = false;
|
||||
return Promise.reject(e);
|
||||
},
|
||||
);
|
||||
};
|
||||
|
@ -18,6 +18,45 @@ const { confirm } = Modal;
|
||||
|
||||
jest.mock('rc-motion');
|
||||
|
||||
(global as any).injectPromise = false;
|
||||
(global as any).rejectPromise = null;
|
||||
|
||||
jest.mock('../../_util/ActionButton', () => {
|
||||
const ActionButton = jest.requireActual('../../_util/ActionButton').default;
|
||||
return (props: any) => {
|
||||
const { actionFn } = props;
|
||||
let mockActionFn: any = actionFn;
|
||||
if (actionFn && (global as any).injectPromise) {
|
||||
mockActionFn = (...args: any) => {
|
||||
let ret = actionFn(...args);
|
||||
|
||||
if (ret.then) {
|
||||
let resolveFn: any;
|
||||
let rejectFn: any;
|
||||
|
||||
ret = ret.then(
|
||||
(v: any) => {
|
||||
resolveFn?.(v);
|
||||
},
|
||||
(e: any) => {
|
||||
rejectFn?.(e)?.catch((err: Error) => {
|
||||
(global as any).rejectPromise = err;
|
||||
});
|
||||
},
|
||||
);
|
||||
ret.then = (resolve: any, reject: any) => {
|
||||
resolveFn = resolve;
|
||||
rejectFn = reject;
|
||||
};
|
||||
}
|
||||
|
||||
return ret;
|
||||
};
|
||||
}
|
||||
return <ActionButton {...props} actionFn={mockActionFn} />;
|
||||
};
|
||||
});
|
||||
|
||||
describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
// Inject CSSMotion to replace with No transition support
|
||||
const MockCSSMotion = genCSSMotion(false);
|
||||
@ -60,6 +99,11 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
jest.useFakeTimers();
|
||||
});
|
||||
|
||||
beforeEach(() => {
|
||||
(global as any).injectPromise = false;
|
||||
(global as any).rejectPromise = null;
|
||||
});
|
||||
|
||||
afterEach(async () => {
|
||||
errorSpy.mockReset();
|
||||
Modal.destroyAll();
|
||||
@ -169,6 +213,8 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
});
|
||||
|
||||
it('should emit error when onOk return Promise.reject', async () => {
|
||||
(global as any).injectPromise = true;
|
||||
|
||||
const error = new Error('something wrong');
|
||||
await open({
|
||||
onOk: () => Promise.reject(error),
|
||||
@ -179,7 +225,7 @@ describe('Modal.confirm triggers callbacks correctly', () => {
|
||||
// wait promise
|
||||
await waitFakeTimer();
|
||||
|
||||
expect(errorSpy).toHaveBeenCalledWith(error);
|
||||
expect((global as any).rejectPromise instanceof Error).toBeTruthy();
|
||||
});
|
||||
|
||||
it('shows animation when close', async () => {
|
||||
|
Loading…
Reference in New Issue
Block a user