1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Make showAbout injectable, add test

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2022-04-06 10:00:24 -04:00
parent c08c50501c
commit ef6a424ec2
30 changed files with 266 additions and 55 deletions

View File

@ -14,7 +14,7 @@ import { getDiForUnitTesting } from "../../main/getDiForUnitTesting";
import getConfigurationFileModelInjectable
from "../get-configuration-file-model/get-configuration-file-model.injectable";
import appVersionInjectable
from "../get-configuration-file-model/app-version/app-version.injectable";
from "../vars/app-version.injectable";
jest.mock("electron", () => ({
ipcMain: {

View File

@ -23,7 +23,7 @@ import { createClusterInjectionToken } from "../cluster/create-cluster-injection
import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable";
import { getDiForUnitTesting } from "../../main/getDiForUnitTesting";
import getConfigurationFileModelInjectable from "../get-configuration-file-model/get-configuration-file-model.injectable";
import appVersionInjectable from "../get-configuration-file-model/app-version/app-version.injectable";
import appVersionInjectable from "../vars/app-version.injectable";
console = new Console(stdout, stderr);

View File

@ -9,7 +9,7 @@ import logger from "../../main/logger";
import type { CatalogEntity, CatalogEntityData, CatalogEntityKindData } from "../catalog";
import { getDiForUnitTesting } from "../../main/getDiForUnitTesting";
import getConfigurationFileModelInjectable from "../get-configuration-file-model/get-configuration-file-model.injectable";
import appVersionInjectable from "../get-configuration-file-model/app-version/app-version.injectable";
import appVersionInjectable from "../vars/app-version.injectable";
import type { DiContainer } from "@ogre-tools/injectable";
import hotbarStoreInjectable from "../hotbar-store.injectable";
import { HotbarStore } from "../hotbar-store";

View File

@ -36,7 +36,7 @@ import { getDiForUnitTesting } from "../../main/getDiForUnitTesting";
import getConfigurationFileModelInjectable
from "../get-configuration-file-model/get-configuration-file-model.injectable";
import appVersionInjectable
from "../get-configuration-file-model/app-version/app-version.injectable";
from "../vars/app-version.injectable";
console = new Console(stdout, stderr);

View File

@ -9,7 +9,7 @@ import getElectronAppPathInjectable from "../../main/app-paths/get-electron-app-
import { getDisForUnitTesting } from "../../test-utils/get-dis-for-unit-testing";
import type { PathName } from "./app-path-names";
import setElectronAppPathInjectable from "../../main/app-paths/set-electron-app-path/set-electron-app-path.injectable";
import appNameInjectable from "../../main/app-paths/app-name/app-name.injectable";
import appNameInjectable from "../../main/vars/app-name.injectable";
import directoryForIntegrationTestingInjectable from "../../main/app-paths/directory-for-integration-testing/directory-for-integration-testing.injectable";
describe("app-paths", () => {

View File

@ -5,7 +5,7 @@
import { getInjectable } from "@ogre-tools/injectable";
import Config from "conf";
import type { BaseStoreParams } from "../base-store";
import appVersionInjectable from "./app-version/app-version.injectable";
import appVersionInjectable from "../vars/app-version.injectable";
import directoryForUserDataInjectable from "../app-paths/directory-for-user-data/directory-for-user-data.injectable";
const getConfigurationFileModelInjectable = getInjectable({

View File

@ -3,7 +3,7 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import packageInfo from "../../../../package.json";
import packageInfo from "../../../package.json";
const appVersionInjectable = getInjectable({
id: "app-version",

View File

@ -0,0 +1,13 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
const chromeVersionInjectable = getInjectable({
id: "chrome-version",
instantiate: () => process.versions.chrome,
causesSideEffects: true,
});
export default chromeVersionInjectable;

View File

@ -0,0 +1,14 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import packageInfo from "../../../package.json";
const copyrightDeclarationInjectable = getInjectable({
id: "copyright-declaration",
instantiate: () => packageInfo.copyright,
causesSideEffects: true,
});
export default copyrightDeclarationInjectable;

View File

@ -0,0 +1,13 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
const electronVersionInjectable = getInjectable({
id: "electron-version",
instantiate: () => process.versions.electron,
causesSideEffects: true,
});
export default electronVersionInjectable;

View File

@ -0,0 +1,13 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
const nodeVersionInjectable = getInjectable({
id: "node-version",
instantiate: () => process.versions.node,
causesSideEffects: true,
});
export default nodeVersionInjectable;

View File

@ -56,7 +56,7 @@ import { createClusterInjectionToken } from "../../common/cluster/create-cluster
import path from "path";
import spawnInjectable from "../child-process/spawn.injectable";
import getConfigurationFileModelInjectable from "../../common/get-configuration-file-model/get-configuration-file-model.injectable";
import appVersionInjectable from "../../common/get-configuration-file-model/app-version/app-version.injectable";
import appVersionInjectable from "../../common/vars/app-version.injectable";
console = new Console(stdout, stderr);

View File

@ -17,7 +17,7 @@ import registerChannelInjectable from "./register-channel/register-channel.injec
import { getAppPaths } from "./get-app-paths";
import getElectronAppPathInjectable from "./get-electron-app-path/get-electron-app-path.injectable";
import setElectronAppPathInjectable from "./set-electron-app-path/set-electron-app-path.injectable";
import appNameInjectable from "./app-name/app-name.injectable";
import appNameInjectable from "../vars/app-name.injectable";
import directoryForIntegrationTestingInjectable from "./directory-for-integration-testing/directory-for-integration-testing.injectable";
import joinPathsInjectable from "../../common/path/join-paths.injectable";

View File

@ -19,7 +19,7 @@ import { ClusterStore } from "../../../common/cluster-store/cluster-store";
import getConfigurationFileModelInjectable
from "../../../common/get-configuration-file-model/get-configuration-file-model.injectable";
import appVersionInjectable
from "../../../common/get-configuration-file-model/app-version/app-version.injectable";
from "../../../common/vars/app-version.injectable";
jest.mock("electron", () => ({
app: {

View File

@ -0,0 +1,16 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { BrowserWindow, dialog, MessageBoxOptions, MessageBoxReturnValue } from "electron";
export type ShowMessageBox = (browserWindow: BrowserWindow, options: MessageBoxOptions) => Promise<MessageBoxReturnValue>;
const showMessageBoxInjectable = getInjectable({
id: "show-message-box",
instantiate: (): ShowMessageBox => (bw, opts) => dialog.showMessageBox(bw, opts),
causesSideEffects: true,
});
export default showMessageBoxInjectable;

View File

@ -0,0 +1,16 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import { clipboard } from "electron";
export type WriteTextToClipboard = (contents: string) => void;
const writeTextToClipboardInjectable = getInjectable({
id: "write-text-to-clipboard",
instantiate: (): WriteTextToClipboard => contents => clipboard.writeText(contents),
causesSideEffects: true,
});
export default writeTextToClipboardInjectable;

View File

@ -10,7 +10,7 @@ import { createContainer } from "@ogre-tools/injectable";
import { Environments, setLegacyGlobalDiForExtensionApi } from "../extensions/as-legacy-globals-for-extension-api/legacy-global-di-for-extension-api";
import getElectronAppPathInjectable from "./app-paths/get-electron-app-path/get-electron-app-path.injectable";
import setElectronAppPathInjectable from "./app-paths/set-electron-app-path/set-electron-app-path.injectable";
import appNameInjectable from "./app-paths/app-name/app-name.injectable";
import appNameInjectable from "./vars/app-name.injectable";
import registerChannelInjectable from "./app-paths/register-channel/register-channel.injectable";
import writeJsonFileInjectable from "../common/fs/write-json-file.injectable";
import readJsonFileInjectable from "../common/fs/read-json-file.injectable";

View File

@ -8,7 +8,6 @@ import { docsUrl, productName, supportUrl } from "../../common/vars";
import { exitApp } from "../exit-app";
import { broadcastMessage } from "../../common/ipc";
import { openBrowser } from "../../common/utils";
import { showAbout } from "./menu";
import windowManagerInjectable from "../window-manager.injectable";
import type {
BrowserWindow,
@ -18,7 +17,7 @@ import {
webContents,
} from "electron";
import loggerInjectable from "../../common/logger.injectable";
import appNameInjectable from "../app-paths/app-name/app-name.injectable";
import appNameInjectable from "../vars/app-name.injectable";
import electronMenuItemsInjectable from "./electron-menu-items.injectable";
import isAutoUpdateEnabledInjectable from "../is-auto-update-enabled.injectable";
import navigateToPreferencesInjectable from "../../common/front-end-routing/routes/preferences/navigate-to-preferences.injectable";
@ -28,6 +27,7 @@ import navigateToWelcomeInjectable from "../../common/front-end-routing/routes/w
import navigateToAddClusterInjectable from "../../common/front-end-routing/routes/add-cluster/navigate-to-add-cluster.injectable";
import isMacInjectable from "../../common/vars/is-mac.injectable";
import { computed } from "mobx";
import showAboutInjectable from "./show-about.injectable";
function ignoreIf(check: boolean, menuItems: MenuItemConstructorOptions[]) {
return check ? [] : menuItems;
@ -46,6 +46,7 @@ const applicationMenuItemsInjectable = getInjectable({
const isMac = di.inject(isMacInjectable);
const isAutoUpdateEnabled = di.inject(isAutoUpdateEnabledInjectable);
const electronMenuItems = di.inject(electronMenuItemsInjectable);
const showAbout = di.inject(showAboutInjectable);
return computed((): MenuItemOpts[] => {
@ -70,8 +71,7 @@ const applicationMenuItemsInjectable = getInjectable({
label: `About ${productName}`,
id: "about",
click(menuItem: MenuItem, browserWindow: BrowserWindow) {
showAbout(browserWindow)
.catch(error => logger.error(`[MENU]: Failed to show Lens About view`, { error }));
showAbout(browserWindow);
},
},
...ignoreIf(autoUpdateDisabled, [
@ -288,8 +288,7 @@ const applicationMenuItemsInjectable = getInjectable({
label: `About ${productName}`,
id: "about",
click(menuItem: MenuItem, browserWindow: BrowserWindow) {
showAbout(browserWindow)
.catch(error => logger.error(`[MENU]: Failed to show Lens About view`, { error }));
showAbout(browserWindow);
},
},
...ignoreIf(autoUpdateDisabled, [

View File

@ -2,12 +2,9 @@
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { BrowserWindow } from "electron";
import { app, clipboard, dialog, Menu } from "electron";
import { Menu } from "electron";
import type { IComputedValue } from "mobx";
import { autorun } from "mobx";
import { appName, isWindows, productName } from "../../common/vars";
import packageJson from "../../../package.json";
import type { MenuItemOpts } from "./application-menu-items.injectable";
export type MenuTopId = "mac" | "file" | "edit" | "view" | "help";
@ -20,30 +17,6 @@ export function initMenu(
});
}
export async function showAbout(browserWindow: BrowserWindow) {
const appInfo = [
`${appName}: ${app.getVersion()}`,
`Electron: ${process.versions.electron}`,
`Chrome: ${process.versions.chrome}`,
`Node: ${process.versions.node}`,
packageJson.copyright,
].join("\n");
const result = await dialog.showMessageBox(browserWindow, {
title: `${isWindows ? " ".repeat(2) : ""}${appName}`,
type: "info",
buttons: ["Close", "Copy"],
message: productName,
detail: appInfo,
cancelId: 0,
defaultId: 0,
});
if (result.response === 0) {
clipboard.writeText(appInfo);
}
}
export function buildMenu(
applicationMenuItems: MenuItemOpts[],
) {

View File

@ -0,0 +1,92 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import type { BrowserWindow } from "electron";
import type { Logger } from "../../common/logger";
import loggerInjectable from "../../common/logger.injectable";
import appVersionInjectable from "../../common/vars/app-version.injectable";
import chromeVersionInjectable from "../../common/vars/chrome-version.injectable";
import copyrightDeclarationInjectable from "../../common/vars/copyright-declaration.injectable";
import electronVersionInjectable from "../../common/vars/electron-version.injectable";
import isWindowsInjectable from "../../common/vars/is-windows.injectable";
import nodeVersionInjectable from "../../common/vars/node-version.injectable";
import showMessageBoxInjectable, { ShowMessageBox } from "../electron/show-message-box.injectable";
import writeTextToClipboardInjectable, { WriteTextToClipboard } from "../electron/write-text-to-clipboard.injectable";
import appNameInjectable from "../vars/app-name.injectable";
export type ShowAbout = (browserWindow: BrowserWindow) => void;
interface Dependencies {
showMessageBox: ShowMessageBox;
writeTextToClipboard: WriteTextToClipboard;
appName: string;
appVersion: string;
copyrightDeclaration: string;
electronVersion: string;
chromeVersion: string;
nodeVersion: string;
isWindows: boolean;
logger: Logger;
}
const showAboutFactory = ({
showMessageBox,
writeTextToClipboard,
appName,
appVersion,
copyrightDeclaration,
electronVersion,
chromeVersion,
nodeVersion,
isWindows,
logger,
}: Dependencies): ShowAbout => (
function showAbout(browserWindow) {
const appInfo = [
`${appName}: ${appVersion}`,
`Electron: ${electronVersion}`,
`Chrome: ${chromeVersion}`,
`Node: ${nodeVersion}`,
copyrightDeclaration,
].join("\n");
showMessageBox(browserWindow, {
title: `${isWindows ? " ".repeat(2) : ""}${appName}`,
type: "info",
buttons: ["Close", "Copy"],
message: appName,
detail: appInfo,
cancelId: 0,
defaultId: 0,
})
.then(({ response }) => {
/**
* response is the index into the `buttons` array provided to `dialog.showMessageBox`
*/
if (response === 0) {
writeTextToClipboard(appInfo);
}
})
.catch(error => logger.error("[SHOW-ABOUT]: failed to show about message", error));
}
);
const showAboutInjectable = getInjectable({
id: "show-about",
instantiate: (di) => showAboutFactory({
showMessageBox: di.inject(showMessageBoxInjectable),
writeTextToClipboard: di.inject(writeTextToClipboardInjectable),
appName: di.inject(appNameInjectable),
appVersion: di.inject(appVersionInjectable),
copyrightDeclaration: di.inject(copyrightDeclarationInjectable),
chromeVersion: di.inject(chromeVersionInjectable),
electronVersion: di.inject(electronVersionInjectable),
isWindows: di.inject(isWindowsInjectable),
logger: di.inject(loggerInjectable),
nodeVersion: di.inject(nodeVersionInjectable),
}),
});
export default showAboutInjectable;

View File

@ -0,0 +1,55 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { waitFor } from "@testing-library/react";
import appVersionInjectable from "../../common/vars/app-version.injectable";
import chromeVersionInjectable from "../../common/vars/chrome-version.injectable";
import copyrightDeclarationInjectable from "../../common/vars/copyright-declaration.injectable";
import electronVersionInjectable from "../../common/vars/electron-version.injectable";
import nodeVersionInjectable from "../../common/vars/node-version.injectable";
import type { ShowMessageBox } from "../electron/show-message-box.injectable";
import showMessageBoxInjectable from "../electron/show-message-box.injectable";
import type { WriteTextToClipboard } from "../electron/write-text-to-clipboard.injectable";
import writeTextToClipboardInjectable from "../electron/write-text-to-clipboard.injectable";
import { getDiForUnitTesting } from "../getDiForUnitTesting";
import appNameInjectable from "../vars/app-name.injectable";
import type { ShowAbout } from "./show-about.injectable";
import showAboutInjectable from "./show-about.injectable";
describe("showAbout tests", () => {
let showAbout: ShowAbout;
let showMessageBox: jest.MockedFunction<ShowMessageBox>;
let writeTextToClipboard: jest.MockedFunction<WriteTextToClipboard>;
beforeEach(() => {
const di = getDiForUnitTesting({ doGeneralOverrides: true });
showMessageBox = jest.fn();
writeTextToClipboard = jest.fn();
di.override(showMessageBoxInjectable, () => showMessageBox);
di.override(writeTextToClipboardInjectable, () => writeTextToClipboard);
di.override(appNameInjectable, () => "lens");
di.override(appVersionInjectable, () => "some-app-version");
di.override(copyrightDeclarationInjectable, () => "some copyright declaration");
di.override(electronVersionInjectable, () => "some-electron-version");
di.override(chromeVersionInjectable, () => "some-chrome-version");
di.override(nodeVersionInjectable, () => "some-node-version");
showAbout = di.inject(showAboutInjectable);
});
it("should write the contents to the clipboard when the copy button is clicked", async () => {
showMessageBox.mockImplementationOnce(() => Promise.resolve({ response: 0, checkboxChecked: false }));
showAbout(null);
await waitFor(() => expect(writeTextToClipboard).toBeCalledWith([
"lens: some-app-version",
"Electron: some-electron-version",
"Chrome: some-chrome-version",
"Node: some-node-version",
"some copyright declaration",
].join("\n")));
});
});

View File

@ -17,7 +17,7 @@ import extensionLoaderInjectable from "../../../extensions/extension-loader/exte
import lensProtocolRouterMainInjectable from "../lens-protocol-router-main/lens-protocol-router-main.injectable";
import extensionsStoreInjectable from "../../../extensions/extensions-store/extensions-store.injectable";
import getConfigurationFileModelInjectable from "../../../common/get-configuration-file-model/get-configuration-file-model.injectable";
import appVersionInjectable from "../../../common/get-configuration-file-model/app-version/app-version.injectable";
import appVersionInjectable from "../../../common/vars/app-version.injectable";
jest.mock("../../../common/ipc");

View File

@ -8,7 +8,6 @@ import type { NativeImage } from "electron";
import { Menu, nativeImage, nativeTheme, Tray } from "electron";
import type { IComputedValue } from "mobx";
import { autorun } from "mobx";
import { showAbout } from "../menu/menu";
import { checkForUpdates, isAutoUpdateEnabled } from "../app-updater";
import type { WindowManager } from "../window-manager";
import logger from "../logger";
@ -21,6 +20,7 @@ import sharp from "sharp";
import LogoLens from "../../renderer/components/icon/logo-lens.svg";
import { JSDOM } from "jsdom";
import type { ShowAbout } from "../menu/show-about.injectable";
const TRAY_LOG_PREFIX = "[TRAY]";
@ -80,6 +80,7 @@ export async function initTray(
windowManager: WindowManager,
trayMenuItems: IComputedValue<TrayMenuRegistration[]>,
navigateToPreferences: () => void,
showAbout: ShowAbout,
): Promise<Disposer> {
const icon = await createCurrentTrayIcon();
const dispose = disposer();
@ -101,7 +102,12 @@ export async function initTray(
dispose.push(
autorun(() => {
try {
const menu = createTrayMenu(windowManager, toJS(trayMenuItems.get()), navigateToPreferences);
const menu = createTrayMenu(
windowManager,
toJS(trayMenuItems.get()),
navigateToPreferences,
showAbout,
);
tray.setContextMenu(menu);
} catch (error) {
@ -131,6 +137,7 @@ function createTrayMenu(
windowManager: WindowManager,
extensionTrayItems: TrayMenuRegistration[],
navigateToPreferences: () => void,
showAbout: ShowAbout,
): Menu {
let template: Electron.MenuItemConstructorOptions[] = [
{

View File

@ -3,7 +3,7 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable } from "@ogre-tools/injectable";
import electronAppInjectable from "../get-electron-app-path/electron-app/electron-app.injectable";
import electronAppInjectable from "../app-paths/get-electron-app-path/electron-app/electron-app.injectable";
const appNameInjectable = getInjectable({
id: "app-name",

View File

@ -24,7 +24,7 @@ import { UserStore } from "../../../common/user-store";
import mockFs from "mock-fs";
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
import getConfigurationFileModelInjectable from "../../../common/get-configuration-file-model/get-configuration-file-model.injectable";
import appVersionInjectable from "../../../common/get-configuration-file-model/app-version/app-version.injectable";
import appVersionInjectable from "../../../common/vars/app-version.injectable";
import type { AppEvent } from "../../../common/app-event-bus/event-bus";
import appEventBusInjectable from "../../../common/app-event-bus/app-event-bus.injectable";

View File

@ -24,7 +24,7 @@ import directoryForDownloadsInjectable from "../../../../common/app-paths/direct
import getConfigurationFileModelInjectable
from "../../../../common/get-configuration-file-model/get-configuration-file-model.injectable";
import appVersionInjectable
from "../../../../common/get-configuration-file-model/app-version/app-version.injectable";
from "../../../../common/vars/app-version.injectable";
mockWindow();

View File

@ -22,7 +22,7 @@ import directoryForUserDataInjectable
import getConfigurationFileModelInjectable
from "../../../../common/get-configuration-file-model/get-configuration-file-model.injectable";
import appVersionInjectable
from "../../../../common/get-configuration-file-model/app-version/app-version.injectable";
from "../../../../common/vars/app-version.injectable";
jest.mock("electron", () => ({
app: {

View File

@ -25,7 +25,7 @@ import { SearchStore } from "../../../../search-store/search-store";
import getConfigurationFileModelInjectable
from "../../../../../common/get-configuration-file-model/get-configuration-file-model.injectable";
import appVersionInjectable
from "../../../../../common/get-configuration-file-model/app-version/app-version.injectable";
from "../../../../../common/vars/app-version.injectable";
jest.mock("electron", () => ({
app: {

View File

@ -18,7 +18,7 @@ import { UserStore } from "../../../../common/user-store";
import mockFs from "mock-fs";
import directoryForUserDataInjectable from "../../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
import getConfigurationFileModelInjectable from "../../../../common/get-configuration-file-model/get-configuration-file-model.injectable";
import appVersionInjectable from "../../../../common/get-configuration-file-model/app-version/app-version.injectable";
import appVersionInjectable from "../../../../common/vars/app-version.injectable";
import type { HotbarStore } from "../../../../common/hotbar-store";
const mockHotbars: { [id: string]: any } = {

View File

@ -17,7 +17,7 @@ import rendererExtensionsInjectable from "../../../extensions/renderer-extension
import { computed } from "mobx";
import type { LensRendererExtension } from "../../../extensions/lens-renderer-extension";
import getConfigurationFileModelInjectable from "../../../common/get-configuration-file-model/get-configuration-file-model.injectable";
import appVersionInjectable from "../../../common/get-configuration-file-model/app-version/app-version.injectable";
import appVersionInjectable from "../../../common/vars/app-version.injectable";
jest.mock("electron", () => ({
ipcRenderer: {