forked from Ivasoft/mattermost-mobile
Add performance metrics to the app (#7953)
* Add performance metrics to the app * add batcher and improve handling * Add tests * Fix test * Address feedback * Address feedback * Address feedback * update podfile
This commit is contained in:
committed by
GitHub
parent
daa38c5fd1
commit
5f01f9e9af
@@ -2,11 +2,12 @@
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import {DatabaseProvider} from '@nozbe/watermelondb/react';
|
||||
import {render} from '@testing-library/react-native';
|
||||
import {render, type RenderOptions} from '@testing-library/react-native';
|
||||
import React, {type ReactElement} from 'react';
|
||||
import {IntlProvider} from 'react-intl';
|
||||
import {SafeAreaProvider} from 'react-native-safe-area-context';
|
||||
|
||||
import ServerUrlProvider from '@context/server';
|
||||
import {ThemeContext, getDefaultThemeByAppearance} from '@context/theme';
|
||||
import {getTranslations} from '@i18n';
|
||||
|
||||
@@ -48,13 +49,13 @@ export function renderWithIntlAndTheme(ui: ReactElement, {locale = 'en', ...rend
|
||||
return render(ui, {wrapper: Wrapper, ...renderOptions});
|
||||
}
|
||||
|
||||
export function renderWithEverything(ui: ReactElement, {locale = 'en', database, ...renderOptions}: {locale?: string; database?: Database; renderOptions?: any} = {}) {
|
||||
export function renderWithEverything(ui: ReactElement, {locale = 'en', database, serverUrl, ...renderOptions}: {locale?: string; database?: Database; serverUrl?: string; renderOptions?: RenderOptions} = {}) {
|
||||
function Wrapper({children}: {children: ReactElement}) {
|
||||
if (!database) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
const wrapper = (
|
||||
<DatabaseProvider database={database}>
|
||||
<IntlProvider
|
||||
locale={locale}
|
||||
@@ -68,6 +69,16 @@ export function renderWithEverything(ui: ReactElement, {locale = 'en', database,
|
||||
</IntlProvider>
|
||||
</DatabaseProvider>
|
||||
);
|
||||
|
||||
if (serverUrl) {
|
||||
return (
|
||||
<ServerUrlProvider server={{displayName: serverUrl, url: serverUrl}}>
|
||||
{wrapper}
|
||||
</ServerUrlProvider>
|
||||
);
|
||||
}
|
||||
|
||||
return wrapper;
|
||||
}
|
||||
|
||||
return render(ui, {wrapper: Wrapper, ...renderOptions});
|
||||
|
||||
11
test/mock_api_client.ts
Normal file
11
test/mock_api_client.ts
Normal file
@@ -0,0 +1,11 @@
|
||||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
|
||||
import type {RequestOptions} from '@mattermost/react-native-network-client';
|
||||
|
||||
export const mockApiClient = {
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
get: jest.fn((url: string, options?: RequestOptions) => ({status: 200, ok: true})),
|
||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||
post: jest.fn((url: string, options?: RequestOptions) => ({status: 200, ok: true})),
|
||||
};
|
||||
@@ -8,6 +8,9 @@ import * as ReactNative from 'react-native';
|
||||
import mockSafeAreaContext from 'react-native-safe-area-context/jest/mock';
|
||||
import {v4 as uuidv4} from 'uuid';
|
||||
|
||||
import {mockApiClient} from './mock_api_client';
|
||||
|
||||
import type {RequestOptions} from '@mattermost/react-native-network-client';
|
||||
import type {ReadDirItem, StatResult} from 'react-native-fs';
|
||||
|
||||
import 'react-native-gesture-handler/jestSetup';
|
||||
@@ -186,17 +189,11 @@ jest.doMock('react-native', () => {
|
||||
|
||||
jest.mock('react-native-vector-icons', () => {
|
||||
const React = jest.requireActual('react');
|
||||
const PropTypes = jest.requireActual('prop-types');
|
||||
class CompassIcon extends React.PureComponent {
|
||||
render() {
|
||||
return React.createElement('Icon', this.props);
|
||||
}
|
||||
}
|
||||
CompassIcon.propTypes = {
|
||||
name: PropTypes.string,
|
||||
size: PropTypes.number,
|
||||
style: PropTypes.oneOfType([PropTypes.array, PropTypes.number, PropTypes.object]),
|
||||
};
|
||||
CompassIcon.getImageSource = jest.fn().mockResolvedValue({});
|
||||
return {
|
||||
createIconSet: () => CompassIcon,
|
||||
@@ -256,6 +253,8 @@ jest.mock('react-native-device-info', () => {
|
||||
hasNotch: jest.fn(() => true),
|
||||
isTablet: jest.fn(() => false),
|
||||
getApplicationName: jest.fn(() => 'Mattermost'),
|
||||
getSystemName: jest.fn(() => 'ios'),
|
||||
getSystemVersion: jest.fn(() => '0.0.0'),
|
||||
};
|
||||
});
|
||||
|
||||
@@ -367,6 +366,8 @@ jest.mock('@screens/navigation', () => ({
|
||||
popToRoot: jest.fn(() => Promise.resolve()),
|
||||
dismissModal: jest.fn(() => Promise.resolve()),
|
||||
dismissAllModals: jest.fn(() => Promise.resolve()),
|
||||
dismissAllModalsAndPopToScreen: jest.fn(),
|
||||
dismissAllModalsAndPopToRoot: jest.fn(),
|
||||
dismissOverlay: jest.fn(() => Promise.resolve()),
|
||||
}));
|
||||
|
||||
@@ -386,6 +387,22 @@ jest.mock('@mattermost/react-native-emm', () => ({
|
||||
useManagedConfig: () => ({}),
|
||||
}));
|
||||
|
||||
jest.mock('@react-native-clipboard/clipboard', () => ({}));
|
||||
|
||||
jest.mock('react-native-document-picker', () => ({}));
|
||||
|
||||
jest.mock('@mattermost/react-native-network-client', () => ({
|
||||
getOrCreateAPIClient: (serverUrl: string) => ({client: {
|
||||
baseUrl: serverUrl,
|
||||
get: (url: string, options?: RequestOptions) => mockApiClient.get(`${serverUrl}${url}`, options),
|
||||
post: (url: string, options?: RequestOptions) => mockApiClient.post(`${serverUrl}${url}`, options),
|
||||
invalidate: jest.fn(),
|
||||
}}),
|
||||
RetryTypes: {
|
||||
EXPONENTIAL_RETRY: 'exponential',
|
||||
},
|
||||
}));
|
||||
|
||||
jest.mock('react-native-safe-area-context', () => mockSafeAreaContext);
|
||||
|
||||
jest.mock('react-native-reanimated', () => require('react-native-reanimated/mock'));
|
||||
@@ -399,7 +416,15 @@ jest.mock('react-native-haptic-feedback', () => {
|
||||
};
|
||||
});
|
||||
|
||||
declare const global: {requestAnimationFrame: (callback: any) => void};
|
||||
declare const global: {
|
||||
requestAnimationFrame: (callback: () => void) => void;
|
||||
performance: {
|
||||
now: () => number;
|
||||
};
|
||||
};
|
||||
|
||||
global.requestAnimationFrame = (callback) => {
|
||||
setTimeout(callback, 0);
|
||||
};
|
||||
|
||||
global.performance.now = () => Date.now();
|
||||
|
||||
@@ -10,6 +10,7 @@ import nock from 'nock';
|
||||
|
||||
import Config from '@assets/config.json';
|
||||
import {Client} from '@client/rest';
|
||||
import {ActionType} from '@constants';
|
||||
import {SYSTEM_IDENTIFIERS} from '@constants/database';
|
||||
import {PUSH_PROXY_STATUS_VERIFIED} from '@constants/push_proxy';
|
||||
import DatabaseManager from '@database/manager';
|
||||
@@ -18,7 +19,6 @@ import {generateId} from '@utils/general';
|
||||
|
||||
import type {APIClientInterface} from '@mattermost/react-native-network-client';
|
||||
|
||||
const PASSWORD = 'password1';
|
||||
const DEFAULT_LOCALE = 'en';
|
||||
|
||||
class TestHelper {
|
||||
@@ -51,8 +51,8 @@ class TestHelper {
|
||||
this.basicRoles = null;
|
||||
}
|
||||
|
||||
setupServerDatabase = async () => {
|
||||
const serverUrl = 'https://appv1.mattermost.com';
|
||||
setupServerDatabase = async (url?: string) => {
|
||||
const serverUrl = url || 'https://appv1.mattermost.com';
|
||||
await DatabaseManager.init([serverUrl]);
|
||||
const {database, operator} = DatabaseManager.serverDatabases[serverUrl]!;
|
||||
|
||||
@@ -112,6 +112,13 @@ class TestHelper {
|
||||
systems: [{id: SYSTEM_IDENTIFIERS.PUSH_VERIFICATION_STATUS, value: PUSH_PROXY_STATUS_VERIFIED}],
|
||||
});
|
||||
|
||||
await operator.handlePosts({
|
||||
actionType: ActionType.POSTS.RECEIVED_NEW,
|
||||
order: [this.basicPost!.id],
|
||||
posts: [this.basicPost!],
|
||||
prepareRecordsOnly: false,
|
||||
});
|
||||
|
||||
return {database, operator};
|
||||
};
|
||||
|
||||
@@ -291,7 +298,7 @@ class TestHelper {
|
||||
return 'success' + this.generateId() + '@simulator.amazonses.com';
|
||||
};
|
||||
|
||||
fakePost = (channelId: string) => {
|
||||
fakePost = (channelId: string, userId?: string): Post => {
|
||||
const time = Date.now();
|
||||
|
||||
return {
|
||||
@@ -301,6 +308,17 @@ class TestHelper {
|
||||
update_at: time,
|
||||
message: `Unit Test ${this.generateId()}`,
|
||||
type: '',
|
||||
delete_at: 0,
|
||||
edit_at: 0,
|
||||
hashtags: '',
|
||||
is_pinned: false,
|
||||
metadata: {},
|
||||
original_id: '',
|
||||
pending_post_id: '',
|
||||
props: {},
|
||||
reply_count: 0,
|
||||
root_id: '',
|
||||
user_id: userId || this.generateId(),
|
||||
};
|
||||
};
|
||||
|
||||
@@ -314,7 +332,7 @@ class TestHelper {
|
||||
};
|
||||
};
|
||||
|
||||
fakeTeam = () => {
|
||||
fakeTeam = (): Team => {
|
||||
const name = this.generateId();
|
||||
let inviteId = this.generateId();
|
||||
if (inviteId.length > 32) {
|
||||
@@ -322,6 +340,7 @@ class TestHelper {
|
||||
}
|
||||
|
||||
return {
|
||||
id: this.generateId(),
|
||||
name,
|
||||
display_name: `Unit Test ${name}`,
|
||||
type: 'O' as const,
|
||||
@@ -334,6 +353,9 @@ class TestHelper {
|
||||
allow_open_invite: true,
|
||||
group_constrained: false,
|
||||
last_team_icon_update: 0,
|
||||
create_at: 0,
|
||||
delete_at: 0,
|
||||
update_at: 0,
|
||||
};
|
||||
};
|
||||
|
||||
@@ -361,11 +383,9 @@ class TestHelper {
|
||||
};
|
||||
};
|
||||
|
||||
fakeUser = () => {
|
||||
fakeUser = (): UserProfile => {
|
||||
return {
|
||||
email: this.fakeEmail(),
|
||||
allow_marketing: true,
|
||||
password: PASSWORD,
|
||||
locale: DEFAULT_LOCALE,
|
||||
username: this.generateId(),
|
||||
first_name: this.generateId(),
|
||||
@@ -373,6 +393,27 @@ class TestHelper {
|
||||
create_at: Date.now(),
|
||||
delete_at: 0,
|
||||
roles: 'system_user',
|
||||
auth_service: '',
|
||||
id: this.generateId(),
|
||||
nickname: '',
|
||||
notify_props: this.fakeNotifyProps(),
|
||||
position: '',
|
||||
update_at: 0,
|
||||
};
|
||||
};
|
||||
|
||||
fakeNotifyProps = (): UserNotifyProps => {
|
||||
return {
|
||||
channel: 'false',
|
||||
comments: 'root',
|
||||
desktop: 'default',
|
||||
desktop_sound: 'false',
|
||||
email: 'false',
|
||||
first_name: 'false',
|
||||
highlight_keys: '',
|
||||
mention_keys: '',
|
||||
push: 'default',
|
||||
push_status: 'away',
|
||||
};
|
||||
};
|
||||
|
||||
@@ -665,6 +706,7 @@ class TestHelper {
|
||||
};
|
||||
|
||||
wait = (time: number) => new Promise((resolve) => setTimeout(resolve, time));
|
||||
tick = () => new Promise((r) => setImmediate(r));
|
||||
}
|
||||
|
||||
export default new TestHelper();
|
||||
|
||||
Reference in New Issue
Block a user