import React from 'react';
import { Alert } from 'react-native';
import { cleanup, renderHook, waitFor } from '@testing-library/react-native';
import { Chat } from '../../../components';
import { initiateClientWithChannels } from '../../../mock-builders/api/initiateClientWithChannels';
import { generateFileReference } from '../../../mock-builders/attachments';
import { NativeHandlers } from '../../../native';
import { AttachmentPickerProvider } from '../../attachmentPickerContext/AttachmentPickerContext';
import { ChannelContextValue, ChannelProvider } from '../../channelContext/ChannelContext';
import { MessageComposerProvider } from '../../messageComposerContext/MessageComposerContext';
import {
InputMessageInputContextValue,
MessageInputProvider,
useMessageInputContext,
} from '../MessageInputContext';
jest.spyOn(Alert, 'alert');
const Wrapper = ({ channel, client, props }) => {
return (
{props.children}
);
};
describe("MessageInputContext's pickFile", () => {
let channel;
let chatClient;
beforeEach(async () => {
const { client, channels } = await initiateClientWithChannels();
channel = channels[0];
chatClient = client;
});
afterEach(() => {
jest.clearAllMocks();
cleanup();
});
const initialProps = {};
it('run pickFile when availableUploadSlots is 0 and alert is triggered 1 number of times', async () => {
jest
.spyOn(channel.messageComposer.attachmentManager, 'availableUploadSlots', 'get')
.mockReturnValue(0);
const { result } = renderHook(() => useMessageInputContext(), {
initialProps,
wrapper: (props) => ,
});
await waitFor(() => {
result.current.pickFile();
});
expect(Alert.alert).toHaveBeenCalledTimes(1);
expect(Alert.alert).toHaveBeenCalledWith('Maximum number of files reached');
});
it.each([
[false, undefined, true],
[false, undefined, false],
[false, [generateFileReference(), generateFileReference()], true],
[false, [], false],
[true, [generateFileReference(), generateFileReference()], false],
])(
'allow uploads %p when pickDocument returns assets %p and cancelled %p',
async (allowed, assets, cancelled) => {
const { attachmentManager } = channel.messageComposer;
jest.spyOn(NativeHandlers, 'pickDocument').mockImplementation(
jest.fn().mockResolvedValue({
assets,
cancelled,
}),
);
jest.spyOn(attachmentManager, 'availableUploadSlots', 'get').mockReturnValue(2);
const { result } = renderHook(() => useMessageInputContext(), {
initialProps,
wrapper: (props) => ,
});
const uploadFilesSpy = jest.spyOn(attachmentManager, 'uploadFiles');
await waitFor(() => {
result.current.pickFile();
});
await waitFor(() => {
expect(NativeHandlers.pickDocument).toHaveBeenCalledTimes(1);
expect(NativeHandlers.pickDocument).toHaveBeenCalledWith({ maxNumberOfFiles: 2 });
if (allowed) {
expect(uploadFilesSpy).toHaveBeenCalledTimes(2);
} else {
expect(uploadFilesSpy).not.toHaveBeenCalled();
}
});
},
);
});
describe("MessageInputContext's pickAndUploadImageFromNativePicker", () => {
let channel;
let chatClient;
beforeEach(async () => {
const { client, channels } = await initiateClientWithChannels();
channel = channels[0];
chatClient = client;
});
afterEach(() => {
jest.clearAllMocks();
cleanup();
});
const initialProps = {};
it('run pickAndUploadImageFromNativePicker when availableUploadSlots is 0 and alert is triggered 1 number of times', async () => {
jest
.spyOn(channel.messageComposer.attachmentManager, 'availableUploadSlots', 'get')
.mockReturnValue(0);
const { result } = renderHook(() => useMessageInputContext(), {
initialProps,
wrapper: (props) => ,
});
await waitFor(() => {
result.current.pickAndUploadImageFromNativePicker();
});
expect(Alert.alert).toHaveBeenCalledTimes(1);
expect(Alert.alert).toHaveBeenCalledWith('Maximum number of files reached');
});
it('should show permissions alert when askToOpenSettings is true', async () => {
jest
.spyOn(channel.messageComposer.attachmentManager, 'availableUploadSlots', 'get')
.mockReturnValue(2);
jest.spyOn(NativeHandlers, 'pickImage').mockImplementation(
jest.fn().mockResolvedValue({
askToOpenSettings: true,
}),
);
const { result } = renderHook(() => useMessageInputContext(), {
initialProps,
wrapper: (props) => ,
});
await waitFor(() => {
result.current.pickAndUploadImageFromNativePicker();
});
expect(Alert.alert).toHaveBeenCalledTimes(1);
});
it.each([
[false, undefined, true],
[false, undefined, false],
[false, [generateFileReference(), generateFileReference()], true],
[false, [], false],
[true, [generateFileReference(), generateFileReference()], false],
])(
'allow uploads %p when pickImage returns assets %p and cancelled %p',
async (allowed, assets, cancelled) => {
const { attachmentManager } = channel.messageComposer;
jest.spyOn(NativeHandlers, 'pickImage').mockImplementation(
jest.fn().mockResolvedValue({
assets,
cancelled,
}),
);
jest.spyOn(attachmentManager, 'availableUploadSlots', 'get').mockReturnValue(2);
const { result } = renderHook(() => useMessageInputContext(), {
initialProps,
wrapper: (props) => ,
});
const uploadFilesSpy = jest.spyOn(attachmentManager, 'uploadFiles');
await waitFor(() => {
result.current.pickAndUploadImageFromNativePicker();
});
await waitFor(() => {
expect(NativeHandlers.pickImage).toHaveBeenCalledTimes(1);
if (allowed) {
expect(uploadFilesSpy).toHaveBeenCalledTimes(2);
} else {
expect(uploadFilesSpy).not.toHaveBeenCalled();
}
});
},
);
it('does not crash when pickImage returns an asset with a null mime type', async () => {
const { attachmentManager } = channel.messageComposer;
jest.spyOn(NativeHandlers, 'pickImage').mockImplementation(
jest.fn().mockResolvedValue({
assets: [
{
duration: 0,
height: 100,
name: 'IMG_0001',
size: 123,
type: null,
uri: 'file:///tmp/IMG_0001',
width: 200,
},
],
cancelled: false,
}),
);
jest.spyOn(attachmentManager, 'availableUploadSlots', 'get').mockReturnValue(2);
const { result } = renderHook(() => useMessageInputContext(), {
initialProps,
wrapper: (props) => ,
});
const uploadFilesSpy = jest.spyOn(attachmentManager, 'uploadFiles');
await waitFor(() => {
result.current.pickAndUploadImageFromNativePicker();
});
await waitFor(() => {
expect(uploadFilesSpy).toHaveBeenCalledWith([
expect.objectContaining({
type: 'image/*',
}),
]);
});
});
});
describe("MessageInputContext's takeAndUploadImage", () => {
let channel;
let chatClient;
beforeEach(async () => {
const { client, channels } = await initiateClientWithChannels();
channel = channels[0];
chatClient = client;
});
afterEach(() => {
jest.clearAllMocks();
cleanup();
});
const initialProps = {};
it('run takeAndUploadImage when availableUploadSlots is 0 and alert is triggered 1 number of times', async () => {
jest
.spyOn(channel.messageComposer.attachmentManager, 'availableUploadSlots', 'get')
.mockReturnValue(0);
const { result } = renderHook(() => useMessageInputContext(), {
initialProps,
wrapper: (props) => ,
});
await waitFor(() => {
result.current.takeAndUploadImage();
});
expect(Alert.alert).toHaveBeenCalledTimes(1);
expect(Alert.alert).toHaveBeenCalledWith('Maximum number of files reached');
});
it('should show permissions alert when askToOpenSettings is true', async () => {
jest
.spyOn(channel.messageComposer.attachmentManager, 'availableUploadSlots', 'get')
.mockReturnValue(2);
jest.spyOn(NativeHandlers, 'takePhoto').mockImplementation(
jest.fn().mockResolvedValue({
askToOpenSettings: true,
}),
);
const { result } = renderHook(() => useMessageInputContext(), {
initialProps,
wrapper: (props) => ,
});
await waitFor(() => {
result.current.takeAndUploadImage();
});
expect(Alert.alert).toHaveBeenCalledTimes(1);
});
it.each([
[false, undefined, true],
[false, undefined, false],
[false, generateFileReference(), true],
[false, [], false],
[true, generateFileReference(), false],
])(
'allow uploads %p when pickImage returns assets %p and cancelled %p',
async (allowed, asset, cancelled) => {
const { attachmentManager } = channel.messageComposer;
jest.spyOn(NativeHandlers, 'takePhoto').mockImplementation(
jest.fn().mockResolvedValue({
...asset,
cancelled,
}),
);
jest.spyOn(attachmentManager, 'availableUploadSlots', 'get').mockReturnValue(2);
const { result } = renderHook(() => useMessageInputContext(), {
initialProps,
wrapper: (props) => ,
});
const uploadFilesSpy = jest.spyOn(attachmentManager, 'uploadFiles');
await waitFor(() => {
result.current.takeAndUploadImage();
});
await waitFor(() => {
expect(NativeHandlers.takePhoto).toHaveBeenCalledTimes(1);
expect(NativeHandlers.takePhoto).toHaveBeenCalledWith({
compressImageQuality: undefined,
mediaType: undefined,
});
if (allowed) {
expect(uploadFilesSpy).toHaveBeenCalledTimes(1);
} else {
expect(uploadFilesSpy).not.toHaveBeenCalled();
}
});
},
);
});