stream-chat-react-native-core 5.13.0-beta.2 → 5.13.0-beta.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/lib/commonjs/components/MessageInput/AttachButton.js +4 -10
  2. package/lib/commonjs/components/MessageInput/AttachButton.js.map +1 -1
  3. package/lib/commonjs/components/MessageInput/CommandsButton.js +4 -10
  4. package/lib/commonjs/components/MessageInput/CommandsButton.js.map +1 -1
  5. package/lib/commonjs/components/MessageInput/SendButton.js +7 -7
  6. package/lib/commonjs/components/MessageInput/SendButton.js.map +1 -1
  7. package/lib/commonjs/mock-builders/api/sendReaction.js.map +1 -1
  8. package/lib/commonjs/version.json +1 -1
  9. package/lib/module/components/MessageInput/AttachButton.js +4 -10
  10. package/lib/module/components/MessageInput/AttachButton.js.map +1 -1
  11. package/lib/module/components/MessageInput/CommandsButton.js +4 -10
  12. package/lib/module/components/MessageInput/CommandsButton.js.map +1 -1
  13. package/lib/module/components/MessageInput/SendButton.js +7 -7
  14. package/lib/module/components/MessageInput/SendButton.js.map +1 -1
  15. package/lib/module/mock-builders/api/sendReaction.js.map +1 -1
  16. package/lib/module/version.json +1 -1
  17. package/package.json +1 -1
  18. package/src/__tests__/offline-support/index.test.ts +13 -0
  19. package/src/__tests__/offline-support/offline-feature.js +686 -0
  20. package/src/__tests__/offline-support/optimistic-update.js +374 -0
  21. package/src/components/MessageInput/AttachButton.tsx +3 -4
  22. package/src/components/MessageInput/CommandsButton.tsx +3 -4
  23. package/src/components/MessageInput/SendButton.tsx +4 -3
  24. package/src/components/MessageInput/__tests__/__snapshots__/AttachButton.test.js.snap +120 -152
  25. package/src/components/MessageInput/__tests__/__snapshots__/SendButton.test.js.snap +248 -248
  26. package/src/components/Thread/__tests__/__snapshots__/Thread.test.js.snap +182 -214
  27. package/src/version.json +1 -1
  28. package/lib/typescript/components/Attachment/__tests__/openUrlSafely.test.d.ts +0 -1
  29. package/lib/typescript/components/ChannelList/hooks/listeners/__tests__/useChannelUpdated.test.d.ts +0 -1
  30. package/lib/typescript/components/ChannelPreview/__tests__/ChannelPreview.test.d.ts +0 -1
  31. package/lib/typescript/components/ChannelPreview/hooks/__tests__/useChannelPreviewDisplayName.test.d.ts +0 -1
  32. package/lib/typescript/components/ChannelPreview/hooks/__tests__/useLatestMessagePreview.test.d.ts +0 -1
  33. package/lib/typescript/components/Chat/hooks/__tests__/useAppSettings.test.d.ts +0 -1
  34. package/lib/typescript/components/ImageGallery/__tests__/AnimatedVideoGallery.test.d.ts +0 -1
  35. package/lib/typescript/components/ImageGallery/__tests__/ImageGallery.test.d.ts +0 -1
  36. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryFooter.test.d.ts +0 -1
  37. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryGrid.test.d.ts +0 -1
  38. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryGridHandle.test.d.ts +0 -1
  39. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryHeader.test.d.ts +0 -1
  40. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryOverlay.test.d.ts +0 -1
  41. package/lib/typescript/components/ImageGallery/__tests__/ImageGalleryVideoControl.test.d.ts +0 -1
  42. package/lib/typescript/components/ImageGallery/components/__tests__/ImageGalleryHeader.test.d.ts +0 -1
  43. package/lib/typescript/components/Message/MessageSimple/__tests__/MessageTextContainer.test.d.ts +0 -1
  44. package/lib/typescript/components/MessageInput/__tests__/AudioAttachmentUploadPreviewExpo.test.d.ts +0 -1
  45. package/lib/typescript/components/MessageInput/__tests__/AudioAttachmentUploadPreviewNative.test.d.ts +0 -1
  46. package/lib/typescript/components/MessageList/__tests__/useMessageList.test.d.ts +0 -1
  47. package/lib/typescript/components/MessageList/utils/__tests__/getDateSeparators.test.d.ts +0 -1
  48. package/lib/typescript/components/Reply/__tests__/Reply.test.d.ts +0 -1
  49. package/lib/typescript/contexts/__tests__/index.test.d.ts +0 -1
  50. package/lib/typescript/contexts/messageInputContext/__tests__/MessageInputContext.test.d.ts +0 -1
  51. package/lib/typescript/contexts/messageInputContext/__tests__/isValidMessage.test.d.ts +0 -1
  52. package/lib/typescript/contexts/messageInputContext/__tests__/pickFile.test.d.ts +0 -1
  53. package/lib/typescript/contexts/messageInputContext/__tests__/removeFile.test.d.ts +0 -1
  54. package/lib/typescript/contexts/messageInputContext/__tests__/removeImage.test.d.ts +0 -1
  55. package/lib/typescript/contexts/messageInputContext/__tests__/sendMessage.test.d.ts +0 -1
  56. package/lib/typescript/contexts/messageInputContext/__tests__/sendMessageAsync.test.d.ts +0 -1
  57. package/lib/typescript/contexts/messageInputContext/__tests__/updateMessage.test.d.ts +0 -1
  58. package/lib/typescript/contexts/messageInputContext/__tests__/uploadFile.test.d.ts +0 -1
  59. package/lib/typescript/contexts/messageInputContext/__tests__/uploadImage.test.d.ts +0 -1
  60. package/lib/typescript/contexts/messageInputContext/__tests__/useMessageDetailsForState.test.d.ts +0 -1
  61. package/lib/typescript/hooks/__tests__/useAppStateListener.test.d.ts +0 -1
  62. package/lib/typescript/hooks/__tests__/useTranslatedMessage.test.d.ts +0 -1
  63. package/lib/typescript/mock-builders/api/channelMocks.d.ts +0 -14
  64. package/lib/typescript/mock-builders/api/getOrCreateChannel.d.ts +0 -19
  65. package/lib/typescript/mock-builders/api/queryMembers.d.ts +0 -161
  66. package/lib/typescript/mock-builders/api/useMockedApis.d.ts +0 -1
  67. package/lib/typescript/mock-builders/api/utils.d.ts +0 -7
  68. package/lib/typescript/mock-builders/event/messageNew.d.ts +0 -2
  69. package/lib/typescript/mock-builders/event/messageRead.d.ts +0 -8
  70. package/lib/typescript/mock-builders/generator/attachment.d.ts +0 -10
  71. package/lib/typescript/mock-builders/generator/channel.d.ts +0 -120
  72. package/lib/typescript/mock-builders/generator/message.d.ts +0 -38
  73. package/lib/typescript/mock-builders/generator/user.d.ts +0 -30
  74. package/lib/typescript/mock-builders/mock.d.ts +0 -3
  75. package/lib/typescript/store/sqlite-utils/__tests__/createSelectQuery.test.d.ts +0 -1
  76. package/lib/typescript/utils/__tests__/patchMessageTextCommand.test.d.ts +0 -1
  77. package/src/__tests__/offline-feature.test.js +0 -675
  78. package/src/__tests__/optimistic-update.test.js +0 -369
  79. /package/src/mock-builders/api/{sendReaction.tsx → sendReaction.ts} +0 -0
@@ -1,369 +0,0 @@
1
- /* eslint-disable no-underscore-dangle */
2
- import React, { useContext, useEffect, useState } from 'react';
3
- import { View } from 'react-native';
4
-
5
- import { act, cleanup, render, waitFor } from '@testing-library/react-native';
6
-
7
- import { v4 as uuidv4 } from 'uuid';
8
-
9
- import { Channel } from '../components/Channel/Channel';
10
- import { Chat } from '../components/Chat/Chat';
11
- import { MessagesContext } from '../contexts';
12
- import { deleteMessageApi } from '../mock-builders/api/deleteMessage';
13
- import { deleteReactionApi } from '../mock-builders/api/deleteReaction';
14
- import { erroredDeleteApi, erroredPostApi } from '../mock-builders/api/error';
15
- import { getOrCreateChannelApi } from '../mock-builders/api/getOrCreateChannel';
16
- import { sendReactionApi } from '../mock-builders/api/sendReaction';
17
- import { useMockedApis } from '../mock-builders/api/useMockedApis';
18
- import dispatchConnectionChangedEvent from '../mock-builders/event/connectionChanged';
19
- import { generateChannelResponse } from '../mock-builders/generator/channel';
20
- import { generateMember } from '../mock-builders/generator/member';
21
- import { generateMessage } from '../mock-builders/generator/message';
22
- import { generateReaction } from '../mock-builders/generator/reaction';
23
- import { generateUser } from '../mock-builders/generator/user';
24
- import { getTestClientWithUser } from '../mock-builders/mock';
25
- import { upsertChannels } from '../store/apis';
26
- import { QuickSqliteClient } from '../store/QuickSqliteClient';
27
- import { BetterSqlite } from '../test-utils/BetterSqlite';
28
-
29
- describe('Optimistic Updates', () => {
30
- let chatClient;
31
-
32
- const getRandomInt = (lower, upper) => Math.floor(lower + Math.random() * (upper - lower + 1));
33
- const createChannel = () => {
34
- const allUsers = Array(20).fill(1).map(generateUser);
35
- const allMessages = [];
36
- const allMembers = [];
37
- const allReactions = [];
38
- const allReads = [];
39
- const id = uuidv4();
40
- const cid = `messaging:${id}`;
41
- const begin = getRandomInt(0, allUsers.length - 2); // begin shouldn't be the end of users.length
42
- const end = getRandomInt(begin + 1, allUsers.length - 1);
43
- const usersForMembers = allUsers.slice(begin, end);
44
- const members = usersForMembers.map((user) =>
45
- generateMember({
46
- cid,
47
- user,
48
- }),
49
- );
50
- const messages = Array(10)
51
- .fill(1)
52
- .map(() => {
53
- const id = uuidv4();
54
- const user = usersForMembers[getRandomInt(0, usersForMembers.length - 1)];
55
-
56
- const begin = getRandomInt(0, usersForMembers.length - 2); // begin shouldn't be the end of users.length
57
- const end = getRandomInt(begin + 1, usersForMembers.length - 1);
58
-
59
- const usersForReactions = usersForMembers.slice(begin, end);
60
- const reactions = usersForReactions.map((user) =>
61
- generateReaction({
62
- message_id: id,
63
- user,
64
- }),
65
- );
66
- allReactions.push(...reactions);
67
- return generateMessage({
68
- cid,
69
- id,
70
- latest_reactions: reactions,
71
- user,
72
- userId: user.id,
73
- });
74
- });
75
-
76
- const reads = members.map((member) => ({
77
- last_read: new Date(new Date().setDate(new Date().getDate() - getRandomInt(0, 20))),
78
- unread_messages: getRandomInt(0, messages.length),
79
- user: member.user,
80
- }));
81
-
82
- allMessages.push(...messages);
83
- allMembers.push(...members);
84
- allReads.push(...reads);
85
-
86
- return generateChannelResponse({
87
- cid,
88
- id,
89
- members,
90
- messages,
91
- });
92
- };
93
-
94
- beforeEach(async () => {
95
- jest.clearAllMocks();
96
-
97
- chatClient = await getTestClientWithUser({ id: 'dan' });
98
- const channelResponse = createChannel();
99
- useMockedApis(chatClient, [getOrCreateChannelApi(channelResponse)]);
100
- channel = chatClient.channel('messaging', channelResponse.id);
101
- await channel.watch();
102
-
103
- channel.cid = channelResponse.channel.cid;
104
- channel.id = channelResponse.channel.id;
105
-
106
- // Populate the DB with channel
107
- QuickSqliteClient.initializeDatabase();
108
- upsertChannels({
109
- channels: [channelResponse],
110
- isLatestMessagesSet: true,
111
- });
112
- });
113
-
114
- afterEach(() => {
115
- QuickSqliteClient.dropTables();
116
- QuickSqliteClient.closeDB();
117
- cleanup();
118
- });
119
-
120
- let channel;
121
- // This component is used for performing effects in a component that consumes ChannelContext,
122
- // i.e. making use of the callbacks & values provided by the Channel component.
123
- // the effect is called every time channelContext changes
124
- const CallbackEffectWithContext = ({ callback, children, context }) => {
125
- const ctx = useContext(context);
126
- const [ready, setReady] = useState(false);
127
- useEffect(() => {
128
- const call = async () => {
129
- await callback(ctx);
130
- setReady(true);
131
- };
132
-
133
- call();
134
- }, []);
135
-
136
- if (!ready) return null;
137
-
138
- return children;
139
- };
140
-
141
- describe('delete message', () => {
142
- it('pending task should exist if deleteMessage request fails', async () => {
143
- const message = generateMessage();
144
-
145
- const { getByTestId } = render(
146
- <Chat client={chatClient} enableOfflineSupport>
147
- <Channel channel={channel} initialValue={message.text}>
148
- <CallbackEffectWithContext
149
- callback={async ({ deleteMessage }) => {
150
- useMockedApis(chatClient, [erroredPostApi()]);
151
- try {
152
- await deleteMessage(message);
153
- } catch (e) {
154
- // do nothing
155
- }
156
- }}
157
- context={MessagesContext}
158
- >
159
- <View testID='children' />
160
- </CallbackEffectWithContext>
161
- </Channel>
162
- </Chat>,
163
- );
164
- await waitFor(() => expect(getByTestId('children')).toBeTruthy());
165
- await waitFor(() => {
166
- const pendingTasksRows = BetterSqlite.selectFromTable('pendingTasks');
167
- const pendingTaskType = pendingTasksRows?.[0]?.type;
168
- const pendingTaskPayload = JSON.parse(pendingTasksRows?.[0]?.payload || '{}');
169
- expect(pendingTaskType).toBe('delete-message');
170
- expect(pendingTaskPayload[0]).toBe(message.id);
171
- });
172
- });
173
-
174
- it('pending task should be cleared if deleteMessage request is succesful', async () => {
175
- const message = generateMessage();
176
- const { getByTestId } = render(
177
- <Chat client={chatClient} enableOfflineSupport>
178
- <Channel channel={channel} initialValue={message.text}>
179
- <CallbackEffectWithContext
180
- callback={({ deleteMessage }) => {
181
- useMockedApis(chatClient, [deleteMessageApi(message)]);
182
- deleteMessage(message);
183
- }}
184
- context={MessagesContext}
185
- >
186
- <View testID='children' />
187
- </CallbackEffectWithContext>
188
- </Channel>
189
- </Chat>,
190
- );
191
- await waitFor(() => expect(getByTestId('children')).toBeTruthy());
192
- await waitFor(() => {
193
- const pendingTasksRows = BetterSqlite.selectFromTable('pendingTasks');
194
- expect(pendingTasksRows.length).toBe(0);
195
- });
196
- });
197
- });
198
-
199
- describe('send reaction', () => {
200
- it('pending task should exist if sendReaction request fails', async () => {
201
- const reaction = generateReaction();
202
- const targetMessage = channel.state.messages[0];
203
-
204
- const { getByTestId } = render(
205
- <Chat client={chatClient} enableOfflineSupport>
206
- <Channel channel={channel}>
207
- <CallbackEffectWithContext
208
- callback={async ({ sendReaction }) => {
209
- useMockedApis(chatClient, [erroredPostApi()]);
210
- try {
211
- await sendReaction(reaction.type, targetMessage.id);
212
- } catch (e) {
213
- // do nothing
214
- }
215
- }}
216
- context={MessagesContext}
217
- >
218
- <View testID='children' />
219
- </CallbackEffectWithContext>
220
- </Channel>
221
- </Chat>,
222
- );
223
- await waitFor(() => expect(getByTestId('children')).toBeTruthy());
224
- await waitFor(() => {
225
- const pendingTasksRows = BetterSqlite.selectFromTable('pendingTasks');
226
- const pendingTaskType = pendingTasksRows?.[0]?.type;
227
- const pendingTaskPayload = JSON.parse(pendingTasksRows?.[0]?.payload || '{}');
228
- expect(pendingTaskType).toBe('send-reaction');
229
- expect(pendingTaskPayload[0]).toBe(targetMessage.id);
230
- });
231
- });
232
-
233
- it('pending task should be cleared if sendReaction request is succesful', async () => {
234
- const reaction = generateReaction();
235
- const targetMessage = channel.state.messages[0];
236
-
237
- const { getByTestId } = render(
238
- <Chat client={chatClient} enableOfflineSupport>
239
- <Channel channel={channel}>
240
- <CallbackEffectWithContext
241
- callback={({ sendReaction }) => {
242
- useMockedApis(chatClient, [sendReactionApi(targetMessage, reaction)]);
243
- sendReaction(reaction.type, targetMessage.id);
244
- }}
245
- context={MessagesContext}
246
- >
247
- <View testID='children' />
248
- </CallbackEffectWithContext>
249
- </Channel>
250
- </Chat>,
251
- );
252
- await waitFor(() => expect(getByTestId('children')).toBeTruthy());
253
- await waitFor(() => {
254
- const pendingTasksRows = BetterSqlite.selectFromTable('pendingTasks');
255
- expect(pendingTasksRows.length).toBe(0);
256
- });
257
- });
258
- });
259
-
260
- describe('delete reaction', () => {
261
- it('pending task should exist if deleteReaction request fails', async () => {
262
- const reaction = generateReaction();
263
- const targetMessage = channel.state.messages[0];
264
-
265
- const { getByTestId } = render(
266
- <Chat client={chatClient} enableOfflineSupport>
267
- <Channel channel={channel}>
268
- <CallbackEffectWithContext
269
- callback={async ({ deleteReaction }) => {
270
- useMockedApis(chatClient, [erroredPostApi()]);
271
- try {
272
- await deleteReaction(reaction.type, targetMessage.id);
273
- } catch (e) {
274
- // do nothing
275
- }
276
- }}
277
- context={MessagesContext}
278
- >
279
- <View testID='children' />
280
- </CallbackEffectWithContext>
281
- </Channel>
282
- </Chat>,
283
- );
284
- await waitFor(() => expect(getByTestId('children')).toBeTruthy());
285
- await waitFor(() => {
286
- const pendingTasksRows = BetterSqlite.selectFromTable('pendingTasks');
287
- const pendingTaskType = pendingTasksRows?.[0]?.type;
288
- const pendingTaskPayload = JSON.parse(pendingTasksRows?.[0]?.payload || '{}');
289
- expect(pendingTaskType).toBe('delete-reaction');
290
- expect(pendingTaskPayload[0]).toBe(targetMessage.id);
291
- });
292
- });
293
-
294
- it('pending task should be cleared if deleteReaction request is succesful', async () => {
295
- const reaction = generateReaction();
296
- const targetMessage = channel.state.messages[0];
297
-
298
- const { getByTestId } = render(
299
- <Chat client={chatClient} enableOfflineSupport>
300
- <Channel channel={channel}>
301
- <CallbackEffectWithContext
302
- callback={async ({ deleteReaction }) => {
303
- useMockedApis(chatClient, [deleteReactionApi(targetMessage, reaction)]);
304
- await deleteReaction(reaction.type, targetMessage.id);
305
- }}
306
- context={MessagesContext}
307
- >
308
- <View testID='children' />
309
- </CallbackEffectWithContext>
310
- </Channel>
311
- </Chat>,
312
- );
313
- await waitFor(() => expect(getByTestId('children')).toBeTruthy());
314
-
315
- await waitFor(() => {
316
- const pendingTasksRows = BetterSqlite.selectFromTable('pendingTasks');
317
- expect(pendingTasksRows.length).toBe(0);
318
- });
319
- });
320
- });
321
-
322
- it('pending task should be executed after connection is recovered', async () => {
323
- const message = channel.state.messages[0];
324
- const reaction = generateReaction();
325
-
326
- const { getByTestId } = render(
327
- <Chat client={chatClient} enableOfflineSupport>
328
- <Channel channel={channel} initialValue={message.text}>
329
- <CallbackEffectWithContext
330
- callback={async ({ deleteMessage, sendReaction }) => {
331
- useMockedApis(chatClient, [erroredDeleteApi()]);
332
- try {
333
- await deleteMessage(reaction);
334
- } catch (e) {
335
- // do nothing
336
- }
337
-
338
- useMockedApis(chatClient, [erroredPostApi()]);
339
- try {
340
- await sendReaction(reaction.type, message.id);
341
- } catch (e) {
342
- // do nothing
343
- }
344
- }}
345
- context={MessagesContext}
346
- >
347
- <View testID='children' />
348
- </CallbackEffectWithContext>
349
- </Channel>
350
- </Chat>,
351
- );
352
- await waitFor(() => expect(getByTestId('children')).toBeTruthy());
353
-
354
- await waitFor(() => {
355
- const pendingTasksRows = BetterSqlite.selectFromTable('pendingTasks');
356
- expect(pendingTasksRows.length).toBe(2);
357
- });
358
-
359
- chatClient.deleteMessage = jest.fn();
360
- channel.sendReaction = jest.fn();
361
-
362
- act(() => dispatchConnectionChangedEvent(chatClient, true));
363
-
364
- await waitFor(() => {
365
- expect(chatClient.deleteMessage).toHaveBeenCalled();
366
- expect(channel.sendReaction).toHaveBeenCalled();
367
- });
368
- });
369
- });