11import React , { useContext , useEffect } from 'react' ;
22import { View } from 'react-native' ;
33
4- import { cleanup , render , waitFor } from '@testing-library/react-native' ;
4+ import { act , cleanup , render , renderHook , waitFor } from '@testing-library/react-native' ;
55import { StreamChat } from 'stream-chat' ;
66
77import { ChannelContext , ChannelProvider } from '../../../contexts/channelContext/ChannelContext' ;
@@ -15,6 +15,7 @@ import { ThreadContext, ThreadProvider } from '../../../contexts/threadContext/T
1515
1616import { getOrCreateChannelApi } from '../../../mock-builders/api/getOrCreateChannel' ;
1717import { useMockedApis } from '../../../mock-builders/api/useMockedApis' ;
18+ import dispatchConnectionChanged from '../../../mock-builders/event/connectionChanged' ;
1819import { generateChannelResponse } from '../../../mock-builders/generator/channel' ;
1920import { generateMember } from '../../../mock-builders/generator/member' ;
2021import { generateMessage } from '../../../mock-builders/generator/message' ;
@@ -23,6 +24,11 @@ import { getTestClientWithUser } from '../../../mock-builders/mock';
2324import { Attachment } from '../../Attachment/Attachment' ;
2425import { Chat } from '../../Chat/Chat' ;
2526import { Channel } from '../Channel' ;
27+ import {
28+ channelInitialState ,
29+ useChannelDataState ,
30+ useChannelMessageDataState ,
31+ } from '../hooks/useChannelDataState' ;
2632
2733// This component is used for performing effects in a component that consumes ChannelContext,
2834// i.e. making use of the callbacks & values provided by the Channel component.
@@ -328,3 +334,240 @@ describe('Channel', () => {
328334 } ) ;
329335 } ) ;
330336} ) ;
337+
338+ describe ( 'Channel initial load useEffect' , ( ) => {
339+ let chatClient ;
340+
341+ const renderComponent = ( props = { } ) =>
342+ render (
343+ < Chat client = { chatClient } >
344+ < Channel { ...props } > { props . children } </ Channel >
345+ </ Chat > ,
346+ ) ;
347+
348+ beforeEach ( async ( ) => {
349+ chatClient = await getTestClientWithUser ( user ) ;
350+ } ) ;
351+
352+ afterEach ( ( ) => {
353+ jest . clearAllMocks ( ) ;
354+ cleanup ( ) ;
355+ } ) ;
356+
357+ it ( 'should not call channel.watch if channel is not initialized' , async ( ) => {
358+ const messages = Array . from ( { length : 10 } , ( _ , i ) => generateMessage ( { id : i } ) ) ;
359+ const mockedChannel = generateChannelResponse ( {
360+ messages,
361+ } ) ;
362+
363+ useMockedApis ( chatClient , [ getOrCreateChannelApi ( mockedChannel ) ] ) ;
364+ const channel = chatClient . channel ( 'messaging' , mockedChannel . id ) ;
365+ await channel . watch ( ) ;
366+ channel . offlineMode = true ;
367+ channel . state = channelInitialState ;
368+ const watchSpy = jest . fn ( ) ;
369+ channel . watch = watchSpy ;
370+
371+ renderComponent ( { channel } ) ;
372+
373+ await waitFor ( ( ) => expect ( watchSpy ) . not . toHaveBeenCalled ( ) ) ;
374+ } ) ;
375+
376+ it ( "should call channel.watch if channel is initialized and it's not in offline mode" , async ( ) => {
377+ const messages = Array . from ( { length : 10 } , ( _ , i ) => generateMessage ( { id : i } ) ) ;
378+ const mockedChannel = generateChannelResponse ( {
379+ messages,
380+ } ) ;
381+
382+ useMockedApis ( chatClient , [ getOrCreateChannelApi ( mockedChannel ) ] ) ;
383+ const channel = chatClient . channel ( 'messaging' , mockedChannel . id ) ;
384+ await channel . watch ( ) ;
385+
386+ channel . state = {
387+ ...channelInitialState ,
388+ members : Object . fromEntries (
389+ Array . from ( { length : 10 } , ( _ , i ) => [ i , generateMember ( { id : i } ) ] ) ,
390+ ) ,
391+ messagePagination : {
392+ hasPrev : true ,
393+ } ,
394+ messages : Array . from ( { length : 10 } , ( _ , i ) => generateMessage ( { id : i } ) ) ,
395+ } ;
396+ const watchSpy = jest . fn ( ) ;
397+
398+ channel . offlineMode = false ;
399+ channel . initialied = false ;
400+ channel . watch = watchSpy ;
401+
402+ renderComponent ( { channel } ) ;
403+
404+ const { result : channelMessageState } = renderHook ( ( ) => useChannelMessageDataState ( channel ) ) ;
405+ const { result : channelState } = renderHook ( ( ) => useChannelDataState ( channel ) ) ;
406+
407+ await waitFor ( ( ) => expect ( watchSpy ) . toHaveBeenCalled ( ) ) ;
408+ await waitFor ( ( ) => expect ( channelMessageState . current . state . messages ) . toHaveLength ( 10 ) ) ;
409+ await waitFor ( ( ) => expect ( Object . keys ( channelState . current . state . members ) ) . toHaveLength ( 10 ) ) ;
410+ } ) ;
411+
412+ function getElementsAround ( array , key , id ) {
413+ const index = array . findIndex ( ( obj ) => obj [ key ] === id ) ;
414+
415+ if ( index === - 1 ) {
416+ return [ ] ;
417+ }
418+
419+ const start = Math . max ( 0 , index - 12 ) ; // 12 before the index
420+ const end = Math . min ( array . length , index + 13 ) ; // 12 after the index
421+ return array . slice ( start , end ) ;
422+ }
423+
424+ it ( 'should call the loadChannelAroundMessage when messageId is passed to a channel' , async ( ) => {
425+ const messages = Array . from ( { length : 105 } , ( _ , i ) => generateMessage ( { id : i } ) ) ;
426+ const messageToSearch = messages [ 50 ] ;
427+ const mockedChannel = generateChannelResponse ( {
428+ messages,
429+ } ) ;
430+
431+ useMockedApis ( chatClient , [ getOrCreateChannelApi ( mockedChannel ) ] ) ;
432+ const channel = chatClient . channel ( 'messaging' , mockedChannel . id ) ;
433+ await channel . watch ( ) ;
434+
435+ const loadMessageIntoState = jest . fn ( ( ) => {
436+ const newMessages = getElementsAround ( messages , 'id' , messageToSearch . id ) ;
437+ channel . state . messages = newMessages ;
438+ } ) ;
439+
440+ channel . state = {
441+ ...channelInitialState ,
442+ loadMessageIntoState,
443+ messagePagination : {
444+ hasNext : true ,
445+ hasPrev : true ,
446+ } ,
447+ messages,
448+ } ;
449+
450+ renderComponent ( { channel, messageId : messageToSearch . id } ) ;
451+
452+ await waitFor ( ( ) => {
453+ expect ( loadMessageIntoState ) . toHaveBeenCalledWith ( messageToSearch . id , undefined , 25 ) ;
454+ } ) ;
455+
456+ const { result : channelMessageState } = renderHook ( ( ) => useChannelMessageDataState ( channel ) ) ;
457+ await waitFor ( ( ) => expect ( channelMessageState . current . state . messages ) . toHaveLength ( 25 ) ) ;
458+ await waitFor ( ( ) =>
459+ expect (
460+ channelMessageState . current . state . messages . find (
461+ ( message ) => message . id === messageToSearch . id ,
462+ ) ,
463+ ) . toBeTruthy ( ) ,
464+ ) ;
465+ } ) ;
466+
467+ it ( "should not call loadChannelAtFirstUnreadMessage if channel's unread count is 0" , async ( ) => {
468+ const mockedChannel = generateChannelResponse ( {
469+ messages : Array . from ( { length : 10 } , ( _ , i ) => generateMessage ( { text : `message-${ i } ` } ) ) ,
470+ } ) ;
471+
472+ useMockedApis ( chatClient , [ getOrCreateChannelApi ( mockedChannel ) ] ) ;
473+ const channel = chatClient . channel ( 'messaging' , mockedChannel . id ) ;
474+ await channel . watch ( ) ;
475+ const messages = Array . from ( { length : 100 } , ( _ , i ) => generateMessage ( { id : i } ) ) ;
476+
477+ const loadMessageIntoState = jest . fn ( ) ;
478+ channel . state = {
479+ ...channelInitialState ,
480+ loadMessageIntoState,
481+ messagePagination : {
482+ hasNext : true ,
483+ hasPrev : true ,
484+ } ,
485+ messages,
486+ } ;
487+ channel . countUnread = jest . fn ( ( ) => 0 ) ;
488+
489+ renderComponent ( { channel, initialScrollToFirstUnreadMessage : true } ) ;
490+
491+ await waitFor ( ( ) => {
492+ expect ( loadMessageIntoState ) . not . toHaveBeenCalled ( ) ;
493+ } ) ;
494+ } ) ;
495+
496+ it ( "should call loadChannelAtFirstUnreadMessage if channel's unread count is greater than 0" , async ( ) => {
497+ const mockedChannel = generateChannelResponse ( {
498+ messages : Array . from ( { length : 10 } , ( _ , i ) => generateMessage ( { text : `message-${ i } ` } ) ) ,
499+ } ) ;
500+
501+ useMockedApis ( chatClient , [ getOrCreateChannelApi ( mockedChannel ) ] ) ;
502+ const channel = chatClient . channel ( 'messaging' , mockedChannel . id ) ;
503+ await channel . watch ( ) ;
504+ const messages = Array . from ( { length : 100 } , ( _ , i ) => generateMessage ( { id : i } ) ) ;
505+
506+ let targetedMessageId = 0 ;
507+ const loadMessageIntoState = jest . fn ( ( id ) => {
508+ targetedMessageId = id ;
509+ const newMessages = getElementsAround ( messages , 'id' , id ) ;
510+ channel . state . messages = newMessages ;
511+ } ) ;
512+
513+ channel . state = {
514+ ...channelInitialState ,
515+ loadMessageIntoState,
516+ messagePagination : {
517+ hasNext : true ,
518+ hasPrev : true ,
519+ } ,
520+ messages,
521+ messageSets : [ { isCurrent : true , isLatest : true } ] ,
522+ } ;
523+
524+ channel . countUnread = jest . fn ( ( ) => 15 ) ;
525+
526+ renderComponent ( { channel, initialScrollToFirstUnreadMessage : true } ) ;
527+
528+ await waitFor ( ( ) => {
529+ expect ( loadMessageIntoState ) . toHaveBeenCalledTimes ( 1 ) ;
530+ } ) ;
531+
532+ const { result : channelMessageState } = renderHook ( ( ) => useChannelMessageDataState ( channel ) ) ;
533+ await waitFor ( ( ) =>
534+ expect (
535+ channelMessageState . current . state . messages . find (
536+ ( message ) => message . id === targetedMessageId ,
537+ ) ,
538+ ) . toBeDefined ( ) ,
539+ ) ;
540+ } ) ;
541+
542+ it ( 'should call resyncChannel when connection changed event is triggered' , async ( ) => {
543+ const mockedChannel = generateChannelResponse ( {
544+ messages : Array . from ( { length : 10 } , ( _ , i ) => generateMessage ( { text : `message-${ i } ` } ) ) ,
545+ } ) ;
546+
547+ useMockedApis ( chatClient , [ getOrCreateChannelApi ( mockedChannel ) ] ) ;
548+ const channel = chatClient . channel ( 'messaging' , mockedChannel . id ) ;
549+ await channel . watch ( ) ;
550+
551+ renderComponent ( { channel } ) ;
552+
553+ await waitFor ( ( ) => {
554+ act ( ( ) => dispatchConnectionChanged ( chatClient , false ) ) ;
555+ } ) ;
556+
557+ await waitFor ( ( ) => {
558+ channel . state . addMessagesSorted (
559+ Array . from ( { length : 10 } , ( _ , i ) =>
560+ generateMessage ( { status : 'failed' , text : `message-${ i } ` } ) ,
561+ ) ,
562+ ) ;
563+ } ) ;
564+
565+ await waitFor ( ( ) => {
566+ act ( ( ) => dispatchConnectionChanged ( chatClient ) ) ;
567+ } ) ;
568+
569+ await waitFor ( ( ) => {
570+ expect ( channel . state . messages . length ) . toBe ( 20 ) ;
571+ } ) ;
572+ } ) ;
573+ } ) ;
0 commit comments