mattermost-mobile-upstream/app/utils/share_logs.test.ts
Rajat Dabade cf49418108
Report a problem not redirect to default email application (#9703)
* review comment

* i18n fix

* review comments

* review comments

* Fix import order in report_problem.test.tsx

Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>

* Add distinctUntilChanged to observeIsFreeEdition and fix skip-screen condition

- Added distinctUntilChanged() to observeIsFreeEdition to match sibling helpers
- Removed attachLogsEnabled from skip-screen condition as it controls file picker for post composition, not report email
- Removed unused attachLogsEnabled prop and observable from settings report_problem component
- Updated tests to reflect the removed condition

Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>

* Remove unused Screens import from report_problem test

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: Cursor Agent <agent@cursor.com>
Co-authored-by: Maria A Nunez <maria.nunez@mattermost.com>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-14 09:10:39 -04:00

220 lines
7.9 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} from 'react-native';
import Share from 'react-native-share';
import {shareLogs, getDefaultReportAProblemLink, metadataToString, emailLogs} from './share_logs';
jest.mock('react-native-share', () => ({
open: jest.fn(),
shareSingle: jest.fn(),
Social: {
EMAIL: 'email',
},
}));
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',
deviceModel: 'iPhone 14',
};
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 mobile 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 mobile 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 mobile 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',
deviceModel: 'iPhone 14',
};
beforeEach(() => {
jest.clearAllMocks();
const logPaths = ['/path/to/log1', '/path/to/log2'];
jest.mocked(TurboLogger.getLogPaths).mockResolvedValue(logPaths);
});
it('should open email composer 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 mobile app',
email: 'support@example.com',
urls: ['file:///path/to/log1', 'file:///path/to/log2'],
social: Share.Social.EMAIL,
}));
});
it('should fall back to Mattermost in subject when siteName is undefined', async () => {
await emailLogs(metadata, undefined, 'support@example.com', false);
expect(Share.shareSingle).toHaveBeenCalledWith(expect.objectContaining({
subject: 'Problem with Mattermost mobile app',
}));
});
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({
email: 'support@example.com',
urls: undefined,
social: Share.Social.EMAIL,
}));
});
it('should open email composer without attachments when excludeLogs is true', async () => {
await emailLogs(metadata, 'My Site', 'support@example.com', true);
expect(Share.shareSingle).toHaveBeenCalledWith(expect.objectContaining({
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 include the body template with metadata in the message', async () => {
await emailLogs(metadata, 'My Site', 'support@example.com', false);
expect(Share.shareSingle).toHaveBeenCalledWith(expect.objectContaining({
message: expect.stringContaining('Please share a description of the problem with reproduction steps:'),
}));
expect(Share.shareSingle).toHaveBeenCalledWith(expect.objectContaining({
message: expect.stringContaining('You may also attach the mobile logs and any relevant screen captures.'),
}));
expect(Share.shareSingle).toHaveBeenCalledWith(expect.objectContaining({
message: expect.stringContaining('App metadata'),
}));
expect(Share.shareSingle).toHaveBeenCalledWith(expect.objectContaining({
message: expect.stringContaining('Current User ID: user1'),
}));
expect(Share.shareSingle).toHaveBeenCalledWith(expect.objectContaining({
message: expect.stringContaining('Device Model: iPhone 14'),
}));
});
});
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',
deviceModel: 'iPhone 14',
};
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\nDevice Model: iPhone 14');
});
});