diff --git a/app/actions/remote/preference.test.ts b/app/actions/remote/preference.test.ts new file mode 100644 index 000000000..1a3120458 --- /dev/null +++ b/app/actions/remote/preference.test.ts @@ -0,0 +1,275 @@ +// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +/* eslint-disable max-lines */ + +import {Preferences} from '@app/constants'; +import {SYSTEM_IDENTIFIERS} from '@constants/database'; +import DatabaseManager from '@database/manager'; +import NetworkManager from '@managers/network_manager'; +import {querySavedPostsPreferences, queryPreferencesByCategoryAndName} from '@queries/servers/preference'; +import TestHelper from '@test/test_helper'; + +import { + fetchMyPreferences, + saveFavoriteChannel, + savePostPreference, + savePreference, + deleteSavedPost, + openChannelIfNeeded, + openAllUnreadChannels, + setDirectChannelVisible, + savePreferredSkinTone, +} from './preference'; + +import type {PreferenceModel} from '@app/database/models/server'; +import type ServerDataOperator from '@database/operator/server_data_operator'; + +const serverUrl = 'baseHandler.test.com'; +let operator: ServerDataOperator; + +const teamId = 'teamid1'; +const channelId = 'channelid1'; +const channel: Channel = { + id: channelId, + display_name: 'channelname', + team_id: teamId, + total_msg_count: 0, +} as Channel; + +const user1 = {id: 'userid1', username: 'user1', email: 'user1@mattermost.com', roles: ''} as UserProfile; + +const preference1 = {category: 'category1', name: 'name1', user_id: user1.id, value: 'value1'} as PreferenceType; +const post1 = {...TestHelper.fakePost(channelId), id: 'postid1'}; + +const throwFunc = () => { + throw Error('error'); +}; + +jest.mock('@queries/servers/preference'); + +const mockClient = { + getMyPreferences: jest.fn(() => [preference1]), + savePreferences: jest.fn(), + deletePreferences: jest.fn(), +}; + +beforeAll(() => { + // eslint-disable-next-line + // @ts-ignore + NetworkManager.getClient = () => mockClient; +}); + +beforeEach(async () => { + await DatabaseManager.init([serverUrl]); + operator = DatabaseManager.serverDatabases[serverUrl]!.operator; +}); + +afterEach(async () => { + await DatabaseManager.destroyServerDatabase(serverUrl); +}); + +describe('preferences', () => { + it('fetchMyPreferences - handle not found database', async () => { + const result = await fetchMyPreferences('foo'); + expect(result).toBeDefined(); + expect(result.error).toBeDefined(); + }); + + it('fetchMyPreferences - base case', async () => { + const result = await fetchMyPreferences(serverUrl); + expect(result).toBeDefined(); + expect(result.error).toBeUndefined(); + expect(result.preferences).toBeDefined(); + expect(result.preferences?.length).toBe(1); + }); + + it('saveFavoriteChannel - handle not found database', async () => { + const result = await saveFavoriteChannel('foo', '', false); + expect(result).toBeDefined(); + expect(result.error).toBeDefined(); + }); + + it('saveFavoriteChannel - base case', async () => { + await operator.handleSystem({systems: [{id: SYSTEM_IDENTIFIERS.CURRENT_USER_ID, value: user1.id}], prepareRecordsOnly: false}); + + const result = await saveFavoriteChannel(serverUrl, channelId, true); + expect(result).toBeDefined(); + expect(result.error).toBeUndefined(); + expect(result.preferences).toBeDefined(); + expect(result.preferences?.length).toBe(0); // Favourite channel preferences are not stored in the database + }); + + it('savePostPreference - handle not found database', async () => { + const result = await savePostPreference('foo', ''); + expect(result).toBeDefined(); + expect(result.error).toBeDefined(); + }); + + it('savePostPreference - base case', async () => { + await operator.handleSystem({systems: [{id: SYSTEM_IDENTIFIERS.CURRENT_USER_ID, value: user1.id}], prepareRecordsOnly: false}); + + const result = await savePostPreference(serverUrl, post1.id); + expect(result).toBeDefined(); + expect(result.error).toBeUndefined(); + expect(result.preferences).toBeDefined(); + expect(result.preferences?.length).toBe(1); + expect(result.preferences?.[0].category).toBe(Preferences.CATEGORIES.SAVED_POST); + }); + + it('savePreference - handle error', async () => { + mockClient.savePreferences.mockImplementationOnce(jest.fn(throwFunc)); + + const result = await savePreference(serverUrl, [preference1]); + expect(result).toBeDefined(); + expect(result.error).toBeDefined(); + }); + + it('savePreference - empty preferences', async () => { + const result = await savePreference(serverUrl, []); + expect(result).toBeDefined(); + expect(result.error).toBeUndefined(); + expect(result.preferences).toBeDefined(); + expect(result.preferences?.length).toBe(0); + }); + + it('deleteSavedPost - handle not found database', async () => { + const result = await deleteSavedPost('foo', ''); + expect(result).toBeDefined(); + expect(result.error).toBeDefined(); + }); + + it('deleteSavedPost - base case', async () => { + await operator.handleSystem({systems: [{id: SYSTEM_IDENTIFIERS.CURRENT_USER_ID, value: user1.id}], prepareRecordsOnly: false}); + + const prefModel = { + user_id: user1.id, + name: post1.id, + category: Preferences.CATEGORIES.SAVED_POST, + value: 'true', + destroyPermanently: jest.fn(), + } as unknown as PreferenceModel; + (querySavedPostsPreferences as jest.Mock).mockReturnValueOnce({fetch: jest.fn(() => [prefModel])}); + + const result = await deleteSavedPost(serverUrl, post1.id); + expect(result).toBeDefined(); + expect(result.error).toBeUndefined(); + expect(result.preference).toBeDefined(); + expect(prefModel.destroyPermanently).toHaveBeenCalledTimes(1); + }); + + it('openChannelIfNeeded - handle not found database', async () => { + const result = await openChannelIfNeeded('foo', '') as {error: unknown}; + expect(result).toBeDefined(); + expect(result.error).toBeDefined(); + }); + + it('openChannelIfNeeded - base case', async () => { + await operator.handleSystem({systems: [{id: SYSTEM_IDENTIFIERS.CURRENT_USER_ID, value: user1.id}], prepareRecordsOnly: false}); + + const {DIRECT_CHANNEL_SHOW, GROUP_CHANNEL_SHOW} = Preferences.CATEGORIES; + const dmPrefModel = { + user_id: user1.id, + name: channelId, + category: DIRECT_CHANNEL_SHOW, + value: 'true', + } as unknown as PreferenceModel; + const gmPrefModel = { + user_id: user1.id, + name: 'gmid', + category: GROUP_CHANNEL_SHOW, + value: 'true', + } as unknown as PreferenceModel; + (queryPreferencesByCategoryAndName as jest.Mock).mockReturnValue({fetch: jest.fn((d, c) => (c === DIRECT_CHANNEL_SHOW ? [dmPrefModel] : [gmPrefModel]))}); + + await operator.handleChannel({channels: [{...channel, type: 'D'}], prepareRecordsOnly: false}); + + const result = await openChannelIfNeeded(serverUrl, channelId) as {preferences?: PreferenceModel[]; error: unknown}; + expect(result).toBeDefined(); + expect(result.error).toBeUndefined(); + expect(result.preferences).toBeDefined(); + expect(result.preferences?.length).toBe(2); + }); + + it('openChannelIfNeeded - not dm/gm', async () => { + await operator.handleChannel({channels: [{...channel, type: 'O'}], prepareRecordsOnly: false}); + + const result = await openChannelIfNeeded(serverUrl, channelId); + expect(result).toMatchObject({}); + }); + + it('openAllUnreadChannels - handle not found database', async () => { + const result = await openAllUnreadChannels('foo'); + expect(result).toBeDefined(); + expect(result.error).toBeDefined(); + }); + + it('openAllUnreadChannels - base case', async () => { + await operator.handleSystem({systems: [{id: SYSTEM_IDENTIFIERS.CURRENT_USER_ID, value: user1.id}], prepareRecordsOnly: false}); + + const {DIRECT_CHANNEL_SHOW, GROUP_CHANNEL_SHOW} = Preferences.CATEGORIES; + const dmPrefModel = { + user_id: user1.id, + name: channelId, + category: DIRECT_CHANNEL_SHOW, + value: 'true', + } as unknown as PreferenceModel; + const gmPrefModel = { + user_id: user1.id, + name: 'gmid', + category: GROUP_CHANNEL_SHOW, + value: 'true', + } as unknown as PreferenceModel; + (queryPreferencesByCategoryAndName as jest.Mock).mockReturnValue({fetch: jest.fn((d, c) => (c === DIRECT_CHANNEL_SHOW ? [dmPrefModel] : [gmPrefModel]))}); + + await operator.handleChannel({channels: [{...channel, type: 'D'}], prepareRecordsOnly: false}); + + const result = await openAllUnreadChannels(serverUrl); + expect(result).toBeDefined(); + expect(result.error).toBeUndefined(); + expect(result.preferences).toBeDefined(); + expect(result.preferences?.length).toBe(0); // no unread channels + }); + + it('setDirectChannelVisible - handle not found database', async () => { + const result = await setDirectChannelVisible('foo', '') as {error: unknown}; + expect(result).toBeDefined(); + expect(result.error).toBeDefined(); + }); + + it('setDirectChannelVisible - base case', async () => { + await operator.handleSystem({systems: [{id: SYSTEM_IDENTIFIERS.CURRENT_USER_ID, value: user1.id}], prepareRecordsOnly: false}); + await operator.handleChannel({channels: [{...channel, type: 'D'}], prepareRecordsOnly: false}); + + const result = await setDirectChannelVisible(serverUrl, channelId) as {preferences?: PreferenceModel[]; error: unknown}; + expect(result).toBeDefined(); + expect(result.error).toBeUndefined(); + expect(result.preferences).toBeDefined(); + expect(result.preferences?.length).toBe(1); + expect(result.preferences?.[0].category).toBe(Preferences.CATEGORIES.DIRECT_CHANNEL_SHOW); + expect(result.preferences?.[0].value).toBe('true'); + }); + + it('setDirectChannelVisible - no channel', async () => { + const result = await setDirectChannelVisible(serverUrl, channelId); + expect(result).toMatchObject({}); + }); + + it('savePreferredSkinTone - handle not found database', async () => { + const result = await savePreferredSkinTone('foo', ''); + expect(result).toBeDefined(); + expect(result.error).toBeDefined(); + }); + + it('savePreferredSkinTone - base case', async () => { + await operator.handleSystem({systems: [{id: SYSTEM_IDENTIFIERS.CURRENT_USER_ID, value: user1.id}], prepareRecordsOnly: false}); + + const result = await savePreferredSkinTone(serverUrl, 'tone'); + expect(result).toBeDefined(); + expect(result.error).toBeUndefined(); + expect(result.preferences).toBeDefined(); + expect(result.preferences?.length).toBe(1); + expect(result.preferences?.[0].category).toBe(Preferences.CATEGORIES.EMOJI); + expect(result.preferences?.[0].value).toBe('tone'); + }); +});