mattermost-mobile/app/actions/websocket/channel.test.ts
Mattermost Build e8f1d0c729
Add autotranslations (#9324) (#9500)
* Add autotranslations

* Develop latest changes and missing features

* i18n-extract

* Fix tests and update api behavior

* Fix minor bugs

* adjustments to shimmer animation, showtranslation modal style

* Update post.tsx

* Update show_translation.tsx

* adjust sizing and opacity of translate icon

* Add channel header translated icon

* Disable auto translation item if it is not a supported language

* Move channel info to the top

* Update edit channel to channel info

* Fix align of option items

* Fix i18n

* Add detox related changes for channel settings changes

* Add tests

* Address changes around the my channel column change

* Address feedback

* Fix test

* Fix bad import

* Fix set my channel autotranslation

* Fix test

* Address feedback

* Add missing files from last commit

* Remove unneeded change

---------


(cherry picked from commit 23565b5135)

Co-authored-by: Daniel Espino García <larkox@gmail.com>
Co-authored-by: Matthew Birtch <mattbirtch@gmail.com>
2026-02-11 08:09:39 +02:00

631 lines
31 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
import {addChannelToDefaultCategory, handleConvertedGMCategories} from '@actions/local/category';
import {markChannelAsViewed, removeCurrentUserFromChannel, setChannelDeleteAt, storeMyChannelsForTeam, updateChannelInfoFromChannel, updateMyChannelFromWebsocket, deletePostsForChannel} from '@actions/local/channel';
import {storePostsForChannel} from '@actions/local/post';
import {fetchMyChannel, fetchChannelById, fetchMissingDirectChannelsInfo} from '@actions/remote/channel';
import {fetchPostsForChannel} from '@actions/remote/post';
import {fetchRolesIfNeeded} from '@actions/remote/role';
import {fetchUsersByIds, updateUsersNoLongerVisible} from '@actions/remote/user';
import {leaveCall} from '@calls/actions/calls';
import {getCurrentCall} from '@calls/state';
import {General} from '@constants';
import DatabaseManager from '@database/manager';
import {deleteChannelMembership, getChannelById, getCurrentChannel, prepareMyChannelsForTeam} from '@queries/servers/channel';
import {setCurrentTeamId, getCurrentChannelId, getCurrentTeamId, getConfig} from '@queries/servers/system';
import {getCurrentUser, getTeammateNameDisplay, getUserById} from '@queries/servers/user';
import EphemeralStore from '@store/ephemeral_store';
import {handleChannelCreatedEvent, handleChannelUnarchiveEvent, handleChannelConvertedEvent, handleChannelUpdatedEvent, handleChannelViewedEvent, handleMultipleChannelsViewedEvent, handleChannelMemberUpdatedEvent, handleChannelDeletedEvent, handleDirectAddedEvent, handleUserAddedToChannelEvent, handleUserRemovedFromChannelEvent} from './channel';
import type ServerDataOperator from '@database/operator/server_data_operator';
import type ChannelModel from '@typings/database/models/servers/channel';
jest.mock('@database/manager');
jest.mock('@store/ephemeral_store');
jest.mock('@actions/local/category');
jest.mock('@actions/remote/channel');
jest.mock('@actions/remote/role');
jest.mock('@actions/remote/post');
jest.mock('@actions/remote/user');
jest.mock('@actions/local/channel');
jest.mock('@actions/local/post');
jest.mock('@queries/servers/channel');
jest.mock('@queries/servers/system');
jest.mock('@queries/servers/user');
jest.mock('@calls/actions');
jest.mock('@actions/local/user');
jest.mock('@utils/log');
jest.mock('@calls/state');
jest.mock('@calls/actions/calls');
const serverUrl = 'baseHandler.test.com';
describe('WebSocket Channel Actions', () => {
let msg: any;
let operator: ServerDataOperator;
const teamId = 'teamid1';
const channelId = 'channelid1';
const channel = {id: channelId, team_id: teamId} as Channel;
const channelModel = {
id: channelId,
type: General.PRIVATE_CHANNEL,
teamId,
createAt: 0,
updateAt: 0,
deleteAt: 0,
displayName: 'channeldisplayname',
name: 'channelname',
} as ChannelModel;
const userId = 'userid1';
const mockedGetChannelById = jest.mocked(getChannelById);
const mockedFetchMyChannel = jest.mocked(fetchMyChannel);
const mockedPrepareMyChannelsForTeam = jest.mocked(prepareMyChannelsForTeam);
const mockedFetchChannelById = jest.mocked(fetchChannelById);
beforeEach(async () => {
await DatabaseManager.init([serverUrl]);
operator = DatabaseManager.serverDatabases[serverUrl]!.operator;
msg = {
data: {
team_id: teamId,
channel_id: channelId,
channel: JSON.stringify({id: channelId, type: General.PRIVATE_CHANNEL, team_id: teamId}),
},
broadcast: {
channel_id: channelId,
userId,
user_id: userId,
},
};
DatabaseManager.getActiveServerUrl = jest.fn().mockResolvedValue(serverUrl);
});
afterEach(async () => {
await DatabaseManager.destroyServerDatabase(serverUrl);
jest.restoreAllMocks();
});
describe('handleChannelCreatedEvent', () => {
it('should handle channel created event', async () => {
(EphemeralStore.creatingChannel as boolean) = false;
mockedGetChannelById.mockResolvedValue(undefined);
mockedFetchMyChannel.mockResolvedValue({channels: [channel], memberships: [{} as any]});
mockedPrepareMyChannelsForTeam.mockResolvedValue([[] as any]);
(addChannelToDefaultCategory as jest.Mock).mockResolvedValue({models: []});
await handleChannelCreatedEvent(serverUrl, msg);
expect(getChannelById).toHaveBeenCalled();
expect(fetchMyChannel).toHaveBeenCalledWith(serverUrl, teamId, channelId, true);
expect(prepareMyChannelsForTeam).toHaveBeenCalled();
expect(addChannelToDefaultCategory).toHaveBeenCalled();
});
it('should handle channel created event - no channels', async () => {
(EphemeralStore.creatingChannel as boolean) = false;
mockedGetChannelById.mockResolvedValue(undefined);
mockedFetchMyChannel.mockResolvedValue({channels: undefined, memberships: undefined});
await handleChannelCreatedEvent(serverUrl, msg);
expect(getChannelById).toHaveBeenCalled();
expect(fetchMyChannel).toHaveBeenCalledWith(serverUrl, teamId, channelId, true);
expect(prepareMyChannelsForTeam).not.toHaveBeenCalled();
});
it('should handle channel created event - no members', async () => {
(EphemeralStore.creatingChannel as boolean) = false;
mockedGetChannelById.mockResolvedValue(undefined);
mockedFetchMyChannel.mockResolvedValue({channels: [channel], memberships: undefined});
await handleChannelCreatedEvent(serverUrl, msg);
expect(getChannelById).toHaveBeenCalled();
expect(fetchMyChannel).toHaveBeenCalledWith(serverUrl, teamId, channelId, true);
expect(prepareMyChannelsForTeam).not.toHaveBeenCalled();
});
it('should handle channel created event - nothing to prepare', async () => {
(EphemeralStore.creatingChannel as boolean) = false;
mockedGetChannelById.mockResolvedValue(undefined);
mockedFetchMyChannel.mockResolvedValue({channels: [channel], memberships: [{} as any]});
mockedPrepareMyChannelsForTeam.mockResolvedValue([]);
await handleChannelCreatedEvent(serverUrl, msg);
expect(getChannelById).toHaveBeenCalled();
expect(fetchMyChannel).toHaveBeenCalledWith(serverUrl, teamId, channelId, true);
expect(prepareMyChannelsForTeam).toHaveBeenCalled();
expect(addChannelToDefaultCategory).not.toHaveBeenCalled();
});
it('should return if creatingChannel is true', async () => {
(EphemeralStore.creatingChannel as boolean) = true;
await handleChannelCreatedEvent(serverUrl, msg);
expect(getChannelById).not.toHaveBeenCalled();
});
it('should return if channel already exists', async () => {
(EphemeralStore.creatingChannel as boolean) = false;
mockedGetChannelById.mockResolvedValue(channelModel);
await handleChannelCreatedEvent(serverUrl, msg);
expect(getChannelById).toHaveBeenCalled();
expect(fetchMyChannel).not.toHaveBeenCalled();
});
});
describe('handleChannelUnarchiveEvent', () => {
it('should handle channel unarchive event', async () => {
(EphemeralStore.isArchivingChannel as jest.Mock).mockReturnValue(false);
await handleChannelUnarchiveEvent(serverUrl, msg);
expect(setChannelDeleteAt).toHaveBeenCalledWith(serverUrl, channelId, 0);
});
it('should return if channel is being archived', async () => {
(EphemeralStore.isArchivingChannel as jest.Mock).mockReturnValue(true);
await handleChannelUnarchiveEvent(serverUrl, msg);
expect(setChannelDeleteAt).not.toHaveBeenCalled();
});
});
describe('handleChannelConvertedEvent', () => {
it('should handle channel converted event', async () => {
(EphemeralStore.isConvertingChannel as jest.Mock).mockReturnValue(false);
mockedFetchChannelById.mockResolvedValue({channel});
jest.spyOn(operator, 'handleChannel').mockResolvedValueOnce([]);
await handleChannelConvertedEvent(serverUrl, msg);
expect(EphemeralStore.isConvertingChannel).toHaveBeenCalledWith(channelId);
expect(fetchChannelById).toHaveBeenCalled();
expect(operator.handleChannel).toHaveBeenCalled();
});
it('should handle channel converted event - no channel', async () => {
(EphemeralStore.isConvertingChannel as jest.Mock).mockReturnValue(false);
mockedFetchChannelById.mockResolvedValue({error: 'some error'});
jest.spyOn(operator, 'handleChannel').mockResolvedValueOnce([]);
await handleChannelConvertedEvent(serverUrl, msg);
expect(fetchChannelById).toHaveBeenCalled();
expect(operator.handleChannel).not.toHaveBeenCalled();
});
it('should return if channel is being converted', async () => {
(EphemeralStore.isConvertingChannel as jest.Mock).mockReturnValue(true);
await handleChannelConvertedEvent(serverUrl, msg);
expect(fetchChannelById).not.toHaveBeenCalled();
});
});
describe('handleChannelUpdatedEvent', () => {
it('should handle channel updated event', async () => {
(EphemeralStore.isConvertingChannel as jest.Mock).mockReturnValue(false);
mockedGetChannelById.mockResolvedValue({...channelModel, type: General.GM_CHANNEL} as ChannelModel);
(updateChannelInfoFromChannel as jest.Mock).mockResolvedValue({model: []});
jest.spyOn(operator, 'handleChannel').mockResolvedValueOnce([]);
(getCurrentChannelId as jest.Mock).mockResolvedValue(channelId);
(getCurrentTeamId as jest.Mock).mockResolvedValue('otherteamid');
await handleChannelUpdatedEvent(serverUrl, msg);
expect(getChannelById).toHaveBeenCalled();
expect(operator.handleChannel).toHaveBeenCalled();
expect(updateChannelInfoFromChannel).toHaveBeenCalled();
expect(handleConvertedGMCategories).toHaveBeenCalled();
expect(setCurrentTeamId).toHaveBeenCalled();
});
it('should return if channel is being converted', async () => {
(EphemeralStore.isConvertingChannel as jest.Mock).mockReturnValue(true);
await handleChannelUpdatedEvent(serverUrl, msg);
});
it('should not call handleConvertedGMCategories if channel type is not GM', async () => {
mockedGetChannelById.mockResolvedValue(channelModel);
(updateChannelInfoFromChannel as jest.Mock).mockResolvedValue({model: []});
await handleChannelUpdatedEvent(serverUrl, msg);
expect(handleConvertedGMCategories).not.toHaveBeenCalled();
});
it('should not call setCurrentTeamId if current team ID is the same', async () => {
mockedGetChannelById.mockResolvedValue({...channelModel, type: General.GM_CHANNEL} as ChannelModel);
(updateChannelInfoFromChannel as jest.Mock).mockResolvedValue({model: []});
(getCurrentChannelId as jest.Mock).mockResolvedValue(channelId);
(getCurrentTeamId as jest.Mock).mockResolvedValue(teamId);
await handleChannelUpdatedEvent(serverUrl, msg);
expect(setCurrentTeamId).not.toHaveBeenCalled();
});
it('should call deletePostsForChannel when autotranslation is disabled', async () => {
jest.mocked(EphemeralStore.isConvertingChannel).mockReturnValue(false);
mockedGetChannelById.mockResolvedValue({...channelModel, autotranslation: true} as ChannelModel);
msg.data.channel = JSON.stringify({id: channelId, type: General.PRIVATE_CHANNEL, team_id: teamId, autotranslation: false});
jest.mocked(updateChannelInfoFromChannel).mockResolvedValue({model: []});
jest.spyOn(operator, 'handleChannel').mockResolvedValueOnce([]);
await handleChannelUpdatedEvent(serverUrl, msg);
expect(deletePostsForChannel).toHaveBeenCalledWith(serverUrl, channelId);
});
it('should not call deletePostsForChannel when autotranslation stays enabled', async () => {
jest.mocked(EphemeralStore.isConvertingChannel).mockReturnValue(false);
mockedGetChannelById.mockResolvedValue({...channelModel, autotranslation: true} as ChannelModel);
msg.data.channel = JSON.stringify({id: channelId, type: General.PRIVATE_CHANNEL, team_id: teamId, autotranslation: true});
jest.mocked(updateChannelInfoFromChannel).mockResolvedValue({model: []});
jest.spyOn(operator, 'handleChannel').mockResolvedValueOnce([]);
(deletePostsForChannel as jest.Mock).mockClear();
await handleChannelUpdatedEvent(serverUrl, msg);
expect(deletePostsForChannel).not.toHaveBeenCalled();
});
});
describe('handleChannelViewedEvent', () => {
it('should handle channel viewed event', async () => {
(DatabaseManager.getActiveServerUrl as jest.Mock).mockResolvedValue(serverUrl);
(getCurrentChannelId as jest.Mock).mockResolvedValue('different_channel_id');
(EphemeralStore.isSwitchingToChannel as jest.Mock).mockReturnValue(false);
await handleChannelViewedEvent(serverUrl, msg);
expect(getCurrentChannelId).toHaveBeenCalled();
expect(markChannelAsViewed).toHaveBeenCalledWith(serverUrl, channelId);
});
it('should return if current channel ID is the same and not switching to channel', async () => {
(DatabaseManager.getActiveServerUrl as jest.Mock).mockResolvedValue(serverUrl);
(getCurrentChannelId as jest.Mock).mockResolvedValue(channelId);
(EphemeralStore.isSwitchingToChannel as jest.Mock).mockReturnValue(false);
await handleChannelViewedEvent(serverUrl, msg);
expect(markChannelAsViewed).not.toHaveBeenCalled();
});
});
describe('handleMultipleChannelsViewedEvent', () => {
it('should handle multiple channels viewed event', async () => {
msg.data.channel_times = {channel_id_1: 123, channel_id_2: 456};
(DatabaseManager.getActiveServerUrl as jest.Mock).mockResolvedValue(serverUrl);
(getCurrentChannelId as jest.Mock).mockResolvedValue('different_channel_id');
(EphemeralStore.isSwitchingToChannel as jest.Mock).mockReturnValue(false);
(markChannelAsViewed as jest.Mock).mockResolvedValue({member: {}});
await handleMultipleChannelsViewedEvent(serverUrl, msg);
expect(getCurrentChannelId).toHaveBeenCalled();
expect(markChannelAsViewed).toHaveBeenCalledWith(serverUrl, 'channel_id_1', false, true);
expect(markChannelAsViewed).toHaveBeenCalledWith(serverUrl, 'channel_id_2', false, true);
});
it('should handle multiple channels viewed event - failed', async () => {
msg.data.channel_times = {channel_id_1: 123};
(DatabaseManager.getActiveServerUrl as jest.Mock).mockResolvedValue(serverUrl);
(getCurrentChannelId as jest.Mock).mockResolvedValue('different_channel_id');
(EphemeralStore.isSwitchingToChannel as jest.Mock).mockReturnValue(false);
(markChannelAsViewed as jest.Mock).mockRejectedValueOnce({message: 'error'});
await handleMultipleChannelsViewedEvent(serverUrl, msg);
expect(getCurrentChannelId).toHaveBeenCalled();
expect(markChannelAsViewed).toHaveBeenCalledWith(serverUrl, 'channel_id_1', false, true);
});
it('should return if current channel ID is the same and not switching to channel', async () => {
msg.data.channel_times = {channel_id_1: 123, channel_id_2: 456};
(DatabaseManager.getActiveServerUrl as jest.Mock).mockResolvedValue(serverUrl);
(getCurrentChannelId as jest.Mock).mockResolvedValue('channel_id_1');
(EphemeralStore.isSwitchingToChannel as jest.Mock).mockReturnValue(false);
await handleMultipleChannelsViewedEvent(serverUrl, msg);
expect(markChannelAsViewed).not.toHaveBeenCalledWith(serverUrl, 'channel_id_1', false, true);
expect(markChannelAsViewed).toHaveBeenCalledWith(serverUrl, 'channel_id_2', false, true);
});
});
describe('handleChannelMemberUpdatedEvent', () => {
it('should handle channel member updated event', async () => {
const mockMember = JSON.stringify({id: 'member_id', channel_id: channelId, user_id: userId, roles: ''});
msg.data = {channelMember: mockMember};
mockedGetChannelById.mockResolvedValue(channelModel);
(updateChannelInfoFromChannel as jest.Mock).mockResolvedValue({model: []});
(updateMyChannelFromWebsocket as jest.Mock).mockResolvedValue({model: {}});
(fetchRolesIfNeeded as jest.Mock).mockResolvedValue({roles: []});
jest.spyOn(operator, 'batchRecords').mockResolvedValueOnce();
await handleChannelMemberUpdatedEvent(serverUrl, msg);
expect(fetchRolesIfNeeded).toHaveBeenCalled();
expect(operator.batchRecords).toHaveBeenCalled();
});
});
describe('handleDirectAddedEvent', () => {
it('should handle direct added event', async () => {
msg.data = {teammate_id: userId};
(EphemeralStore.creatingDMorGMTeammates as string[]) = [];
mockedGetChannelById.mockResolvedValue(undefined);
mockedFetchMyChannel.mockResolvedValue({channels: [channel], memberships: [{} as any]});
(getCurrentUser as jest.Mock).mockResolvedValue({id: userId, locale: 'en'});
(getTeammateNameDisplay as jest.Mock).mockResolvedValue('username');
(fetchMissingDirectChannelsInfo as jest.Mock).mockResolvedValue({directChannels: [{}], users: [{}]});
(storeMyChannelsForTeam as jest.Mock).mockResolvedValue({models: []});
(addChannelToDefaultCategory as jest.Mock).mockResolvedValue({models: []});
await handleDirectAddedEvent(serverUrl, msg);
expect(getChannelById).toHaveBeenCalled();
expect(fetchMyChannel).toHaveBeenCalledWith(serverUrl, '', channelId, true);
expect(getCurrentUser).toHaveBeenCalled();
expect(getTeammateNameDisplay).toHaveBeenCalled();
expect(fetchMissingDirectChannelsInfo).toHaveBeenCalledWith(serverUrl, [channel], 'en', 'username', userId, true);
expect(storeMyChannelsForTeam).toHaveBeenCalledWith(serverUrl, '', [{}], [{}], true);
expect(addChannelToDefaultCategory).toHaveBeenCalledWith(serverUrl, channel, true);
});
it('should handle direct added event - already adding DM', async () => {
msg.data = {teammate_id: userId};
(EphemeralStore.creatingDMorGMTeammates as string[]) = [userId];
await handleDirectAddedEvent(serverUrl, msg);
expect(getChannelById).not.toHaveBeenCalled();
});
it('should handle direct added event - already adding GM', async () => {
const teammateIds = [userId, 'userid2'];
msg.data = {teammate_ids: JSON.stringify(teammateIds)};
(EphemeralStore.creatingDMorGMTeammates as string[]) = teammateIds;
await handleDirectAddedEvent(serverUrl, msg);
expect(getChannelById).not.toHaveBeenCalled();
});
it('should return if channel already exists', async () => {
mockedGetChannelById.mockResolvedValue(channelModel);
await handleDirectAddedEvent(serverUrl, msg);
expect(getChannelById).toHaveBeenCalled();
expect(fetchMyChannel).not.toHaveBeenCalled();
});
it('should return if no channels exist', async () => {
mockedGetChannelById.mockResolvedValue(undefined);
mockedFetchMyChannel.mockResolvedValue({channels: undefined, memberships: [{} as any]});
await handleDirectAddedEvent(serverUrl, msg);
expect(getChannelById).toHaveBeenCalled();
expect(fetchMyChannel).toHaveBeenCalled();
expect(getCurrentUser).not.toHaveBeenCalled();
});
it('should return if no current user exists', async () => {
mockedGetChannelById.mockResolvedValue(undefined);
mockedFetchMyChannel.mockResolvedValue({channels: [channel], memberships: [{} as any]});
(getCurrentUser as jest.Mock).mockResolvedValue(null);
await handleDirectAddedEvent(serverUrl, msg);
expect(getChannelById).toHaveBeenCalled();
expect(fetchMyChannel).toHaveBeenCalled();
expect(getCurrentUser).toHaveBeenCalled();
expect(fetchMissingDirectChannelsInfo).not.toHaveBeenCalled();
});
it('should return if no direct channels exists', async () => {
mockedGetChannelById.mockResolvedValue(undefined);
mockedFetchMyChannel.mockResolvedValue({channels: [channel], memberships: [{} as any]});
(getCurrentUser as jest.Mock).mockResolvedValue({id: userId, locale: 'en'});
(getTeammateNameDisplay as jest.Mock).mockResolvedValue('username');
(fetchMissingDirectChannelsInfo as jest.Mock).mockResolvedValue({directChannels: [], users: [{}]});
await handleDirectAddedEvent(serverUrl, msg);
expect(getChannelById).toHaveBeenCalled();
expect(fetchMyChannel).toHaveBeenCalled();
expect(getCurrentUser).toHaveBeenCalled();
expect(fetchMissingDirectChannelsInfo).toHaveBeenCalled();
expect(storeMyChannelsForTeam).not.toHaveBeenCalled();
});
});
describe('handleUserAddedToChannelEvent', () => {
it('should handle user added to channel event for current user', async () => {
(getCurrentUser as jest.Mock).mockResolvedValue({id: userId});
mockedFetchMyChannel.mockResolvedValue({channels: [channel], memberships: [{} as any]});
mockedPrepareMyChannelsForTeam.mockResolvedValue([[] as any]);
(addChannelToDefaultCategory as jest.Mock).mockResolvedValue({models: []});
(fetchPostsForChannel as jest.Mock).mockResolvedValue({posts: [{}], order: ['order'], authors: [{}], actionType: 'action', previousPostId: 'prev_id'});
(storePostsForChannel as jest.Mock).mockResolvedValue({models: []});
await handleUserAddedToChannelEvent(serverUrl, msg);
expect(getCurrentUser).toHaveBeenCalled();
expect(fetchMyChannel).toHaveBeenCalledWith(serverUrl, teamId, channelId, true);
expect(prepareMyChannelsForTeam).toHaveBeenCalled();
expect(addChannelToDefaultCategory).toHaveBeenCalledWith(serverUrl, channel, true);
expect(fetchPostsForChannel).toHaveBeenCalledWith(serverUrl, channelId, true);
expect(storePostsForChannel).toHaveBeenCalledWith(serverUrl, channelId, [{}], ['order'], 'prev_id', 'action', [{}], true);
});
it('should handle user added to channel event for current user - already joining', async () => {
(getCurrentUser as jest.Mock).mockResolvedValue({id: userId});
(EphemeralStore.isLeavingChannel as jest.Mock).mockReturnValueOnce(false);
(EphemeralStore.isJoiningChannel as jest.Mock).mockReturnValueOnce(true);
await handleUserAddedToChannelEvent(serverUrl, msg);
expect(getCurrentUser).toHaveBeenCalled();
expect(fetchMyChannel).not.toHaveBeenCalled();
});
it('should handle user added to channel event for another user', async () => {
(getCurrentUser as jest.Mock).mockResolvedValue({id: 'other_user_id'});
(getUserById as jest.Mock).mockResolvedValue(null);
(fetchUsersByIds as jest.Mock).mockResolvedValue({users: [{id: userId, roles: ''}]});
mockedGetChannelById.mockResolvedValue(channelModel);
await handleUserAddedToChannelEvent(serverUrl, msg);
expect(getCurrentUser).toHaveBeenCalled();
expect(getUserById).toHaveBeenCalled();
expect(fetchUsersByIds).toHaveBeenCalledWith(serverUrl, [userId], true);
expect(getChannelById).toHaveBeenCalled();
});
});
describe('handleUserRemovedFromChannelEvent', () => {
it('should handle user removed from channel event for current user', async () => {
(getCurrentUser as jest.Mock).mockResolvedValue({id: userId, isGuest: false});
(getCurrentChannelId as jest.Mock).mockResolvedValue(channelId);
(deleteChannelMembership as jest.Mock).mockResolvedValue({models: []});
await handleUserRemovedFromChannelEvent(serverUrl, msg);
expect(getCurrentUser).toHaveBeenCalled();
expect(getCurrentChannelId).toHaveBeenCalled();
expect(removeCurrentUserFromChannel).toHaveBeenCalledWith(serverUrl, channelId);
});
it('should handle user removed from channel event - no current user', async () => {
(getCurrentUser as jest.Mock).mockResolvedValue(null);
await handleUserRemovedFromChannelEvent(serverUrl, msg);
expect(getCurrentUser).toHaveBeenCalled();
expect(getCurrentChannelId).not.toHaveBeenCalled();
});
it('should handle user removed from channel event - already leaving', async () => {
(EphemeralStore.isLeavingChannel as jest.Mock).mockReturnValueOnce(true);
(getCurrentCall as jest.Mock).mockReturnValueOnce({channelId});
await handleUserRemovedFromChannelEvent(serverUrl, msg);
expect(getCurrentCall).toHaveBeenCalled();
expect(leaveCall).toHaveBeenCalled();
expect(getCurrentUser).not.toHaveBeenCalled();
});
it('should handle user removed from channel event - already leaving, leave call', async () => {
(EphemeralStore.isLeavingChannel as jest.Mock).mockReturnValueOnce(true);
await handleUserRemovedFromChannelEvent(serverUrl, msg);
expect(getCurrentCall).toHaveBeenCalled();
expect(leaveCall).not.toHaveBeenCalled();
expect(getCurrentUser).not.toHaveBeenCalled();
});
it('should handle user removed from channel event for another user', async () => {
(getCurrentUser as jest.Mock).mockResolvedValue({id: 'other_user_id', isGuest: false});
(deleteChannelMembership as jest.Mock).mockResolvedValue({models: []});
await handleUserRemovedFromChannelEvent(serverUrl, msg);
expect(getCurrentUser).toHaveBeenCalled();
expect(deleteChannelMembership).toHaveBeenCalled();
});
it('should handle user removed from channel event for guest user', async () => {
(getCurrentUser as jest.Mock).mockResolvedValue({id: userId, isGuest: true});
(updateUsersNoLongerVisible as jest.Mock).mockResolvedValue({models: []});
await handleUserRemovedFromChannelEvent(serverUrl, msg);
expect(getCurrentUser).toHaveBeenCalled();
expect(updateUsersNoLongerVisible).toHaveBeenCalledWith(serverUrl, true);
});
it('should handle user removed from channel event for guest user, leave call', async () => {
(getCurrentUser as jest.Mock).mockResolvedValue({id: userId, isGuest: true});
(updateUsersNoLongerVisible as jest.Mock).mockResolvedValue({models: []});
(getCurrentCall as jest.Mock).mockReturnValueOnce({channelId});
await handleUserRemovedFromChannelEvent(serverUrl, msg);
expect(getCurrentUser).toHaveBeenCalled();
expect(updateUsersNoLongerVisible).toHaveBeenCalledWith(serverUrl, true);
expect(leaveCall).toHaveBeenCalled();
});
});
describe('handleChannelDeletedEvent', () => {
it('should handle channel deleted event', async () => {
(EphemeralStore.isLeavingChannel as jest.Mock).mockReturnValueOnce(false);
(EphemeralStore.isArchivingChannel as jest.Mock).mockReturnValueOnce(false);
(getCurrentUser as jest.Mock).mockResolvedValue({id: userId, isGuest: false});
(getCurrentChannel as jest.Mock).mockResolvedValue({id: channelId});
(getConfig as jest.Mock).mockResolvedValue({ExperimentalViewArchivedChannels: 'false'});
await handleChannelDeletedEvent(serverUrl, msg);
expect(getCurrentUser).toHaveBeenCalled();
expect(setChannelDeleteAt).toHaveBeenCalledWith(serverUrl, channelId, undefined);
expect(removeCurrentUserFromChannel).toHaveBeenCalledWith(serverUrl, channelId);
});
it('should handle channel deleted event - leaving channel, early return', async () => {
(EphemeralStore.isLeavingChannel as jest.Mock).mockReturnValueOnce(true);
(EphemeralStore.isArchivingChannel as jest.Mock).mockReturnValueOnce(false);
await handleChannelDeletedEvent(serverUrl, msg);
expect(getCurrentUser).not.toHaveBeenCalled();
});
it('should handle channel deleted event for guest user', async () => {
(EphemeralStore.isLeavingChannel as jest.Mock).mockReturnValueOnce(false);
(EphemeralStore.isArchivingChannel as jest.Mock).mockReturnValueOnce(false);
(getCurrentUser as jest.Mock).mockResolvedValue({id: userId, isGuest: true});
(getCurrentChannel as jest.Mock).mockResolvedValue({id: channelId});
(getConfig as jest.Mock).mockResolvedValue({ExperimentalViewArchivedChannels: 'false'});
await handleChannelDeletedEvent(serverUrl, msg);
expect(getCurrentUser).toHaveBeenCalled();
expect(setChannelDeleteAt).toHaveBeenCalledWith(serverUrl, channelId, undefined);
expect(updateUsersNoLongerVisible).toHaveBeenCalledWith(serverUrl);
expect(removeCurrentUserFromChannel).toHaveBeenCalledWith(serverUrl, channelId);
});
it('should handle channel deleted event with ExperimentalViewArchivedChannels enabled', async () => {
(EphemeralStore.isLeavingChannel as jest.Mock).mockReturnValueOnce(false);
(EphemeralStore.isArchivingChannel as jest.Mock).mockReturnValueOnce(false);
(getCurrentUser as jest.Mock).mockResolvedValue({id: userId, isGuest: false});
(getCurrentChannel as jest.Mock).mockResolvedValue({id: channelId});
(getConfig as jest.Mock).mockResolvedValue({ExperimentalViewArchivedChannels: 'true'});
await handleChannelDeletedEvent(serverUrl, msg);
expect(getCurrentUser).toHaveBeenCalled();
expect(setChannelDeleteAt).toHaveBeenCalledWith(serverUrl, channelId, undefined);
expect(removeCurrentUserFromChannel).not.toHaveBeenCalled();
});
});
});