MM-59426 Add tests for entry common functions (#8515)

* test: Add tests for entry common functions

* increase functions coverage to 80%

---------

Co-authored-by: yasserfaraazkhan <attitude3cena.yf@gmail.com>
This commit is contained in:
Joram Wilander 2025-01-28 08:09:43 -05:00 committed by GitHub
parent 6a96ca52ad
commit 3ef637ff9d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 959 additions and 2 deletions

View file

@ -0,0 +1,957 @@
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
/* eslint-disable max-lines */
import {nativeApplicationVersion} from 'expo-application';
import {RESULTS} from 'react-native-permissions';
import {handleKickFromChannel, fetchAllMyChannelsForAllTeams, fetchMissingDirectChannelsInfo, type MyChannelsRequest} from '@actions/remote/channel';
import {fetchGroupsForMember} from '@actions/remote/groups';
import {fetchPostsForUnreadChannels} from '@actions/remote/post';
import {fetchMyPreferences} from '@actions/remote/preference';
import {fetchConfigAndLicense} from '@actions/remote/systems';
import {fetchMyTeams, fetchTeamsThreads, updateCanJoinTeams, handleKickFromTeam, type MyTeamsRequest} from '@actions/remote/team';
import {fetchMe, updateAllUsersSince, autoUpdateTimezone} from '@actions/remote/user';
import {Preferences, Screens} from '@constants';
import {SYSTEM_IDENTIFIERS} from '@constants/database';
import {PUSH_PROXY_STATUS_VERIFIED} from '@constants/push_proxy';
import DatabaseManager from '@database/manager';
import NetworkManager from '@managers/network_manager';
import {getDeviceToken} from '@queries/app/global';
import {getCurrentChannelId, getCurrentTeamId, setCurrentTeamAndChannelId} from '@queries/servers/system';
import NavigationStore from '@store/navigation_store';
import {entry, setExtraSessionProps, verifyPushProxy, entryInitialChannelId, restDeferredAppEntryActions, handleEntryAfterLoadNavigation, deferredAppEntryActions} from './common';
jest.mock('@actions/remote/channel');
jest.mock('@actions/remote/preference');
jest.mock('@actions/remote/systems');
jest.mock('@actions/remote/team');
jest.mock('@actions/remote/user');
jest.mock('@actions/remote/post');
jest.mock('@actions/remote/groups');
jest.mock('@actions/remote/thread');
jest.mock('@queries/app/global');
jest.mock('@queries/servers/system');
jest.mock('@queries/servers/system', () => {
const original = jest.requireActual('@queries/servers/system');
return {
...original,
getCurrentTeamId: jest.fn(),
getCurrentChannelId: jest.fn(),
setCurrentTeamAndChannelId: jest.fn(original.setCurrentTeamAndChannelId),
};
});
jest.mock('react-native-permissions');
jest.mock('expo-application');
describe('actions/remote/entry/common', () => {
const serverUrl = 'https://server.example.com';
let mockClient: any;
const mockOperator = {
handleSystem: jest.fn(),
handleUsers: jest.fn(),
handlePreferences: jest.fn(),
handleTeams: jest.fn(),
handleChannels: jest.fn(),
handlePosts: jest.fn(),
handleCategories: jest.fn(),
handleGroups: jest.fn(),
handleRoles: jest.fn(),
};
const mockQuery = {
fetch: jest.fn().mockReturnValue(['true']),
};
const mockCollection = {
query: jest.fn().mockReturnValue(mockQuery),
};
const mockDatabase = {
get: jest.fn().mockReturnValue(mockCollection),
collections: {
get: jest.fn().mockReturnValue(mockCollection),
},
};
beforeEach(async () => {
jest.clearAllMocks();
mockClient = {
setExtraSessionProps: jest.fn(),
ping: jest.fn().mockResolvedValue({
data: {
CanReceiveNotifications: true,
},
}),
};
NetworkManager.init([{serverUrl} as ServerCredential]);
NetworkManager.getClient = jest.fn().mockReturnValue(mockClient);
DatabaseManager.init = jest.fn().mockResolvedValue(undefined);
DatabaseManager.getServerDatabaseAndOperator = jest.fn().mockReturnValue({
database: mockDatabase,
operator: mockOperator,
});
// Reset mock implementations
(RESULTS as any).GRANTED = 'granted';
require('react-native-permissions').checkNotifications = jest.fn().mockResolvedValue({status: RESULTS.GRANTED});
require('expo-application').nativeApplicationVersion = '0.0.0';
});
describe('entry', () => {
it('should fetch initial data successfully', async () => {
const mockConfig = {Version: '7.8.0'};
const mockLicense = {};
(fetchConfigAndLicense as jest.Mock).mockResolvedValue({error: false, config: mockConfig, license: mockLicense});
const mockPreferences = {preferences: []};
(fetchMyPreferences as jest.Mock).mockResolvedValue(mockPreferences);
const mockTeams = {teams: [], memberships: []};
(fetchMyTeams as jest.Mock).mockResolvedValue(mockTeams);
const mockUser = {user: {id: 'user1', roles: '', username: 'user1'}};
(fetchMe as jest.Mock).mockResolvedValue(mockUser);
const mockChannels = {channels: [], memberships: []};
(fetchAllMyChannelsForAllTeams as jest.Mock).mockResolvedValue(mockChannels);
const result = await entry(serverUrl);
expect(result).toEqual(expect.objectContaining({
initialChannelId: '',
initialTeamId: '',
models: expect.any(Array),
prefData: mockPreferences,
teamData: mockTeams,
chData: mockChannels,
meData: mockUser,
gmConverted: false,
}));
});
it('should handle errors in data fetching', async () => {
const mockError = new Error('Network error');
(fetchConfigAndLicense as jest.Mock).mockResolvedValue({error: mockError});
const result = await entry(serverUrl);
expect(result).toEqual({
error: mockError,
});
});
});
describe('entryInitialChannelId', () => {
it('should return requested channel id for DM/GM channels', async () => {
const channels = [
{id: 'dm1', type: 'D', name: 'dm-channel'},
] as Channel[];
const memberships = [{channel_id: 'dm1'}] as ChannelMembership[];
const result = await entryInitialChannelId(
mockDatabase as any,
'dm1',
'',
'',
'en',
channels,
memberships,
);
expect(result).toBe('dm1');
});
it('should return default channel when available', async () => {
const channels = [
{id: 'town-square', name: 'town-square', team_id: 'team1', type: 'O'},
] as Channel[];
const memberships = [{channel_id: 'town-square'}] as ChannelMembership[];
const result = await entryInitialChannelId(
mockDatabase as any,
'',
'team1',
'team1',
'en',
channels,
memberships,
);
expect(result).toBe('town-square');
});
});
describe('setExtraSessionProps', () => {
it('should set extra session properties when notifications are granted', async () => {
(RESULTS as any).GRANTED = 'granted';
const mockCheckNotifications = jest.fn().mockResolvedValue({status: RESULTS.GRANTED});
require('react-native-permissions').checkNotifications = mockCheckNotifications;
jest.mocked(getDeviceToken).mockResolvedValueOnce('deviceToken');
const result = await setExtraSessionProps(serverUrl);
expect(result).toEqual({});
expect(mockClient.setExtraSessionProps).toHaveBeenCalledWith(
expect.any(String),
false,
nativeApplicationVersion,
undefined,
);
});
it('should set extra session properties when notifications are limited', async () => {
(RESULTS as any).LIMITED = 'limited';
const mockCheckNotifications = jest.fn().mockResolvedValue({status: RESULTS.LIMITED});
require('react-native-permissions').checkNotifications = mockCheckNotifications;
jest.mocked(getDeviceToken).mockResolvedValueOnce('deviceToken');
const result = await setExtraSessionProps(serverUrl);
expect(result).toEqual({});
expect(mockClient.setExtraSessionProps).toHaveBeenCalledWith(
expect.any(String),
false,
nativeApplicationVersion,
undefined,
);
});
it('should handle errors gracefully', async () => {
const mockError = new Error('Failed to set props');
const mockCheckNotifications = jest.fn().mockRejectedValue(mockError);
require('react-native-permissions').checkNotifications = mockCheckNotifications;
jest.mocked(getDeviceToken).mockResolvedValueOnce('deviceToken');
const result = await setExtraSessionProps(serverUrl);
expect(result).toEqual({error: mockError});
});
});
describe('deferredAppEntryActions', () => {
it('should call autoUpdateTimezone', async () => {
const since = 123456789;
const currentUserId = 'user1';
const currentUserLocale = 'en';
const preferences = [{
category: 'advanced_settings',
name: 'feature_enabled',
value: 'true',
user_id: 'user1',
}];
const config = {
Version: '7.8.0',
CollapsedThreads: 'false',
FeatureFlagCollapsedThreads: 'true',
} as ClientConfig;
const license = {} as ClientLicense;
const teamData = {teams: [], memberships: []};
const chData = undefined;
await deferredAppEntryActions(
serverUrl,
since,
currentUserId,
currentUserLocale,
preferences,
config,
license,
teamData,
chData,
);
expect(autoUpdateTimezone).toHaveBeenCalledWith(serverUrl, undefined);
});
});
describe('restDeferredAppEntryActions', () => {
global.setTimeout = jest.fn((cb) => cb()) as any;
it('should execute deferred actions correctly', async () => {
const since = 123456789;
const currentUserId = 'user1';
const currentUserLocale = 'en';
const preferences = [{
category: 'advanced_settings',
name: 'feature_enabled',
value: 'true',
user_id: 'user1',
}];
const config = {
Version: '7.8.0',
CollapsedThreads: 'false',
FeatureFlagCollapsedThreads: 'true',
LockTeammateNameDisplay: 'false',
TeammateNameDisplay: 'username',
} as ClientConfig;
const license = {} as ClientLicense;
const teamData = {
teams: [{id: 'team1', display_name: 'Team 1'}],
memberships: [{team_id: 'team1', user_id: 'user1'}],
} as MyTeamsRequest;
const chData = {
channels: [
{id: 'dm1', type: 'D', name: 'dm-channel'},
{id: 'channel1', type: 'O', name: 'channel1', team_id: 'team1'},
],
memberships: [
{channel_id: 'dm1', user_id: 'user1'},
{channel_id: 'channel1', user_id: 'user1'},
],
} as MyChannelsRequest;
const initialTeamId = 'team1';
const initialChannelId = 'channel1';
await restDeferredAppEntryActions(
serverUrl,
since,
currentUserId,
currentUserLocale,
preferences,
config,
license,
teamData,
chData,
initialTeamId,
initialChannelId,
);
expect(fetchMissingDirectChannelsInfo).toHaveBeenCalled();
expect(updateAllUsersSince).toHaveBeenCalledWith(serverUrl, since, false, undefined);
expect(updateCanJoinTeams).toHaveBeenCalledWith(serverUrl);
expect(fetchPostsForUnreadChannels).toHaveBeenCalled();
expect(fetchGroupsForMember).toHaveBeenCalledWith(serverUrl, currentUserId, false, undefined);
});
it('should handle missing data gracefully', async () => {
const since = 123456789;
const currentUserId = 'user1';
const currentUserLocale = 'en';
const preferences = undefined;
const config = {
Version: '7.8.0',
CollapsedThreads: 'false',
} as ClientConfig;
const license = {} as ClientLicense;
const teamData = {
teams: [],
memberships: [],
};
const chData = undefined;
await restDeferredAppEntryActions(
serverUrl,
since,
currentUserId,
currentUserLocale,
preferences,
config,
license,
teamData,
chData,
);
expect(updateAllUsersSince).toHaveBeenCalledWith(serverUrl, since, false, undefined);
expect(updateCanJoinTeams).toHaveBeenCalledWith(serverUrl);
expect(fetchGroupsForMember).toHaveBeenCalledWith(serverUrl, currentUserId, false, undefined);
expect(fetchMissingDirectChannelsInfo).not.toHaveBeenCalled();
expect(fetchPostsForUnreadChannels).not.toHaveBeenCalled();
expect(fetchTeamsThreads).not.toHaveBeenCalled();
});
it('should handle teams order preference correctly', async () => {
const since = 123456789;
const currentUserId = 'user1';
const currentUserLocale = 'en';
const preferences = [{
category: Preferences.CATEGORIES.TEAMS_ORDER,
name: '',
value: 'team2,team1',
user_id: 'user1',
}];
const config = {
Version: '7.8.0',
CollapsedThreads: 'true',
FeatureFlagCollapsedThreads: 'true',
} as ClientConfig;
const license = {} as ClientLicense;
const teamData = {
teams: [
{id: 'team1', display_name: 'Team 1'},
{id: 'team2', display_name: 'Team 2'},
],
memberships: [
{team_id: 'team1', user_id: 'user1'},
{team_id: 'team2', user_id: 'user1'},
],
} as MyTeamsRequest;
const chData = {
channels: [
{id: 'channel1', team_id: 'team1', type: 'O'},
{id: 'channel2', team_id: 'team2', type: 'O'},
],
memberships: [
{channel_id: 'channel1', user_id: 'user1'},
{channel_id: 'channel2', user_id: 'user1'},
],
} as MyChannelsRequest;
await restDeferredAppEntryActions(
serverUrl,
since,
currentUserId,
currentUserLocale,
preferences,
config,
license,
teamData,
chData,
'team1',
'channel1',
);
expect(fetchTeamsThreads).toHaveBeenCalled();
expect(fetchPostsForUnreadChannels).toHaveBeenCalled();
});
it('should handle direct channels info correctly', async () => {
const since = 123456789;
const currentUserId = 'user1';
const currentUserLocale = 'en';
const preferences = [] as PreferenceType[];
const config = {
Version: '7.8.0',
CollapsedThreads: 'false',
LockTeammateNameDisplay: 'false',
TeammateNameDisplay: 'username',
} as ClientConfig;
const license = {} as ClientLicense;
const teamData = {teams: [], memberships: []};
const chData = {
channels: [
{id: 'dm1', type: 'D', name: 'user1__user2'},
{id: 'gm1', type: 'G', name: 'group-message'},
],
memberships: [
{channel_id: 'dm1', user_id: 'user1'},
{channel_id: 'gm1', user_id: 'user1'},
],
} as MyChannelsRequest;
await restDeferredAppEntryActions(
serverUrl,
since,
currentUserId,
currentUserLocale,
preferences,
config,
license,
teamData,
chData,
);
expect(fetchMissingDirectChannelsInfo).toHaveBeenCalledWith(
serverUrl,
expect.arrayContaining([
expect.objectContaining({id: 'dm1'}),
expect.objectContaining({id: 'gm1'}),
]),
currentUserLocale,
'username',
currentUserId,
false,
undefined,
);
});
it('should sort teams when preferences are missing', async () => {
const since = 123456789;
const currentUserId = 'user1';
const currentUserLocale = 'en';
const preferences: PreferenceType[] = [];
const config = {
Version: '7.8.0',
CollapsedThreads: 'false',
} as ClientConfig;
const license = {} as ClientLicense;
const teamData = {
teams: [
{id: 'team1', display_name: 'Zebra'},
{id: 'team2', display_name: 'Alpha'},
],
memberships: [
{team_id: 'team1', user_id: 'user1'},
{team_id: 'team2', user_id: 'user1'},
],
} as MyTeamsRequest;
const chData = {
channels: [],
memberships: [],
} as MyChannelsRequest;
await restDeferredAppEntryActions(
serverUrl,
since,
currentUserId,
currentUserLocale,
preferences,
config,
license,
teamData,
chData,
undefined,
undefined,
);
expect(teamData.teams?.[0]?.display_name).toBe('Alpha');
expect(teamData.teams?.[1]?.display_name).toBe('Zebra');
});
it('should handle extra teams correctly when sorted teams are provided', async () => {
const since = 123456789;
const currentUserId = 'user1';
const currentUserLocale = 'en';
const preferences = [{
category: Preferences.CATEGORIES.TEAMS_ORDER,
name: '',
value: 'team3,team1',
user_id: 'user1',
}];
const config = {
Version: '7.8.0',
CollapsedThreads: 'true',
FeatureFlagCollapsedThreads: 'true',
} as ClientConfig;
const license = {} as ClientLicense;
const teamData = {
teams: [
{id: 'team1', display_name: 'Team 1'},
{id: 'team2', display_name: 'Team 2'},
{id: 'team3', display_name: 'Team 3'},
],
memberships: [
{team_id: 'team1', user_id: 'user1'},
{team_id: 'team2', user_id: 'user1'},
{team_id: 'team3', user_id: 'user1'},
],
} as MyTeamsRequest;
const chData = {
channels: [
{id: 'channel1', team_id: 'team1', type: 'O'},
{id: 'channel2', team_id: 'team2', type: 'O'},
],
memberships: [
{channel_id: 'channel1', user_id: 'user1'},
{channel_id: 'channel2', user_id: 'user1'},
],
} as MyChannelsRequest;
await restDeferredAppEntryActions(
serverUrl,
since,
currentUserId,
currentUserLocale,
preferences,
config,
license,
teamData,
chData,
'team1',
'channel1',
);
// Check that 'team3' (which was in memberships but not sorted) is in the 'extraTeams' result
expect(fetchTeamsThreads).toHaveBeenCalled();
expect(fetchPostsForUnreadChannels).toHaveBeenCalled();
// Optionally check if team3 is sorted after team1 based on display name or the intended order
expect(teamData.teams?.[0]?.display_name).toBe('Team 1');
expect(teamData.teams?.[1]?.display_name).toBe('Team 2');
expect(teamData.teams?.[2]?.display_name).toBe('Team 3');
});
it('should sort extra teams correctly by display name', async () => {
const since = 123456789;
const currentUserId = 'user1';
const currentUserLocale = 'en';
const preferences = [{
category: Preferences.CATEGORIES.TEAMS_ORDER,
name: '',
value: 'team1,team2', // Teams that are already sorted based on preferences
user_id: 'user1',
}];
const config = {
Version: '7.8.0',
CollapsedThreads: 'true',
FeatureFlagCollapsedThreads: 'true',
} as ClientConfig;
const license = {} as ClientLicense;
const teamData = {
teams: [
{id: 'team1', display_name: 'Team 1'},
{id: 'team2', display_name: 'Team 2'},
{id: 'team3', display_name: 'Alpha Team'},
{id: 'team4', display_name: 'Zebra Team'},
],
memberships: [
{team_id: 'team1', user_id: 'user1'},
{team_id: 'team2', user_id: 'user1'},
{team_id: 'team3', user_id: 'user1'},
{team_id: 'team4', user_id: 'user1'},
],
} as MyTeamsRequest;
const chData = {
channels: [],
memberships: [],
} as MyChannelsRequest;
// Call the function under test
await restDeferredAppEntryActions(
serverUrl,
since,
currentUserId,
currentUserLocale,
preferences,
config,
license,
teamData,
chData,
'team1', // initialTeamId
'channel1', // initialChannelId
);
// Extract the extra teams (those that are not in the preferences-sorted list)
const extraTeams = [...(teamData.memberships || [])].
filter((membership) => !preferences[0].value.split(',').includes(membership.team_id)). // Filter teams not in sorted order
map((membership) => (teamData.teams ?? []).find((team) => team.id === membership.team_id)!). // Map to actual team data
sort((a, b) => a.display_name.toLocaleLowerCase().localeCompare(b.display_name.toLocaleLowerCase())); // Sort by display_name
// Test that the extra teams are sorted alphabetically by display_name
expect(extraTeams[0].display_name).toBe('Alpha Team'); // Alphabetically first
expect(extraTeams[1].display_name).toBe('Zebra Team'); // Alphabetically last
});
});
describe('verifyPushProxy', () => {
it('should verify push proxy status successfully', async () => {
jest.mocked(getDeviceToken).mockResolvedValueOnce('deviceToken');
await verifyPushProxy(serverUrl);
expect(mockClient.ping).toHaveBeenCalled();
});
it('should handle error gracefully', async () => {
jest.mocked(getDeviceToken).mockResolvedValueOnce('deviceToken');
mockClient.ping.mockRejectedValueOnce(new Error('Network error'));
await verifyPushProxy(serverUrl);
expect(mockOperator.handleSystem).not.toHaveBeenCalled();
});
it('should handle verified push proxy response', async () => {
jest.mocked(getDeviceToken).mockResolvedValueOnce('deviceToken');
mockClient.ping.mockResolvedValueOnce({
data: {
CanReceiveNotifications: true,
},
});
await verifyPushProxy(serverUrl);
expect(mockOperator.handleSystem).toHaveBeenCalledWith({
systems: [{
id: SYSTEM_IDENTIFIERS.PUSH_VERIFICATION_STATUS,
value: PUSH_PROXY_STATUS_VERIFIED,
}],
prepareRecordsOnly: false,
});
});
it('should handle missing device token', async () => {
jest.mocked(getDeviceToken).mockResolvedValueOnce('');
await verifyPushProxy(serverUrl);
expect(mockClient.ping).not.toHaveBeenCalled();
});
it('should handle push proxy not available response', async () => {
jest.mocked(getDeviceToken).mockResolvedValueOnce('deviceToken');
mockClient.ping.mockResolvedValueOnce({
data: {
CanReceiveNotifications: 'false',
},
});
await verifyPushProxy(serverUrl);
expect(mockOperator.handleSystem).toHaveBeenCalledWith({
systems: [{
id: SYSTEM_IDENTIFIERS.PUSH_VERIFICATION_STATUS,
value: 'not_available',
}],
prepareRecordsOnly: false,
});
});
it('should handle push proxy unknown response', async () => {
jest.mocked(getDeviceToken).mockResolvedValueOnce('deviceToken');
mockClient.ping.mockResolvedValueOnce({
data: {
CanReceiveNotifications: 'unknown',
},
});
await verifyPushProxy(serverUrl);
expect(mockOperator.handleSystem).not.toHaveBeenCalled();
});
it('should handle network error', async () => {
jest.mocked(getDeviceToken).mockResolvedValueOnce('deviceToken');
mockClient.ping.mockRejectedValueOnce(new Error('Network error'));
await verifyPushProxy(serverUrl);
expect(mockOperator.handleSystem).not.toHaveBeenCalled();
});
});
describe('handleEntryAfterLoadNavigation', () => {
beforeEach(() => {
jest.clearAllMocks();
});
const teamMembers = [{team_id: 'team1', delete_at: 0} as TeamMembership];
const channelMembers = [{channel_id: 'channel1'} as ChannelMembership];
it('should handle first load or no team scenario', async () => {
await handleEntryAfterLoadNavigation(
serverUrl,
teamMembers,
channelMembers,
'team1',
'channel1',
'initialTeam1',
'initialChannel1',
false,
);
expect(mockOperator.handleSystem).toHaveBeenCalled();
});
it('should handle current team switch during loading', async () => {
jest.mocked(getCurrentTeamId).mockResolvedValueOnce('team2');
await handleEntryAfterLoadNavigation(
serverUrl,
teamMembers,
channelMembers,
'team1',
'channel1',
'initialTeam1',
'initialChannel1',
false,
);
expect(handleKickFromTeam).toHaveBeenCalled();
});
it('should handle initial team switch during loading', async () => {
jest.mocked(getCurrentTeamId).mockResolvedValueOnce('team1');
await handleEntryAfterLoadNavigation(
serverUrl,
teamMembers,
channelMembers,
'team1',
'channel1',
'initialTeam1',
'initialChannel1',
false,
);
expect(handleKickFromTeam).toHaveBeenCalled();
});
it('should handle initial team switch during loading', async () => {
jest.mocked(getCurrentTeamId).mockResolvedValueOnce('team1');
await handleEntryAfterLoadNavigation(
serverUrl,
teamMembers,
channelMembers,
'team1',
'channel1',
'initialTeam1',
'initialChannel1',
true,
);
expect(setCurrentTeamAndChannelId).toHaveBeenCalled();
});
it('should handle current channel switch during loading', async () => {
jest.mocked(getCurrentTeamId).mockResolvedValueOnce('team1');
jest.mocked(getCurrentChannelId).mockResolvedValueOnce('channel2');
await handleEntryAfterLoadNavigation(
serverUrl,
teamMembers,
channelMembers,
'team1',
'channel1',
'team1',
'initialChannel1',
true,
);
expect(setCurrentTeamAndChannelId).toHaveBeenCalled();
});
it('should handle initial channel switch during loading', async () => {
jest.mocked(getCurrentTeamId).mockResolvedValueOnce('team1');
jest.mocked(getCurrentChannelId).mockResolvedValueOnce('channel1');
await handleEntryAfterLoadNavigation(
serverUrl,
teamMembers,
channelMembers,
'team1',
'channel1',
'team1',
'initialChannel1',
true,
);
expect(setCurrentTeamAndChannelId).toHaveBeenCalled();
});
it('should handle current channel switch during loading - thread mounted', async () => {
jest.spyOn(NavigationStore, 'getScreensInStack').mockReturnValue([Screens.THREAD]);
jest.mocked(getCurrentTeamId).mockResolvedValueOnce('team1');
jest.mocked(getCurrentChannelId).mockResolvedValueOnce('channel2');
await handleEntryAfterLoadNavigation(
serverUrl,
teamMembers,
channelMembers,
'team1',
'channel1',
'team1',
'initialChannel1',
true,
);
expect(handleKickFromChannel).toHaveBeenCalled();
});
it('should handle initial channel switch during loading - thread mounted', async () => {
jest.spyOn(NavigationStore, 'getScreensInStack').mockReturnValue([Screens.THREAD]);
jest.mocked(getCurrentTeamId).mockResolvedValueOnce('team1');
jest.mocked(getCurrentChannelId).mockResolvedValueOnce('channel1');
await handleEntryAfterLoadNavigation(
serverUrl,
teamMembers,
channelMembers,
'team1',
'channel1',
'team1',
'initialChannel1',
true,
);
expect(handleKickFromChannel).toHaveBeenCalled();
});
it('should handle error gracefully', async () => {
const consoleDebugSpy = jest.spyOn(console, 'debug').mockImplementation(() => {});
(DatabaseManager.getServerDatabaseAndOperator as jest.Mock).mockImplementation(() => {
throw new Error('Test error');
});
await handleEntryAfterLoadNavigation(
serverUrl,
teamMembers,
channelMembers,
'team1',
'channel1',
'initialTeam1',
'initialChannel1',
false,
);
expect(consoleDebugSpy).toHaveBeenCalled();
consoleDebugSpy.mockRestore();
});
it('should handle tablet device scenario', async () => {
jest.spyOn(NavigationStore, 'getScreensInStack').mockReturnValue([]);
jest.spyOn(require('@utils/helpers'), 'isTablet').mockReturnValue(true);
await handleEntryAfterLoadNavigation(
serverUrl,
teamMembers,
channelMembers,
'team1',
'channel1',
'initialTeam1',
'initialChannel1',
false,
);
expect(mockOperator.handleSystem).toHaveBeenCalled();
});
it('should handle channel screen mounted scenario', async () => {
jest.spyOn(NavigationStore, 'getScreensInStack').mockReturnValue([Screens.CHANNEL]);
jest.spyOn(require('@utils/helpers'), 'isTablet').mockReturnValue(false);
await handleEntryAfterLoadNavigation(
serverUrl,
teamMembers,
channelMembers,
'team1',
'differentChannel',
'team1',
'initialChannel1',
false,
);
expect(mockOperator.handleSystem).toHaveBeenCalled();
});
it('should handle threads screen mounted scenario', async () => {
jest.spyOn(NavigationStore, 'getScreensInStack').mockReturnValue([Screens.THREAD]);
jest.spyOn(require('@utils/helpers'), 'isTablet').mockReturnValue(false);
await handleEntryAfterLoadNavigation(
serverUrl,
teamMembers,
channelMembers,
'team1',
'differentChannel',
'team1',
'initialChannel1',
false,
);
expect(mockOperator.handleSystem).toHaveBeenCalled();
});
it('should handle kick from team scenario', async () => {
jest.spyOn(NavigationStore, 'getScreensInStack').mockReturnValue([]);
await handleEntryAfterLoadNavigation(
serverUrl,
teamMembers,
channelMembers,
'differentTeam',
'channel1',
'initialTeam1',
'initialChannel1',
false,
);
expect(mockOperator.handleSystem).toHaveBeenCalled();
});
});
});

View file

@ -204,7 +204,7 @@ const entryRest = async (serverUrl: string, teamId?: string, channelId?: string,
}
};
async function entryInitialChannelId(database: Database, requestedChannelId = '', requestedTeamId = '', initialTeamId: string, locale: string, channels?: Channel[], memberships?: ChannelMember[]) {
export async function entryInitialChannelId(database: Database, requestedChannelId = '', requestedTeamId = '', initialTeamId: string, locale: string, channels?: Channel[], memberships?: ChannelMember[]) {
const membershipIds = new Set(memberships?.map((m) => m.channel_id));
const requestedChannel = channels?.find((c) => (c.id === requestedChannelId) && membershipIds.has(c.id));
@ -242,7 +242,7 @@ async function entryInitialChannelId(database: Database, requestedChannelId = ''
return myFirstTeamChannel?.id || '';
}
async function restDeferredAppEntryActions(
export async function restDeferredAppEntryActions(
serverUrl: string, since: number, currentUserId: string, currentUserLocale: string, preferences: PreferenceType[] | undefined,
config: ClientConfig, license: ClientLicense | undefined, teamData: MyTeamsRequest, chData: MyChannelsRequest | undefined,
initialTeamId?: string, initialChannelId?: string, groupLabel?: BaseRequestGroupLabel,