
* Move sendToRenderer to respective singletons * Move to using ViewManager call for getting view by webContentsId * Move show and create logic to main window, handle deep linking seperately * Move resizing logic and event handing to mainWindow * Move server switching logic to main/app * Move tab switching logic to main/app, rely on showById for most usage * Migrate remaining functions, remove windowManager objects, set up imports for self-contained singletons * Fix E2E tests * Update src/main/app/servers.ts Co-authored-by: Elias Nahum <nahumhbl@gmail.com> --------- Co-authored-by: Elias Nahum <nahumhbl@gmail.com>
396 lines
12 KiB
JavaScript
396 lines
12 KiB
JavaScript
// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved.
|
|
// See LICENSE.txt for license information.
|
|
|
|
'use strict';
|
|
import cp from 'child_process';
|
|
|
|
import {Notification, shell, app} from 'electron';
|
|
|
|
import {getFocusAssist} from 'windows-focus-assist';
|
|
import {getDoNotDisturb as getDarwinDoNotDisturb} from 'macos-notification-state';
|
|
|
|
import {PLAY_SOUND} from 'common/communication';
|
|
import Config from 'common/config';
|
|
|
|
import {localizeMessage} from 'main/i18nManager';
|
|
import MainWindow from 'main/windows/mainWindow';
|
|
import ViewManager from 'main/views/viewManager';
|
|
|
|
import getLinuxDoNotDisturb from './dnd-linux';
|
|
|
|
import {displayMention, displayDownloadCompleted, currentNotifications} from './index';
|
|
|
|
const mentions = [];
|
|
|
|
jest.mock('child_process', () => ({
|
|
execSync: jest.fn(),
|
|
}));
|
|
|
|
jest.mock('electron', () => {
|
|
class NotificationMock {
|
|
static isSupported = jest.fn();
|
|
static didConstruct = jest.fn();
|
|
|
|
constructor(options) {
|
|
NotificationMock.didConstruct();
|
|
this.callbackMap = new Map();
|
|
mentions.push({body: options.body, value: this});
|
|
}
|
|
|
|
on = (event, callback) => {
|
|
this.callbackMap.set(event, callback);
|
|
}
|
|
|
|
show = jest.fn().mockImplementation(() => {
|
|
this.callbackMap.get('show')();
|
|
});
|
|
|
|
click = jest.fn().mockImplementation(() => {
|
|
this.callbackMap.get('click')();
|
|
});
|
|
|
|
close = jest.fn();
|
|
}
|
|
|
|
return {
|
|
app: {
|
|
getAppPath: () => '/path/to/app',
|
|
dock: {
|
|
bounce: jest.fn(),
|
|
},
|
|
},
|
|
Notification: NotificationMock,
|
|
shell: {
|
|
showItemInFolder: jest.fn(),
|
|
},
|
|
};
|
|
});
|
|
|
|
jest.mock('windows-focus-assist', () => ({
|
|
getFocusAssist: jest.fn(),
|
|
}));
|
|
|
|
jest.mock('macos-notification-state', () => ({
|
|
getDoNotDisturb: jest.fn(),
|
|
}));
|
|
jest.mock('../views/viewManager', () => ({
|
|
getViewByWebContentsId: () => ({
|
|
id: 'server_id',
|
|
tab: {
|
|
server: {
|
|
name: 'server_name',
|
|
},
|
|
},
|
|
}),
|
|
showById: jest.fn(),
|
|
}));
|
|
jest.mock('../windows/mainWindow', () => ({
|
|
get: jest.fn(),
|
|
sendToRenderer: jest.fn(),
|
|
}));
|
|
|
|
jest.mock('main/i18nManager', () => ({
|
|
localizeMessage: jest.fn(),
|
|
}));
|
|
|
|
jest.mock('common/config', () => ({}));
|
|
|
|
describe('main/notifications', () => {
|
|
describe('displayMention', () => {
|
|
const mainWindow = {
|
|
flashFrame: jest.fn(),
|
|
};
|
|
|
|
beforeEach(() => {
|
|
Notification.isSupported.mockImplementation(() => true);
|
|
getFocusAssist.mockReturnValue({value: false});
|
|
getDarwinDoNotDisturb.mockReturnValue(false);
|
|
Config.notifications = {};
|
|
MainWindow.get.mockReturnValue(mainWindow);
|
|
});
|
|
|
|
afterEach(() => {
|
|
jest.resetAllMocks();
|
|
Config.notifications = {};
|
|
});
|
|
|
|
it('should do nothing when Notification is not supported', () => {
|
|
Notification.isSupported.mockImplementation(() => false);
|
|
displayMention(
|
|
'test',
|
|
'test body',
|
|
{id: 'channel_id'},
|
|
'team_id',
|
|
'http://server-1.com/team_id/channel_id',
|
|
false,
|
|
{id: 1},
|
|
{},
|
|
);
|
|
expect(Notification.didConstruct).not.toBeCalled();
|
|
});
|
|
|
|
it('should do nothing when alarms only is enabled on windows', () => {
|
|
const originalPlatform = process.platform;
|
|
Object.defineProperty(process, 'platform', {
|
|
value: 'win32',
|
|
});
|
|
|
|
getFocusAssist.mockReturnValue({value: 2});
|
|
displayMention(
|
|
'test',
|
|
'test body',
|
|
{id: 'channel_id'},
|
|
'team_id',
|
|
'http://server-1.com/team_id/channel_id',
|
|
false,
|
|
{id: 1},
|
|
{},
|
|
);
|
|
expect(Notification.didConstruct).not.toBeCalled();
|
|
|
|
Object.defineProperty(process, 'platform', {
|
|
value: originalPlatform,
|
|
});
|
|
});
|
|
|
|
it('should do nothing when dnd is enabled on mac', () => {
|
|
const originalPlatform = process.platform;
|
|
Object.defineProperty(process, 'platform', {
|
|
value: 'darwin',
|
|
});
|
|
|
|
getDarwinDoNotDisturb.mockReturnValue(true);
|
|
displayMention(
|
|
'test',
|
|
'test body',
|
|
{id: 'channel_id'},
|
|
'team_id',
|
|
'http://server-1.com/team_id/channel_id',
|
|
false,
|
|
{id: 1},
|
|
{},
|
|
);
|
|
expect(Notification.didConstruct).not.toBeCalled();
|
|
|
|
Object.defineProperty(process, 'platform', {
|
|
value: originalPlatform,
|
|
});
|
|
});
|
|
|
|
it('should play notification sound when custom sound is provided', () => {
|
|
displayMention(
|
|
'test',
|
|
'test body',
|
|
{id: 'channel_id'},
|
|
'team_id',
|
|
'http://server-1.com/team_id/channel_id',
|
|
false,
|
|
{id: 1},
|
|
{soundName: 'test_sound'},
|
|
);
|
|
expect(MainWindow.sendToRenderer).toHaveBeenCalledWith(PLAY_SOUND, 'test_sound');
|
|
});
|
|
|
|
it('should remove existing notification from the same channel/team on windows', () => {
|
|
const originalPlatform = process.platform;
|
|
Object.defineProperty(process, 'platform', {
|
|
value: 'win32',
|
|
});
|
|
|
|
displayMention(
|
|
'test',
|
|
'test body',
|
|
{id: 'channel_id'},
|
|
'team_id',
|
|
'http://server-1.com/team_id/channel_id',
|
|
false,
|
|
{id: 1},
|
|
{},
|
|
);
|
|
|
|
expect(currentNotifications.has('team_id:channel_id')).toBe(true);
|
|
|
|
const existingMention = currentNotifications.get('team_id:channel_id');
|
|
currentNotifications.delete = jest.fn();
|
|
displayMention(
|
|
'test',
|
|
'test body 2',
|
|
{id: 'channel_id'},
|
|
'team_id',
|
|
'http://server-1.com/team_id/channel_id',
|
|
false,
|
|
{id: 1},
|
|
{},
|
|
);
|
|
|
|
expect(currentNotifications.delete).toHaveBeenCalled();
|
|
expect(existingMention.close).toHaveBeenCalled();
|
|
|
|
Object.defineProperty(process, 'platform', {
|
|
value: originalPlatform,
|
|
});
|
|
});
|
|
|
|
it('should switch tab when clicking on notification', () => {
|
|
displayMention(
|
|
'click_test',
|
|
'mention_click_body',
|
|
{id: 'channel_id'},
|
|
'team_id',
|
|
'http://server-1.com/team_id/channel_id',
|
|
false,
|
|
{id: 1, send: jest.fn()},
|
|
{},
|
|
);
|
|
const mention = mentions.find((m) => m.body === 'mention_click_body');
|
|
mention.value.click();
|
|
expect(ViewManager.showById).toHaveBeenCalledWith('server_id');
|
|
});
|
|
|
|
it('linux/windows - should not flash frame when config item is not set', () => {
|
|
const originalPlatform = process.platform;
|
|
Object.defineProperty(process, 'platform', {
|
|
value: 'linux',
|
|
});
|
|
displayMention(
|
|
'click_test',
|
|
'mention_click_body',
|
|
{id: 'channel_id'},
|
|
'team_id',
|
|
'http://server-1.com/team_id/channel_id',
|
|
false,
|
|
{id: 1, send: jest.fn()},
|
|
{},
|
|
);
|
|
Object.defineProperty(process, 'platform', {
|
|
value: originalPlatform,
|
|
});
|
|
expect(mainWindow.flashFrame).not.toBeCalled();
|
|
});
|
|
|
|
it('linux/windows - should flash frame when config item is set', () => {
|
|
Config.notifications = {
|
|
flashWindow: true,
|
|
};
|
|
const originalPlatform = process.platform;
|
|
Object.defineProperty(process, 'platform', {
|
|
value: 'linux',
|
|
});
|
|
displayMention(
|
|
'click_test',
|
|
'mention_click_body',
|
|
{id: 'channel_id'},
|
|
'team_id',
|
|
'http://server-1.com/team_id/channel_id',
|
|
false,
|
|
{id: 1, send: jest.fn()},
|
|
{},
|
|
);
|
|
Object.defineProperty(process, 'platform', {
|
|
value: originalPlatform,
|
|
});
|
|
expect(mainWindow.flashFrame).toBeCalledWith(true);
|
|
});
|
|
|
|
it('mac - should not bounce icon when config item is not set', () => {
|
|
const originalPlatform = process.platform;
|
|
Object.defineProperty(process, 'platform', {
|
|
value: 'darwin',
|
|
});
|
|
displayMention(
|
|
'click_test',
|
|
'mention_click_body',
|
|
{id: 'channel_id'},
|
|
'team_id',
|
|
'http://server-1.com/team_id/channel_id',
|
|
false,
|
|
{id: 1, send: jest.fn()},
|
|
{},
|
|
);
|
|
Object.defineProperty(process, 'platform', {
|
|
value: originalPlatform,
|
|
});
|
|
expect(app.dock.bounce).not.toBeCalled();
|
|
});
|
|
|
|
it('mac - should bounce icon when config item is set', () => {
|
|
Config.notifications = {
|
|
bounceIcon: true,
|
|
bounceIconType: 'critical',
|
|
};
|
|
const originalPlatform = process.platform;
|
|
Object.defineProperty(process, 'platform', {
|
|
value: 'darwin',
|
|
});
|
|
displayMention(
|
|
'click_test',
|
|
'mention_click_body',
|
|
{id: 'channel_id'},
|
|
'team_id',
|
|
'http://server-1.com/team_id/channel_id',
|
|
false,
|
|
{id: 1, send: jest.fn()},
|
|
{},
|
|
);
|
|
Object.defineProperty(process, 'platform', {
|
|
value: originalPlatform,
|
|
});
|
|
expect(app.dock.bounce).toHaveBeenCalledWith('critical');
|
|
});
|
|
});
|
|
|
|
describe('displayDownloadCompleted', () => {
|
|
beforeEach(() => {
|
|
Notification.isSupported.mockImplementation(() => true);
|
|
getFocusAssist.mockReturnValue({value: false});
|
|
getDarwinDoNotDisturb.mockReturnValue(false);
|
|
});
|
|
|
|
it('should open file when clicked', () => {
|
|
getDarwinDoNotDisturb.mockReturnValue(false);
|
|
localizeMessage.mockReturnValue('test_filename');
|
|
displayDownloadCompleted(
|
|
'test_filename',
|
|
'/path/to/file',
|
|
'server_name',
|
|
);
|
|
const mention = mentions.find((m) => m.body.includes('test_filename'));
|
|
mention.value.click();
|
|
expect(shell.showItemInFolder).toHaveBeenCalledWith('/path/to/file');
|
|
});
|
|
});
|
|
|
|
describe('getLinuxDoNotDisturb', () => {
|
|
let originalPlatform;
|
|
beforeAll(() => {
|
|
originalPlatform = process.platform;
|
|
Object.defineProperty(process, 'platform', {
|
|
value: 'linux',
|
|
});
|
|
});
|
|
|
|
afterAll(() => {
|
|
Object.defineProperty(process, 'platform', {
|
|
value: originalPlatform,
|
|
});
|
|
});
|
|
|
|
it('should return false', () => {
|
|
cp.execSync.mockReturnValue('true');
|
|
expect(getLinuxDoNotDisturb()).toBe(false);
|
|
});
|
|
|
|
it('should return false if error is thrown', () => {
|
|
cp.execSync.mockImplementation(() => {
|
|
throw Error('error');
|
|
});
|
|
expect(getLinuxDoNotDisturb()).toBe(false);
|
|
});
|
|
|
|
it('should return true', () => {
|
|
cp.execSync.mockReturnValue('false');
|
|
expect(getLinuxDoNotDisturb()).toBe(true);
|
|
});
|
|
});
|
|
});
|