Skip to content

Commit d812160

Browse files
committed
test: add test for message input context and few other components/utils
1 parent 3c2aa69 commit d812160

File tree

13 files changed

+758
-615
lines changed

13 files changed

+758
-615
lines changed

package/jest-setup.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ registerNativeHandlers({
2525
unsubscribe: () => {},
2626
}),
2727
pickDocument: () => null,
28+
pickImage: () => null,
2829
saveFile: () => null,
2930
SDK: 'stream-chat-react-native',
3031
shareImage: () => null,

package/native-package/yarn.lock

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3450,10 +3450,10 @@ statuses@~1.5.0:
34503450
resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c"
34513451
integrity sha512-OpZ3zP+jT1PI7I8nemJX4AKmAX070ZkYPVWV/AaKTJl+tXCTGyVdC1a4SL8RUQYEwk/f34ZX8UTykN68FwrqAA==
34523452

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

3472-
stream-chat@^9.2.0:
3473-
version "9.3.0"
3474-
resolved "https://registry.yarnpkg.com/stream-chat/-/stream-chat-9.3.0.tgz#35ca4db9e841eb92d07413ae156de0500ad77b23"
3475-
integrity sha512-S73B3HrvmQvJjq58Zjo50vh74juhsWsVRpT+OBjGAxSGxlA+ITkZ3vKs8Y/r2eDK7mBTMmX5QCruFaDJH5dRuw==
3472+
stream-chat@^9.3.0:
3473+
version "9.5.1"
3474+
resolved "https://registry.yarnpkg.com/stream-chat/-/stream-chat-9.5.1.tgz#b8260bc1d1470ae3c91d8c40d22f41e9c4523d7b"
3475+
integrity sha512-X9w22JfEp2cTggAwyt0gyvwe8VBy1qvJENliNen/2FJDpS3k6PCaeSO6MHNXz3c0Qy21hqxuu8/b32jCSe4LSA==
34763476
dependencies:
34773477
"@types/jsonwebtoken" "^9.0.8"
34783478
"@types/ws" "^8.5.14"

package/src/components/AutoCompleteInput/AutoCompleteSuggestionItem.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ const UnMemoizedAutoCompleteSuggestionItem = ({
134134
<Pressable
135135
onPress={handlePress}
136136
style={({ pressed }) => [{ opacity: pressed ? 0.8 : 1 }, itemStyle]}
137+
testID='suggestion-item'
137138
>
138139
<SuggestionItem item={itemProps} triggerType={triggerType} />
139140
</Pressable>

package/src/components/AutoCompleteInput/AutoCompleteSuggestionList.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,7 @@ export const AutoCompleteSuggestionList = ({
9999
flatlist,
100100
{ backgroundColor: white, maxHeight, shadowColor: black },
101101
]}
102+
testID={'auto-complete-suggestion-list'}
102103
/>
103104
</View>
104105
);
Lines changed: 162 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,69 +1,192 @@
11
import React from 'react';
22

3-
import { act, fireEvent, render, waitFor } from '@testing-library/react-native';
3+
import {
4+
act,
5+
cleanup,
6+
fireEvent,
7+
render,
8+
screen,
9+
userEvent,
10+
waitFor,
11+
} from '@testing-library/react-native';
412

5-
import { getOrCreateChannelApi } from '../../../mock-builders/api/getOrCreateChannel';
6-
import { useMockedApis } from '../../../mock-builders/api/useMockedApis';
7-
import { generateChannelResponse } from '../../../mock-builders/generator/channel';
8-
import { generateUser } from '../../../mock-builders/generator/user';
9-
import { getTestClientWithUser } from '../../../mock-builders/mock';
13+
import { initiateClientWithChannels } from '../../../mock-builders/api/initiateClientWithChannels';
1014
import { Channel } from '../../Channel/Channel';
1115
import { Chat } from '../../Chat/Chat';
1216
import { AutoCompleteInput } from '../AutoCompleteInput';
13-
import { AutoCompleteSuggestionList } from '../AutoCompleteSuggestionList';
17+
18+
const renderComponent = ({ channelProps, client, props }) => {
19+
return render(
20+
<Chat client={client}>
21+
<Channel {...channelProps}>
22+
<AutoCompleteInput {...props} />
23+
</Channel>
24+
</Chat>,
25+
);
26+
};
1427

1528
describe('AutoCompleteInput', () => {
16-
const clientUser = generateUser();
17-
let chatClient;
29+
let client;
1830
let channel;
1931

20-
const getAutoCompleteComponent = () => (
21-
<Chat client={chatClient}>
22-
<Channel channel={channel}>
23-
<AutoCompleteInput />
24-
<AutoCompleteSuggestionList />
25-
</Channel>
26-
</Chat>
27-
);
32+
beforeAll(async () => {
33+
const { client: chatClient, channels } = await initiateClientWithChannels();
34+
client = chatClient;
35+
channel = channels[0];
36+
});
2837

29-
const initializeChannel = async (c) => {
30-
useMockedApis(chatClient, [getOrCreateChannelApi(c)]);
38+
afterEach(() => {
39+
jest.clearAllMocks();
40+
cleanup();
41+
});
3142

32-
channel = chatClient.channel('messaging');
43+
it('should render AutoCompleteInput', async () => {
44+
const channelProps = { channel };
45+
const props = {};
3346

34-
await channel.watch();
35-
};
47+
renderComponent({ channelProps, client, props });
3648

37-
beforeEach(async () => {
38-
chatClient = await getTestClientWithUser(clientUser);
39-
await initializeChannel(generateChannelResponse());
40-
});
49+
const { queryByTestId } = screen;
4150

42-
afterEach(() => {
43-
channel = null;
51+
const input = queryByTestId('auto-complete-text-input');
52+
53+
await waitFor(() => {
54+
expect(input).toBeTruthy();
55+
});
4456
});
4557

46-
it('should render AutoCompleteInput and trigger open/close suggestions with / commands', async () => {
47-
const { queryByTestId } = render(getAutoCompleteComponent());
58+
it('should have the editable prop as false when the message composer config is set', async () => {
59+
const channelProps = { channel };
60+
const props = {};
61+
62+
channel.messageComposer.updateConfig({ text: { enabled: false } });
63+
64+
renderComponent({ channelProps, client, props });
65+
66+
const { queryByTestId } = screen;
4867

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

51-
const onSelectionChange = input.props.onSelectionChange;
70+
await waitFor(() => {
71+
expect(input.props.editable).toBeFalsy();
72+
});
73+
});
74+
75+
it('should have the maxLength same as the one on the config of channel', async () => {
76+
jest.spyOn(channel, 'getConfig').mockReturnValue({
77+
max_message_length: 10,
78+
});
79+
const channelProps = { channel };
80+
const props = {};
81+
82+
renderComponent({ channelProps, client, props });
83+
84+
const { queryByTestId } = screen;
85+
86+
const input = queryByTestId('auto-complete-text-input');
5287

5388
await waitFor(() => {
54-
expect(input).toBeTruthy();
89+
expect(input.props.maxLength).toBe(10);
5590
});
91+
});
92+
93+
it('should call the textComposer handleChange when the onChangeText is triggered', () => {
94+
const { textComposer } = channel.messageComposer;
95+
96+
const spyHandleChange = jest.spyOn(textComposer, 'handleChange');
97+
98+
const channelProps = { channel };
99+
const props = {};
100+
101+
renderComponent({ channelProps, client, props });
56102

57-
await act(async () => {
58-
await onSelectionChange({
103+
const { queryByTestId } = screen;
104+
105+
const input = queryByTestId('auto-complete-text-input');
106+
107+
act(() => {
108+
userEvent.type(input, 'hello');
109+
});
110+
111+
waitFor(() => {
112+
expect(spyHandleChange).toHaveBeenCalled();
113+
expect(spyHandleChange).toHaveBeenCalledWith({
114+
selection: { end: 5, start: 5 },
115+
text: 'hello',
116+
});
117+
expect(input.props.value).toBe('hello');
118+
});
119+
});
120+
121+
it('should style the text input with maxHeight that is set by the layout', () => {
122+
const channelProps = { channel };
123+
const props = { numberOfLines: 10 };
124+
125+
renderComponent({ channelProps, client, props });
126+
127+
const { queryByTestId } = screen;
128+
129+
const input = queryByTestId('auto-complete-text-input');
130+
131+
act(() => {
132+
fireEvent(input, 'contentSizeChange', {
133+
nativeEvent: {
134+
contentSize: { height: 100 },
135+
},
136+
});
137+
});
138+
139+
waitFor(() => {
140+
expect(input.props.style[1].maxHeight).toBe(1000);
141+
});
142+
});
143+
144+
it('should call the textComposer setSelection when the onSelectionChange is triggered', () => {
145+
const { textComposer } = channel.messageComposer;
146+
147+
const spySetSelection = jest.spyOn(textComposer, 'setSelection');
148+
149+
const channelProps = { channel };
150+
const props = {};
151+
152+
renderComponent({ channelProps, client, props });
153+
154+
const { queryByTestId } = screen;
155+
156+
const input = queryByTestId('auto-complete-text-input');
157+
158+
act(() => {
159+
fireEvent(input, 'selectionChange', {
59160
nativeEvent: {
60-
selection: {
61-
end: 1,
62-
start: 1,
63-
},
161+
selection: { end: 5, start: 5 },
64162
},
65163
});
66-
await fireEvent.changeText(input, '/');
164+
});
165+
166+
waitFor(() => {
167+
expect(spySetSelection).toHaveBeenCalled();
168+
expect(spySetSelection).toHaveBeenCalledWith({ end: 5, start: 5 });
169+
});
170+
});
171+
172+
// TODO: Add a test for command
173+
it.each([
174+
{ cooldownActive: false, result: 'Send a message' },
175+
{ cooldownActive: true, result: 'Slow mode ON' },
176+
])('should have the placeholderText as Slow mode ON when cooldown is active', async (data) => {
177+
const channelProps = { channel };
178+
const props = {
179+
cooldownActive: data.cooldownActive,
180+
};
181+
182+
renderComponent({ channelProps, client, props });
183+
184+
const { queryByTestId } = screen;
185+
186+
const input = queryByTestId('auto-complete-text-input');
187+
188+
await waitFor(() => {
189+
expect(input.props.placeholder).toBe(data.result);
67190
});
68191
});
69192
});

package/src/components/AutoCompleteInput/__tests__/AutoCompleteSuggestionList.test.js

Whitespace-only changes.

package/src/components/ImageGallery/__tests__/ImageGallery.test.tsx

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ import React from 'react';
33
import type { SharedValue } from 'react-native-reanimated';
44

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

79
import { LocalMessage } from 'stream-chat';
810

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

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

27+
dayjs.extend(duration);
28+
2529
jest.mock('../../../native.ts', () => {
2630
const View = require('react-native/Libraries/Components/View/View');
2731
return {

package/src/components/MessageInput/__tests__/SendMessageDisallowedIndicator.test.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -149,7 +149,7 @@ describe("SendMessageDisallowedIndicator's edited state", () => {
149149
const message = generateMessage({
150150
attachments: [generateLocalFileUploadAttachmentData()],
151151
cid: 'messaging:channel-id',
152-
text: 'XXX',
152+
text: 'test',
153153
});
154154

155155
const { channel: customChannel, chatClient } = await editedMessageSetup({

0 commit comments

Comments
 (0)