import React from 'react';
import { act, cleanup, renderHook, waitFor } from '@testing-library/react-native';
import { LocalMessage } from 'stream-chat';
import { Chat } from '../../../components';
import { initiateClientWithChannels } from '../../../mock-builders/api/initiateClientWithChannels';
import { generateLocalFileUploadAttachmentData } from '../../../mock-builders/attachments';
import { generateMessage } from '../../../mock-builders/generator/message';
import * as UseMessageComposerAPIContext from '../../messageComposerContext/MessageComposerAPIContext';
import { MessageComposerAPIContextValue } from '../../messageComposerContext/MessageComposerAPIContext';
import { MessageComposerProvider } from '../../messageComposerContext/MessageComposerContext';
import {
OwnCapabilitiesContextValue,
OwnCapabilitiesProvider,
} from '../../ownCapabilitiesContext/OwnCapabilitiesContext';
import {
InputMessageInputContextValue,
MessageInputProvider,
useMessageInputContext,
} from '../MessageInputContext';
const Wrapper = ({ messageComposerContextValue, client, props }) => {
return (
{props.children}
);
};
describe("MessageInputContext's sendMessage", () => {
let channel;
let chatClient;
beforeEach(async () => {
const { client, channels } = await initiateClientWithChannels();
channel = channels[0];
chatClient = client;
});
afterEach(() => {
jest.clearAllMocks();
cleanup();
channel.messageComposer.clear();
});
it('should get into the catch block if the message composer compose throws an error', async () => {
const sendMessageMock = jest.fn();
const initialProps = {
sendMessage: sendMessageMock,
};
const consoleErrorMock = jest.spyOn(console, 'error');
const { result } = renderHook(() => useMessageInputContext(), {
initialProps,
wrapper: (props) => (
),
});
const composerComposeMock = jest.spyOn(channel.messageComposer, 'compose');
composerComposeMock.mockRejectedValue(new Error('Error composing message'));
await waitFor(() => {
result.current.sendMessage();
});
await waitFor(() => {
expect(sendMessageMock).not.toHaveBeenCalled();
expect(consoleErrorMock).toHaveBeenCalled();
});
});
it('should get into the catch block if the sendMessage throws an error', async () => {
const sendMessageMock = jest.fn();
sendMessageMock.mockRejectedValue(new Error('Error sending message'));
const initialProps = {
sendMessage: sendMessageMock,
};
const consoleErrorMock = jest.spyOn(console, 'error');
const { result } = renderHook(() => useMessageInputContext(), {
initialProps,
wrapper: (props) => (
),
});
await act(async () => {
const text = 'Hello there';
await channel.messageComposer.textComposer.handleChange({
selection: {
end: text.length,
start: text.length,
},
text,
});
});
await waitFor(() => {
result.current.sendMessage();
});
await waitFor(() => {
expect(sendMessageMock).toHaveBeenCalled();
expect(consoleErrorMock).toHaveBeenCalled();
});
});
it('should not call composer clear if composition has poll id in it', async () => {
const sendMessageMock = jest.fn();
const clearSpy = jest.spyOn(channel.messageComposer, 'clear');
const initialProps = {
sendMessage: sendMessageMock,
};
const { pollComposer } = channel.messageComposer;
jest.spyOn(chatClient, 'createPoll').mockResolvedValue({ poll: { id: 'test-poll-id' } });
const { result } = renderHook(() => useMessageInputContext(), {
initialProps,
wrapper: (props) => (
),
});
await act(async () => {
await pollComposer.updateFields({
id: 'test-poll',
name: 'Test Poll',
options: [
{ id: 1, text: '1' },
{ id: 2, text: '2' },
],
});
await channel.messageComposer.createPoll();
});
await waitFor(() => {
result.current.sendMessage();
});
await waitFor(() => {
expect(clearSpy).not.toHaveBeenCalled();
expect(sendMessageMock).toHaveBeenCalledTimes(1);
});
});
it('should send message', async () => {
const sendMessageMock = jest.fn();
const clearSpy = jest.spyOn(channel.messageComposer, 'clear');
const initialProps = {
sendMessage: sendMessageMock,
};
const { result } = renderHook(() => useMessageInputContext(), {
initialProps,
wrapper: (props) => (
),
});
await act(async () => {
const text = 'Hello there';
await channel.messageComposer.textComposer.handleChange({
selection: {
end: text.length,
start: text.length,
},
text,
});
});
await waitFor(() => {
result.current.sendMessage();
});
await waitFor(() => {
expect(clearSpy).toHaveBeenCalled();
expect(sendMessageMock).toHaveBeenCalledTimes(1);
});
});
});
describe("MessageInputContext's editMessage", () => {
let channel;
let chatClient;
beforeAll(async () => {
const { client, channels } = await initiateClientWithChannels();
channel = channels[0];
chatClient = client;
});
afterEach(() => {
jest.clearAllMocks();
cleanup();
});
it('should clear the edited state when the composition is empty', async () => {
const editMessageMock = jest.fn();
const initialProps = {
editMessage: editMessageMock,
};
const clearEditingStateMock = jest.fn();
jest.spyOn(UseMessageComposerAPIContext, 'useMessageComposerAPIContext').mockReturnValue({
clearEditingState: clearEditingStateMock,
} as unknown as MessageComposerAPIContextValue);
const message = generateMessage({
attachments: [generateLocalFileUploadAttachmentData()],
cid: 'messaging:channel-id',
text: 'test',
}) as LocalMessage;
const { result } = renderHook(() => useMessageInputContext(), {
initialProps,
wrapper: (props) => (
),
});
await waitFor(() => {
result.current.sendMessage();
});
await waitFor(() => {
expect(clearEditingStateMock).toHaveBeenCalled();
});
});
});