Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
146 changes: 146 additions & 0 deletions apps/meteor/client/hooks/roomActions/useMediaCallRoomAction.spec.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,146 @@
import type { IUser, IRoom } from '@rocket.chat/core-typings';
import { mockAppRoot } from '@rocket.chat/mock-providers';
import type { SubscriptionWithRoom } from '@rocket.chat/ui-contexts';
import { useMediaCallAction } from '@rocket.chat/ui-voip';
import { act, renderHook } from '@testing-library/react';

import { useMediaCallRoomAction } from './useMediaCallRoomAction';
import FakeRoomProvider from '../../../tests/mocks/client/FakeRoomProvider';
import { createFakeRoom, createFakeSubscription, createFakeUser } from '../../../tests/mocks/data';

jest.mock('@rocket.chat/ui-contexts', () => ({
...jest.requireActual('@rocket.chat/ui-contexts'),
useUserAvatarPath: jest.fn((_args: any) => 'avatar-url'),
}));

jest.mock('@rocket.chat/ui-voip', () => ({
useMediaCallAction: jest.fn(),
}));

const getUserInfoMocked = jest.fn().mockResolvedValue({ user: createFakeUser({ _id: 'peer-uid', username: 'peer-username' }) });

const appRoot = (overrides: { user?: IUser | null; room?: IRoom; subscription?: SubscriptionWithRoom } = {}) => {
const {
user = createFakeUser({ _id: 'own-uid', username: 'own-username' }),
room = createFakeRoom({ uids: ['own-uid', 'peer-uid'] }),
subscription = createFakeSubscription(),
} = overrides;

const root = mockAppRoot()
.withRoom(room)
.withEndpoint('GET', '/v1/users.info', getUserInfoMocked)
.wrap((children) => (
<FakeRoomProvider roomOverrides={room} subscriptionOverrides={subscription}>
{children}
</FakeRoomProvider>
));

if (user !== null) {
root.withUser(user);
}

return root.build();
};

describe('useMediaCallRoomAction', () => {
const useMediaCallActionMocked = jest.mocked(useMediaCallAction);

beforeEach(() => {
jest.clearAllMocks();

useMediaCallActionMocked.mockReturnValue({
action: jest.fn(),
title: 'Start_call',
icon: 'phone',
});
});

it('should return undefined if ownUserId is not defined', () => {
const { result } = renderHook(() => useMediaCallRoomAction(), {
wrapper: appRoot({ user: null }),
});

expect(result.current).toBeUndefined();
});

it('should return undefined if there are no other users in the room', () => {
const fakeRoom = createFakeRoom({ uids: ['own-uid'] });
const { result } = renderHook(() => useMediaCallRoomAction(), {
wrapper: appRoot({ room: fakeRoom }),
});

expect(result.current).toBeUndefined();
});

it('should return undefined if there are more than one other user (Group DM)', () => {
const fakeRoom = createFakeRoom({ uids: ['own-uid', 'peer-uid-1', 'peer-uid-2'] });
const { result } = renderHook(() => useMediaCallRoomAction(), {
wrapper: appRoot({ room: fakeRoom }),
});

expect(result.current).toBeUndefined();
});

it('should return undefined if callAction is undefined', () => {
useMediaCallActionMocked.mockReturnValue(undefined);

const { result } = renderHook(() => useMediaCallRoomAction(), {
wrapper: appRoot(),
});

expect(result.current).toBeUndefined();
});

it('should return undefined if subscription is blocked', () => {
const fakeBlockedSubscription = createFakeSubscription({ blocker: false, blocked: true });
const { result } = renderHook(() => useMediaCallRoomAction(), {
wrapper: appRoot({ subscription: fakeBlockedSubscription }),
});

expect(result.current).toBeUndefined();
});

it('should return undefined if subscription is blocker', () => {
const fakeBlockedSubscription = createFakeSubscription({ blocked: false, blocker: true });
const { result } = renderHook(() => useMediaCallRoomAction(), {
wrapper: appRoot({ subscription: fakeBlockedSubscription }),
});

expect(result.current).toBeUndefined();
});

it('should return undefined if room is federated', () => {
const fakeFederatedRoom = createFakeRoom({ uids: ['own-uid', 'peer-uid'], federated: true });
const { result } = renderHook(() => useMediaCallRoomAction(), {
wrapper: appRoot({ room: fakeFederatedRoom }),
});

expect(result.current).toBeUndefined();
});

it('should return the action config if all conditions are met', () => {
const actionMock = jest.fn();
useMediaCallActionMocked.mockReturnValue({
action: actionMock,
title: 'Start_call',
icon: 'phone',
});

const { result } = renderHook(() => useMediaCallRoomAction(), {
wrapper: appRoot(),
});

expect(result.current).toEqual({
id: 'start-voice-call',
title: 'Start_call',
icon: 'phone',
featured: true,
action: expect.any(Function),
groups: ['direct'],
});

// Test the action trigger
act(() => result.current?.action?.());
expect(actionMock).toHaveBeenCalled();
});
});
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { isRoomFederated } from '@rocket.chat/core-typings';
import { useUserAvatarPath, useUserId } from '@rocket.chat/ui-contexts';
import type { TranslationKey, RoomToolboxActionConfig } from '@rocket.chat/ui-contexts';
import type { PeerInfo } from '@rocket.chat/ui-voip';
Expand All @@ -23,9 +24,11 @@ const getPeerId = (uids: string[], ownUserId: string | undefined) => {
};

export const useMediaCallRoomAction = () => {
const { uids = [] } = useRoom();
const room = useRoom();
const { uids = [] } = room;
const subscription = useRoomSubscription();
const ownUserId = useUserId();
const federated = isRoomFederated(room);

const getAvatarUrl = useUserAvatarPath();

Expand All @@ -52,7 +55,7 @@ export const useMediaCallRoomAction = () => {
const blocked = subscription?.blocked || subscription?.blocker;

return useMemo((): RoomToolboxActionConfig | undefined => {
if (!peerId || !callAction || blocked) {
if (!peerId || !callAction || blocked || federated) {
return undefined;
}

Expand All @@ -66,5 +69,5 @@ export const useMediaCallRoomAction = () => {
action: () => action(),
groups: ['direct'] as const,
};
}, [peerId, callAction, blocked]);
}, [peerId, callAction, blocked, federated]);
};
Original file line number Diff line number Diff line change
@@ -1,12 +1,10 @@
import { mockAppRoot } from '@rocket.chat/mock-providers';
import type { SubscriptionWithRoom } from '@rocket.chat/ui-contexts';
import { renderHook } from '@testing-library/react';

import { useRoomMenuActions } from './useRoomMenuActions';
import { createFakeRoom, createFakeSubscription } from '../../../../../tests/mocks/data';
import { createFakeSubscription } from '../../../../../tests/mocks/data';

const mockRoom = createFakeRoom({ _id: 'room1', t: 'c', name: 'room1', fname: 'Room 1' });
const mockSubscription = createFakeSubscription({ name: 'room1', t: 'c', disableNotifications: false, rid: 'room1' });
const mockSubscription = createFakeSubscription({ name: 'room1', fname: 'Room 1', t: 'c', disableNotifications: false, rid: 'room1' });

jest.mock('../../../../../client/lib/rooms/roomCoordinator', () => ({
roomCoordinator: {
Expand Down Expand Up @@ -42,7 +40,7 @@ describe('useRoomMenuActions', () => {
it('should return all menu options for normal rooms', () => {
const { result } = renderHook(() => useRoomMenuActions(mockHookProps), {
wrapper: mockAppRoot()
.withSubscriptions([{ ...mockSubscription, rid: 'room1' }] as unknown as SubscriptionWithRoom[])
.withSubscription({ ...mockSubscription, rid: 'room1' })
.withPermission('leave-c')
.withPermission('leave-p')
.withSetting('Favorite_Rooms', true)
Expand All @@ -59,7 +57,7 @@ describe('useRoomMenuActions', () => {
it('should return priorities section for omnichannel room', () => {
const { result } = renderHook(() => useRoomMenuActions({ ...mockHookProps, type: 'l' }), {
wrapper: mockAppRoot()
.withSubscriptions([{ ...mockSubscription, ...mockRoom, t: 'l' }] as unknown as SubscriptionWithRoom[])
.withSubscription({ ...mockSubscription, t: 'l' })
.withPermission('leave-c')
.withPermission('leave-p')
.withSetting('Favorite_Rooms', true)
Expand All @@ -76,7 +74,7 @@ describe('useRoomMenuActions', () => {
it('should not return any menu option if hideDefaultOptions', () => {
const { result } = renderHook(() => useRoomMenuActions({ ...mockHookProps, hideDefaultOptions: true }), {
wrapper: mockAppRoot()
.withSubscriptions([{ ...mockSubscription, ...mockRoom }] as unknown as SubscriptionWithRoom[])
.withSubscription(mockSubscription)
.withPermission('leave-c')
.withPermission('leave-p')
.withSetting('Favorite_Rooms', true)
Expand All @@ -89,7 +87,7 @@ describe('useRoomMenuActions', () => {
it('should not return favorite room option if setting is disabled', () => {
const { result } = renderHook(() => useRoomMenuActions(mockHookProps), {
wrapper: mockAppRoot()
.withSubscriptions([{ ...mockSubscription, ...mockRoom }] as unknown as SubscriptionWithRoom[])
.withSubscription(mockSubscription)
.withPermission('leave-c')
.withPermission('leave-p')
.withSetting('Favorite_Rooms', false)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import { mockAppRoot } from '@rocket.chat/mock-providers';
import type { SubscriptionWithRoom } from '@rocket.chat/ui-contexts';
import { renderHook } from '@testing-library/react';

import { useRoomLeave } from './useRoomLeave';
Expand All @@ -25,7 +24,7 @@ jest.mock('../../../../../../../client/lib/rooms/roomCoordinator', () => ({
it('should return leave function if user has subscription', () => {
const wrapper = mockAppRoot()
.withPermission('leave-c')
.withSubscriptions([{ ...mockSubscription, rid: 'room1' }] as unknown as SubscriptionWithRoom[])
.withSubscription({ ...mockSubscription, rid: 'room1' })
.build();

const { result } = renderHook(() => useRoomLeave(mockRoom), { wrapper });
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
import { mockAppRoot } from '@rocket.chat/mock-providers';
import { useMediaCallContext } from '@rocket.chat/ui-voip';
import { act, renderHook } from '@testing-library/react';

import { useUserMediaCallAction } from './useUserMediaCallAction';
import { createFakeRoom, createFakeSubscription, createFakeUser } from '../../../../../../tests/mocks/data';

jest.mock('@rocket.chat/ui-contexts', () => ({
...jest.requireActual('@rocket.chat/ui-contexts'),
useUserAvatarPath: jest.fn().mockReturnValue((_args: any) => 'avatar-url'),
}));

jest.mock('@rocket.chat/ui-voip', () => ({
...jest.requireActual('@rocket.chat/ui-voip'),
useMediaCallContext: jest.fn().mockImplementation(() => ({
state: 'closed',
onToggleWidget: jest.fn(),
})),
}));

jest.mock('../../../contexts/UserCardContext', () => ({
useUserCard: jest.fn().mockReturnValue({ closeUserCard: jest.fn() }),
}));

const useMediaCallContextMocked = jest.mocked(useMediaCallContext);

describe('useUserMediaCallAction', () => {
const fakeUser = createFakeUser({ _id: 'own-uid' });
const mockRid = 'room-id';

afterEach(() => {
jest.clearAllMocks();
});

it('should return undefined if room is federated', () => {
const { result } = renderHook(() => useUserMediaCallAction(fakeUser, mockRid), {
wrapper: mockAppRoot()
.withJohnDoe()
.withRoom(createFakeRoom({ federated: true }))
.build(),
});

expect(result.current).toBeUndefined();
});

it('should return undefined if state is unauthorized', () => {
useMediaCallContextMocked.mockReturnValueOnce({
state: 'unauthorized',
onToggleWidget: undefined,
onEndCall: undefined,
peerInfo: undefined,
});

const { result } = renderHook(() => useUserMediaCallAction(fakeUser, mockRid), { wrapper: mockAppRoot().build() });
expect(result.current).toBeUndefined();
});

it('should return undefined if subscription is blocked', () => {
const { result } = renderHook(() => useUserMediaCallAction(fakeUser, mockRid), {
wrapper: mockAppRoot()
.withJohnDoe()
.withRoom(createFakeRoom())
.withSubscription(createFakeSubscription({ blocker: false, blocked: true }))
.build(),
});

expect(result.current).toBeUndefined();
});

it('should return undefined if subscription is blocker', () => {
const { result } = renderHook(() => useUserMediaCallAction(fakeUser, mockRid), {
wrapper: mockAppRoot()
.withJohnDoe()
.withRoom(createFakeRoom())
.withSubscription(createFakeSubscription({ blocker: true, blocked: false }))
.build(),
});

expect(result.current).toBeUndefined();
});

it('should return undefined if user is own user', () => {
const { result } = renderHook(() => useUserMediaCallAction(fakeUser, mockRid), {
wrapper: mockAppRoot().withUser(fakeUser).withRoom(createFakeRoom()).withSubscription(createFakeSubscription()).build(),
});

expect(result.current).toBeUndefined();
});

it('should return action if conditions are met', () => {
const fakeUser = createFakeUser();
const { result } = renderHook(() => useUserMediaCallAction(fakeUser, mockRid), {
wrapper: mockAppRoot()
.withJohnDoe()
.withRoom(createFakeRoom())
.withSubscription(createFakeSubscription())
.withTranslations('en', 'core', {
Voice_call__user_: 'Voice call {{user}}',
})
.build(),
});

expect(result.current).toEqual(
expect.objectContaining({
type: 'communication',
icon: 'phone',
title: `Voice call ${fakeUser.name}`,
disabled: false,
}),
);
});

it('should call onClick handler correctly', () => {
const mockOnToggleWidget = jest.fn();
useMediaCallContextMocked.mockReturnValueOnce({
state: 'closed',
onToggleWidget: mockOnToggleWidget,
peerInfo: undefined,
onEndCall: () => undefined,
});

const { result } = renderHook(() => useUserMediaCallAction(fakeUser, mockRid));

act(() => result.current?.onClick());

expect(mockOnToggleWidget).toHaveBeenCalledWith({
userId: fakeUser._id,
displayName: fakeUser.name,
avatarUrl: 'avatar-url',
});
});

it('should be disabled if state is not closed, new, or unlicensed', () => {
useMediaCallContextMocked.mockReturnValueOnce({
state: 'calling',
onToggleWidget: jest.fn(),
peerInfo: undefined,
onEndCall: () => undefined,
});

const { result } = renderHook(() => useUserMediaCallAction(fakeUser, mockRid));

expect(result.current?.disabled).toBe(true);
});
});
Loading
Loading