* Add Report a Problem functionality * update cache pinned SHA version from 4.0.2 to 4.2.0 * Address feedback * Fix tests * Fix some issues and update kotlin coroutines version * Fix delete file for iOS * Bump 1 more version for coroutines * Use rxjava instead of kotlin coroutines to avoid security issue * Move path prefix to avoid test error * Address feedback * Address feedback * Address feedback * Use mailto on iOS * Fix tests related to button changes * Address feedback * Update icon and fix onboarding buttons * Fix test --------- Co-authored-by: Angelos Kyratzakos <angelos.kyratzakos@mattermost.com> Co-authored-by: Mattermost Build <build@mattermost.com>
250 lines
9.2 KiB
TypeScript
250 lines
9.2 KiB
TypeScript
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
import TurboLogger from '@mattermost/react-native-turbo-log';
|
|
import {Alert, Platform} from 'react-native';
|
|
import Share from 'react-native-share';
|
|
|
|
import {shareLogs, getDefaultReportAProblemLink, metadataToString, emailLogs} from './share_logs';
|
|
import {tryOpenURL} from './url';
|
|
|
|
jest.mock('react-native-share', () => ({
|
|
open: jest.fn(),
|
|
shareSingle: jest.fn(),
|
|
Social: {
|
|
EMAIL: 'email',
|
|
},
|
|
}));
|
|
|
|
jest.mock('./url', () => ({
|
|
tryOpenURL: jest.fn(),
|
|
}));
|
|
|
|
jest.mock('react-native/Libraries/Alert/Alert', () => ({
|
|
alert: jest.fn(),
|
|
}));
|
|
|
|
describe('shareLogs', () => {
|
|
const metadata = {
|
|
currentUserId: 'user1',
|
|
currentTeamId: 'team1',
|
|
serverVersion: '1.0.0',
|
|
appVersion: '2.0.0',
|
|
appPlatform: 'ios',
|
|
};
|
|
|
|
beforeEach(() => {
|
|
jest.clearAllMocks();
|
|
|
|
const logPaths = ['/path/to/log1', '/path/to/log2'];
|
|
jest.mocked(TurboLogger.getLogPaths).mockResolvedValue(logPaths);
|
|
});
|
|
|
|
it('should share logs with attachments when excludeLogs is false', async () => {
|
|
await shareLogs(metadata, 'My Site', 'support@example.com', false);
|
|
|
|
expect(Share.open).toHaveBeenCalledWith(expect.objectContaining({
|
|
subject: 'Problem with My Site React Native app',
|
|
email: 'support@example.com',
|
|
urls: ['file:///path/to/log1', 'file:///path/to/log2'],
|
|
}));
|
|
});
|
|
|
|
it('should handle an empty list of log paths', async () => {
|
|
jest.mocked(TurboLogger.getLogPaths).mockResolvedValue([]);
|
|
|
|
await shareLogs(metadata, 'My Site', 'support@example.com', false);
|
|
|
|
expect(Share.open).toHaveBeenCalledWith(expect.objectContaining({
|
|
subject: 'Problem with My Site React Native app',
|
|
email: 'support@example.com',
|
|
urls: undefined,
|
|
}));
|
|
});
|
|
|
|
it('should share without logs when excludeLogs is true', async () => {
|
|
await shareLogs(metadata, 'My Site', 'support@example.com', true);
|
|
|
|
expect(Share.open).toHaveBeenCalledWith(expect.objectContaining({
|
|
subject: 'Problem with My Site React Native app',
|
|
email: 'support@example.com',
|
|
urls: undefined,
|
|
}));
|
|
});
|
|
|
|
it('should handle errors', async () => {
|
|
const error = new Error('Share failed');
|
|
jest.mocked(Share.open).mockRejectedValue(error);
|
|
|
|
await shareLogs(metadata, 'My Site', 'support@example.com');
|
|
|
|
expect(Alert.alert).toHaveBeenCalledWith('Error', 'Error: Share failed');
|
|
});
|
|
|
|
it('should pass the correct metadata to the share function', async () => {
|
|
await shareLogs(metadata, 'My Site', 'support@example.com', false);
|
|
|
|
expect(Share.open).toHaveBeenCalledWith(expect.objectContaining({
|
|
message: expect.stringContaining('Current User ID: user1'),
|
|
}));
|
|
|
|
expect(Share.open).toHaveBeenCalledWith(expect.objectContaining({
|
|
message: expect.stringContaining('Current Team ID: team1'),
|
|
}));
|
|
|
|
expect(Share.open).toHaveBeenCalledWith(expect.objectContaining({
|
|
message: expect.stringContaining('Server Version: 1.0.0'),
|
|
}));
|
|
|
|
expect(Share.open).toHaveBeenCalledWith(expect.objectContaining({
|
|
message: expect.stringContaining('App Version: 2.0.0'),
|
|
}));
|
|
|
|
expect(Share.open).toHaveBeenCalledWith(expect.objectContaining({
|
|
message: expect.stringContaining('App Platform: ios'),
|
|
}));
|
|
});
|
|
});
|
|
|
|
describe('emailLogs', () => {
|
|
const metadata = {
|
|
currentUserId: 'user1',
|
|
currentTeamId: 'team1',
|
|
serverVersion: '1.0.0',
|
|
appVersion: '2.0.0',
|
|
appPlatform: 'ios',
|
|
};
|
|
|
|
let originalPlatform: typeof Platform.OS;
|
|
beforeAll(() => {
|
|
originalPlatform = Platform.OS;
|
|
});
|
|
|
|
afterAll(() => {
|
|
Platform.OS = originalPlatform;
|
|
});
|
|
|
|
describe('android', () => {
|
|
beforeAll(() => {
|
|
Platform.OS = 'android';
|
|
});
|
|
beforeEach(() => {
|
|
jest.clearAllMocks();
|
|
|
|
const logPaths = ['/path/to/log1', '/path/to/log2'];
|
|
jest.mocked(TurboLogger.getLogPaths).mockResolvedValue(logPaths);
|
|
});
|
|
|
|
it('should share logs with attachments when excludeLogs is false', async () => {
|
|
await emailLogs(metadata, 'My Site', 'support@example.com', false);
|
|
|
|
expect(Share.shareSingle).toHaveBeenCalledWith(expect.objectContaining({
|
|
subject: 'Problem with My Site React Native app',
|
|
email: 'support@example.com',
|
|
urls: ['file:///path/to/log1', 'file:///path/to/log2'],
|
|
social: Share.Social.EMAIL,
|
|
}));
|
|
});
|
|
|
|
it('should handle an empty list of log paths', async () => {
|
|
jest.mocked(TurboLogger.getLogPaths).mockResolvedValue([]);
|
|
|
|
await emailLogs(metadata, 'My Site', 'support@example.com', false);
|
|
|
|
expect(Share.shareSingle).toHaveBeenCalledWith(expect.objectContaining({
|
|
subject: 'Problem with My Site React Native app',
|
|
email: 'support@example.com',
|
|
urls: undefined,
|
|
social: Share.Social.EMAIL,
|
|
}));
|
|
});
|
|
|
|
it('should share without logs when excludeLogs is true', async () => {
|
|
await emailLogs(metadata, 'My Site', 'support@example.com', true);
|
|
|
|
expect(Share.shareSingle).toHaveBeenCalledWith(expect.objectContaining({
|
|
subject: 'Problem with My Site React Native app',
|
|
email: 'support@example.com',
|
|
urls: undefined,
|
|
social: Share.Social.EMAIL,
|
|
}));
|
|
});
|
|
|
|
it('should handle errors', async () => {
|
|
const error = new Error('Share failed');
|
|
jest.mocked(Share.shareSingle).mockRejectedValue(error);
|
|
|
|
await emailLogs(metadata, 'My Site', 'support@example.com');
|
|
|
|
expect(Alert.alert).toHaveBeenCalledWith('Error', 'Error: Share failed');
|
|
});
|
|
|
|
it('should pass the correct metadata to the share function', async () => {
|
|
await emailLogs(metadata, 'My Site', 'support@example.com', false);
|
|
|
|
expect(Share.shareSingle).toHaveBeenCalledWith(expect.objectContaining({
|
|
message: expect.stringContaining('Current User ID: user1'),
|
|
}));
|
|
|
|
expect(Share.shareSingle).toHaveBeenCalledWith(expect.objectContaining({
|
|
message: expect.stringContaining('Current Team ID: team1'),
|
|
}));
|
|
|
|
expect(Share.shareSingle).toHaveBeenCalledWith(expect.objectContaining({
|
|
message: expect.stringContaining('Server Version: 1.0.0'),
|
|
}));
|
|
|
|
expect(Share.shareSingle).toHaveBeenCalledWith(expect.objectContaining({
|
|
message: expect.stringContaining('App Version: 2.0.0'),
|
|
}));
|
|
|
|
expect(Share.shareSingle).toHaveBeenCalledWith(expect.objectContaining({
|
|
message: expect.stringContaining('App Platform: ios'),
|
|
}));
|
|
});
|
|
});
|
|
describe('ios', () => {
|
|
beforeAll(() => {
|
|
Platform.OS = 'ios';
|
|
});
|
|
|
|
it('should open the correct mailto link', async () => {
|
|
await emailLogs(metadata, 'My Site', 'support@example.com', false);
|
|
|
|
expect(tryOpenURL).toHaveBeenCalledTimes(1);
|
|
expect(tryOpenURL).toHaveBeenCalledWith(expect.stringMatching(/^mailto:support@example\.com\?subject=Problem%20with%20My%20Site%20React%20Native%20app&body=/));
|
|
expect(tryOpenURL).toHaveBeenCalledWith(expect.stringContaining(encodeURIComponent('Current User ID: user1')));
|
|
expect(tryOpenURL).toHaveBeenCalledWith(expect.stringContaining(encodeURIComponent('Current Team ID: team1')));
|
|
expect(tryOpenURL).toHaveBeenCalledWith(expect.stringContaining(encodeURIComponent('Server Version: 1.0.0')));
|
|
expect(tryOpenURL).toHaveBeenCalledWith(expect.stringContaining(encodeURIComponent('App Version: 2.0.0')));
|
|
expect(tryOpenURL).toHaveBeenCalledWith(expect.stringContaining(encodeURIComponent('App Platform: ios')));
|
|
});
|
|
});
|
|
});
|
|
|
|
describe('getDefaultReportAProblemLink', () => {
|
|
it('should return licensed link when isLicensed is true', () => {
|
|
const link = getDefaultReportAProblemLink(true);
|
|
expect(link).toBe('https://mattermost.com/pl/report_a_problem_licensed');
|
|
});
|
|
|
|
it('should return unlicensed link when isLicensed is false', () => {
|
|
const link = getDefaultReportAProblemLink(false);
|
|
expect(link).toBe('https://mattermost.com/pl/report_a_problem_unlicensed');
|
|
});
|
|
});
|
|
|
|
describe('metadataToString', () => {
|
|
it('should return a string with the correct metadata', () => {
|
|
const metadata = {
|
|
currentUserId: 'user1',
|
|
currentTeamId: 'team1',
|
|
serverVersion: '1.0.0',
|
|
appVersion: '2.0.0',
|
|
appPlatform: 'ios',
|
|
};
|
|
|
|
const string = metadataToString(metadata);
|
|
expect(string).toBe('Current User ID: user1\nCurrent Team ID: team1\nServer Version: 1.0.0\nApp Version: 2.0.0\nApp Platform: ios');
|
|
});
|
|
});
|