mattermost-mobile/app/queries/servers/channel.test.ts
Elias Nahum d1d3fda83a
Request metrics improvements (#8420)
* Network metrics

* update network-client ref

* fix unit tests

* missing catch error parsing

* Replace API's to fetch all teams and channels for a user
Update groupLabel to use a type definition
Include effective Latency and Average Speed in the metrics
Include parallel and sequential request counts

* update network library and fix tests

* feat(MM-61865): send network request telemetry data to the server (#8436)

* feat(MM-61865): send network info telemetry data

* unit testing

* fix latency vs effectiveLatency

* cleanup test

* fix failing tests

* fix spelling error

* fix failing test

* more cleanup

* fix: improve parallel requests calculation (#8439)

* fix: improve parallel requests calculation

* fix test issue

* multiple parallelGroups testing

* calculateAverageSpeedWithCategories test

* categorizedRequests in it's own describe

* clean up duplicate tests

* check for when groupLabel is non-existent

* a case when groupLabel is non-existent

* more testing with effective latency.

* resolveAndFlattenModels with a capital F

* add try..catch within resolveAndFlattenModels

* update groupLabel to fix failing lint

* fix linting issue due to unknown group label

* forgot to push changes

* fix the indentation problem again

* add env var option for COLLECT_NETWORK_METRICS

---------

Co-authored-by: Rahim Rahman <rahim.rahman@mattermost.com>
Co-authored-by: Mattermost Build <build@mattermost.com>
2025-01-16 13:55:29 -07:00

1554 lines
62 KiB
TypeScript

// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
/* eslint-disable max-lines */
import {Database, Model, Query, Relation, Q} from '@nozbe/watermelondb';
import {of as of$} from 'rxjs';
import {General, Permissions} from '@constants';
import {MM_TABLES} from '@constants/database';
import ServerDataOperator from '@database/operator/server_data_operator';
import {hasPermission} from '@utils/role';
import {prepareChannels,
prepareMissingChannelsForAllTeams,
prepareMyChannelsForTeam,
prepareDeleteChannel,
prepareDeleteBookmarks,
type ChannelMembershipsExtended,
queryAllChannels,
queryAllChannelsForTeam,
queryAllChannelsInfo,
queryAllChannelsInfoForTeam,
queryAllMyChannel,
queryAllMyChannelsForTeam,
queryAllUnreadDMsAndGMsIds,
queryChannelsById,
queryChannelsByTypes,
queryUserChannelsByTypes,
queryTeamDefaultChannel,
queryMyChannelsByTeam,
queryUsersOnChannel,
getMyChannel,
observeMyChannel,
observeMyChannelRoles,
getChannelById,
observeChannel,
getChannelByName,
getDefaultChannelForTeam,
getCurrentChannel,
getCurrentChannelInfo,
observeCurrentChannel,
getChannelInfo,
deleteChannelMembership,
addChannelMembership,
getMembersCountByChannelsId,
queryAllMyChannelSettings,
queryMyChannelSettingsByIds,
queryMyChannelUnreads,
queryMyRecentChannels,
observeChannelInfo,
observeAllMyChannelNotifyProps,
observeNotifyPropsByChannels,
observeMyChannelMentionCount,
observeArchiveChannelsByTerm,
observeChannelsByLastPostAt,
observeChannelSettings,
observeDirectChannelsByTerm,
observeIsMutedSetting,
observeJoinedChannelsByTerm,
observeNotDirectChannelsByTerm,
queryChannelMembers,
queryChannelsForAutocomplete,
observeChannelMembers,
} from './channel';
import {queryRoles} from './role';
import {getCurrentChannelId, observeCurrentChannelId, observeCurrentUserId} from './system';
import {observeTeammateNameDisplay} from './user';
import type {UserModel} from '@database/models/server';
import type ChannelModel from '@typings/database/models/servers/channel';
import type ChannelBookmarkModel from '@typings/database/models/servers/channel_bookmark';
import type ChannelInfoModel from '@typings/database/models/servers/channel_info';
import type ChannelMembershipModel from '@typings/database/models/servers/channel_membership';
import type MyChannelModel from '@typings/database/models/servers/my_channel';
import type MyChannelSettingsModel from '@typings/database/models/servers/my_channel_settings';
jest.mock('./role');
jest.mock('./system');
jest.mock('./user');
jest.mock('@utils/role');
describe('prepareChannels', () => {
let operator: ServerDataOperator;
beforeEach(() => {
operator = {
handleChannel: jest.fn(),
handleChannelInfo: jest.fn(),
handleChannelMembership: jest.fn(),
handleMyChannel: jest.fn(),
handleMyChannelSettings: jest.fn(),
} as unknown as ServerDataOperator;
});
it('should prepare channels, channelInfos, channelMemberships, memberships, and myChannelSettings', () => {
const channels = [{id: 'channel1'}, {id: 'channel2'}] as Channel[];
const channelInfos = [{id: 'channel1'}, {id: 'channel2'}] as ChannelInfo[];
const channelMemberships = [{channel_id: 'channel1', user_id: 'user1'}, {channel_id: 'channel2', user_id: 'user2'}] as ChannelMembershipsExtended[];
const memberships = [{channel_id: 'channel1', user_id: 'user1'}, {channel_id: 'channel2', user_id: 'user2'}] as ChannelMembership[];
const channelRecords = Promise.resolve([]);
const channelInfoRecords = Promise.resolve([]);
const membershipRecords = Promise.resolve([]);
const myChannelRecords = Promise.resolve([]);
const myChannelSettingsRecords = Promise.resolve([]);
(operator.handleChannel as jest.Mock).mockReturnValue(channelRecords);
(operator.handleChannelInfo as jest.Mock).mockReturnValue(channelInfoRecords);
(operator.handleChannelMembership as jest.Mock).mockReturnValue(membershipRecords);
(operator.handleMyChannel as jest.Mock).mockReturnValue(myChannelRecords);
(operator.handleMyChannelSettings as jest.Mock).mockReturnValue(myChannelSettingsRecords);
const result = prepareChannels(operator, channels, channelInfos, channelMemberships, memberships, true);
expect(result).toEqual([channelRecords, channelInfoRecords, membershipRecords, myChannelRecords, myChannelSettingsRecords]);
expect(operator.handleChannel).toHaveBeenCalledWith({channels, prepareRecordsOnly: true});
expect(operator.handleChannelInfo).toHaveBeenCalledWith({channelInfos, prepareRecordsOnly: true});
expect(operator.handleChannelMembership).toHaveBeenCalledWith({channelMemberships, prepareRecordsOnly: true});
expect(operator.handleMyChannel).toHaveBeenCalledWith({channels, myChannels: memberships, prepareRecordsOnly: true, isCRTEnabled: true});
expect(operator.handleMyChannelSettings).toHaveBeenCalledWith({settings: memberships, prepareRecordsOnly: true});
});
it('should return an empty array if an error occurs', () => {
(operator.handleChannel as jest.Mock).mockImplementation(() => {
throw new Error('Test error');
});
const result = prepareChannels(operator);
expect(result).toEqual([]);
});
});
describe('prepareMissingChannelsForAllTeams', () => {
let operator: ServerDataOperator;
beforeEach(() => {
operator = {
handleChannel: jest.fn(),
handleChannelInfo: jest.fn(),
handleChannelMembership: jest.fn(),
handleMyChannel: jest.fn(),
handleMyChannelSettings: jest.fn(),
} as unknown as ServerDataOperator;
});
it('should prepare missing channels for all teams', () => {
const channels = [
{id: 'channel1', header: 'header1', purpose: 'purpose1', last_post_at: 123, last_root_post_at: 456},
{id: 'channel2', header: 'header2', purpose: 'purpose2', last_post_at: 789, last_root_post_at: 101112},
] as Channel[];
const channelMembers = [
{channel_id: 'channel1', user_id: 'user1'},
{channel_id: 'channel2', user_id: 'user2'},
] as ChannelMembership[];
const channelRecords = Promise.resolve([]);
const channelInfoRecords = Promise.resolve([]);
const membershipRecords = Promise.resolve([]);
const myChannelRecords = Promise.resolve([]);
const myChannelSettingsRecords = Promise.resolve([]);
(operator.handleChannel as jest.Mock).mockReturnValue(channelRecords);
(operator.handleChannelInfo as jest.Mock).mockReturnValue(channelInfoRecords);
(operator.handleChannelMembership as jest.Mock).mockReturnValue(membershipRecords);
(operator.handleMyChannel as jest.Mock).mockReturnValue(myChannelRecords);
(operator.handleMyChannelSettings as jest.Mock).mockReturnValue(myChannelSettingsRecords);
const result = prepareMissingChannelsForAllTeams(operator, channels, channelMembers, true);
expect(result).toEqual([channelRecords, channelInfoRecords, membershipRecords, myChannelRecords, myChannelSettingsRecords]);
expect(operator.handleChannel).toHaveBeenCalledWith({channels, prepareRecordsOnly: true});
expect(operator.handleChannelInfo).toHaveBeenCalledWith({
channelInfos: [
{id: 'channel1', header: 'header1', purpose: 'purpose1', guest_count: 0, member_count: 0, pinned_post_count: 0, files_count: 0},
{id: 'channel2', header: 'header2', purpose: 'purpose2', guest_count: 0, member_count: 0, pinned_post_count: 0, files_count: 0},
],
prepareRecordsOnly: true,
});
expect(operator.handleChannelMembership).toHaveBeenCalledWith({
channelMemberships: [
{channel_id: 'channel1', user_id: 'user1', id: 'channel1', last_post_at: 123, last_root_post_at: 456},
{channel_id: 'channel2', user_id: 'user2', id: 'channel2', last_post_at: 789, last_root_post_at: 101112},
],
prepareRecordsOnly: true,
});
expect(operator.handleMyChannel).toHaveBeenCalledWith({
channels,
myChannels: [
{channel_id: 'channel1', user_id: 'user1', id: 'channel1', last_post_at: 123, last_root_post_at: 456},
{channel_id: 'channel2', user_id: 'user2', id: 'channel2', last_post_at: 789, last_root_post_at: 101112},
],
prepareRecordsOnly: true,
isCRTEnabled: true,
});
expect(operator.handleMyChannelSettings).toHaveBeenCalledWith({
settings: [
{channel_id: 'channel1', user_id: 'user1', id: 'channel1', last_post_at: 123, last_root_post_at: 456},
{channel_id: 'channel2', user_id: 'user2', id: 'channel2', last_post_at: 789, last_root_post_at: 101112},
],
prepareRecordsOnly: true,
});
});
it('should return an empty array if an error occurs', () => {
(operator.handleChannel as jest.Mock).mockImplementation(() => {
throw new Error('Test error');
});
const result = prepareMissingChannelsForAllTeams(operator, [], []);
expect(result).toEqual([]);
});
});
describe('prepareMyChannelsForTeam', () => {
let operator: ServerDataOperator;
let database: Database;
let query: jest.Mock;
beforeEach(() => {
query = jest.fn();
database = {
get: () => ({
query,
}),
} as unknown as Database;
operator = {
handleChannel: jest.fn(),
handleChannelInfo: jest.fn(),
handleChannelMembership: jest.fn(),
handleMyChannel: jest.fn(),
handleMyChannelSettings: jest.fn(),
database,
} as unknown as ServerDataOperator;
});
it('should prepare my channels for a team', async () => {
const teamId = 'team_id';
const channels = [
{id: 'channel1', header: 'header1', purpose: 'purpose1', last_post_at: 123, last_root_post_at: 456},
{id: 'channel2', header: 'header2', purpose: 'purpose2', last_post_at: 789, last_root_post_at: 101112},
] as Channel[];
const channelMembers = [
{channel_id: 'channel1', user_id: 'user1'},
{channel_id: 'channel2', user_id: 'user2'},
] as ChannelMembership[];
const allChannelsForTeam = {
channel1: {id: 'channel1'},
channel2: {id: 'channel2'},
};
const allChannelsInfoForTeam = {
channel1: {id: 'channel1', memberCount: 10, guestCount: 2, pinnedPostCount: 1, filesCount: 5},
channel2: {id: 'channel2', memberCount: 20, guestCount: 3, pinnedPostCount: 2, filesCount: 10},
};
const channelsQuery = {fetch: jest.fn().mockResolvedValue(Object.values(allChannelsForTeam))};
const channelInfosQuery = {fetch: jest.fn().mockResolvedValue(Object.values(allChannelsInfoForTeam))};
query.mockReturnValueOnce(channelsQuery);
query.mockReturnValueOnce(channelInfosQuery);
const channelRecords = Promise.resolve([]);
const channelInfoRecords = Promise.resolve([]);
const membershipRecords = Promise.resolve([]);
const myChannelRecords = Promise.resolve([]);
const myChannelSettingsRecords = Promise.resolve([]);
(operator.handleChannel as jest.Mock).mockReturnValue(channelRecords);
(operator.handleChannelInfo as jest.Mock).mockReturnValue(channelInfoRecords);
(operator.handleChannelMembership as jest.Mock).mockReturnValue(membershipRecords);
(operator.handleMyChannel as jest.Mock).mockReturnValue(myChannelRecords);
(operator.handleMyChannelSettings as jest.Mock).mockReturnValue(myChannelSettingsRecords);
query = jest.fn().mockResolvedValueOnce(Object.entries(allChannelsForTeam).map((c) => c[1])).mockResolvedValueOnce(Object.entries(allChannelsInfoForTeam).map((i) => i[1]));
const result = await prepareMyChannelsForTeam(operator, teamId, channels, channelMembers, true);
query = jest.fn();
expect(result).toEqual([channelRecords, channelInfoRecords, membershipRecords, myChannelRecords, myChannelSettingsRecords]);
expect(operator.handleChannel).toHaveBeenCalledWith({channels, prepareRecordsOnly: true});
expect(operator.handleChannelInfo).toHaveBeenCalledWith({
channelInfos: [
{id: 'channel1', header: 'header1', purpose: 'purpose1', guest_count: 2, member_count: 10, pinned_post_count: 1, files_count: 5},
{id: 'channel2', header: 'header2', purpose: 'purpose2', guest_count: 3, member_count: 20, pinned_post_count: 2, files_count: 10},
],
prepareRecordsOnly: true,
});
expect(operator.handleChannelMembership).toHaveBeenCalledWith({
channelMemberships: [
{channel_id: 'channel1', user_id: 'user1'},
{channel_id: 'channel2', user_id: 'user2'},
],
prepareRecordsOnly: true,
});
expect(operator.handleMyChannel).toHaveBeenCalledWith({
channels,
myChannels: [
{channel_id: 'channel1', user_id: 'user1', id: 'channel1'},
{channel_id: 'channel2', user_id: 'user2', id: 'channel2'},
],
prepareRecordsOnly: true,
isCRTEnabled: true,
});
expect(operator.handleMyChannelSettings).toHaveBeenCalledWith({
settings: [
{channel_id: 'channel1', user_id: 'user1', id: 'channel1'},
{channel_id: 'channel2', user_id: 'user2', id: 'channel2'},
],
prepareRecordsOnly: true,
});
});
});
describe('prepareDeleteChannel', () => {
let channel: ChannelModel;
beforeEach(() => {
channel = {
prepareDestroyPermanently: jest.fn().mockReturnValue({}),
membership: {fetch: jest.fn()} as unknown as Relation<Model>,
info: {fetch: jest.fn()} as unknown as Relation<Model>,
categoryChannel: {fetch: jest.fn()} as unknown as Relation<Model>,
members: {fetch: jest.fn()} as unknown as Query<Model>,
drafts: {fetch: jest.fn()} as unknown as Query<Model>,
postsInChannel: {fetch: jest.fn()} as unknown as Query<Model>,
posts: {fetch: jest.fn()} as unknown as Query<Model>,
bookmarks: {fetch: jest.fn()} as unknown as Query<Model>,
} as unknown as ChannelModel;
});
it('should prepare models for deletion', async () => {
const prepareDestroyPermanently = jest.fn().mockReturnValue({});
const membershipModel = {prepareDestroyPermanently: jest.fn().mockReturnValue({id: 'membership'})};
const infoModel = {prepareDestroyPermanently: jest.fn().mockReturnValue({id: 'info'})};
const categoryChannelModel = {prepareDestroyPermanently: jest.fn().mockReturnValue({id: 'category'})};
const memberModels = [{prepareDestroyPermanently: jest.fn().mockReturnValue({id: 'member'})}];
const draftModels = [{prepareDestroyPermanently: jest.fn().mockReturnValue({id: 'draft'})}];
const postsInChannelModels = [{prepareDestroyPermanently}];
const postModels = [{id: 'post1', prepareDestroyPermanently: jest.fn().mockReturnValue({id: 'post'})}];
const bookmarkModels = [{id: 'bookmark1', prepareDestroyPermanently: jest.fn().mockReturnValue({id: 'bookmark'})}];
(channel.membership.fetch as jest.Mock).mockResolvedValue(membershipModel);
(channel.info.fetch as jest.Mock).mockResolvedValue(infoModel);
(channel.categoryChannel.fetch as jest.Mock).mockResolvedValue(categoryChannelModel);
(channel.members.fetch as jest.Mock).mockResolvedValue(memberModels);
(channel.drafts.fetch as jest.Mock).mockResolvedValue(draftModels);
(channel.postsInChannel.fetch as jest.Mock).mockResolvedValue(postsInChannelModels);
(channel.posts.fetch as jest.Mock).mockResolvedValue(postModels);
(channel.bookmarks.fetch as jest.Mock).mockResolvedValue(bookmarkModels);
const result = await prepareDeleteChannel(channel);
expect(result).toEqual([
{},
{id: 'membership'},
{id: 'info'},
{id: 'category'},
{id: 'member'},
{id: 'draft'},
{},
{id: 'post'},
{id: 'bookmark'},
]);
expect(channel.prepareDestroyPermanently).toHaveBeenCalled();
expect(channel.membership.fetch).toHaveBeenCalled();
expect(channel.info.fetch).toHaveBeenCalled();
expect(channel.categoryChannel.fetch).toHaveBeenCalled();
expect(channel.members.fetch).toHaveBeenCalled();
expect(channel.drafts.fetch).toHaveBeenCalled();
expect(channel.postsInChannel.fetch).toHaveBeenCalled();
expect(channel.posts.fetch).toHaveBeenCalled();
expect(channel.bookmarks.fetch).toHaveBeenCalled();
});
it('should handle errors gracefully', async () => {
(channel.membership.fetch as jest.Mock).mockRejectedValue(new Error('Test error'));
(channel.info.fetch as jest.Mock).mockRejectedValue(new Error('Test error'));
(channel.categoryChannel.fetch as jest.Mock).mockRejectedValue(new Error('Test error'));
const result = await prepareDeleteChannel(channel);
expect(result).toEqual([{}]);
expect(channel.prepareDestroyPermanently).toHaveBeenCalled();
});
});
describe('prepareDeleteBookmarks', () => {
let bookmark: ChannelBookmarkModel;
beforeEach(() => {
bookmark = {
prepareDestroyPermanently: jest.fn().mockReturnValue({}),
file: {fetch: jest.fn()} as unknown as Relation<Model>,
fileId: 'file_id',
} as unknown as ChannelBookmarkModel;
});
it('should prepare bookmark and associated file for deletion', async () => {
const fileModel = {prepareDestroyPermanently: jest.fn().mockReturnValue({})};
(bookmark.file.fetch as jest.Mock).mockResolvedValue(fileModel);
const result = await prepareDeleteBookmarks(bookmark);
expect(result).toEqual([{}, {}]);
expect(bookmark.prepareDestroyPermanently).toHaveBeenCalled();
expect(bookmark.file.fetch).toHaveBeenCalled();
expect(fileModel.prepareDestroyPermanently).toHaveBeenCalled();
});
it('should handle errors gracefully when fetching associated file', async () => {
(bookmark.file.fetch as jest.Mock).mockRejectedValue(new Error('Test error'));
const result = await prepareDeleteBookmarks(bookmark);
expect(result).toEqual([{}]);
expect(bookmark.prepareDestroyPermanently).toHaveBeenCalled();
expect(bookmark.file.fetch).toHaveBeenCalled();
});
it('should prepare only the bookmark for deletion if no associated file', async () => {
bookmark.fileId = undefined;
const result = await prepareDeleteBookmarks(bookmark);
expect(result).toEqual([{}]);
expect(bookmark.prepareDestroyPermanently).toHaveBeenCalled();
expect(bookmark.file.fetch).not.toHaveBeenCalled();
});
});
describe('Channel Queries', () => {
let database: Database;
let mockQuery: jest.Mock;
let mockCollection: { query: jest.Mock};
beforeEach(() => {
mockQuery = jest.fn(() => ({extend: jest.fn()}));
mockCollection = {query: mockQuery};
database = {
get: jest.fn().mockReturnValue(mockCollection),
} as unknown as Database;
});
it('should query all channels', () => {
queryAllChannels(database);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL);
expect(mockQuery).toHaveBeenCalled();
});
it('should query all channels for a team', () => {
const teamId = 'team_id';
queryAllChannelsForTeam(database, teamId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL);
expect(mockQuery).toHaveBeenCalledWith(Q.where('team_id', teamId));
});
it('should query all channel info', () => {
queryAllChannelsInfo(database);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL_INFO);
expect(mockQuery).toHaveBeenCalled();
});
it('should query all channel info for a team', () => {
const teamId = 'team_id';
queryAllChannelsInfoForTeam(database, teamId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL_INFO);
expect(mockQuery).toHaveBeenCalledWith(Q.on(MM_TABLES.SERVER.CHANNEL, Q.where('team_id', teamId)));
});
it('should query all my channels', () => {
queryAllMyChannel(database);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.MY_CHANNEL);
expect(mockQuery).toHaveBeenCalled();
});
it('should query all my channels for a team', () => {
const teamId = 'team_id';
queryAllMyChannelsForTeam(database, teamId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.MY_CHANNEL);
expect(mockQuery).toHaveBeenCalledWith(Q.on(MM_TABLES.SERVER.CHANNEL, Q.where('team_id', Q.oneOf([teamId, '']))));
});
it('should query all unread DMs and GMs ids', () => {
queryAllUnreadDMsAndGMsIds(database);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL);
expect(mockQuery).toHaveBeenCalledWith(
Q.on(MM_TABLES.SERVER.MY_CHANNEL, Q.or(
Q.where('mentions_count', Q.gt(0)),
Q.where('message_count', Q.gt(0)),
)),
Q.where('type', Q.oneOf([General.GM_CHANNEL, General.DM_CHANNEL])),
);
});
it('should query channels by their IDs', () => {
const channelIds = ['channel1', 'channel2'];
queryChannelsById(database, channelIds);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL);
expect(mockQuery).toHaveBeenCalledWith(Q.where('id', Q.oneOf(channelIds)));
});
it('should query channels by their types', () => {
const channelTypes: ChannelType[] = ['O', 'P'];
queryChannelsByTypes(database, channelTypes);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL);
expect(mockQuery).toHaveBeenCalledWith(Q.where('type', Q.oneOf(channelTypes)));
});
it('should query user channels by their types', () => {
const userId = 'user_id';
const channelTypes: ChannelType[] = ['O', 'P'];
queryUserChannelsByTypes(database, userId, channelTypes);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL);
expect(mockQuery).toHaveBeenCalledWith(
Q.where('type', Q.oneOf(channelTypes)),
Q.on(MM_TABLES.SERVER.CHANNEL_MEMBERSHIP, Q.where('user_id', userId)),
);
});
it('should query the default channel for a team', () => {
const teamId = 'team_id';
queryTeamDefaultChannel(database, teamId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL);
expect(mockQuery).toHaveBeenCalledWith(
Q.where('team_id', teamId),
Q.where('name', General.DEFAULT_CHANNEL),
);
});
it('should query my channels by team', () => {
const teamId = 'team_id';
queryMyChannelsByTeam(database, teamId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.MY_CHANNEL);
expect(mockQuery).toHaveBeenCalledWith(
Q.on(MM_TABLES.SERVER.CHANNEL, Q.and(
Q.where('team_id', Q.eq(teamId)),
Q.where('delete_at', Q.eq(0)),
)),
);
});
it('should include deleted channels if includeDeleted is true', () => {
const teamId = 'team_id';
queryMyChannelsByTeam(database, teamId, true);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.MY_CHANNEL);
expect(mockQuery).toHaveBeenCalledWith(
Q.on(MM_TABLES.SERVER.CHANNEL, Q.and(
Q.where('team_id', Q.eq(teamId)),
)),
);
});
it('should query users on a channel', () => {
const channelId = 'channel_id';
queryUsersOnChannel(database, channelId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.USER);
expect(mockQuery).toHaveBeenCalledWith(Q.on(MM_TABLES.SERVER.CHANNEL_MEMBERSHIP, Q.where('channel_id', channelId)));
});
it('should query all my channel settings', () => {
queryAllMyChannelSettings(database);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.MY_CHANNEL_SETTINGS);
expect(mockQuery).toHaveBeenCalled();
});
it('should query my channel settings by IDs', () => {
const ids = ['id1', 'id2'];
queryMyChannelSettingsByIds(database, ids);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.MY_CHANNEL_SETTINGS);
expect(mockQuery).toHaveBeenCalledWith(Q.where('id', Q.oneOf(ids)));
});
it('should query my channel unreads', () => {
const currentTeamId = 'team_id';
queryMyChannelUnreads(database, currentTeamId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.MY_CHANNEL);
expect(mockQuery).toHaveBeenCalledWith(
Q.on(
MM_TABLES.SERVER.CHANNEL,
Q.and(
Q.or(
Q.where('team_id', Q.eq(currentTeamId)),
Q.where('team_id', Q.eq('')),
),
Q.where('delete_at', Q.eq(0)),
),
),
Q.or(
Q.where('is_unread', Q.eq(true)),
Q.where('mentions_count', Q.gte(0)),
),
Q.sortBy('last_post_at', Q.desc),
);
});
it('should query my recent channels', () => {
const take = 10;
queryMyRecentChannels(database, take);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.MY_CHANNEL);
expect(mockQuery).toHaveBeenCalled();
});
it('should query my recent channels without take', () => {
const take = 0;
queryMyRecentChannels(database, take);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.MY_CHANNEL);
expect(mockQuery).toHaveBeenCalled();
});
it('should query channels for autocomplete', () => {
const matchTerm = 'test';
const teamId = 'team_id';
queryChannelsForAutocomplete(database, matchTerm, true, teamId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL);
expect(mockQuery).toHaveBeenCalled();
});
it('should query channels for autocomplete with no search', () => {
const matchTerm = 'test';
const teamId = 'team_id';
queryChannelsForAutocomplete(database, matchTerm, false, teamId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL);
expect(mockQuery).toHaveBeenCalled();
});
it('should query channel members', () => {
const channelId = 'channel_id';
queryChannelMembers(database, channelId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL_MEMBERSHIP);
expect(mockQuery).toHaveBeenCalledWith(
Q.where('channel_id', channelId),
);
});
});
describe('Channel Functions', () => {
let database: Database;
beforeEach(() => {
database = {
get: jest.fn(),
} as unknown as Database;
});
describe('getMyChannel', () => {
it('should return the channel member if found', async () => {
const channelId = 'channel_id';
const mockMember = {id: channelId} as MyChannelModel;
(database.get as jest.Mock).mockReturnValue({
find: jest.fn().mockResolvedValue(mockMember),
});
const result = await getMyChannel(database, channelId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.MY_CHANNEL);
expect(result).toEqual(mockMember);
});
it('should return undefined if the channel member is not found', async () => {
const channelId = 'channel_id';
(database.get as jest.Mock).mockReturnValue({
find: jest.fn().mockRejectedValue(new Error('Not found')),
});
const result = await getMyChannel(database, channelId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.MY_CHANNEL);
expect(result).toBeUndefined();
});
});
describe('observeMyChannel', () => {
it('should observe the channel member', () => {
const channelId = 'channel_id';
const mockQuery = jest.fn().mockReturnValue({
observe: jest.fn().mockReturnValue(of$([{id: channelId, observe: jest.fn().mockReturnValue(of$({id: channelId}))}])),
});
(database.get as jest.Mock).mockReturnValue({
query: mockQuery,
});
const result = observeMyChannel(database, channelId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.MY_CHANNEL);
expect(mockQuery).toHaveBeenCalledWith(Q.where('id', channelId), Q.take(1));
result.subscribe((value) => {
expect(value).toEqual({id: channelId});
});
});
it('should return undefined if the channel member is not found', () => {
const channelId = 'channel_id';
const mockQuery = jest.fn().mockReturnValue({
observe: jest.fn().mockReturnValue(of$([])),
});
(database.get as jest.Mock).mockReturnValue({
query: mockQuery,
});
const result = observeMyChannel(database, channelId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.MY_CHANNEL);
expect(mockQuery).toHaveBeenCalledWith(Q.where('id', channelId), Q.take(1));
result.subscribe((value) => {
expect(value).toBeUndefined();
});
});
});
describe('observeMyChannelRoles', () => {
it('should observe the channel member roles', () => {
const channelId = 'channel_id';
const roles = 'role1 role2';
const mockQuery = jest.fn().mockReturnValue({
observe: jest.fn().mockReturnValue(of$([{id: channelId, roles, observe: jest.fn().mockReturnValue(of$({roles}))}])),
});
(database.get as jest.Mock).mockReturnValue({
query: mockQuery,
});
const result = observeMyChannelRoles(database, channelId);
result.subscribe((value) => {
expect(value).toEqual(roles);
});
});
it('should return undefined if the channel member is not found', () => {
const channelId = 'channel_id';
const mockQuery = jest.fn().mockReturnValue({
observe: jest.fn().mockReturnValue(of$([])),
});
(database.get as jest.Mock).mockReturnValue({
query: mockQuery,
});
const result = observeMyChannelRoles(database, channelId);
result.subscribe((value) => {
expect(value).toBeUndefined();
});
});
});
describe('getChannelById', () => {
it('should return the channel if found', async () => {
const channelId = 'channel_id';
const mockChannel = {id: channelId} as ChannelModel;
(database.get as jest.Mock).mockReturnValue({
find: jest.fn().mockResolvedValue(mockChannel),
});
const result = await getChannelById(database, channelId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL);
expect(result).toEqual(mockChannel);
});
it('should return undefined if the channel is not found', async () => {
const channelId = 'channel_id';
(database.get as jest.Mock).mockReturnValue({
find: jest.fn().mockRejectedValue(new Error('Not found')),
});
const result = await getChannelById(database, channelId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL);
expect(result).toBeUndefined();
});
});
describe('observeChannel', () => {
it('should observe the channel', () => {
const channelId = 'channel_id';
const mockQuery = jest.fn().mockReturnValue({
observe: jest.fn().mockReturnValue(of$([{id: channelId, observe: jest.fn().mockReturnValue(of$({id: channelId}))}])),
});
(database.get as jest.Mock).mockReturnValue({
query: mockQuery,
});
const result = observeChannel(database, channelId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL);
expect(mockQuery).toHaveBeenCalledWith(Q.where('id', channelId), Q.take(1));
result.subscribe((value) => {
expect(value).toEqual({id: channelId});
});
});
it('should return undefined if the channel is not found', () => {
const channelId = 'channel_id';
const mockQuery = jest.fn().mockReturnValue({
observe: jest.fn().mockReturnValue(of$([])),
});
(database.get as jest.Mock).mockReturnValue({
query: mockQuery,
});
const result = observeChannel(database, channelId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL);
expect(mockQuery).toHaveBeenCalledWith(Q.where('id', channelId), Q.take(1));
result.subscribe((value) => {
expect(value).toBeUndefined();
});
});
});
describe('getChannelByName', () => {
it('should return the channel if found', async () => {
const teamId = 'team_id';
const channelName = 'channel_name';
const mockChannel = {id: 'channel_id', name: channelName} as ChannelModel;
(database.get as jest.Mock).mockReturnValue({
query: jest.fn().mockReturnValue({
fetch: jest.fn().mockResolvedValue([mockChannel]),
}),
});
const result = await getChannelByName(database, teamId, channelName);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL);
expect(result).toEqual(mockChannel);
});
it('should return undefined if the channel is not found', async () => {
const teamId = 'team_id';
const channelName = 'channel_name';
(database.get as jest.Mock).mockReturnValue({
query: jest.fn().mockReturnValue({
fetch: jest.fn().mockResolvedValue([]),
}),
});
const result = await getChannelByName(database, teamId, channelName);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL);
expect(result).toBeUndefined();
});
});
describe('getChannelInfo', () => {
it('should return the channel info if found', async () => {
const channelId = 'channel_id';
const mockChannelInfo = {id: channelId} as ChannelInfoModel;
(database.get as jest.Mock).mockReturnValue({
find: jest.fn().mockResolvedValue(mockChannelInfo),
});
const result = await getChannelInfo(database, channelId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL_INFO);
expect(result).toEqual(mockChannelInfo);
});
it('should return undefined if the channel info is not found', async () => {
const channelId = 'channel_id';
(database.get as jest.Mock).mockReturnValue({
find: jest.fn().mockRejectedValue(new Error('Not found')),
});
const result = await getChannelInfo(database, channelId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL_INFO);
expect(result).toBeUndefined();
});
});
describe('getDefaultChannelForTeam', () => {
let mockQuery: jest.Mock;
let mockCollection: { query: jest.Mock };
beforeEach(() => {
mockQuery = jest.fn();
mockCollection = {query: mockQuery};
database = {
get: jest.fn().mockReturnValue(mockCollection),
} as unknown as Database;
});
it('should return the default channel for the team', async () => {
const teamId = 'team_id';
const defaultChannel = {id: 'default_channel', name: General.DEFAULT_CHANNEL} as ChannelModel;
const myFirstTeamChannel = {id: 'first_team_channel'} as ChannelModel;
const roles = [{permissions: [Permissions.JOIN_PUBLIC_CHANNELS]}];
(queryRoles as jest.Mock).mockReturnValue({fetch: jest.fn().mockResolvedValue(roles)});
(hasPermission as jest.Mock).mockReturnValue(true);
(mockQuery as jest.Mock).mockReturnValue({
fetch: jest.fn().mockResolvedValue([defaultChannel, myFirstTeamChannel]),
});
const result = await getDefaultChannelForTeam(database, teamId);
expect(queryRoles).toHaveBeenCalledWith(database);
expect(hasPermission).toHaveBeenCalledWith(roles, Permissions.JOIN_PUBLIC_CHANNELS);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL);
expect(mockQuery).toHaveBeenCalledWith(
Q.on(MM_TABLES.SERVER.MY_CHANNEL, 'id', Q.notEq('')),
Q.and(
Q.where('team_id', teamId),
Q.where('delete_at', Q.eq(0)),
Q.where('type', General.OPEN_CHANNEL),
),
Q.sortBy('display_name', Q.asc),
);
expect(result).toEqual(defaultChannel);
});
it('should return the default channel for the team with ignore id', async () => {
const teamId = 'team_id';
const defaultChannel = {id: 'default_channel', name: General.DEFAULT_CHANNEL} as ChannelModel;
const myFirstTeamChannel = {id: 'first_team_channel'} as ChannelModel;
(queryRoles as jest.Mock).mockReturnValue({fetch: jest.fn().mockResolvedValue([])});
(hasPermission as jest.Mock).mockReturnValue(true);
(mockQuery as jest.Mock).mockReturnValue({
fetch: jest.fn().mockResolvedValue([defaultChannel, myFirstTeamChannel]),
});
const result = await getDefaultChannelForTeam(database, teamId, 'ignoreid');
expect(queryRoles).toHaveBeenCalledWith(database);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL);
expect(mockQuery).toHaveBeenCalledWith(
Q.on(MM_TABLES.SERVER.MY_CHANNEL, 'id', Q.notEq('')),
Q.and(
Q.where('team_id', teamId),
Q.where('delete_at', Q.eq(0)),
Q.where('type', General.OPEN_CHANNEL),
Q.where('id', Q.notEq('ignoreid')),
),
Q.sortBy('display_name', Q.asc),
);
expect(result).toEqual(defaultChannel);
});
it('should return the first team channel if no default channel is found', async () => {
const teamId = 'team_id';
const myFirstTeamChannel = {id: 'first_team_channel'} as ChannelModel;
const roles = [{permissions: []}];
(queryRoles as jest.Mock).mockReturnValue({fetch: jest.fn().mockResolvedValue(roles)});
(hasPermission as jest.Mock).mockReturnValue(false);
(mockQuery as jest.Mock).mockReturnValue({
fetch: jest.fn().mockResolvedValue([myFirstTeamChannel]),
});
const result = await getDefaultChannelForTeam(database, teamId);
expect(queryRoles).toHaveBeenCalledWith(database);
expect(hasPermission).toHaveBeenCalledWith(roles, Permissions.JOIN_PUBLIC_CHANNELS);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL);
expect(mockQuery).toHaveBeenCalledWith(
Q.on(MM_TABLES.SERVER.MY_CHANNEL, 'id', Q.notEq('')),
Q.and(
Q.where('team_id', teamId),
Q.where('delete_at', Q.eq(0)),
Q.where('type', General.OPEN_CHANNEL),
),
Q.sortBy('display_name', Q.asc),
);
expect(result).toEqual(myFirstTeamChannel);
});
it('should return undefined if no channels are found', async () => {
const teamId = 'team_id';
const roles = [{permissions: [Permissions.JOIN_PUBLIC_CHANNELS]}];
(queryRoles as jest.Mock).mockReturnValue({fetch: jest.fn().mockResolvedValue(roles)});
(hasPermission as jest.Mock).mockReturnValue(true);
(mockQuery as jest.Mock).mockReturnValue({
fetch: jest.fn().mockResolvedValue([]),
});
const result = await getDefaultChannelForTeam(database, teamId);
expect(queryRoles).toHaveBeenCalledWith(database);
expect(hasPermission).toHaveBeenCalledWith(roles, Permissions.JOIN_PUBLIC_CHANNELS);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL);
expect(mockQuery).toHaveBeenCalledWith(
Q.on(MM_TABLES.SERVER.MY_CHANNEL, 'id', Q.notEq('')),
Q.and(
Q.where('team_id', teamId),
Q.where('delete_at', Q.eq(0)),
Q.where('type', General.OPEN_CHANNEL),
),
Q.sortBy('display_name', Q.asc),
);
expect(result).toBeUndefined();
});
});
describe('getCurrentChannel', () => {
it('should return the current channel if found', async () => {
const currentChannelId = 'current_channel_id';
const mockChannel = {id: currentChannelId} as ChannelModel;
(getCurrentChannelId as jest.Mock).mockResolvedValue(currentChannelId);
(database.get as jest.Mock).mockReturnValue({
find: jest.fn().mockResolvedValue(mockChannel),
});
const result = await getCurrentChannel(database);
expect(getCurrentChannelId).toHaveBeenCalledWith(database);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL);
expect(result).toEqual(mockChannel);
});
it('should return undefined if no current channel is found', async () => {
(getCurrentChannelId as jest.Mock).mockResolvedValue(undefined);
const result = await getCurrentChannel(database);
expect(getCurrentChannelId).toHaveBeenCalledWith(database);
expect(result).toBeUndefined();
});
});
describe('getCurrentChannelInfo', () => {
it('should return the current channel info if found', async () => {
const currentChannelId = 'current_channel_id';
const mockChannelInfo = {id: currentChannelId} as ChannelInfoModel;
(getCurrentChannelId as jest.Mock).mockResolvedValue(currentChannelId);
(database.get as jest.Mock).mockReturnValue({
find: jest.fn().mockResolvedValue(mockChannelInfo),
});
const result = await getCurrentChannelInfo(database);
expect(getCurrentChannelId).toHaveBeenCalledWith(database);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL_INFO);
expect(result).toEqual(mockChannelInfo);
});
it('should return undefined if no current channel info is found', async () => {
(getCurrentChannelId as jest.Mock).mockResolvedValue(undefined);
const result = await getCurrentChannelInfo(database);
expect(getCurrentChannelId).toHaveBeenCalledWith(database);
expect(result).toBeUndefined();
});
});
describe('observeCurrentChannel', () => {
it('should observe the current channel', () => {
const currentChannelId = 'current_channel_id';
const mockChannel = {id: currentChannelId, observe: jest.fn().mockReturnValue(of$({id: currentChannelId}))} as unknown as ChannelModel;
const mockQuery = jest.fn().mockReturnValue({
observe: jest.fn().mockReturnValue(of$([mockChannel])),
});
(database.get as jest.Mock).mockReturnValue({
query: mockQuery,
});
(observeCurrentChannelId as jest.Mock).mockReturnValue(of$(currentChannelId));
const result = observeCurrentChannel(database);
expect(observeCurrentChannelId).toHaveBeenCalledWith(database);
result.subscribe((value) => {
expect(value).toEqual({id: currentChannelId});
});
});
it('should return undefined if no current channel is found', () => {
const currentChannelId = 'current_channel_id';
const mockQuery = jest.fn().mockReturnValue({
observe: jest.fn().mockReturnValue(of$([])),
});
(database.get as jest.Mock).mockReturnValue({
query: mockQuery,
});
(observeCurrentChannelId as jest.Mock).mockReturnValue(of$(currentChannelId));
const result = observeCurrentChannel(database);
expect(observeCurrentChannelId).toHaveBeenCalledWith(database);
result.subscribe((value) => {
expect(value).toBeUndefined();
});
});
});
describe('getChannelInfo', () => {
it('should return the channel info if found', async () => {
const channelId = 'channel_id';
const mockChannelInfo = {id: channelId} as ChannelInfoModel;
(database.get as jest.Mock).mockReturnValue({
find: jest.fn().mockResolvedValue(mockChannelInfo),
});
const result = await getChannelInfo(database, channelId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL_INFO);
expect(result).toEqual(mockChannelInfo);
});
it('should return undefined if the channel info is not found', async () => {
const channelId = 'channel_id';
(database.get as jest.Mock).mockReturnValue({
find: jest.fn().mockRejectedValue(new Error('Not found')),
});
const result = await getChannelInfo(database, channelId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL_INFO);
expect(result).toBeUndefined();
});
});
});
describe('Channel Membership Functions', () => {
let operator: ServerDataOperator;
let database: Database;
beforeEach(() => {
database = {
get: jest.fn(),
} as unknown as Database;
operator = {
database,
handleChannelMembership: jest.fn(),
batchRecords: jest.fn(),
} as unknown as ServerDataOperator;
});
describe('deleteChannelMembership', () => {
it('should delete channel membership and return models', async () => {
const userId = 'user_id';
const channelId = 'channel_id';
const mockMembership = {
prepareDestroyPermanently: jest.fn().mockReturnValue({}),
} as unknown as ChannelMembershipModel;
(database.get as jest.Mock).mockReturnValue({
query: jest.fn().mockReturnValue({
fetch: jest.fn().mockResolvedValue([mockMembership]),
}),
});
const result = await deleteChannelMembership(operator, userId, channelId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL_MEMBERSHIP);
expect(result.models).toEqual([{}]);
expect(operator.batchRecords).toHaveBeenCalledWith([{}], 'deleteChannelMembership');
});
it('should return models without batching if prepareRecordsOnly is true', async () => {
const userId = 'user_id';
const channelId = 'channel_id';
const mockMembership = {
prepareDestroyPermanently: jest.fn().mockReturnValue({}),
} as unknown as ChannelMembershipModel;
(database.get as jest.Mock).mockReturnValue({
query: jest.fn().mockReturnValue({
fetch: jest.fn().mockResolvedValue([mockMembership]),
}),
});
const result = await deleteChannelMembership(operator, userId, channelId, true);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL_MEMBERSHIP);
expect(result.models).toEqual([{}]);
expect(operator.batchRecords).not.toHaveBeenCalled();
});
it('should return an error if an exception occurs', async () => {
const userId = 'user_id';
const channelId = 'channel_id';
const error = new Error('Test error');
(database.get as jest.Mock).mockReturnValue({
query: jest.fn().mockReturnValue({
fetch: jest.fn().mockRejectedValue(error),
}),
});
const result = await deleteChannelMembership(operator, userId, channelId);
expect(result.error).toEqual(error);
});
});
describe('addChannelMembership', () => {
it('should add channel membership and return an empty object', async () => {
const userId = 'user_id';
const channelId = 'channel_id';
const result = await addChannelMembership(operator, userId, channelId);
expect(operator.handleChannelMembership).toHaveBeenCalledWith({
channelMemberships: [{channel_id: channelId, user_id: userId}],
prepareRecordsOnly: false,
});
expect(result).toEqual({});
});
it('should return an error if an exception occurs', async () => {
const userId = 'user_id';
const channelId = 'channel_id';
const error = new Error('Test error');
(operator.handleChannelMembership as jest.Mock).mockRejectedValue(error);
const result = await addChannelMembership(operator, userId, channelId);
expect(result.error).toEqual(error);
});
});
describe('getMembersCountByChannelsId', () => {
let mockQuery: jest.Mock;
let mockCollection: { query: jest.Mock };
beforeEach(() => {
mockQuery = jest.fn();
mockCollection = {query: mockQuery};
database = {
get: jest.fn().mockReturnValue(mockCollection),
} as unknown as Database;
});
it('should return the members count by channel IDs', async () => {
const channelsId = ['channel1', 'channel2'];
const mockMemberships = [
{channelId: 'channel1'},
{channelId: 'channel1'},
{channelId: 'channel2'},
] as ChannelMembershipModel[];
(mockQuery as jest.Mock).mockReturnValue({
fetch: jest.fn().mockResolvedValue(mockMemberships),
});
const result = await getMembersCountByChannelsId(database, channelsId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL_MEMBERSHIP);
expect(mockQuery).toHaveBeenCalledWith(Q.where('channel_id', Q.oneOf(channelsId)));
expect(result).toEqual({channel1: 2, channel2: 1});
});
it('should return zero counts for channels with no members', async () => {
const channelsId = ['channel1', 'channel2'];
const mockMemberships = [] as ChannelMembershipModel[];
(mockQuery as jest.Mock).mockReturnValue({
fetch: jest.fn().mockResolvedValue(mockMemberships),
});
const result = await getMembersCountByChannelsId(database, channelsId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL_MEMBERSHIP);
expect(mockQuery).toHaveBeenCalledWith(Q.where('channel_id', Q.oneOf(channelsId)));
expect(result).toEqual({channel1: 0, channel2: 0});
});
it('should handle errors gracefully', async () => {
const channelsId = ['channel1', 'channel2'];
const error = new Error('Test error');
(mockQuery as jest.Mock).mockReturnValue({
fetch: jest.fn().mockRejectedValue(error),
});
await expect(getMembersCountByChannelsId(database, channelsId)).rejects.toThrow(error);
});
});
});
describe('Channel Observations', () => {
let database: Database;
let mockQuery: jest.Mock;
let mockCollection: { query: jest.Mock };
beforeEach(() => {
mockQuery = jest.fn();
mockCollection = {query: mockQuery};
database = {
get: jest.fn().mockReturnValue(mockCollection),
} as unknown as Database;
});
it('should observe channel info', () => {
const channelId = 'channel_id';
const mockChannelInfo = {id: channelId, observe: jest.fn().mockReturnValue(of$({id: channelId}))} as unknown as ChannelInfoModel;
mockQuery.mockReturnValue({
observe: jest.fn().mockReturnValue(of$([mockChannelInfo])),
});
const result = observeChannelInfo(database, channelId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL_INFO);
expect(mockQuery).toHaveBeenCalledWith(Q.where('id', channelId), Q.take(1));
result.subscribe((value) => {
expect(value).toEqual({id: channelId});
});
});
it('should observe all my channel notify props', () => {
const mockSettings = [
{id: 'id1', notifyProps: {mark_unread: 'all'}},
{id: 'id2', notifyProps: {mark_unread: 'mention'}},
] as MyChannelSettingsModel[];
mockQuery.mockReturnValue({
observeWithColumns: jest.fn().mockReturnValue(of$(mockSettings)),
});
const result = observeAllMyChannelNotifyProps(database);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.MY_CHANNEL_SETTINGS);
result.subscribe((value) => {
expect(value).toEqual({
id1: {mark_unread: 'all'},
id2: {mark_unread: 'mention'},
});
});
});
it('should observe notify props by channels', () => {
const channels = [
{id: 'channel1'},
{id: 'channel2'},
] as ChannelModel[];
const mockSettings = [
{id: 'channel1', notifyProps: {mark_unread: 'all'}},
{id: 'channel2', notifyProps: {mark_unread: 'mention'}},
] as MyChannelSettingsModel[];
mockQuery.mockReturnValue({
observeWithColumns: jest.fn().mockReturnValue(of$(mockSettings)),
});
const result = observeNotifyPropsByChannels(database, channels);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.MY_CHANNEL_SETTINGS);
result.subscribe((value) => {
expect(value).toEqual({
channel1: {mark_unread: 'all'},
channel2: {mark_unread: 'mention'},
});
});
});
it('should observe my channel mention count', () => {
const teamId = 'team_id';
const mockChannels = [
{mentionsCount: 2, isUnread: true},
{mentionsCount: 3, isUnread: false},
] as MyChannelModel[];
mockQuery.mockReturnValue({
observeWithColumns: jest.fn().mockReturnValue(of$(mockChannels)),
});
const result = observeMyChannelMentionCount(database, teamId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.MY_CHANNEL);
result.subscribe((value) => {
expect(value).toEqual(5);
});
});
it('should observe my channel mention count with no team id', () => {
const mockChannels = [
{mentionsCount: 2, isUnread: true},
{mentionsCount: 3, isUnread: false},
] as MyChannelModel[];
mockQuery.mockReturnValue({
observeWithColumns: jest.fn().mockReturnValue(of$(mockChannels)),
});
const result = observeMyChannelMentionCount(database);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.MY_CHANNEL);
result.subscribe((value) => {
expect(value).toEqual(5);
});
});
it('should observe direct channels by term', () => {
const term = '@test';
const mockCurrentUserId = 'user_id';
const mockChannels = [{id: 'channel1'}] as MyChannelModel[];
(observeCurrentUserId as jest.Mock).mockReturnValue(of$(mockCurrentUserId));
mockQuery.mockReturnValue({
observe: jest.fn().mockReturnValue(of$(mockChannels)),
});
const result = observeDirectChannelsByTerm(database, term);
result.subscribe((value) => {
expect(value).toEqual(mockChannels);
});
});
it('should observe not direct channels by term', () => {
const term = 'test';
const mockTeammateNameSetting = General.TEAMMATE_NAME_DISPLAY.SHOW_USERNAME;
const mockUsers = [{id: 'user1'}] as UserModel[];
(observeTeammateNameDisplay as jest.Mock).mockReturnValue(of$(mockTeammateNameSetting));
mockQuery.mockReturnValue({
observe: jest.fn().mockReturnValue(of$(mockUsers)),
});
const result = observeNotDirectChannelsByTerm(database, term);
result.subscribe((value) => {
expect(value).toEqual(mockUsers);
});
});
it('should observe joined channels by term', () => {
const term = 'test';
const mockChannels = [{id: 'channel1'}] as MyChannelModel[];
mockQuery.mockReturnValue({
observe: jest.fn().mockReturnValue(of$(mockChannels)),
});
const result = observeJoinedChannelsByTerm(database, term);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.MY_CHANNEL);
result.subscribe((value) => {
expect(value).toEqual(mockChannels);
});
});
it('should observe joined channels by term with @ mention', () => {
const term = '@test';
const result = observeJoinedChannelsByTerm(database, term);
result.subscribe((value) => {
expect(value).toEqual([]);
});
});
it('should observe archive channels by term', () => {
const term = 'test';
const mockChannels = [{id: 'channel1'}] as MyChannelModel[];
mockQuery.mockReturnValue({
observe: jest.fn().mockReturnValue(of$(mockChannels)),
});
const result = observeArchiveChannelsByTerm(database, term);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.MY_CHANNEL);
result.subscribe((value) => {
expect(value).toEqual(mockChannels);
});
});
it('should observe joined channels by term with @ mention', () => {
const term = '@test';
const result = observeArchiveChannelsByTerm(database, term);
result.subscribe((value) => {
expect(value).toEqual([]);
});
});
it('should observe channel settings', () => {
const channelId = 'channel_id';
const mockSettings = {id: channelId, observe: jest.fn().mockReturnValue(of$({id: channelId}))} as unknown as MyChannelSettingsModel;
mockQuery.mockReturnValue({
observe: jest.fn().mockReturnValue(of$([mockSettings])),
});
const result = observeChannelSettings(database, channelId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.MY_CHANNEL_SETTINGS);
result.subscribe((value) => {
expect(value).toEqual({id: channelId});
});
});
it('should observe is muted setting', () => {
const channelId = 'channel_id';
const mockSettings = {id: channelId, notifyProps: {mark_unread: General.MENTION}, observe: jest.fn().mockReturnValue(of$({id: channelId, notifyProps: {mark_unread: General.MENTION}}))} as unknown as MyChannelSettingsModel;
mockQuery.mockReturnValue({
observe: jest.fn().mockReturnValue(of$([mockSettings])),
});
const result = observeIsMutedSetting(database, channelId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.MY_CHANNEL_SETTINGS);
result.subscribe((value) => {
expect(value).toEqual(true);
});
});
it('should observe channels by last post at', () => {
const myChannels = [{id: 'channel1'}] as MyChannelModel[];
const mockChannels = [{id: 'channel1'}] as ChannelModel[];
mockQuery.mockReturnValue({
observe: jest.fn().mockReturnValue(of$(mockChannels)),
});
const result = observeChannelsByLastPostAt(database, myChannels);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL);
result.subscribe((value) => {
expect(value).toEqual(mockChannels);
});
});
it('should observe channel members', () => {
const channelId = 'channel_id';
const mockMembers = [{id: 'member1'}, {id: 'member2'}] as ChannelMembershipModel[];
mockQuery.mockReturnValue({
observe: jest.fn().mockReturnValue(of$(mockMembers)),
});
const result = observeChannelMembers(database, channelId);
expect(database.get).toHaveBeenCalledWith(MM_TABLES.SERVER.CHANNEL_MEMBERSHIP);
expect(mockQuery).toHaveBeenCalledWith(Q.where('channel_id', channelId));
result.subscribe((value) => {
expect(value).toEqual(mockMembers);
});
});
});