import React from 'react'; import { SmileOutlined } from '@ant-design/icons'; import message, { actWrapper } from '..'; import { act, fireEvent, sleep } from '../../../tests/utils'; import { awaitPromise, triggerMotionEnd } from './util'; describe('message', () => { beforeAll(() => { actWrapper(act); }); beforeEach(() => { jest.useFakeTimers(); }); afterEach(async () => { // Clean up message.destroy(); await triggerMotionEnd(); act(() => { jest.runAllTimers(); }); jest.useRealTimers(); await awaitPromise(); }); it('should be able to hide manually', async () => { const hide1 = message.info('whatever', 0); const hide2 = message.info('whatever', 0); await awaitPromise(); expect(document.querySelectorAll('.ant-message-notice')).toHaveLength(2); hide1(); await triggerMotionEnd(); expect(document.querySelectorAll('.ant-message-notice')).toHaveLength(1); hide2(); await triggerMotionEnd(); expect(document.querySelectorAll('.ant-message-notice')).toHaveLength(0); }); it('should be able to remove manually with a unique key', async () => { const key1 = 'key1'; const key2 = 'key2'; message.info({ content: 'Message1', key: 'key1', duration: 0 }); message.info({ content: 'Message2', key: 'key2', duration: 0 }); await awaitPromise(); expect(document.querySelectorAll('.ant-message-notice')).toHaveLength(2); message.destroy(key1); await triggerMotionEnd(); expect(document.querySelectorAll('.ant-message-notice')).toHaveLength(1); message.destroy(key2); await triggerMotionEnd(); expect(document.querySelectorAll('.ant-message-notice')).toHaveLength(0); }); it('should be able to destroy globally', async () => { message.info('whatever', 0); message.info('whatever', 0); await awaitPromise(); expect(document.querySelectorAll('.ant-message')).toHaveLength(1); expect(document.querySelectorAll('.ant-message-notice')).toHaveLength(2); message.destroy(); await triggerMotionEnd(); expect(document.querySelectorAll('.ant-message')).toHaveLength(0); expect(document.querySelectorAll('.ant-message-notice')).toHaveLength(0); }); it('should not need to use duration argument when using the onClose arguments', async () => { const onClose = jest.fn(); const close = message.info('whatever', onClose); await awaitPromise(); close(); await triggerMotionEnd(); expect(onClose).toHaveBeenCalled(); }); it('should have the default duration when using the onClose arguments', async () => { const onClose = jest.fn(); message.info('whatever', onClose); await awaitPromise(); act(() => { jest.advanceTimersByTime(2500); }); expect(document.querySelector('.ant-message-move-up-leave')).toBeFalsy(); act(() => { jest.advanceTimersByTime(1000); }); expect(document.querySelector('.ant-message-move-up-leave')).toBeTruthy(); }); it('trigger onClick method', async () => { const onClick = jest.fn(); message.info({ onClick, duration: 0, content: 'message info', }); await awaitPromise(); expect(document.querySelectorAll('.ant-message-notice')).toHaveLength(1); fireEvent.click(document.querySelector('.ant-message-notice')!); expect(onClick).toHaveBeenCalled(); }); it('should be called like promise', async () => { const onClose = jest.fn(); message.info('whatever').then(onClose); await awaitPromise(); act(() => { jest.advanceTimersByTime(2500); }); expect(onClose).not.toHaveBeenCalled(); act(() => { jest.advanceTimersByTime(1000); }); await sleep(); // Wait to let event loop run expect(onClose).toHaveBeenCalled(); }); // https://github.com/ant-design/ant-design/issues/8201 it('should hide message correctly', async () => { const hide = message.loading('Action in progress..', 0); await awaitPromise(); expect(document.querySelectorAll('.ant-message-notice')).toHaveLength(1); hide!(); await triggerMotionEnd(); expect(document.querySelectorAll('.ant-message-notice')).toHaveLength(0); }); it('should allow custom icon', async () => { message.open({ content: 'Message', icon: }); await awaitPromise(); expect(document.querySelector('.anticon-smile')).toBeTruthy(); }); it('should have no icon', async () => { message.open({ content: 'Message', icon: }); await awaitPromise(); expect(document.querySelector('.ant-message-notice .anticon')).toBeFalsy(); }); it('should have no icon when not pass icon props', async () => { message.open({ content: 'Message' }); await awaitPromise(); expect(document.querySelector('.ant-message-notice .anticon')).toBeFalsy(); }); // https://github.com/ant-design/ant-design/issues/8201 it('should destroy messages correctly', async () => { message.loading('Action in progress1..', 0); message.loading('Action in progress2..', 0); setTimeout(() => message.destroy(), 1000); await awaitPromise(); expect(document.querySelectorAll('.ant-message-notice')).toHaveLength(2); await triggerMotionEnd(); expect(document.querySelectorAll('.ant-message-notice')).toHaveLength(0); }); it('should support update message content with a unique key', async () => { const key = 'updatable'; message.loading({ content: 'Loading...', key }); // Testing that content of the message should be updated. setTimeout(() => message.success({ content: 'Loaded', key }), 1000); setTimeout(() => message.destroy(), 3000); await awaitPromise(); expect(document.querySelectorAll('.ant-message-notice')).toHaveLength(1); act(() => { jest.advanceTimersByTime(1500); }); expect(document.querySelectorAll('.ant-message-notice')).toHaveLength(1); expect(document.querySelector('.ant-message-move-up-leave')).toBeFalsy(); await triggerMotionEnd(); expect(document.querySelectorAll('.ant-message-notice')).toHaveLength(0); }); it('update message content with a unique key and cancel manually', async () => { const key = 'updatable'; const hideLoading = message.loading({ content: 'Loading...', key, duration: 0 }); await awaitPromise(); setTimeout(() => { act(() => { hideLoading(); }); }, 1000); expect(document.querySelectorAll('.ant-message-notice')).toHaveLength(1); act(() => { jest.advanceTimersByTime(1500); }); expect(document.querySelectorAll('.ant-message-move-up-leave')).toHaveLength(1); }); it('should not throw error when pass null', async () => { message.error(null); await awaitPromise(); }); });