mirror of
https://github.com/mattermost/mattermost-mobile.git
synced 2026-11-09 12:40:12 +00:00
* implements auto cache cleanup when zero persistence mode is enabled (0 value) * uses memory flag with sqlite instead of loki when running in zero persistence mode * renames ephemeral mode manager and improves readability * zero persistence refactors and restore values during transitions * fixes ephemeral mode tests * use initializeClient instead of just initialize to wait for doReconnect to finish that way teams loading is awaited while WS reconnects during ZPM transitions * adds inital sync as a mount hook to prevent undesired load error states during app cold start in ZPM mode, we need a way to load team and channels without showing loading error during the transition. The nre is initial sync hook allows for it * reset started sync subject on wipe * removes extra log lines * resets tracked server during ephemeral mode transitions * improvements to apply persistence mode changes when something fails * address coderabbit PR suggestions * add batching time logging * throws ephemeral mode change error as is * make deleteServerDatabaseFiles private * inline derive persistence flag function * return current user id when refetching current user * support zero persistence mode server for push notifications * adds support for zero persistence mode when sharing to mattermost * adds clarifying comment * catch and log error deleting files * reorder translations to correct position * adds some new tests to improve coverage * ios push notification native fix * logout when fetchMe fails with 401 status code during reconnection * properly surface errors * return proper false value when checking for zero persistence flag * change comments and properly await on some operations * prevent not set persistence mode to report as an error Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * include servers with no persistence flag set in share list * disable button for accessibility Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> * improves when to store and remove signing key from global area * review push notification reception running in zero persistence mode * add server to ephemeral mode manager right after login --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
217 lines
8.7 KiB
TypeScript
217 lines
8.7 KiB
TypeScript
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
import {ActionType} from '@constants';
|
|
import DatabaseManager from '@database/manager';
|
|
import NetworkManager from '@managers/network_manager';
|
|
import PerformanceMetricsManager from '@managers/performance_metrics_manager';
|
|
import {prepareThreadsFromReceivedPosts} from '@queries/servers/thread';
|
|
import {NavigationStore} from '@store/navigation_store';
|
|
import {mockApiClient} from '@test/mock_api_client';
|
|
import TestHelper from '@test/test_helper';
|
|
|
|
import {pushNotificationEntry} from './notification';
|
|
|
|
import type ServerDataOperator from '@database/operator/server_data_operator';
|
|
|
|
jest.mock('@managers/performance_metrics_manager');
|
|
jest.mock('@store/navigation_store');
|
|
|
|
const mockDismissKeyboard = jest.fn();
|
|
jest.mock('@utils/keyboard', () => ({
|
|
dismissKeyboard: (...args: unknown[]) => mockDismissKeyboard(...args),
|
|
}));
|
|
|
|
let mockEmitNotificationError: jest.Mock;
|
|
jest.mock('@utils/notification', () => {
|
|
const original = jest.requireActual('@utils/notification');
|
|
mockEmitNotificationError = jest.fn();
|
|
return {
|
|
...original,
|
|
emitNotificationError: mockEmitNotificationError,
|
|
};
|
|
});
|
|
|
|
const mockedNavigationStore = jest.mocked(NavigationStore);
|
|
|
|
describe('Performance metrics are set correctly', () => {
|
|
const serverUrl = 'http://www.someserverurl.com';
|
|
let operator: ServerDataOperator;
|
|
let post: Post;
|
|
beforeAll(() => {
|
|
mockApiClient.get.mockImplementation((url: string) => {
|
|
if (url.match(/\/api\/v4\/channels\/[a-z1-90-]*\/posts/)) {
|
|
return {status: 200, ok: true, data: {order: [], posts: {}}};
|
|
}
|
|
if (url.match(/\/api\/v4\/channels\/[a-z1-90-]*\/stats/)) {
|
|
return {status: 200, ok: true, data: {}};
|
|
}
|
|
if (url.match(/\/api\/v4\/posts\/[a-z1-90-]*\/thread/)) {
|
|
return {status: 200, ok: true, data: {order: [], posts: {}}};
|
|
}
|
|
console.log(`GET ${url} not registered in the mock`);
|
|
return {status: 404, ok: false};
|
|
});
|
|
|
|
mockApiClient.post.mockImplementation((url: string) => {
|
|
if (url.match(/\/api\/v4\/channels\/members\/me\/view/)) {
|
|
return {status: 200, ok: true, data: {}};
|
|
}
|
|
|
|
console.log(`POST ${url} not registered in the mock`);
|
|
return {status: 404, ok: false};
|
|
});
|
|
mockedNavigationStore.waitUntilScreenIsTop.mockImplementation(() => Promise.resolve());
|
|
|
|
// There are no problems when running the tests for this file alone without this line
|
|
// but for some reason, when running several tests together, it fails if we don't add this.
|
|
mockedNavigationStore.getScreensInStack.mockImplementation(() => []);
|
|
});
|
|
afterAll(() => {
|
|
mockApiClient.get.mockReset();
|
|
mockApiClient.post.mockReset();
|
|
});
|
|
|
|
beforeEach(async () => {
|
|
const client = await NetworkManager.createClient(serverUrl);
|
|
expect(client).toBeTruthy();
|
|
operator = (await TestHelper.setupServerDatabase(serverUrl)).operator;
|
|
await DatabaseManager.setActiveServerDatabase(serverUrl);
|
|
post = TestHelper.fakePost({channel_id: TestHelper.basicChannel!.id});
|
|
await operator.handlePosts({
|
|
actionType: ActionType.POSTS.RECEIVED_NEW,
|
|
order: [post.id],
|
|
posts: [post],
|
|
prepareRecordsOnly: false,
|
|
});
|
|
const threadModels = await prepareThreadsFromReceivedPosts(operator, [post], true);
|
|
await operator.batchRecords(threadModels, 'test');
|
|
});
|
|
|
|
afterEach(async () => {
|
|
await TestHelper.tearDown();
|
|
NetworkManager.invalidateClient(serverUrl);
|
|
mockEmitNotificationError.mockClear();
|
|
});
|
|
|
|
it('channel notification', async () => {
|
|
await operator.handleConfigs({
|
|
configs: [
|
|
{id: 'CollapsedThreads', value: 'default_on'},
|
|
{id: 'FeatureFlagCollapsedThreads', value: 'true'},
|
|
],
|
|
configsToDelete: [],
|
|
prepareRecordsOnly: false,
|
|
});
|
|
|
|
await pushNotificationEntry(serverUrl, {
|
|
channel_id: TestHelper.basicChannel!.id,
|
|
team_id: TestHelper.basicTeam!.id,
|
|
isCRTEnabled: false, // isCRTEnabled is not checked at this level
|
|
post_id: '', // Post ID is not checked at this level
|
|
type: '', // Type is not checked at this level
|
|
version: '', // Version is not checked at this level
|
|
});
|
|
|
|
expect(mockDismissKeyboard).toHaveBeenCalled();
|
|
expect(PerformanceMetricsManager.setLoadTarget).toHaveBeenCalledWith('CHANNEL');
|
|
});
|
|
|
|
it('thread notification', async () => {
|
|
const commentPost = TestHelper.fakePost({channel_id: TestHelper.basicChannel!.id, root_id: post.id});
|
|
await operator.handlePosts({
|
|
actionType: ActionType.POSTS.RECEIVED_NEW,
|
|
order: [commentPost.id],
|
|
posts: [commentPost],
|
|
prepareRecordsOnly: false,
|
|
});
|
|
const threadModels = await prepareThreadsFromReceivedPosts(operator, [commentPost], true);
|
|
await operator.batchRecords(threadModels, 'test');
|
|
await operator.handleConfigs({
|
|
configs: [
|
|
{id: 'CollapsedThreads', value: 'default_on'},
|
|
{id: 'FeatureFlagCollapsedThreads', value: 'true'},
|
|
],
|
|
configsToDelete: [],
|
|
prepareRecordsOnly: false,
|
|
});
|
|
|
|
await pushNotificationEntry(serverUrl, {
|
|
root_id: post.id,
|
|
channel_id: TestHelper.basicChannel!.id,
|
|
team_id: TestHelper.basicTeam!.id,
|
|
isCRTEnabled: false, // isCRTEnabled is not checked at this level
|
|
post_id: '', // Post ID is not checked at this level
|
|
type: '', // Type is not checked at this level
|
|
version: '', // Version is not checked at this level
|
|
});
|
|
|
|
expect(PerformanceMetricsManager.setLoadTarget).toHaveBeenCalledWith('THREAD');
|
|
});
|
|
|
|
it('thread notification with wrong root id', async () => {
|
|
const commentPost = TestHelper.fakePost({channel_id: TestHelper.basicChannel!.id, root_id: post.id});
|
|
await operator.handlePosts({
|
|
actionType: ActionType.POSTS.RECEIVED_NEW,
|
|
order: [commentPost.id],
|
|
posts: [commentPost],
|
|
prepareRecordsOnly: false,
|
|
});
|
|
const threadModels = await prepareThreadsFromReceivedPosts(operator, [commentPost], true);
|
|
await operator.batchRecords(threadModels, 'test');
|
|
await operator.handleConfigs({
|
|
configs: [
|
|
{id: 'CollapsedThreads', value: 'default_on'},
|
|
{id: 'FeatureFlagCollapsedThreads', value: 'true'},
|
|
],
|
|
configsToDelete: [],
|
|
prepareRecordsOnly: false,
|
|
});
|
|
|
|
await pushNotificationEntry(serverUrl, {
|
|
root_id: commentPost.id,
|
|
channel_id: TestHelper.basicChannel!.id,
|
|
team_id: TestHelper.basicTeam!.id,
|
|
isCRTEnabled: false, // isCRTEnabled is not checked at this level
|
|
post_id: '', // Post ID is not checked at this level
|
|
type: '', // Type is not checked at this level
|
|
version: '', // Version is not checked at this level
|
|
});
|
|
|
|
expect(PerformanceMetricsManager.setLoadTarget).toHaveBeenCalledWith('THREAD');
|
|
});
|
|
|
|
it('thread notification with non crt', async () => {
|
|
const commentPost = TestHelper.fakePost({channel_id: TestHelper.basicChannel!.id, root_id: post.id});
|
|
await operator.handlePosts({
|
|
actionType: ActionType.POSTS.RECEIVED_NEW,
|
|
order: [commentPost.id],
|
|
posts: [commentPost],
|
|
prepareRecordsOnly: false,
|
|
});
|
|
const threadModels = await prepareThreadsFromReceivedPosts(operator, [commentPost], true);
|
|
await operator.batchRecords(threadModels, 'test');
|
|
await operator.handleConfigs({
|
|
configs: [
|
|
{id: 'CollapsedThreads', value: 'disabled'},
|
|
{id: 'FeatureFlagCollapsedThreads', value: 'false'},
|
|
],
|
|
configsToDelete: [],
|
|
prepareRecordsOnly: false,
|
|
});
|
|
|
|
await pushNotificationEntry(serverUrl, {
|
|
root_id: post.id,
|
|
channel_id: TestHelper.basicChannel!.id,
|
|
team_id: TestHelper.basicTeam!.id,
|
|
isCRTEnabled: false, // isCRTEnabled is not checked at this level
|
|
post_id: '', // Post ID is not checked at this level
|
|
type: '', // Type is not checked at this level
|
|
version: '', // Version is not checked at this level
|
|
});
|
|
|
|
expect(PerformanceMetricsManager.setLoadTarget).toHaveBeenCalledWith('CHANNEL');
|
|
});
|
|
|
|
});
|