Skip to content

Commit fe294a2

Browse files
committed
fix: add tests
1 parent 4ec4985 commit fe294a2

File tree

2 files changed

+136
-9
lines changed

2 files changed

+136
-9
lines changed

package/src/components/MessageList/MessageList.tsx

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ import { ThreadContextValue, useThreadContext } from '../../contexts/threadConte
5555

5656
import { DefaultStreamChatGenerics, FileTypes } from '../../types/types';
5757

58-
const WAIT_FOR_SCROLL_TO_OFFSET_TIMEOUT = 150;
58+
const WAIT_FOR_SCROLL_TIMEOUT = 150;
5959
const MAX_RETRIES_AFTER_SCROLL_FAILURE = 10;
6060
const styles = StyleSheet.create({
6161
container: {
@@ -520,7 +520,7 @@ const MessageListWithContext = <
520520
flatListRef.current?.scrollToOffset({
521521
offset: 0,
522522
});
523-
}, 50);
523+
}, WAIT_FOR_SCROLL_TIMEOUT);
524524
setTimeout(() => {
525525
channelResyncScrollSet.current = true;
526526
if (channel.countUnread() > 0) {
@@ -577,7 +577,7 @@ const MessageListWithContext = <
577577
animated: true,
578578
offset: 0,
579579
});
580-
}, WAIT_FOR_SCROLL_TO_OFFSET_TIMEOUT); // flatlist might take a bit to update, so a small delay is needed
580+
}, WAIT_FOR_SCROLL_TIMEOUT); // flatlist might take a bit to update, so a small delay is needed
581581
}
582582
}
583583
// eslint-disable-next-line react-hooks/exhaustive-deps
@@ -588,16 +588,15 @@ const MessageListWithContext = <
588588
* Note: This effect fires on every list change with a small debounce so that scrolling isnt abrupted by an immediate rerender
589589
*/
590590
useEffect(() => {
591+
if (!targetedMessage) return;
591592
scrollToDebounceTimeoutRef.current = setTimeout(async () => {
592-
const messageIdToScroll: string | undefined = targetedMessage;
593-
if (!messageIdToScroll) return;
594593
const indexOfParentInMessageList = processedMessageList.findIndex(
595-
(message) => message?.id === messageIdToScroll,
594+
(message) => message?.id === targetedMessage,
596595
);
597596

598597
// the message we want to scroll to has not been loaded in the state yet
599598
if (indexOfParentInMessageList === -1) {
600-
await loadChannelAroundMessage({ messageId: messageIdToScroll, setTargetedMessage });
599+
await loadChannelAroundMessage({ messageId: targetedMessage, setTargetedMessage });
601600
} else {
602601
if (!flatListRef.current) return;
603602
// By a fresh scroll we should clear the retries for the previous failed scroll
@@ -613,7 +612,7 @@ const MessageListWithContext = <
613612
});
614613
setTargetedMessage(undefined);
615614
}
616-
}, WAIT_FOR_SCROLL_TO_OFFSET_TIMEOUT);
615+
}, WAIT_FOR_SCROLL_TIMEOUT);
617616

618617
// eslint-disable-next-line react-hooks/exhaustive-deps
619618
}, [targetedMessage]);
@@ -895,7 +894,7 @@ const MessageListWithContext = <
895894
scrollToIndexFailedRetryCountRef.current += 1;
896895
onScrollToIndexFailedRef.current(info);
897896
}
898-
}, WAIT_FOR_SCROLL_TO_OFFSET_TIMEOUT);
897+
}, WAIT_FOR_SCROLL_TIMEOUT);
899898

900899
// Only when index is greater than 0 and in range of items in FlatList
901900
// this onScrollToIndexFailed will be called again

package/src/components/MessageList/__tests__/MessageList.test.js

Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import { channelInitialState } from '../../Channel/hooks/useChannelDataState';
1818
import * as MessageListPaginationHook from '../../Channel/hooks/useMessageListPagination';
1919
import { Chat } from '../../Chat/Chat';
2020
import { MessageList } from '../MessageList';
21+
import { FlatList } from 'react-native';
2122

2223
describe('MessageList', () => {
2324
afterEach(cleanup);
@@ -465,6 +466,133 @@ describe('MessageList', () => {
465466
expect(queryByLabelText('Inline unread indicator')).not.toBeTruthy();
466467
});
467468
});
469+
470+
it('should call markRead function when message.new event is dispatched and new messages are received', async () => {
471+
const user = generateUser();
472+
const mockedChannel = generateChannelResponse({
473+
members: [generateMember({ user })],
474+
});
475+
476+
const chatClient = await getTestClientWithUser({ id: user.id });
477+
useMockedApis(chatClient, [getOrCreateChannelApi(mockedChannel)]);
478+
const channel = chatClient.channel('messaging', mockedChannel.id);
479+
await channel.watch();
480+
481+
const user2 = generateUser();
482+
const newMessage = generateMessage({ user: user2 });
483+
484+
const markReadFn = jest.fn();
485+
486+
render(
487+
<OverlayProvider>
488+
<Chat client={chatClient}>
489+
<Channel channel={channel}>
490+
<MessageList markRead={markReadFn} />
491+
</Channel>
492+
</Chat>
493+
</OverlayProvider>,
494+
);
495+
496+
act(() => dispatchMessageNewEvent(chatClient, newMessage, mockedChannel.channel));
497+
498+
await waitFor(() => {
499+
expect(markReadFn).toHaveBeenCalledTimes(1);
500+
});
501+
});
502+
503+
it("should scroll to the targeted message if it's present in the list", async () => {
504+
const user = generateUser();
505+
const mockedChannel = generateChannelResponse({
506+
members: [generateMember({ user })],
507+
});
508+
509+
const messages = Array.from({ length: 30 }, (_, i) =>
510+
generateMessage({ id: `${i}`, text: `message-${i}` }),
511+
);
512+
513+
const chatClient = await getTestClientWithUser({ id: user.id });
514+
useMockedApis(chatClient, [getOrCreateChannelApi(mockedChannel)]);
515+
const channel = chatClient.channel('messaging', mockedChannel.id);
516+
await channel.watch();
517+
518+
const targetedMessage = messages[15].id;
519+
520+
channel.state = {
521+
...channelInitialState,
522+
latestMessages: [],
523+
messages,
524+
};
525+
526+
const flatListRefMock = jest
527+
.spyOn(FlatList.prototype, 'scrollToIndex')
528+
.mockImplementation(() => {});
529+
530+
render(
531+
<OverlayProvider>
532+
<Chat client={chatClient}>
533+
<Channel channel={channel}>
534+
<MessageList targetedMessage={targetedMessage} />
535+
</Channel>
536+
</Chat>
537+
</OverlayProvider>,
538+
);
539+
540+
await waitFor(() => {
541+
expect(flatListRefMock).toHaveBeenCalledWith({
542+
animated: false,
543+
index: 14,
544+
viewPosition: 0.5,
545+
});
546+
});
547+
});
548+
549+
it("should load more messages around the message id if the targeted message isn't present in the list", async () => {
550+
const user = generateUser();
551+
const mockedChannel = generateChannelResponse({
552+
members: [generateMember({ user })],
553+
});
554+
555+
const messages = Array.from({ length: 20 }, (_, i) =>
556+
generateMessage({ id: `${i}`, text: `message-${i}` }),
557+
);
558+
559+
const chatClient = await getTestClientWithUser({ id: user.id });
560+
useMockedApis(chatClient, [getOrCreateChannelApi(mockedChannel)]);
561+
const channel = chatClient.channel('messaging', mockedChannel.id);
562+
await channel.watch();
563+
564+
const targetedMessage = 21;
565+
const setTargetedMessage = jest.fn();
566+
567+
channel.state = {
568+
...channelInitialState,
569+
latestMessages: [],
570+
messages,
571+
};
572+
573+
const loadChannelAroundMessage = jest.fn(() => Promise.resolve());
574+
575+
render(
576+
<OverlayProvider>
577+
<Chat client={chatClient}>
578+
<Channel channel={channel}>
579+
<MessageList
580+
targetedMessage={targetedMessage}
581+
loadChannelAroundMessage={loadChannelAroundMessage}
582+
setTargetedMessage={setTargetedMessage}
583+
/>
584+
</Channel>
585+
</Chat>
586+
</OverlayProvider>,
587+
);
588+
589+
await waitFor(() => {
590+
expect(loadChannelAroundMessage).toHaveBeenCalledWith({
591+
messageId: targetedMessage,
592+
setTargetedMessage,
593+
});
594+
});
595+
});
468596
});
469597

470598
describe('MessageList pagination', () => {

0 commit comments

Comments
 (0)