import React from 'react'; import { Text } from 'react-native'; import { act, render } from '@testing-library/react-native'; import type { Channel } from 'stream-chat'; import { WithComponents } from '../../../contexts/componentsContext/ComponentsContext'; import type { ChannelActionItem } from '../../ChannelList/hooks/useChannelActionItems'; import * as ChannelActionItemsModule from '../../ChannelList/hooks/useChannelActionItems'; import * as ChannelActionsModule from '../../ChannelList/hooks/useChannelActions'; import { ChannelSwipableWrapper } from '../ChannelSwipableWrapper'; import * as UseIsChannelMutedModule from '../hooks/useIsChannelMuted'; const rightActionsProbe = { items: [] as Array<{ action: () => void; id: string }>, }; const mockSwipableWrapper = jest.fn( ({ children, swipableProps, }: React.PropsWithChildren<{ swipableProps?: { renderRightActions?: (...args: never[]) => void }; }>) => { const rightActions = swipableProps?.renderRightActions?.({} as never, {} as never); return ( <> {children} {rightActions} ); }, ); jest.mock('../../../contexts/themeContext/ThemeContext', () => ({ useTheme: () => ({ theme: { semantics: { accentPrimary: '#00f', backgroundCoreSurfaceDefault: '#fff', textOnAccent: '#000', textPrimary: '#111', }, }, }), })); jest.mock('../../../contexts/swipeableContext/SwipeRegistryContext', () => ({ useSwipeRegistryContext: () => ({ closeAll: jest.fn(), }), })); jest.mock('../../UIComponents/BottomSheetModal', () => ({ BottomSheetModal: ({ children }: React.PropsWithChildren) => <>{children}, })); jest.mock('../../UIComponents/SwipableWrapper', () => ({ RightActions: ({ items }: { items: Array<{ action: () => void; id: string }> }) => { rightActionsProbe.items = items; return null; }, SwipableWrapper: (...args: unknown[]) => mockSwipableWrapper(...args), })); describe('ChannelSwipableWrapper', () => { const channel = { cid: 'messaging:test-channel', id: 'test-channel' } as Channel; beforeEach(() => { jest.clearAllMocks(); rightActionsProbe.items = []; }); it('uses channel mute for direct-channel swipe actions and keeps mute user in the sheet', () => { const muteChannel = jest.fn(); const unmuteChannel = jest.fn(); const customBottomSheet = jest.fn(() => null); const items: ChannelActionItem[] = [ { Icon: () => null, action: jest.fn(), id: 'mute', label: 'Mute User', placement: 'sheet', type: 'standard', }, { Icon: () => null, action: jest.fn(), id: 'archive', label: 'Archive Chat', placement: 'sheet', type: 'standard', }, ]; jest.spyOn(ChannelActionsModule, 'useChannelActions').mockReturnValue({ archive: jest.fn(), blockUser: jest.fn(), deleteChannel: jest.fn(), leave: jest.fn(), muteChannel, muteUser: jest.fn(), pin: jest.fn(), unarchive: jest.fn(), unblockUser: jest.fn(), unmuteChannel, unmuteUser: jest.fn(), unpin: jest.fn(), }); jest.spyOn(ChannelActionItemsModule, 'useChannelActionItems').mockReturnValue(items); jest.spyOn(UseIsChannelMutedModule, 'useIsChannelMuted').mockReturnValue({ createdAt: null, expiresAt: null, muted: false, }); render( child , ); expect(customBottomSheet).toHaveBeenCalledWith( expect.objectContaining({ channel, items, }), undefined, ); expect(rightActionsProbe.items.map((item) => item.id)).toEqual(['openSheet', 'mute']); act(() => { rightActionsProbe.items[1].action(); }); expect(muteChannel).toHaveBeenCalledTimes(1); expect(unmuteChannel).not.toHaveBeenCalled(); }); it('removes mute group from the sheet while keeping mute as the quick swipe action', () => { const muteChannel = jest.fn(); const customBottomSheet = jest.fn(() => null); const muteItem = { Icon: () => null, action: jest.fn(), id: 'mute', label: 'Mute Group', placement: 'swipe', type: 'standard', } as const satisfies ChannelActionItem; const archiveItem = { Icon: () => null, action: jest.fn(), id: 'archive', label: 'Archive Group', placement: 'both', type: 'standard', } as const satisfies ChannelActionItem; jest.spyOn(ChannelActionsModule, 'useChannelActions').mockReturnValue({ archive: jest.fn(), blockUser: jest.fn(), deleteChannel: jest.fn(), leave: jest.fn(), muteChannel, muteUser: jest.fn(), pin: jest.fn(), unarchive: jest.fn(), unblockUser: jest.fn(), unmuteChannel: jest.fn(), unmuteUser: jest.fn(), unpin: jest.fn(), }); jest .spyOn(ChannelActionItemsModule, 'useChannelActionItems') .mockReturnValue([muteItem, archiveItem]); jest.spyOn(UseIsChannelMutedModule, 'useIsChannelMuted').mockReturnValue({ createdAt: null, expiresAt: null, muted: false, }); render( child , ); expect(customBottomSheet).toHaveBeenCalledWith( expect.objectContaining({ channel, items: [archiveItem], }), undefined, ); expect(rightActionsProbe.items.map((item) => item.id)).toEqual(['openSheet', 'mute']); act(() => { rightActionsProbe.items[1].action(); }); expect(muteChannel).toHaveBeenCalledTimes(1); }); });