mattermost-mobile/app/actions/remote/entry/deferred.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

968 lines
39 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
/* eslint-disable max-lines */
import {act} from '@testing-library/react-native';
import {fetchMyChannelsForTeam, fetchMissingDirectChannelsInfo, type MyChannelsRequest} from '@actions/remote/channel';
import {fetchGroupsForMember} from '@actions/remote/groups';
import {fetchPostsForUnreadChannels} from '@actions/remote/post';
import {fetchScheduledPosts} from '@actions/remote/scheduled_post';
import {fetchTeamsThreads, updateCanJoinTeams, type MyTeamsRequest} from '@actions/remote/team';
import {autoUpdateTimezone, updateAllUsersSince, type MyUserRequest} from '@actions/remote/user';
import {Preferences} from '@constants';
import DatabaseManager from '@database/manager';
import {processEntryModels, processEntryModelsForDeletion} from '@queries/servers/entry';
import {deferredAppEntryActions, restDeferredAppEntryActions, testExports} from './deferred';
jest.mock('@actions/remote/channel');
jest.mock('@actions/remote/scheduled_post');
jest.mock('@actions/remote/team');
jest.mock('@actions/remote/user');
jest.mock('@actions/remote/post');
jest.mock('@actions/remote/groups');
jest.mock('@queries/servers/entry');
describe('actions/remote/entry/deferred', () => {
const serverUrl = 'https://server.example.com';
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(),
};
beforeEach(async () => {
jest.clearAllMocks();
DatabaseManager.getServerDatabaseAndOperator = jest.fn().mockReturnValue({
database: {},
operator: mockOperator,
});
});
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;
const meData = undefined;
await deferredAppEntryActions(
serverUrl,
since,
currentUserId,
currentUserLocale,
preferences,
config,
license,
teamData,
chData,
meData,
);
expect(autoUpdateTimezone).toHaveBeenCalledWith(serverUrl, undefined);
});
});
describe('restDeferredAppEntryActions', () => {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
global.setTimeout = jest.fn((cb) => cb()) as any;
const since = 123456789;
const currentUserId = 'user1';
const currentUserLocale = 'en';
const defaultConfig = {
Version: '7.8.0',
CollapsedThreads: 'false',
FeatureFlagCollapsedThreads: 'true',
LockTeammateNameDisplay: 'false',
TeammateNameDisplay: 'username',
} as ClientConfig;
const license = {} as ClientLicense;
const defaultTeamData = {
teams: [{id: 'team1', display_name: 'Team 1'}],
memberships: [{team_id: 'team1', user_id: 'user1'}],
} as MyTeamsRequest;
const defaultChData = {
channels: [
{id: 'dm1', type: 'D', name: 'dm-channel'} as Channel,
{id: 'channel1', type: 'O', name: 'channel1', team_id: 'team1'} as Channel,
],
memberships: [
{channel_id: 'dm1', user_id: 'user1'} as ChannelMembership,
{channel_id: 'channel1', user_id: 'user1'} as ChannelMembership,
],
categories: [],
} as MyChannelsRequest;
const defaultMeData = {
user: {id: 'user1', roles: '', username: 'user1'},
} as MyUserRequest;
const initialTeamId = 'team1';
const initialChannelId = 'channel1';
it('should execute deferred actions correctly', async () => {
const preferences = [{
category: 'advanced_settings',
name: 'feature_enabled',
value: 'true',
user_id: 'user1',
}];
await restDeferredAppEntryActions(
serverUrl,
since,
currentUserId,
currentUserLocale,
preferences,
defaultConfig,
license,
defaultTeamData,
defaultChData,
defaultMeData,
initialTeamId,
initialChannelId,
);
expect(fetchMissingDirectChannelsInfo).toHaveBeenCalled();
expect(updateAllUsersSince).toHaveBeenCalledWith(serverUrl, since, false, undefined);
expect(updateCanJoinTeams).toHaveBeenCalledWith(serverUrl);
expect(processEntryModelsForDeletion).toHaveBeenCalledWith({serverUrl, operator: mockOperator, teamData: defaultTeamData, chData: defaultChData});
expect(fetchPostsForUnreadChannels).toHaveBeenCalled();
expect(fetchGroupsForMember).toHaveBeenCalledWith(serverUrl, currentUserId, false, undefined);
expect(fetchScheduledPosts).toHaveBeenCalledWith(serverUrl, initialTeamId, true, undefined);
});
it('should handle missing data gracefully', async () => {
const preferences = undefined;
const config = {
Version: '7.8.0',
CollapsedThreads: 'false',
} as ClientConfig;
const teamData = {
teams: [],
memberships: [],
};
const chData = undefined;
const meData = undefined;
await restDeferredAppEntryActions(
serverUrl,
since,
currentUserId,
currentUserLocale,
preferences,
config,
license,
teamData,
chData,
meData,
);
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 preferences = [{
category: Preferences.CATEGORIES.TEAMS_ORDER,
name: '',
value: 'team2,team1',
user_id: 'user1',
}];
const config = {
...defaultConfig,
CollapsedThreads: 'true',
} as ClientConfig;
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 act(async () => {
await restDeferredAppEntryActions(
serverUrl,
since,
currentUserId,
currentUserLocale,
preferences,
config,
license,
teamData,
chData,
defaultMeData,
'team1',
'channel1',
);
});
expect(fetchTeamsThreads).toHaveBeenCalled();
expect(fetchPostsForUnreadChannels).toHaveBeenCalled();
});
it('should handle direct channels info correctly', async () => {
const preferences = [] as PreferenceType[];
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,
defaultConfig,
license,
teamData,
chData,
defaultMeData,
);
expect(fetchMissingDirectChannelsInfo).toHaveBeenCalledWith(
serverUrl,
expect.arrayContaining([
expect.objectContaining({id: 'dm1'}),
expect.objectContaining({id: 'gm1'}),
]),
currentUserLocale,
'username',
currentUserId,
false,
undefined,
);
});
it('should show all teams in order even when fetchMyChannelsForTeam throws an error', async () => {
jest.mocked(fetchMyChannelsForTeam).mockRejectedValueOnce(new Error('test')).mockResolvedValueOnce({
channels: [],
memberships: [],
} as MyChannelsRequest);
const preferences = [{
category: Preferences.CATEGORIES.TEAMS_ORDER,
name: '',
value: 'team1,team2',
user_id: 'user1',
}];
const config = {
...defaultConfig,
CollapsedThreads: 'true',
} as ClientConfig;
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 act(async () => {
await restDeferredAppEntryActions(
serverUrl,
since,
currentUserId,
currentUserLocale,
preferences,
config,
license,
teamData,
chData,
defaultMeData,
);
});
expect(processEntryModels).toHaveBeenCalledWith(serverUrl,
expect.objectContaining({
teamData: expect.objectContaining({
teams: expect.arrayContaining([
expect.objectContaining({id: 'team1'}),
]),
}),
}),
);
expect(processEntryModels).toHaveBeenCalledWith(serverUrl,
expect.objectContaining({
teamData: expect.objectContaining({
teams: expect.arrayContaining([
expect.objectContaining({id: 'team2'}),
]),
}),
}),
);
});
});
describe('sortTeamsByPreferences', () => {
let mockTeamMap: Map<string, Team>;
let mockTeamData: MyTeamsRequest;
const {sortTeamsByPreferences} = testExports;
beforeEach(() => {
mockTeamMap = new Map([
['team1', {id: 'team1', display_name: 'Team Alpha'} as Team],
['team2', {id: 'team2', display_name: 'Team Beta'} as Team],
['team3', {id: 'team3', display_name: 'Team Gamma'} as Team],
['team4', {id: 'team4', display_name: 'Team Delta'} as Team],
]);
mockTeamData = {
teams: [
{id: 'team1', display_name: 'Team Alpha'} as Team,
{id: 'team2', display_name: 'Team Beta'} as Team,
{id: 'team3', display_name: 'Team Gamma'} as Team,
{id: 'team4', display_name: 'Team Delta'} as Team,
],
memberships: [
{team_id: 'team1', user_id: 'user1', mention_count: 0, msg_count: 0, roles: '', delete_at: 0, scheme_user: false, scheme_admin: false},
{team_id: 'team2', user_id: 'user1', mention_count: 0, msg_count: 0, roles: '', delete_at: 0, scheme_user: false, scheme_admin: false},
{team_id: 'team3', user_id: 'user1', mention_count: 0, msg_count: 0, roles: '', delete_at: 0, scheme_user: false, scheme_admin: false},
{team_id: 'team4', user_id: 'user1', mention_count: 0, msg_count: 0, roles: '', delete_at: 0, scheme_user: false, scheme_admin: false},
],
};
});
it('should sort teams alphabetically when no preferences are provided', () => {
const preferences = undefined;
const result = sortTeamsByPreferences(mockTeamData, preferences, mockTeamMap);
expect(result[0].display_name).toBe('Team Alpha');
expect(result[1].display_name).toBe('Team Beta');
expect(result[2].display_name).toBe('Team Delta');
expect(result[3].display_name).toBe('Team Gamma');
});
it('should sort teams alphabetically when preferences array is empty', () => {
const preferences: PreferenceType[] = [];
const result = sortTeamsByPreferences(mockTeamData, preferences, mockTeamMap);
expect(result[0].display_name).toBe('Team Alpha');
expect(result[1].display_name).toBe('Team Beta');
expect(result[2].display_name).toBe('Team Delta');
expect(result[3].display_name).toBe('Team Gamma');
});
it('should sort teams according to preferences order when teams order preference exists', () => {
const preferences: PreferenceType[] = [{
category: Preferences.CATEGORIES.TEAMS_ORDER,
name: '',
value: 'team3,team1,team4',
user_id: 'user1',
}];
const result = sortTeamsByPreferences(mockTeamData, preferences, mockTeamMap);
expect(result[0].display_name).toBe('Team Gamma'); // team3
expect(result[1].display_name).toBe('Team Alpha'); // team1
expect(result[2].display_name).toBe('Team Delta'); // team4
expect(result[3].display_name).toBe('Team Beta'); // team2 (extra team, sorted alphabetically)
});
it('should handle teams not in preferences by sorting them alphabetically', () => {
const preferences: PreferenceType[] = [{
category: Preferences.CATEGORIES.TEAMS_ORDER,
name: '',
value: 'team1,team3', // Only team1 and team3 in preferences
user_id: 'user1',
}];
const result = sortTeamsByPreferences(mockTeamData, preferences, mockTeamMap);
expect(result[0].display_name).toBe('Team Alpha'); // team1 (from preferences)
expect(result[1].display_name).toBe('Team Gamma'); // team3 (from preferences)
expect(result[2].display_name).toBe('Team Beta'); // team2 (extra, sorted alphabetically)
expect(result[3].display_name).toBe('Team Delta'); // team4 (extra, sorted alphabetically)
});
it('should filter out teams that are not in memberships', () => {
const preferences: PreferenceType[] = [{
category: Preferences.CATEGORIES.TEAMS_ORDER,
name: '',
value: 'team1,team5,team2', // team5 doesn't exist in memberships
user_id: 'user1',
}];
const result = sortTeamsByPreferences(mockTeamData, preferences, mockTeamMap);
expect(result[0].display_name).toBe('Team Alpha'); // team1 (from preferences)
expect(result[1].display_name).toBe('Team Beta'); // team2 (from preferences)
expect(result[2].display_name).toBe('Team Delta'); // team4 (extra, sorted alphabetically)
expect(result[3].display_name).toBe('Team Gamma'); // team3 (extra, sorted alphabetically)
expect(result.length).toBe(4); // team5 is filtered out
});
it('should handle case-insensitive sorting for extra teams', () => {
const teamDataWithMixedCase: MyTeamsRequest = {
teams: [
{id: 'team1', display_name: 'alpha team'} as Team,
{id: 'team2', display_name: 'BETA TEAM'} as Team,
{id: 'team3', display_name: 'Gamma Team'} as Team,
{id: 'team4', display_name: 'delta team'} as Team,
],
memberships: mockTeamData.memberships,
};
const teamMapWithMixedCase = new Map([
['team1', {id: 'team1', display_name: 'alpha team'} as Team],
['team2', {id: 'team2', display_name: 'BETA TEAM'} as Team],
['team3', {id: 'team3', display_name: 'Gamma Team'} as Team],
['team4', {id: 'team4', display_name: 'delta team'} as Team],
]);
const preferences: PreferenceType[] = [{
category: Preferences.CATEGORIES.TEAMS_ORDER,
name: '',
value: 'team1', // Only team1 in preferences
user_id: 'user1',
}];
const result = sortTeamsByPreferences(teamDataWithMixedCase, preferences, teamMapWithMixedCase);
expect(result[0].display_name).toBe('alpha team'); // team1 (from preferences)
expect(result[1].display_name).toBe('BETA TEAM'); // team2 (extra, sorted alphabetically)
expect(result[2].display_name).toBe('delta team'); // team4 (extra, sorted alphabetically)
expect(result[3].display_name).toBe('Gamma Team'); // team3 (extra, sorted alphabetically)
});
it('should handle empty teams array', () => {
const emptyTeamData: MyTeamsRequest = {
teams: [],
memberships: [],
};
const preferences: PreferenceType[] = [{
category: Preferences.CATEGORIES.TEAMS_ORDER,
name: '',
value: 'team1,team2',
user_id: 'user1',
}];
const result = sortTeamsByPreferences(emptyTeamData, preferences, new Map());
expect(result).toEqual([]);
});
it('should handle teams with missing display_name', () => {
const teamDataWithMissingNames: MyTeamsRequest = {
teams: [
{id: 'team1', display_name: 'Team Alpha'} as Team,
{id: 'team2', display_name: ''} as Team,
{id: 'team3', display_name: 'Team Gamma'} as Team,
],
memberships: mockTeamData.memberships!.slice(0, 3),
};
const teamMapWithMissingNames = new Map([
['team1', {id: 'team1', display_name: 'Team Alpha'} as Team],
['team2', {id: 'team2', display_name: ''} as Team],
['team3', {id: 'team3', display_name: 'Team Gamma'} as Team],
]);
const preferences: PreferenceType[] = [{
category: Preferences.CATEGORIES.TEAMS_ORDER,
name: '',
value: 'team1,team3',
user_id: 'user1',
}];
const result = sortTeamsByPreferences(teamDataWithMissingNames, preferences, teamMapWithMissingNames);
expect(result[0].display_name).toBe('Team Alpha'); // team1 (from preferences)
expect(result[1].display_name).toBe('Team Gamma'); // team3 (from preferences)
expect(result[2].display_name).toBe(''); // team2 (extra, empty string sorts first)
});
it('should handle teams that exist in preferences but not in teamMap', () => {
const preferences: PreferenceType[] = [{
category: Preferences.CATEGORIES.TEAMS_ORDER,
name: '',
value: 'team1,team5,team2', // team5 exists in preferences but not in teamMap
user_id: 'user1',
}];
const result = sortTeamsByPreferences(mockTeamData, preferences, mockTeamMap);
expect(result[0].display_name).toBe('Team Alpha'); // team1 (from preferences, exists in teamMap)
expect(result[1].display_name).toBe('Team Beta'); // team2 (from preferences, exists in teamMap)
expect(result[2].display_name).toBe('Team Delta'); // team4 (extra, sorted alphabetically)
expect(result[3].display_name).toBe('Team Gamma'); // team3 (extra, sorted alphabetically)
expect(result.length).toBe(4); // team5 is filtered out (not in teamMap)
});
it('should handle empty preferences value', () => {
const preferences: PreferenceType[] = [{
category: Preferences.CATEGORIES.TEAMS_ORDER,
name: '',
value: '', // Empty value
user_id: 'user1',
}];
const result = sortTeamsByPreferences(mockTeamData, preferences, mockTeamMap);
expect(result[0].display_name).toBe('Team Alpha');
expect(result[1].display_name).toBe('Team Beta');
expect(result[2].display_name).toBe('Team Delta');
expect(result[3].display_name).toBe('Team Gamma');
});
it('should handle preferences with only one team', () => {
const preferences: PreferenceType[] = [{
category: Preferences.CATEGORIES.TEAMS_ORDER,
name: '',
value: 'team2', // Only one team in preferences
user_id: 'user1',
}];
const result = sortTeamsByPreferences(mockTeamData, preferences, mockTeamMap);
expect(result[0].display_name).toBe('Team Beta'); // team2 (from preferences)
expect(result[1].display_name).toBe('Team Alpha'); // team1 (extra, sorted alphabetically)
expect(result[2].display_name).toBe('Team Delta'); // team4 (extra, sorted alphabetically)
expect(result[3].display_name).toBe('Team Gamma'); // team3 (extra, sorted alphabetically)
});
it('should handle undefined teamData.memberships', () => {
const teamDataWithUndefinedMemberships: MyTeamsRequest = {
teams: mockTeamData.teams,
memberships: undefined,
};
const preferences: PreferenceType[] = [{
category: Preferences.CATEGORIES.TEAMS_ORDER,
name: '',
value: 'team1,team2',
user_id: 'user1',
}];
const result = sortTeamsByPreferences(teamDataWithUndefinedMemberships, preferences, mockTeamMap);
// When memberships is undefined, membershipSet becomes empty
// Since we have preferences (sortedTeamIds.size > 0), it goes to the first path
// But no teams match the membershipSet filter, so both sortedTeams and extraTeams are empty
expect(result).toEqual([]);
});
it('should handle undefined teamData.teams', () => {
const teamDataWithUndefinedTeams: MyTeamsRequest = {
teams: undefined,
memberships: mockTeamData.memberships,
};
const preferences: PreferenceType[] = [{
category: Preferences.CATEGORIES.TEAMS_ORDER,
name: '',
value: 'team1,team2',
user_id: 'user1',
}];
// Create an empty teamMap since teamData.teams is undefined
const emptyTeamMap = new Map<string, Team>();
const result = sortTeamsByPreferences(teamDataWithUndefinedTeams, preferences, emptyTeamMap);
// When teams is undefined, teamMap is empty, so no teams can be found
expect(result).toEqual([]);
});
it('should handle empty teamData.memberships array', () => {
const teamDataWithEmptyMemberships: MyTeamsRequest = {
teams: mockTeamData.teams,
memberships: [],
};
const preferences: PreferenceType[] = [{
category: Preferences.CATEGORIES.TEAMS_ORDER,
name: '',
value: 'team1,team2',
user_id: 'user1',
}];
const result = sortTeamsByPreferences(teamDataWithEmptyMemberships, preferences, mockTeamMap);
// When memberships is empty, membershipSet becomes empty
// Since we have preferences (sortedTeamIds.size > 0), it goes to the first path
// But no teams match the membershipSet filter, so both sortedTeams and extraTeams are empty
expect(result).toEqual([]);
});
it('should handle both undefined teams and memberships', () => {
const teamDataWithUndefinedBoth: MyTeamsRequest = {
teams: undefined,
memberships: undefined,
};
const preferences: PreferenceType[] = [{
category: Preferences.CATEGORIES.TEAMS_ORDER,
name: '',
value: 'team1,team2',
user_id: 'user1',
}];
const result = sortTeamsByPreferences(teamDataWithUndefinedBoth, preferences, mockTeamMap);
// When both teams and memberships are undefined, it should return empty array
expect(result).toEqual([]);
});
it('should handle empty teams array with undefined memberships', () => {
const teamDataWithEmptyTeamsAndUndefinedMemberships: MyTeamsRequest = {
teams: [],
memberships: undefined,
};
const preferences: PreferenceType[] = [{
category: Preferences.CATEGORIES.TEAMS_ORDER,
name: '',
value: 'team1,team2',
user_id: 'user1',
}];
const result = sortTeamsByPreferences(teamDataWithEmptyTeamsAndUndefinedMemberships, preferences, mockTeamMap);
// When teams is empty and memberships is undefined, it should return empty array
expect(result).toEqual([]);
});
it('should handle undefined teams with empty memberships', () => {
const teamDataWithUndefinedTeamsAndEmptyMemberships: MyTeamsRequest = {
teams: undefined,
memberships: [],
};
const preferences: PreferenceType[] = [{
category: Preferences.CATEGORIES.TEAMS_ORDER,
name: '',
value: 'team1,team2',
user_id: 'user1',
}];
const result = sortTeamsByPreferences(teamDataWithUndefinedTeamsAndEmptyMemberships, preferences, mockTeamMap);
// When teams is undefined and memberships is empty, it should return empty array
expect(result).toEqual([]);
});
});
describe('combineChannelsData', () => {
const {combineChannelsData} = testExports;
it('should combine channels when both target and source have channels', () => {
const target: MyChannelsRequest = {
channels: [
{id: 'channel1', name: 'Channel 1', type: 'O', team_id: 'team1'} as Channel,
{id: 'channel2', name: 'Channel 2', type: 'O', team_id: 'team1'} as Channel,
],
memberships: [
{channel_id: 'channel1', user_id: 'user1'} as ChannelMembership,
{channel_id: 'channel2', user_id: 'user1'} as ChannelMembership,
],
categories: [
{id: 'category1', display_name: 'Category 1', team_id: 'team1', sort_order: 0, sorting: 'alpha', type: 'custom', muted: false, collapsed: false, channel_ids: ['channel1', 'channel2']} as CategoryWithChannels,
],
};
const source: MyChannelsRequest = {
channels: [
{id: 'channel3', name: 'Channel 3', type: 'O', team_id: 'team2'} as Channel,
{id: 'channel4', name: 'Channel 4', type: 'O', team_id: 'team2'} as Channel,
],
memberships: [
{channel_id: 'channel3', user_id: 'user1'} as ChannelMembership,
{channel_id: 'channel4', user_id: 'user1'} as ChannelMembership,
],
categories: [
{id: 'category2', display_name: 'Category 2', team_id: 'team2', sort_order: 1, sorting: 'alpha', type: 'custom', muted: false, collapsed: false, channel_ids: ['channel3', 'channel4']} as CategoryWithChannels,
],
};
combineChannelsData(target, source);
expect(target.channels).toHaveLength(4);
expect(target.channels).toEqual([
{id: 'channel1', name: 'Channel 1', type: 'O', team_id: 'team1'} as Channel,
{id: 'channel2', name: 'Channel 2', type: 'O', team_id: 'team1'} as Channel,
{id: 'channel3', name: 'Channel 3', type: 'O', team_id: 'team2'} as Channel,
{id: 'channel4', name: 'Channel 4', type: 'O', team_id: 'team2'} as Channel,
]);
expect(target.memberships).toHaveLength(4);
expect(target.memberships).toEqual([
{channel_id: 'channel1', user_id: 'user1'} as ChannelMembership,
{channel_id: 'channel2', user_id: 'user1'} as ChannelMembership,
{channel_id: 'channel3', user_id: 'user1'} as ChannelMembership,
{channel_id: 'channel4', user_id: 'user1'} as ChannelMembership,
]);
expect(target.categories).toHaveLength(2);
expect(target.categories).toEqual([
{id: 'category1', display_name: 'Category 1', team_id: 'team1', sort_order: 0, sorting: 'alpha', type: 'custom', muted: false, collapsed: false, channel_ids: ['channel1', 'channel2']} as CategoryWithChannels,
{id: 'category2', display_name: 'Category 2', team_id: 'team2', sort_order: 1, sorting: 'alpha', type: 'custom', muted: false, collapsed: false, channel_ids: ['channel3', 'channel4']} as CategoryWithChannels,
]);
});
it('should combine channels when target has no channels but source does', () => {
const target: MyChannelsRequest = {
channels: undefined,
memberships: [],
};
const source: MyChannelsRequest = {
channels: [
{id: 'channel1', name: 'Channel 1', type: 'O', team_id: 'team1'} as Channel,
],
memberships: [
{channel_id: 'channel1', user_id: 'user1'} as ChannelMembership,
],
};
combineChannelsData(target, source);
// When target.channels is undefined, concat returns undefined
expect(target.channels).toBeUndefined();
});
it('should combine channels when target has channels but source has no channels', () => {
const target: MyChannelsRequest = {
channels: [
{id: 'channel1', name: 'Channel 1', type: 'O', team_id: 'team1'} as Channel,
],
memberships: [
{channel_id: 'channel1', user_id: 'user1'} as ChannelMembership,
],
};
const source: MyChannelsRequest = {
channels: undefined,
memberships: [],
};
combineChannelsData(target, source);
expect(target.channels).toHaveLength(1);
expect(target.channels).toEqual([
{id: 'channel1', name: 'Channel 1', type: 'O', team_id: 'team1'} as Channel,
]);
});
it('should combine memberships when both target and source have memberships', () => {
const target: MyChannelsRequest = {
channels: [],
memberships: [
{channel_id: 'channel1', user_id: 'user1'} as ChannelMembership,
{channel_id: 'channel2', user_id: 'user1'} as ChannelMembership,
],
};
const source: MyChannelsRequest = {
channels: [],
memberships: [
{channel_id: 'channel3', user_id: 'user1'} as ChannelMembership,
{channel_id: 'channel4', user_id: 'user1'} as ChannelMembership,
],
};
combineChannelsData(target, source);
expect(target.memberships).toHaveLength(4);
expect(target.memberships).toEqual([
{channel_id: 'channel1', user_id: 'user1'} as ChannelMembership,
{channel_id: 'channel2', user_id: 'user1'} as ChannelMembership,
{channel_id: 'channel3', user_id: 'user1'} as ChannelMembership,
{channel_id: 'channel4', user_id: 'user1'} as ChannelMembership,
]);
});
it('should combine memberships when target has no memberships but source does', () => {
const target: MyChannelsRequest = {
channels: [],
memberships: undefined,
};
const source: MyChannelsRequest = {
channels: [],
memberships: [
{channel_id: 'channel1', user_id: 'user1'} as ChannelMembership,
],
};
combineChannelsData(target, source);
// When target.memberships is undefined, concat returns undefined
expect(target.memberships).toBeUndefined();
});
it('should combine memberships when target has memberships but source has no memberships', () => {
const target: MyChannelsRequest = {
channels: [],
memberships: [
{channel_id: 'channel1', user_id: 'user1'} as ChannelMembership,
],
};
const source: MyChannelsRequest = {
channels: [],
memberships: undefined,
};
combineChannelsData(target, source);
expect(target.memberships).toHaveLength(1);
expect(target.memberships).toEqual([
{channel_id: 'channel1', user_id: 'user1'} as ChannelMembership,
]);
});
it('should handle empty arrays in source', () => {
const target: MyChannelsRequest = {
channels: [
{id: 'channel1', name: 'Channel 1', type: 'O', team_id: 'team1'} as Channel,
],
memberships: [
{channel_id: 'channel1', user_id: 'user1'} as ChannelMembership,
],
};
const source: MyChannelsRequest = {
channels: [],
memberships: [],
};
combineChannelsData(target, source);
expect(target.channels).toHaveLength(1);
expect(target.memberships).toHaveLength(1);
});
it('should handle empty arrays in target', () => {
const target: MyChannelsRequest = {
channels: [],
memberships: [],
};
const source: MyChannelsRequest = {
channels: [
{id: 'channel1', name: 'Channel 1', type: 'O', team_id: 'team1'} as Channel,
],
memberships: [
{channel_id: 'channel1', user_id: 'user1'} as ChannelMembership,
],
};
combineChannelsData(target, source);
expect(target.channels).toHaveLength(1);
expect(target.memberships).toHaveLength(1);
});
it('should handle undefined values in both target and source', () => {
const target: MyChannelsRequest = {
channels: undefined,
memberships: undefined,
categories: undefined,
};
const source: MyChannelsRequest = {
channels: undefined,
memberships: undefined,
categories: undefined,
};
combineChannelsData(target, source);
expect(target.channels).toBeUndefined();
expect(target.memberships).toBeUndefined();
expect(target.categories).toBeUndefined();
});
it('should handle mixed undefined and defined values', () => {
const target: MyChannelsRequest = {
channels: [
{id: 'channel1', name: 'Channel 1', type: 'O', team_id: 'team1'} as Channel,
],
memberships: undefined,
};
const source: MyChannelsRequest = {
channels: undefined,
memberships: [
{channel_id: 'channel1', user_id: 'user1'} as ChannelMembership,
],
};
combineChannelsData(target, source);
expect(target.channels).toHaveLength(1);
// When target.memberships is undefined, concat returns undefined
expect(target.memberships).toBeUndefined();
});
});
});
/* eslint-enable max-lines */