diff --git a/src/extensions/__tests__/extension-loader.test.ts b/src/extensions/__tests__/extension-loader.test.ts index 44f80741c0..c0b233ca4b 100644 --- a/src/extensions/__tests__/extension-loader.test.ts +++ b/src/extensions/__tests__/extension-loader.test.ts @@ -20,16 +20,14 @@ */ import type { ExtensionLoader } from "../extension-loader"; -import { ipcRenderer } from "electron"; -import type { - ExtensionsStore, -} from "../extensions-store/extensions-store"; import { Console } from "console"; import { stdout, stderr } from "process"; import { getDiForUnitTesting } from "../getDiForUnitTesting"; import extensionLoaderInjectable from "../extension-loader/extension-loader.injectable"; -import extensionsStoreInjectable from "../extensions-store/extensions-store.injectable"; import { AppPaths } from "../../common/app-paths"; +import { runInAction } from "mobx"; +import updateExtensionsStateInjectable + from "../extension-loader/update-extensions-state/update-extensions-state.injectable"; console = new Console(stdout, stderr); @@ -124,28 +122,24 @@ jest.mock( }, ); +// TODO: Remove explicit global initialization at unclear time window AppPaths.init(); describe("ExtensionLoader", () => { let extensionLoader: ExtensionLoader; - let extensionsStoreStub: ExtensionsStore; - + let updateExtensionStateMock: jest.Mock; + beforeEach(() => { const di = getDiForUnitTesting(); + updateExtensionStateMock = jest.fn(); + + di.override(updateExtensionsStateInjectable, () => updateExtensionStateMock); + extensionLoader = di.inject(extensionLoaderInjectable); - - // TODO: Find out how to either easily create mocks of interfaces with a lot of members or - // introduce design for more minimal interfaces - // @ts-ignore - extensionsStoreStub = { - mergeState: jest.fn(), - }; - - di.override(extensionsStoreInjectable, () => extensionsStoreStub); }); - it.only("renderer updates extension after ipc broadcast", async done => { + it("renderer updates extension after ipc broadcast", async done => { expect(extensionLoader.userExtensions).toMatchInlineSnapshot(`Map {}`); await extensionLoader.init(); @@ -184,26 +178,26 @@ describe("ExtensionLoader", () => { }); it("updates ExtensionsStore after isEnabled is changed", async () => { - (extensionsStoreStub.mergeState as any).mockClear(); - - // Disable sending events in this test - (ipcRenderer.on as any).mockImplementation(); - await extensionLoader.init(); - expect(extensionsStoreStub.mergeState).not.toHaveBeenCalled(); + expect(updateExtensionStateMock).not.toHaveBeenCalled(); - Array.from(extensionLoader.userExtensions.values())[0].isEnabled = false; - - expect(extensionsStoreStub.mergeState).toHaveBeenCalledWith({ - "manifest/path": { - enabled: false, - name: "TestExtension", - }, - "manifest/path2": { - enabled: true, - name: "TestExtension2", - }, + runInAction(() => { + extensionLoader.setIsEnabled("manifest/path", false); }); + + expect(updateExtensionStateMock).toHaveBeenCalledWith( + expect.objectContaining({ + "manifest/path": { + enabled: false, + name: "TestExtension", + }, + + "manifest/path2": { + enabled: true, + name: "TestExtension2", + }, + }), + ); }); }); diff --git a/src/extensions/extension-loader/extension-loader.injectable.ts b/src/extensions/extension-loader/extension-loader.injectable.ts index 647ccd01e1..66f613f8e0 100644 --- a/src/extensions/extension-loader/extension-loader.injectable.ts +++ b/src/extensions/extension-loader/extension-loader.injectable.ts @@ -18,15 +18,15 @@ * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ -import { getInjectable } from "@ogre-tools/injectable"; -import { lifecycleEnum } from "@ogre-tools/injectable"; +import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable"; import { ExtensionLoader } from "./extension-loader"; -import extensionsStoreInjectable from "../extensions-store/extensions-store.injectable"; +import updateExtensionsStateInjectable from "./update-extensions-state/update-extensions-state.injectable"; const extensionLoaderInjectable = getInjectable({ - instantiate: (di) => new ExtensionLoader({ - extensionsStore: di.inject(extensionsStoreInjectable), - }), + instantiate: (di) => + new ExtensionLoader({ + updateExtensionsState: di.inject(updateExtensionsStateInjectable), + }), lifecycle: lifecycleEnum.singleton, }); diff --git a/src/extensions/extension-loader/extension-loader.ts b/src/extensions/extension-loader/extension-loader.ts index 072f873927..bee23ccd0e 100644 --- a/src/extensions/extension-loader/extension-loader.ts +++ b/src/extensions/extension-loader/extension-loader.ts @@ -30,10 +30,10 @@ import { Disposer, toJS } from "../../common/utils"; import logger from "../../main/logger"; import type { KubernetesCluster } from "../common-api/catalog"; import type { InstalledExtension } from "../extension-discovery/extension-discovery"; -import type { ExtensionsStore } from "../extensions-store/extensions-store"; import type { LensExtension, LensExtensionConstructor, LensExtensionId } from "../lens-extension"; import type { LensRendererExtension } from "../lens-renderer-extension"; import * as registries from "../registries"; +import type { LensExtensionState } from "../extensions-store/extensions-store"; export function extensionPackagesRoot() { return path.join(AppPaths.get("userData")); @@ -42,7 +42,7 @@ export function extensionPackagesRoot() { const logModule = "[EXTENSIONS-LOADER]"; interface Dependencies { - extensionsStore: ExtensionsStore + updateExtensionsState: (extensionsState: Record) => void } /** @@ -158,10 +158,13 @@ export class ExtensionLoader { fireImmediately: true, }); - // save state on change `extension.isEnabled` - reaction(() => this.storeState, extensionsState => { - this.dependencies.extensionsStore.mergeState(extensionsState); - }); + reaction( + () => this.storeState, + + (state) => { + this.dependencies.updateExtensionsState(state); + }, + ); } initExtensions(extensions?: Map) { diff --git a/src/extensions/extension-loader/update-extensions-state/update-extensions-state.injectable.ts b/src/extensions/extension-loader/update-extensions-state/update-extensions-state.injectable.ts new file mode 100644 index 0000000000..dbc62520cd --- /dev/null +++ b/src/extensions/extension-loader/update-extensions-state/update-extensions-state.injectable.ts @@ -0,0 +1,29 @@ +/** + * Copyright (c) 2021 OpenLens Authors + * + * Permission is hereby granted, free of charge, to any person obtaining a copy of + * this software and associated documentation files (the "Software"), to deal in + * the Software without restriction, including without limitation the rights to + * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of + * the Software, and to permit persons to whom the Software is furnished to do so, + * subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS + * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR + * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER + * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN + * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + */ +import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable"; +import extensionsStoreInjectable from "../../extensions-store/extensions-store.injectable"; + +const updateExtensionsStateInjectable = getInjectable({ + instantiate: (di) => di.inject(extensionsStoreInjectable).mergeState, + lifecycle: lifecycleEnum.singleton, +}); + +export default updateExtensionsStateInjectable;