@@ -25,20 +25,28 @@ import {
2525 MsgType ,
2626 Room ,
2727} from 'matrix-js-sdk/src/matrix' ;
28+ import { Thread } from 'matrix-js-sdk/src/models/thread' ;
2829
2930import MessageActionBar from '../../../../src/components/views/messages/MessageActionBar' ;
3031import {
3132 getMockClientWithEventEmitter ,
3233 mockClientMethodsUser ,
3334 mockClientMethodsEvents ,
35+ makeBeaconInfoEvent ,
3436} from '../../../test-utils' ;
3537import { RoomPermalinkCreator } from '../../../../src/utils/permalinks/Permalinks' ;
3638import RoomContext , { TimelineRenderingType } from '../../../../src/contexts/RoomContext' ;
3739import { IRoomState } from '../../../../src/components/structures/RoomView' ;
3840import dispatcher from '../../../../src/dispatcher/dispatcher' ;
3941import SettingsStore from '../../../../src/settings/SettingsStore' ;
42+ import { Action } from '../../../../src/dispatcher/actions' ;
43+ import { UserTab } from '../../../../src/components/views/dialogs/UserTab' ;
44+ import { showThread } from '../../../../src/dispatcher/dispatch-actions/threads' ;
4045
4146jest . mock ( '../../../../src/dispatcher/dispatcher' ) ;
47+ jest . mock ( '../../../../src/dispatcher/dispatch-actions/threads' , ( ) => ( {
48+ showThread : jest . fn ( ) ,
49+ } ) ) ;
4250
4351describe ( '<MessageActionBar />' , ( ) => {
4452 const userId = '@alice:server.org' ;
@@ -360,4 +368,100 @@ describe('<MessageActionBar />', () => {
360368 it . todo ( 'unsends event on cancel click' ) ;
361369 it . todo ( 'retrys event on retry click' ) ;
362370 } ) ;
371+
372+ describe ( 'thread button' , ( ) => {
373+ beforeEach ( ( ) => {
374+ Thread . setServerSideSupport ( true , false ) ;
375+ } ) ;
376+
377+ describe ( 'when threads feature is not enabled' , ( ) => {
378+ it ( 'does not render thread button when threads does not have server support' , ( ) => {
379+ jest . spyOn ( SettingsStore , 'getValue' ) . mockReturnValue ( false ) ;
380+ Thread . setServerSideSupport ( false , false ) ;
381+ const { queryByLabelText } = getComponent ( { mxEvent : alicesMessageEvent } ) ;
382+ expect ( queryByLabelText ( 'Reply in thread' ) ) . toBeFalsy ( ) ;
383+ } ) ;
384+
385+ it ( 'renders thread button when threads has server support' , ( ) => {
386+ jest . spyOn ( SettingsStore , 'getValue' ) . mockReturnValue ( false ) ;
387+ const { queryByLabelText } = getComponent ( { mxEvent : alicesMessageEvent } ) ;
388+ expect ( queryByLabelText ( 'Reply in thread' ) ) . toBeTruthy ( ) ;
389+ } ) ;
390+
391+ it ( 'opens user settings on click' , ( ) => {
392+ jest . spyOn ( SettingsStore , 'getValue' ) . mockReturnValue ( false ) ;
393+ const { getByLabelText } = getComponent ( { mxEvent : alicesMessageEvent } ) ;
394+
395+ act ( ( ) => {
396+ fireEvent . click ( getByLabelText ( 'Reply in thread' ) ) ;
397+ } ) ;
398+
399+ expect ( dispatcher . dispatch ) . toHaveBeenCalledWith ( {
400+ action : Action . ViewUserSettings ,
401+ initialTabId : UserTab . Labs ,
402+ } ) ;
403+ } ) ;
404+ } ) ;
405+
406+ describe ( 'when threads feature is enabled' , ( ) => {
407+ beforeEach ( ( ) => {
408+ jest . spyOn ( SettingsStore , 'getValue' ) . mockImplementation ( setting => setting === 'feature_thread' ) ;
409+ } ) ;
410+
411+ it ( 'renders thread button on own actionable event' , ( ) => {
412+ const { queryByLabelText } = getComponent ( { mxEvent : alicesMessageEvent } ) ;
413+ expect ( queryByLabelText ( 'Reply in thread' ) ) . toBeTruthy ( ) ;
414+ } ) ;
415+
416+ it ( 'does not render thread button for a beacon_info event' , ( ) => {
417+ const beaconInfoEvent = makeBeaconInfoEvent ( userId , roomId ) ;
418+ const { queryByLabelText } = getComponent ( { mxEvent : beaconInfoEvent } ) ;
419+ expect ( queryByLabelText ( 'Reply in thread' ) ) . toBeFalsy ( ) ;
420+ } ) ;
421+
422+ it ( 'opens thread on click' , ( ) => {
423+ const { getByLabelText } = getComponent ( { mxEvent : alicesMessageEvent } ) ;
424+
425+ act ( ( ) => {
426+ fireEvent . click ( getByLabelText ( 'Reply in thread' ) ) ;
427+ } ) ;
428+
429+ expect ( showThread ) . toHaveBeenCalledWith ( {
430+ rootEvent : alicesMessageEvent ,
431+ push : false ,
432+ } ) ;
433+ } ) ;
434+
435+ it ( 'opens parent thread for a thread reply message' , ( ) => {
436+ const threadReplyEvent = new MatrixEvent ( {
437+ type : EventType . RoomMessage ,
438+ sender : userId ,
439+ room_id : roomId ,
440+ content : {
441+ msgtype : MsgType . Text ,
442+ body : 'this is a thread reply' ,
443+ } ,
444+ } ) ;
445+ // mock the thread stuff
446+ jest . spyOn ( threadReplyEvent , 'isThreadRelation' , 'get' ) . mockReturnValue ( true ) ;
447+ // set alicesMessageEvent as the root event
448+ jest . spyOn ( threadReplyEvent , 'getThread' ) . mockReturnValue (
449+ { rootEvent : alicesMessageEvent } as unknown as Thread ,
450+ ) ;
451+ const { getByLabelText } = getComponent ( { mxEvent : threadReplyEvent } ) ;
452+
453+ act ( ( ) => {
454+ fireEvent . click ( getByLabelText ( 'Reply in thread' ) ) ;
455+ } ) ;
456+
457+ expect ( showThread ) . toHaveBeenCalledWith ( {
458+ rootEvent : alicesMessageEvent ,
459+ initialEvent : threadReplyEvent ,
460+ highlighted : true ,
461+ scroll_into_view : true ,
462+ push : false ,
463+ } ) ;
464+ } ) ;
465+ } ) ;
466+ } ) ;
363467} ) ;
0 commit comments