From b20e1399714188d77ea29114698119a1367d2de0 Mon Sep 17 00:00:00 2001 From: Devin Binnie <52460000+devinbinnie@users.noreply.github.com> Date: Thu, 25 Nov 2021 10:41:12 -0500 Subject: [PATCH] [MM-40316] Unit tests for main/menus (#1877) * Unit tests for main/menus/app * Also this * Unit tests for main/menus/tray --- package.json | 5 +- src/main/main.ts | 8 +- src/main/menus/app.test.js | 209 ++++++++++++++++++++++++++++++++++++ src/main/menus/app.ts | 16 ++- src/main/menus/tray.test.js | 40 +++++++ src/main/menus/tray.ts | 10 +- 6 files changed, 266 insertions(+), 22 deletions(-) create mode 100644 src/main/menus/app.test.js create mode 100644 src/main/menus/tray.test.js diff --git a/package.json b/package.json index 64ba8cd2..71d52e53 100644 --- a/package.json +++ b/package.json @@ -70,7 +70,10 @@ "jsx", "json" ], - "testMatch": ["**/src/**/*.test.js"] + "testMatch": ["**/src/**/*.test.js"], + "globals": { + "__HASH_VERSION__": "5.0.0" + } }, "devDependencies": { "@babel/cli": "^7.14.5", diff --git a/src/main/main.ts b/src/main/main.ts index 07ecfd52..0f55cd87 100644 --- a/src/main/main.ts +++ b/src/main/main.ts @@ -58,8 +58,8 @@ import CriticalErrorHandler from './CriticalErrorHandler'; import upgradeAutoLaunch from './autoLaunch'; import CertificateStore from './certificateStore'; import TrustedOriginsStore from './trustedOrigins'; -import appMenu from './menus/app'; -import trayMenu from './menus/tray'; +import {createMenu as createAppMenu} from './menus/app'; +import {createMenu as createTrayMenu} from './menus/tray'; import allowProtocolDialog from './allowProtocolDialog'; import AppVersionManager from './AppVersionManager'; import initCookieManager from './cookieManager'; @@ -863,13 +863,13 @@ function handleCloseAppMenu() { } function handleUpdateMenuEvent(event: IpcMainEvent, menuConfig: Config) { - const aMenu = appMenu.createMenu(menuConfig); + const aMenu = createAppMenu(menuConfig); Menu.setApplicationMenu(aMenu); aMenu.addListener('menu-will-close', handleCloseAppMenu); // set up context menu for tray icon if (shouldShowTrayIcon()) { - const tMenu = trayMenu.createMenu(menuConfig.data!); + const tMenu = createTrayMenu(menuConfig.data!); setTrayMenu(tMenu); } } diff --git a/src/main/menus/app.test.js b/src/main/menus/app.test.js new file mode 100644 index 00000000..722c61e2 --- /dev/null +++ b/src/main/menus/app.test.js @@ -0,0 +1,209 @@ +// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +'use strict'; + +import * as WindowManager from 'main/windows/windowManager'; + +import {createTemplate} from './app'; + +jest.mock('electron', () => ({ + app: { + name: 'AppName', + getVersion: () => '5.0.0', + }, +})); + +jest.mock('main/windows/windowManager', () => ({ + getCurrentTeamName: jest.fn(), +})); + +jest.mock('common/tabs/TabView', () => ({ + getTabDisplayName: (name) => name, +})); + +describe('main/menus/app', () => { + const config = { + data: { + enableServerManagement: true, + teams: [{ + name: 'example', + url: 'http://example.com', + order: 0, + tabs: [ + { + name: 'TAB_MESSAGING', + order: 0, + isOpen: true, + }, + { + name: 'TAB_FOCALBOARD', + order: 1, + isOpen: true, + }, + { + name: 'TAB_PLAYBOOKS', + order: 2, + isOpen: true, + }, + ], + lastActiveTab: 0, + }, { + name: 'github', + url: 'https://github.com/', + order: 1, + tabs: [ + { + name: 'TAB_MESSAGING', + order: 0, + isOpen: true, + }, + { + name: 'TAB_FOCALBOARD', + order: 1, + isOpen: true, + }, + { + name: 'TAB_PLAYBOOKS', + order: 2, + isOpen: true, + }, + ], + lastActiveTab: 0, + }], + helpLink: 'http://link-to-help.site.com', + }, + }; + + describe('mac only', () => { + let originalPlatform; + beforeAll(() => { + originalPlatform = process.platform; + Object.defineProperty(process, 'platform', { + value: 'darwin', + }); + }); + + afterAll(() => { + Object.defineProperty(process, 'platform', { + value: originalPlatform, + }); + }); + + it('should have first menu name as AppName', () => { + const menu = createTemplate(config); + const appNameMenu = menu.find((item) => item.label === '&AppName'); + expect(appNameMenu).not.toBe(undefined); + }); + + it('should include About in menu on mac', () => { + const menu = createTemplate(config); + const appNameMenu = menu.find((item) => item.label === '&AppName'); + const menuItem = appNameMenu.submenu.find((item) => item.label === 'About AppName'); + expect(menuItem).not.toBe(undefined); + expect(menuItem.role).toBe('about'); + }); + + it('should contain hide options', () => { + const menu = createTemplate(config); + const appNameMenu = menu.find((item) => item.label === '&AppName'); + expect(appNameMenu.submenu).toContainEqual({role: 'hide'}); + expect(appNameMenu.submenu).toContainEqual({role: 'unhide'}); + expect(appNameMenu.submenu).toContainEqual({role: 'hideOthers'}); + }); + + it('should contain zoom and front options in Window', () => { + const menu = createTemplate(config); + const windowMenu = menu.find((item) => item.label === '&Window'); + expect(windowMenu.role).toBe('windowMenu'); + expect(windowMenu.submenu).toContainEqual({role: 'zoom'}); + expect(windowMenu.submenu).toContainEqual({role: 'front'}); + }); + }); + + it('should show `Sign in to Another Server` if `enableServerManagement` is true', () => { + const menu = createTemplate(config); + const fileMenu = menu.find((item) => item.label === '&AppName' || item.label === '&File'); + const signInOption = fileMenu.submenu.find((item) => item.label === 'Sign in to Another Server'); + expect(signInOption).not.toBe(undefined); + }); + + it('should not show `Sign in to Another Server` if `enableServerManagement` is false', () => { + const modifiedConfig = { + ...config, + enableServerManagement: false, + }; + const menu = createTemplate(modifiedConfig); + const fileMenu = menu.find((item) => item.label === '&AppName' || item.label === '&File'); + const signInOption = fileMenu.submenu.find((item) => item.label === 'Sign in to Another Server'); + expect(signInOption).not.toBe(undefined); + }); + + it('should show the first 9 servers (using order) in the Window menu', () => { + const modifiedConfig = { + data: { + ...config.data, + teams: [...Array(15).keys()].map((key) => ({ + name: `server-${key}`, + url: `http://server-${key}.com`, + order: (key + 5) % 15, + lastActiveTab: 0, + tab: [ + { + name: 'TAB_MESSAGING', + isOpen: true, + }, + ], + })), + }, + }; + const menu = createTemplate(modifiedConfig); + const windowMenu = menu.find((item) => item.label === '&Window'); + for (let i = 10; i < 15; i++) { + const menuItem = windowMenu.submenu.find((item) => item.label === `server-${i}`); + expect(menuItem).not.toBe(undefined); + } + for (let i = 0; i < 4; i++) { + const menuItem = windowMenu.submenu.find((item) => item.label === `server-${i}`); + expect(menuItem).not.toBe(undefined); + } + for (let i = 4; i < 10; i++) { + const menuItem = windowMenu.submenu.find((item) => item.label === `server-${i}`); + expect(menuItem).toBe(undefined); + } + }); + + it('should show the first 9 tabs (using order) in the Window menu', () => { + WindowManager.getCurrentTeamName.mockImplementation(() => config.data.teams[0].name); + + const modifiedConfig = { + data: { + ...config.data, + teams: [ + { + ...config.data.teams[0], + tabs: [...Array(15).keys()].map((key) => ({ + name: `tab-${key}`, + isOpen: true, + order: (key + 5) % 15, + })), + }, + ], + }, + }; + const menu = createTemplate(modifiedConfig); + const windowMenu = menu.find((item) => item.label === '&Window'); + for (let i = 10; i < 15; i++) { + const menuItem = windowMenu.submenu.find((item) => item.label === ` tab-${i}`); + expect(menuItem).not.toBe(undefined); + } + for (let i = 0; i < 4; i++) { + const menuItem = windowMenu.submenu.find((item) => item.label === ` tab-${i}`); + expect(menuItem).not.toBe(undefined); + } + for (let i = 4; i < 10; i++) { + const menuItem = windowMenu.submenu.find((item) => item.label === ` tab-${i}`); + expect(menuItem).toBe(undefined); + } + }); +}); diff --git a/src/main/menus/app.ts b/src/main/menus/app.ts index b2bd8e26..70e570e9 100644 --- a/src/main/menus/app.ts +++ b/src/main/menus/app.ts @@ -9,9 +9,9 @@ import {SHOW_NEW_SERVER_MODAL} from 'common/communication'; import Config from 'common/config'; import {TabType, getTabDisplayName} from 'common/tabs/TabView'; -import * as WindowManager from '../windows/windowManager'; +import * as WindowManager from 'main/windows/windowManager'; -function createTemplate(config: Config) { +export function createTemplate(config: Config) { const separatorItem: MenuItemConstructorOptions = { type: 'separator', }; @@ -122,7 +122,7 @@ function createTemplate(config: Config) { }, }, { role: 'togglefullscreen', - accelerator: process.platform === 'darwin' ? 'Ctrl+Cmd+F' : 'F11', + accelerator: isMac ? 'Ctrl+Cmd+F' : 'F11', }, separatorItem, { label: 'Actual Size', role: 'resetZoom', @@ -210,7 +210,7 @@ function createTemplate(config: Config) { ] : []), { role: 'close', accelerator: 'CmdOrCtrl+W', - }, separatorItem, ...teams.slice(0, 9).sort((teamA, teamB) => teamA.order - teamB.order).map((team, i) => { + }, separatorItem, ...teams.sort((teamA, teamB) => teamA.order - teamB.order).slice(0, 9).map((team, i) => { const items = []; items.push({ label: team.name, @@ -220,7 +220,7 @@ function createTemplate(config: Config) { }, }); if (WindowManager.getCurrentTeamName() === team.name) { - team.tabs.filter((tab) => tab.isOpen).slice(0, 9).sort((teamA, teamB) => teamA.order - teamB.order).forEach((tab, i) => { + team.tabs.filter((tab) => tab.isOpen).sort((teamA, teamB) => teamA.order - teamB.order).slice(0, 9).forEach((tab, i) => { items.push({ label: ` ${getTabDisplayName(tab.name as TabType)}`, accelerator: `CmdOrCtrl+${i + 1}`, @@ -273,11 +273,7 @@ function createTemplate(config: Config) { return template; } -function createMenu(config: Config) { +export function createMenu(config: Config) { // TODO: Electron is enforcing certain variables that it doesn't need return Menu.buildFromTemplate(createTemplate(config) as Array); } - -export default { - createMenu, -}; diff --git a/src/main/menus/tray.test.js b/src/main/menus/tray.test.js new file mode 100644 index 00000000..594efe94 --- /dev/null +++ b/src/main/menus/tray.test.js @@ -0,0 +1,40 @@ +// Copyright (c) 2016-present Mattermost, Inc. All Rights Reserved. +// See LICENSE.txt for license information. + +'use strict'; + +import {createTemplate} from './tray'; + +jest.mock('main/windows/windowManager', () => ({})); + +describe('main/menus/tray', () => { + it('should show the first 9 servers (using order)', () => { + const config = { + teams: [...Array(15).keys()].map((key) => ({ + name: `server-${key}`, + url: `http://server-${key}.com`, + order: (key + 5) % 15, + lastActiveTab: 0, + tab: [ + { + name: 'TAB_MESSAGING', + isOpen: true, + }, + ], + })), + }; + const menu = createTemplate(config); + for (let i = 10; i < 15; i++) { + const menuItem = menu.find((item) => item.label === `server-${i}`); + expect(menuItem).not.toBe(undefined); + } + for (let i = 0; i < 4; i++) { + const menuItem = menu.find((item) => item.label === `server-${i}`); + expect(menuItem).not.toBe(undefined); + } + for (let i = 4; i < 10; i++) { + const menuItem = menu.find((item) => item.label === `server-${i}`); + expect(menuItem).toBe(undefined); + } + }); +}); diff --git a/src/main/menus/tray.ts b/src/main/menus/tray.ts index 914852dc..6fb47575 100644 --- a/src/main/menus/tray.ts +++ b/src/main/menus/tray.ts @@ -8,10 +8,10 @@ import {CombinedConfig} from 'types/config'; import * as WindowManager from '../windows/windowManager'; -function createTemplate(config: CombinedConfig) { +export function createTemplate(config: CombinedConfig) { const teams = config.teams; const template = [ - ...teams.slice(0, 9).sort((teamA, teamB) => teamA.order - teamB.order).map((team) => { + ...teams.sort((teamA, teamB) => teamA.order - teamB.order).slice(0, 9).map((team) => { return { label: team.name, click: () => { @@ -34,11 +34,7 @@ function createTemplate(config: CombinedConfig) { return template; } -function createMenu(config: CombinedConfig) { +export function createMenu(config: CombinedConfig) { // TODO: Electron is enforcing certain variables that it doesn't need return Menu.buildFromTemplate(createTemplate(config) as Array); } - -export default { - createMenu, -};