import React from 'react'; import { act, fireEvent, render, screen, userEvent } from '@testing-library/react-native'; import { Provider } from 'react-redux'; import { MessageComposerContainer } from './MessageComposerContainer'; import { setPermissions } from '../../actions/permissions'; import { addSettings } from '../../actions/settings'; import { selectServerRequest } from '../../actions/server'; import { setUser } from '../../actions/login'; import { mockedStore } from '../../reducers/mockedStore'; import { IPermissionsState } from '../../reducers/permissions'; import { IMessage } from '../../definitions'; import { colors } from '../../lib/constants'; import { IRoomContext, RoomContext } from '../../views/RoomView/context'; const initialStoreState = () => { const baseUrl = 'https://open.rocket.chat'; mockedStore.dispatch(selectServerRequest(baseUrl, '6.4.0')); mockedStore.dispatch(setUser({ id: 'abc', username: 'rocket.cat', name: 'Rocket Cat', roles: ['user'] })); const permissions: IPermissionsState = { 'mobile-upload-file': ['user'] }; mockedStore.dispatch(setPermissions(permissions)); mockedStore.dispatch(addSettings({ Message_AudioRecorderEnabled: true })); }; initialStoreState(); const initialContext = { rid: 'rid', tmid: undefined, sharing: false, action: null, selectedMessages: [], editCancel: jest.fn(), editRequest: jest.fn(), onSendMessage: jest.fn(), onRemoveQuoteMessage: jest.fn() }; const Render = ({ context }: { context?: Partial }) => ( ); describe('MessageComposer', () => { test('renders correctly', () => { render(); expect(screen.getByTestId('message-composer-input')).toBeOnTheScreen(); expect(screen.getByTestId('message-composer-actions')).toBeOnTheScreen(); expect(screen.getByTestId('message-composer-send-audio')).toBeOnTheScreen(); expect(screen.toJSON()).toMatchSnapshot(); }); test('renders correctly with audio recorder disabled', () => { mockedStore.dispatch(addSettings({ Message_AudioRecorderEnabled: false })); render(); expect(screen.queryByTestId('message-composer-send-audio')).not.toBeOnTheScreen(); expect(screen.toJSON()).toMatchSnapshot(); }); test('renders correctly without audio upload permissions', () => { mockedStore.dispatch(setPermissions({})); render(); expect(screen.queryByTestId('message-composer-send-audio')).not.toBeOnTheScreen(); expect(screen.toJSON()).toMatchSnapshot(); }); test('renders correctly with audio recorder disabled and without audio upload permissions', () => { mockedStore.dispatch(addSettings({ Message_AudioRecorderEnabled: false })); mockedStore.dispatch(setPermissions({})); render(); expect(screen.queryByTestId('message-composer-send-audio')).not.toBeOnTheScreen(); expect(screen.toJSON()).toMatchSnapshot(); }); test('renders toolbar when focused', async () => { initialStoreState(); render(); expect(screen.getByTestId('message-composer-actions')).toBeOnTheScreen(); expect(screen.getByTestId('message-composer-send-audio')).toBeOnTheScreen(); expect(screen.queryByTestId('message-composer-open-emoji')).not.toBeOnTheScreen(); expect(screen.queryByTestId('message-composer-open-markdown')).not.toBeOnTheScreen(); expect(screen.queryByTestId('message-composer-mention')).not.toBeOnTheScreen(); await act(async () => { await fireEvent(screen.getByTestId('message-composer-input'), 'focus'); }); expect(screen.getByTestId('message-composer-actions')).toBeOnTheScreen(); expect(screen.getByTestId('message-composer-send-audio')).toBeOnTheScreen(); expect(screen.getByTestId('message-composer-open-emoji')).toBeOnTheScreen(); expect(screen.getByTestId('message-composer-open-markdown')).toBeOnTheScreen(); expect(screen.getByTestId('message-composer-mention')).toBeOnTheScreen(); expect(screen.toJSON()).toMatchSnapshot(); }); test('send message', async () => { const user = userEvent.setup(); const onSendMessage = jest.fn(); render(); expect(screen.getByTestId('message-composer-send-audio')).toBeOnTheScreen(); await user.type(screen.getByTestId('message-composer-input'), 'test'); expect(screen.queryByTestId('message-composer-send-audio')).not.toBeOnTheScreen(); expect(screen.getByTestId('message-composer-send')).toBeOnTheScreen(); await act(async () => { await fireEvent.press(screen.getByTestId('message-composer-send')); }); expect(onSendMessage).toHaveBeenCalledTimes(1); expect(onSendMessage).toHaveBeenCalledWith('test', undefined); expect(screen.toJSON()).toMatchSnapshot(); }); describe('Toolbar', () => { test('tap actions', async () => { render(); await act(async () => { await fireEvent(screen.getByTestId('message-composer-input'), 'focus'); await fireEvent.press(screen.getByTestId('message-composer-actions')); }); expect(screen.toJSON()).toMatchSnapshot(); }); test('tap emoji', async () => { render(); await act(async () => { await fireEvent(screen.getByTestId('message-composer-input'), 'focus'); await fireEvent.press(screen.getByTestId('message-composer-open-emoji')); }); expect(screen.getByTestId('message-composer-close-emoji')).toBeOnTheScreen(); expect(screen.toJSON()).toMatchSnapshot(); }); describe('Markdown', () => { test('tap markdown', async () => { render(); await act(async () => { await fireEvent(screen.getByTestId('message-composer-input'), 'focus'); await fireEvent.press(screen.getByTestId('message-composer-open-markdown')); }); expect(screen.getByTestId('message-composer-close-markdown')).toBeOnTheScreen(); expect(screen.getByTestId('message-composer-bold')).toBeOnTheScreen(); expect(screen.getByTestId('message-composer-italic')).toBeOnTheScreen(); expect(screen.getByTestId('message-composer-strike')).toBeOnTheScreen(); expect(screen.getByTestId('message-composer-code')).toBeOnTheScreen(); expect(screen.getByTestId('message-composer-code-block')).toBeOnTheScreen(); expect(screen.toJSON()).toMatchSnapshot(); }); test('tap bold', async () => { const onSendMessage = jest.fn(); render(); await act(async () => { await fireEvent(screen.getByTestId('message-composer-input'), 'focus'); await fireEvent.press(screen.getByTestId('message-composer-open-markdown')); await fireEvent.press(screen.getByTestId('message-composer-bold')); await fireEvent.press(screen.getByTestId('message-composer-send')); }); expect(onSendMessage).toHaveBeenCalledTimes(1); expect(onSendMessage).toHaveBeenCalledWith('**', undefined); expect(screen.toJSON()).toMatchSnapshot(); }); test('type test and tap bold', async () => { const onSendMessage = jest.fn(); render(); await act(async () => { await fireEvent.changeText(screen.getByTestId('message-composer-input'), 'test'); await fireEvent(screen.getByTestId('message-composer-input'), 'focus'); await fireEvent(screen.getByTestId('message-composer-input'), 'selectionChange', { nativeEvent: { selection: { start: 0, end: 4 } } }); await fireEvent.press(screen.getByTestId('message-composer-open-markdown')); await fireEvent.press(screen.getByTestId('message-composer-bold')); await fireEvent.press(screen.getByTestId('message-composer-send')); }); expect(onSendMessage).toHaveBeenCalledTimes(1); expect(onSendMessage).toHaveBeenCalledWith('*test*', undefined); expect(screen.toJSON()).toMatchSnapshot(); }); test('tap italic', async () => { const onSendMessage = jest.fn(); render(); await act(async () => { await fireEvent(screen.getByTestId('message-composer-input'), 'focus'); await fireEvent.press(screen.getByTestId('message-composer-open-markdown')); await fireEvent.press(screen.getByTestId('message-composer-italic')); await fireEvent.press(screen.getByTestId('message-composer-send')); }); expect(onSendMessage).toHaveBeenCalledTimes(1); expect(onSendMessage).toHaveBeenCalledWith('__', undefined); expect(screen.toJSON()).toMatchSnapshot(); }); test('type test and tap italic', async () => { const onSendMessage = jest.fn(); render(); await act(async () => { await fireEvent.changeText(screen.getByTestId('message-composer-input'), 'test'); await fireEvent(screen.getByTestId('message-composer-input'), 'focus'); await fireEvent(screen.getByTestId('message-composer-input'), 'selectionChange', { nativeEvent: { selection: { start: 0, end: 4 } } }); await fireEvent.press(screen.getByTestId('message-composer-open-markdown')); await fireEvent.press(screen.getByTestId('message-composer-italic')); await fireEvent.press(screen.getByTestId('message-composer-send')); }); expect(onSendMessage).toHaveBeenCalledTimes(1); expect(onSendMessage).toHaveBeenCalledWith('_test_', undefined); expect(screen.toJSON()).toMatchSnapshot(); }); test('tap strike', async () => { const onSendMessage = jest.fn(); render(); await act(async () => { await fireEvent(screen.getByTestId('message-composer-input'), 'focus'); await fireEvent.press(screen.getByTestId('message-composer-open-markdown')); await fireEvent.press(screen.getByTestId('message-composer-strike')); await fireEvent.press(screen.getByTestId('message-composer-send')); }); expect(onSendMessage).toHaveBeenCalledTimes(1); expect(onSendMessage).toHaveBeenCalledWith('~~', undefined); expect(screen.toJSON()).toMatchSnapshot(); }); test('type test and tap strike', async () => { const onSendMessage = jest.fn(); render(); await act(async () => { await fireEvent.changeText(screen.getByTestId('message-composer-input'), 'test'); await fireEvent(screen.getByTestId('message-composer-input'), 'focus'); await fireEvent(screen.getByTestId('message-composer-input'), 'selectionChange', { nativeEvent: { selection: { start: 0, end: 4 } } }); await fireEvent.press(screen.getByTestId('message-composer-open-markdown')); await fireEvent.press(screen.getByTestId('message-composer-strike')); await fireEvent.press(screen.getByTestId('message-composer-send')); }); expect(onSendMessage).toHaveBeenCalledTimes(1); expect(onSendMessage).toHaveBeenCalledWith('~test~', undefined); expect(screen.toJSON()).toMatchSnapshot(); }); test('tap code', async () => { const onSendMessage = jest.fn(); render(); await act(async () => { await fireEvent(screen.getByTestId('message-composer-input'), 'focus'); await fireEvent.press(screen.getByTestId('message-composer-open-markdown')); await fireEvent.press(screen.getByTestId('message-composer-code')); await fireEvent.press(screen.getByTestId('message-composer-send')); }); expect(onSendMessage).toHaveBeenCalledTimes(1); expect(onSendMessage).toHaveBeenCalledWith('``', undefined); expect(screen.toJSON()).toMatchSnapshot(); }); test('type test and tap code', async () => { const onSendMessage = jest.fn(); render(); await act(async () => { await fireEvent.changeText(screen.getByTestId('message-composer-input'), 'test'); await fireEvent(screen.getByTestId('message-composer-input'), 'focus'); await fireEvent(screen.getByTestId('message-composer-input'), 'selectionChange', { nativeEvent: { selection: { start: 0, end: 4 } } }); await fireEvent.press(screen.getByTestId('message-composer-open-markdown')); await fireEvent.press(screen.getByTestId('message-composer-code')); await fireEvent.press(screen.getByTestId('message-composer-send')); }); expect(onSendMessage).toHaveBeenCalledTimes(1); expect(onSendMessage).toHaveBeenCalledWith('`test`', undefined); expect(screen.toJSON()).toMatchSnapshot(); }); test('tap code-block', async () => { const onSendMessage = jest.fn(); render(); await act(async () => { await fireEvent(screen.getByTestId('message-composer-input'), 'focus'); await fireEvent.press(screen.getByTestId('message-composer-open-markdown')); await fireEvent.press(screen.getByTestId('message-composer-code-block')); await fireEvent.press(screen.getByTestId('message-composer-send')); }); expect(onSendMessage).toHaveBeenCalledTimes(1); expect(onSendMessage).toHaveBeenCalledWith('``````', undefined); expect(screen.toJSON()).toMatchSnapshot(); }); test('type test and tap code-block', async () => { const onSendMessage = jest.fn(); render(); await act(async () => { await fireEvent.changeText(screen.getByTestId('message-composer-input'), 'test'); await fireEvent(screen.getByTestId('message-composer-input'), 'focus'); await fireEvent(screen.getByTestId('message-composer-input'), 'selectionChange', { nativeEvent: { selection: { start: 0, end: 4 } } }); await fireEvent.press(screen.getByTestId('message-composer-open-markdown')); await fireEvent.press(screen.getByTestId('message-composer-code-block')); await fireEvent.press(screen.getByTestId('message-composer-send')); }); expect(onSendMessage).toHaveBeenCalledTimes(1); expect(onSendMessage).toHaveBeenCalledWith('```test```', undefined); expect(screen.toJSON()).toMatchSnapshot(); }); }); test('tap mention', async () => { const onSendMessage = jest.fn(); render(); await act(async () => { await fireEvent(screen.getByTestId('message-composer-input'), 'focus'); await fireEvent.press(screen.getByTestId('message-composer-mention')); await fireEvent.press(screen.getByTestId('message-composer-send')); }); expect(onSendMessage).toHaveBeenCalledTimes(1); expect(onSendMessage).toHaveBeenCalledWith('@', undefined); expect(screen.toJSON()).toMatchSnapshot(); }); }); describe('edit message', () => { const onSendMessage = jest.fn(); const editCancel = jest.fn(); const editRequest = jest.fn(); const id = 'messageId'; beforeEach(() => { render(); }); test('init', async () => { await screen.findByTestId('message-composer'); expect(screen.getByTestId('message-composer')).toHaveStyle({ backgroundColor: colors.light.statusBackgroundWarning2 }); expect(screen.getByTestId('message-composer-actions')).toBeOnTheScreen(); expect(screen.queryByTestId('message-composer-send-audio')).not.toBeOnTheScreen(); expect(screen.getByTestId('message-composer-cancel-edit')).toBeOnTheScreen(); }); test('cancel', async () => { await screen.findByTestId('message-composer'); expect(screen.getByTestId('message-composer')).toHaveStyle({ backgroundColor: colors.light.statusBackgroundWarning2 }); await act(async () => { await fireEvent.press(screen.getByTestId('message-composer-cancel-edit')); }); expect(editCancel).toHaveBeenCalledTimes(1); expect(screen.getByTestId('message-composer-actions')).toBeOnTheScreen(); expect(screen.queryByTestId('message-composer-send-audio')).not.toBeOnTheScreen(); expect(screen.getByTestId('message-composer-cancel-edit')).toBeOnTheScreen(); }); test('send', async () => { await screen.findByTestId('message-composer'); expect(screen.getByTestId('message-composer')).toHaveStyle({ backgroundColor: colors.light.statusBackgroundWarning2 }); await act(async () => { await fireEvent.press(screen.getByTestId('message-composer-send')); }); expect(editRequest).toHaveBeenCalledTimes(1); expect(editRequest).toHaveBeenCalledWith({ id, msg: `Message ${id}`, rid: 'rid' }); }); }); const messageIds = ['abc', 'def']; jest.mock('./hooks/useMessage', () => ({ useMessage: (messageId: string) => { if (!messageIds.includes(messageId)) { return null; } const message = { id: messageId, msg: 'quote this', u: { username: 'rocket.cat' } } as IMessage; return message; } })); jest.mock('../../lib/store/auxStore', () => ({ store: { getState: () => mockedStore.getState() } })); describe('Quote', () => { test('Add quote `abc`', async () => { render(); await act(async () => { await screen.findByTestId('composer-quote-abc'); expect(screen.queryByTestId('composer-quote-abc')).toBeOnTheScreen(); expect(screen.toJSON()).toMatchSnapshot(); }); }); test('Add quote `def`', async () => { render(); await act(async () => { await screen.findByTestId('composer-quote-abc'); expect(screen.queryByTestId('composer-quote-abc')).toBeOnTheScreen(); expect(screen.queryByTestId('composer-quote-def')).toBeOnTheScreen(); expect(screen.toJSON()).toMatchSnapshot(); }); }); test('Remove a quote', async () => { const onRemoveQuoteMessage = jest.fn(); render(); await act(async () => { await screen.findByTestId('composer-quote-def'); await fireEvent.press(screen.getByTestId('composer-quote-remove-def')); }); expect(onRemoveQuoteMessage).toHaveBeenCalledTimes(1); expect(onRemoveQuoteMessage).toHaveBeenCalledWith('def'); expect(screen.toJSON()).toMatchSnapshot(); }); }); describe('Audio', () => { test('tap record', async () => { render(); expect(screen.getByTestId('message-composer-send-audio')).toBeOnTheScreen(); await act(async () => { await fireEvent.press(screen.getByTestId('message-composer-send-audio')); }); expect(screen.toJSON()).toMatchSnapshot(); }); }); });