Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions package/jest-setup.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ registerNativeHandlers({
unsubscribe: () => {},
}),
pickDocument: () => null,
pickImage: () => null,
saveFile: () => null,
SDK: 'stream-chat-react-native',
shareImage: () => null,
Expand Down
18 changes: 9 additions & 9 deletions package/native-package/yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -3450,10 +3450,10 @@ statuses@~1.5.0:
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==

[email protected].0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/stream-chat-react-native-core/-/stream-chat-react-native-core-7.1.0.tgz#b5002ec967467a2ac4be54700e5e4e60bbd5fd97"
integrity sha512-Rfecu6kH2zBW0ufhVz076NlpOg6QxNgShGnK4js/ypjSZ4rGZIKMFHNuArLVr/uSuTWiVPNO1zMI/LyvljtwdQ==
[email protected].1:
version "7.1.1"
resolved "https://registry.yarnpkg.com/stream-chat-react-native-core/-/stream-chat-react-native-core-7.1.1.tgz#b22faf35fa5defd24c730873aeba30c172556089"
integrity sha512-9AkSKWzywN2FfsMgDfeoCatr/qoG+zJzM2u5j3PU6WU7qIhZtM/7+2UB0WKAY7fA5MjaoMEzV1mBF+hILP1KOw==
dependencies:
"@gorhom/bottom-sheet" "^5.1.1"
dayjs "1.10.5"
Expand All @@ -3466,13 +3466,13 @@ [email protected]:
path "0.12.7"
react-native-markdown-package "1.8.2"
react-native-url-polyfill "^1.3.0"
stream-chat "^9.2.0"
stream-chat "^9.3.0"
use-sync-external-store "^1.4.0"

stream-chat@^9.2.0:
version "9.3.0"
resolved "https://registry.yarnpkg.com/stream-chat/-/stream-chat-9.3.0.tgz#35ca4db9e841eb92d07413ae156de0500ad77b23"
integrity sha512-S73B3HrvmQvJjq58Zjo50vh74juhsWsVRpT+OBjGAxSGxlA+ITkZ3vKs8Y/r2eDK7mBTMmX5QCruFaDJH5dRuw==
stream-chat@^9.3.0:
version "9.5.1"
resolved "https://registry.yarnpkg.com/stream-chat/-/stream-chat-9.5.1.tgz#b8260bc1d1470ae3c91d8c40d22f41e9c4523d7b"
integrity sha512-X9w22JfEp2cTggAwyt0gyvwe8VBy1qvJENliNen/2FJDpS3k6PCaeSO6MHNXz3c0Qy21hqxuu8/b32jCSe4LSA==
dependencies:
"@types/jsonwebtoken" "^9.0.8"
"@types/ws" "^8.5.14"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ const UnMemoizedAutoCompleteSuggestionItem = ({
<Pressable
onPress={handlePress}
style={({ pressed }) => [{ opacity: pressed ? 0.8 : 1 }, itemStyle]}
testID='suggestion-item'
>
<SuggestionItem item={itemProps} triggerType={triggerType} />
</Pressable>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export const AutoCompleteSuggestionList = ({
flatlist,
{ backgroundColor: white, maxHeight, shadowColor: black },
]}
testID={'auto-complete-suggestion-list'}
/>
</View>
);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,69 +1,192 @@
import React from 'react';

import { act, fireEvent, render, waitFor } from '@testing-library/react-native';
import {
act,
cleanup,
fireEvent,
render,
screen,
userEvent,
waitFor,
} from '@testing-library/react-native';

import { getOrCreateChannelApi } from '../../../mock-builders/api/getOrCreateChannel';
import { useMockedApis } from '../../../mock-builders/api/useMockedApis';
import { generateChannelResponse } from '../../../mock-builders/generator/channel';
import { generateUser } from '../../../mock-builders/generator/user';
import { getTestClientWithUser } from '../../../mock-builders/mock';
import { initiateClientWithChannels } from '../../../mock-builders/api/initiateClientWithChannels';
import { Channel } from '../../Channel/Channel';
import { Chat } from '../../Chat/Chat';
import { AutoCompleteInput } from '../AutoCompleteInput';
import { AutoCompleteSuggestionList } from '../AutoCompleteSuggestionList';

const renderComponent = ({ channelProps, client, props }) => {
return render(
<Chat client={client}>
<Channel {...channelProps}>
<AutoCompleteInput {...props} />
</Channel>
</Chat>,
);
};

describe('AutoCompleteInput', () => {
const clientUser = generateUser();
let chatClient;
let client;
let channel;

const getAutoCompleteComponent = () => (
<Chat client={chatClient}>
<Channel channel={channel}>
<AutoCompleteInput />
<AutoCompleteSuggestionList />
</Channel>
</Chat>
);
beforeAll(async () => {
const { client: chatClient, channels } = await initiateClientWithChannels();
client = chatClient;
channel = channels[0];
});

const initializeChannel = async (c) => {
useMockedApis(chatClient, [getOrCreateChannelApi(c)]);
afterEach(() => {
jest.clearAllMocks();
cleanup();
});

channel = chatClient.channel('messaging');
it('should render AutoCompleteInput', async () => {
const channelProps = { channel };
const props = {};

await channel.watch();
};
renderComponent({ channelProps, client, props });

beforeEach(async () => {
chatClient = await getTestClientWithUser(clientUser);
await initializeChannel(generateChannelResponse());
});
const { queryByTestId } = screen;

afterEach(() => {
channel = null;
const input = queryByTestId('auto-complete-text-input');

await waitFor(() => {
expect(input).toBeTruthy();
});
});

it('should render AutoCompleteInput and trigger open/close suggestions with / commands', async () => {
const { queryByTestId } = render(getAutoCompleteComponent());
it('should have the editable prop as false when the message composer config is set', async () => {
const channelProps = { channel };
const props = {};

channel.messageComposer.updateConfig({ text: { enabled: false } });

renderComponent({ channelProps, client, props });

const { queryByTestId } = screen;

const input = queryByTestId('auto-complete-text-input');

const onSelectionChange = input.props.onSelectionChange;
await waitFor(() => {
expect(input.props.editable).toBeFalsy();
});
});

it('should have the maxLength same as the one on the config of channel', async () => {
jest.spyOn(channel, 'getConfig').mockReturnValue({
max_message_length: 10,
});
const channelProps = { channel };
const props = {};

renderComponent({ channelProps, client, props });

const { queryByTestId } = screen;

const input = queryByTestId('auto-complete-text-input');

await waitFor(() => {
expect(input).toBeTruthy();
expect(input.props.maxLength).toBe(10);
});
});

it('should call the textComposer handleChange when the onChangeText is triggered', () => {
const { textComposer } = channel.messageComposer;

const spyHandleChange = jest.spyOn(textComposer, 'handleChange');

const channelProps = { channel };
const props = {};

renderComponent({ channelProps, client, props });

await act(async () => {
await onSelectionChange({
const { queryByTestId } = screen;

const input = queryByTestId('auto-complete-text-input');

act(() => {
userEvent.type(input, 'hello');
});

waitFor(() => {
expect(spyHandleChange).toHaveBeenCalled();
expect(spyHandleChange).toHaveBeenCalledWith({
selection: { end: 5, start: 5 },
text: 'hello',
});
expect(input.props.value).toBe('hello');
});
});

it('should style the text input with maxHeight that is set by the layout', () => {
const channelProps = { channel };
const props = { numberOfLines: 10 };

renderComponent({ channelProps, client, props });

const { queryByTestId } = screen;

const input = queryByTestId('auto-complete-text-input');

act(() => {
fireEvent(input, 'contentSizeChange', {
nativeEvent: {
contentSize: { height: 100 },
},
});
});

waitFor(() => {
expect(input.props.style[1].maxHeight).toBe(1000);
});
});

it('should call the textComposer setSelection when the onSelectionChange is triggered', () => {
const { textComposer } = channel.messageComposer;

const spySetSelection = jest.spyOn(textComposer, 'setSelection');

const channelProps = { channel };
const props = {};

renderComponent({ channelProps, client, props });

const { queryByTestId } = screen;

const input = queryByTestId('auto-complete-text-input');

act(() => {
fireEvent(input, 'selectionChange', {
nativeEvent: {
selection: {
end: 1,
start: 1,
},
selection: { end: 5, start: 5 },
},
});
await fireEvent.changeText(input, '/');
});

waitFor(() => {
expect(spySetSelection).toHaveBeenCalled();
expect(spySetSelection).toHaveBeenCalledWith({ end: 5, start: 5 });
});
});

// TODO: Add a test for command
it.each([
{ cooldownActive: false, result: 'Send a message' },
{ cooldownActive: true, result: 'Slow mode ON' },
])('should have the placeholderText as Slow mode ON when cooldown is active', async (data) => {
const channelProps = { channel };
const props = {
cooldownActive: data.cooldownActive,
};

renderComponent({ channelProps, client, props });

const { queryByTestId } = screen;

const input = queryByTestId('auto-complete-text-input');

await waitFor(() => {
expect(input.props.placeholder).toBe(data.result);
});
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import React from 'react';
import type { SharedValue } from 'react-native-reanimated';

import { act, fireEvent, render, screen, waitFor } from '@testing-library/react-native';
import dayjs from 'dayjs';
import duration from 'dayjs/plugin/duration';

import { LocalMessage } from 'stream-chat';

Expand All @@ -22,6 +24,8 @@ import { generateMessage } from '../../../mock-builders/generator/message';

import { ImageGallery } from '../ImageGallery';

dayjs.extend(duration);

jest.mock('../../../native.ts', () => {
const View = require('react-native/Libraries/Components/View/View');
return {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ describe("SendMessageDisallowedIndicator's edited state", () => {
const message = generateMessage({
attachments: [generateLocalFileUploadAttachmentData()],
cid: 'messaging:channel-id',
text: 'XXX',
text: 'test',
});

const { channel: customChannel, chatClient } = await editedMessageSetup({
Expand Down
Loading
Loading