From 4bf4089346870ee474b7e9b11241d2918964e6ae Mon Sep 17 00:00:00 2001 From: Sebastian Malton Date: Thu, 7 Apr 2022 14:38:51 -0400 Subject: [PATCH] fix kube-object-menu.test.tsx Signed-off-by: Sebastian Malton --- .../user-store/terminal-config.injectable.ts | 19 ++++++ .../terminal-copy-on-select.injectable.ts | 18 ++++++ .../terminal/create-terminal.injectable.ts | 14 +++- .../terminal-spawning-pool.injectable.ts | 20 ++++++ .../components/dock/terminal/terminal.ts | 64 ++++++++++--------- .../kube-object-menu.test.tsx.snap | 12 +--- .../components/test-utils/renderFor.tsx | 10 +-- src/renderer/getDiForUnitTesting.tsx | 3 + 8 files changed, 113 insertions(+), 47 deletions(-) create mode 100644 src/common/user-store/terminal-config.injectable.ts create mode 100644 src/common/user-store/terminal-copy-on-select.injectable.ts create mode 100644 src/renderer/components/dock/terminal/terminal-spawning-pool.injectable.ts diff --git a/src/common/user-store/terminal-config.injectable.ts b/src/common/user-store/terminal-config.injectable.ts new file mode 100644 index 0000000000..6f5be75eaf --- /dev/null +++ b/src/common/user-store/terminal-config.injectable.ts @@ -0,0 +1,19 @@ +/** + * 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 { computed } from "mobx"; +import { toJS } from "../utils"; +import userStoreInjectable from "./user-store.injectable"; + +const terminalConfigInjectable = getInjectable({ + id: "terminal-config", + instantiate: (di) => { + const store = di.inject(userStoreInjectable); + + return computed(() => toJS(store.terminalConfig)); + }, +}); + +export default terminalConfigInjectable; diff --git a/src/common/user-store/terminal-copy-on-select.injectable.ts b/src/common/user-store/terminal-copy-on-select.injectable.ts new file mode 100644 index 0000000000..543a4f73b9 --- /dev/null +++ b/src/common/user-store/terminal-copy-on-select.injectable.ts @@ -0,0 +1,18 @@ +/** + * 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 { computed } from "mobx"; +import userStoreInjectable from "./user-store.injectable"; + +const terminalCopyOnSelectInjectable = getInjectable({ + id: "terminal-copy-on-select", + instantiate: (di) => { + const store = di.inject(userStoreInjectable); + + return computed(() => store.terminalCopyOnSelect); + }, +}); + +export default terminalCopyOnSelectInjectable; diff --git a/src/renderer/components/dock/terminal/create-terminal.injectable.ts b/src/renderer/components/dock/terminal/create-terminal.injectable.ts index 4cd4f404b8..81c2265d20 100644 --- a/src/renderer/components/dock/terminal/create-terminal.injectable.ts +++ b/src/renderer/components/dock/terminal/create-terminal.injectable.ts @@ -3,15 +3,27 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import { getInjectable } from "@ogre-tools/injectable"; +import type { TerminalDependencies } from "./terminal"; import { Terminal } from "./terminal"; import type { TabId } from "../dock/store"; import type { TerminalApi } from "../../../api/terminal-api"; +import terminalSpawningPoolInjectable from "./terminal-spawning-pool.injectable"; +import terminalConfigInjectable from "../../../../common/user-store/terminal-config.injectable"; +import terminalCopyOnSelectInjectable from "../../../../common/user-store/terminal-copy-on-select.injectable"; export type CreateTerminal = (tabId: TabId, api: TerminalApi) => Terminal; const createTerminalInjectable = getInjectable({ id: "create-terminal", - instantiate: (): CreateTerminal => (tabId, api) => new Terminal(tabId, api), + instantiate: (di): CreateTerminal => { + const dependencies: TerminalDependencies = { + spawningPool: di.inject(terminalSpawningPoolInjectable), + terminalConfig: di.inject(terminalConfigInjectable), + terminalCopyOnSelect: di.inject(terminalCopyOnSelectInjectable), + }; + + return (tabId, api) => new Terminal(dependencies, { tabId, api }); + }, }); export default createTerminalInjectable; diff --git a/src/renderer/components/dock/terminal/terminal-spawning-pool.injectable.ts b/src/renderer/components/dock/terminal/terminal-spawning-pool.injectable.ts new file mode 100644 index 0000000000..11173b9ac8 --- /dev/null +++ b/src/renderer/components/dock/terminal/terminal-spawning-pool.injectable.ts @@ -0,0 +1,20 @@ +/** + * 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 assert from "assert"; + +const terminalSpawningPoolInjectable = getInjectable({ + id: "terminal-spawning-pool", + instantiate: () => { + const pool = document.getElementById("terminal-init"); + + assert(pool, "DOM MUST container #terminal-init element"); + + return pool; + }, + causesSideEffects: true, +}); + +export default terminalSpawningPoolInjectable; diff --git a/src/renderer/components/dock/terminal/terminal.ts b/src/renderer/components/dock/terminal/terminal.ts index ff2202c719..af8146a69d 100644 --- a/src/renderer/components/dock/terminal/terminal.ts +++ b/src/renderer/components/dock/terminal/terminal.ts @@ -4,6 +4,7 @@ */ import debounce from "lodash/debounce"; +import type { IComputedValue } from "mobx"; import { reaction } from "mobx"; import { Terminal as XTerm } from "xterm"; import { FitAddon } from "xterm-addon-fit"; @@ -14,41 +15,36 @@ import { ThemeStore } from "../../../theme.store"; import { disposer } from "../../../utils"; import { isMac } from "../../../../common/vars"; import { once } from "lodash"; -import { UserStore } from "../../../../common/user-store"; import { clipboard } from "electron"; import logger from "../../../../common/logger"; import type { TerminalConfig } from "../../../../common/user-store/preferences-helpers"; import assert from "assert"; +export interface TerminalDependencies { + readonly spawningPool: HTMLElement; + readonly terminalConfig: IComputedValue; + readonly terminalCopyOnSelect: IComputedValue; +} + +export interface TerminalArguments { + tabId: TabId; + api: TerminalApi; +} + export class Terminal { - private terminalConfig: TerminalConfig = UserStore.getInstance().terminalConfig; - - public static spawningPool: HTMLElement; - - static { - const pool = document.getElementById("terminal-init"); - - assert(pool, "FATAL: missing #terminal-init tag in DOM"); - - this.spawningPool = pool; - } - - private xterm: XTerm = new XTerm({ - cursorBlink: true, - cursorStyle: "bar", - fontSize: this.terminalConfig.fontSize, - fontFamily: this.terminalConfig.fontFamily, - }); + private readonly xterm: XTerm; private readonly fitAddon = new FitAddon(); private scrollPos = 0; - private disposer = disposer(); + private readonly disposer = disposer(); + public readonly tabId: TabId; + protected readonly api: TerminalApi; - get elem() { + private get elem() { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion return this.xterm.element!; } - get viewport() { + private get viewport() { // eslint-disable-next-line @typescript-eslint/no-non-null-assertion return this.elem.querySelector(".xterm-viewport")!; } @@ -63,15 +59,25 @@ export class Terminal { const { elem } = this; if (elem) { - Terminal.spawningPool.appendChild(elem); + this.dependencies.spawningPool.appendChild(elem); } } - constructor(public tabId: TabId, protected api: TerminalApi) { + constructor(protected readonly dependencies: TerminalDependencies, { tabId, api }: TerminalArguments) { + this.tabId = tabId; + this.api = api; + const { fontSize, fontFamily } = this.dependencies.terminalConfig.get(); + + this.xterm = new XTerm({ + cursorBlink: true, + cursorStyle: "bar", + fontSize, + fontFamily, + }); // enable terminal addons this.xterm.loadAddon(this.fitAddon); - this.xterm.open(Terminal.spawningPool); + this.xterm.open(this.dependencies.spawningPool); this.xterm.registerLinkMatcher(/https?:\/\/[^\s]+/i, this.onClickLink); this.xterm.attachCustomKeyEventHandler(this.keyHandler); this.xterm.onSelectionChange(this.onSelectionChange); @@ -93,10 +99,10 @@ export class Terminal { }, { fireImmediately: true, }), - reaction(() => UserStore.getInstance().terminalConfig.fontSize, this.setFontSize, { + reaction(() => this.dependencies.terminalConfig.get().fontSize, this.setFontSize, { fireImmediately: true, }), - reaction(() => UserStore.getInstance().terminalConfig.fontFamily, this.setFontFamily, { + reaction(() => this.dependencies.terminalConfig.get().fontFamily, this.setFontFamily, { fireImmediately: true, }), () => onDataHandler.dispose(), @@ -173,7 +179,7 @@ export class Terminal { onContextMenu = () => { if ( // don't paste if user hasn't turned on the feature - UserStore.getInstance().terminalCopyOnSelect + this.dependencies.terminalCopyOnSelect.get() // don't paste if the clipboard doesn't have text && clipboard.availableFormats().includes("text/plain") @@ -185,7 +191,7 @@ export class Terminal { onSelectionChange = () => { const selection = this.xterm.getSelection().trim(); - if (UserStore.getInstance().terminalCopyOnSelect && selection) { + if (this.dependencies.terminalCopyOnSelect.get() && selection) { clipboard.writeText(selection); } }; diff --git a/src/renderer/components/kube-object-menu/__snapshots__/kube-object-menu.test.tsx.snap b/src/renderer/components/kube-object-menu/__snapshots__/kube-object-menu.test.tsx.snap index b0200f73d5..46f3efe6f8 100644 --- a/src/renderer/components/kube-object-menu/__snapshots__/kube-object-menu.test.tsx.snap +++ b/src/renderer/components/kube-object-menu/__snapshots__/kube-object-menu.test.tsx.snap @@ -101,9 +101,7 @@ exports[`kube-object-menu given kube object when removing kube object renders 1`

- Remove - some-kind - + Remove some-kind some-namespace/some-name @@ -198,9 +196,7 @@ exports[`kube-object-menu given kube object with namespace when removing kube ob

- Remove - some-kind - + Remove some-kind some-namespace/some-name @@ -295,9 +291,7 @@ exports[`kube-object-menu given kube object without namespace when removing kube

- Remove - some-kind - + Remove some-kind some-name diff --git a/src/renderer/components/test-utils/renderFor.tsx b/src/renderer/components/test-utils/renderFor.tsx index eb33b72b70..666158b03b 100644 --- a/src/renderer/components/test-utils/renderFor.tsx +++ b/src/renderer/components/test-utils/renderFor.tsx @@ -3,15 +3,9 @@ * Licensed under MIT License. See LICENSE in root directory for more information. */ import React from "react"; - -import type { - RenderResult } from "@testing-library/react"; -import { - render as testingLibraryRender, -} from "@testing-library/react"; - +import type { RenderResult } from "@testing-library/react"; +import { render as testingLibraryRender } from "@testing-library/react"; import type { DiContainer } from "@ogre-tools/injectable"; - import { DiContextProvider } from "@ogre-tools/injectable-react"; export type DiRender = (ui: React.ReactElement) => RenderResult; diff --git a/src/renderer/getDiForUnitTesting.tsx b/src/renderer/getDiForUnitTesting.tsx index 45c6f4b76e..2b74a4adc0 100644 --- a/src/renderer/getDiForUnitTesting.tsx +++ b/src/renderer/getDiForUnitTesting.tsx @@ -33,6 +33,7 @@ import { getAbsolutePathFake } from "../common/test-utils/get-absolute-path-fake import joinPathsInjectable from "../common/path/join-paths.injectable"; import { joinPathsFake } from "../common/test-utils/join-paths-fake"; import hotbarStoreInjectable from "../common/hotbar-store.injectable"; +import terminalSpawningPoolInjectable from "./components/dock/terminal/terminal-spawning-pool.injectable"; export const getDiForUnitTesting = ( { doGeneralOverrides } = { doGeneralOverrides: false }, @@ -57,6 +58,8 @@ export const getDiForUnitTesting = ( di.override(isWindowsInjectable, () => false); di.override(isLinuxInjectable, () => false); + di.override(terminalSpawningPoolInjectable, () => new HTMLElement()); + di.override(getAbsolutePathInjectable, () => getAbsolutePathFake); di.override(joinPathsInjectable, () => joinPathsFake);