From 3c13fef3d47b8413eb58c12b15a8739c89980773 Mon Sep 17 00:00:00 2001 From: Janne Savolainen Date: Mon, 18 Jul 2022 15:03:30 +0300 Subject: [PATCH] Provide a way to unit test usages of storages Signed-off-by: Janne Savolainen --- ...debar-and-tab-navigation-for-core.test.tsx | 20 +------------- ...and-tab-navigation-for-extensions.test.tsx | 20 +------------- src/renderer/getDiForUnitTesting.tsx | 4 +++ .../create-storage.injectable.ts | 2 ++ .../utils/create-storage/create-storage.ts | 4 ++- .../storage-save-delay.injectable.ts | 12 +++++++++ .../create-storage/storages-are-ready.ts | 26 +++++++++++++++++++ 7 files changed, 49 insertions(+), 39 deletions(-) create mode 100644 src/renderer/utils/create-storage/storage-save-delay.injectable.ts create mode 100644 src/renderer/utils/create-storage/storages-are-ready.ts diff --git a/src/behaviours/cluster/sidebar-and-tab-navigation-for-core.test.tsx b/src/behaviours/cluster/sidebar-and-tab-navigation-for-core.test.tsx index 2aec78a47a..bf650f2652 100644 --- a/src/behaviours/cluster/sidebar-and-tab-navigation-for-core.test.tsx +++ b/src/behaviours/cluster/sidebar-and-tab-navigation-for-core.test.tsx @@ -18,12 +18,10 @@ import { frontEndRouteInjectionToken } from "../../common/front-end-routing/fron import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import writeJsonFileInjectable from "../../common/fs/write-json-file.injectable"; -import pathExistsInjectable from "../../common/fs/path-exists.injectable"; import readJsonFileInjectable from "../../common/fs/read-json-file.injectable"; import { navigateToRouteInjectionToken } from "../../common/front-end-routing/navigate-to-route-injection-token"; import sidebarStorageInjectable from "../../renderer/components/layout/sidebar-storage/sidebar-storage.injectable"; import hostedClusterIdInjectable from "../../renderer/cluster-frame-context/hosted-cluster-id.injectable"; -import { advanceFakeTime, useFakeTime } from "../../common/test-utils/use-fake-time"; describe("cluster - sidebar and tab navigation for core", () => { let applicationBuilder: ApplicationBuilder; @@ -31,8 +29,6 @@ describe("cluster - sidebar and tab navigation for core", () => { let rendered: RenderResult; beforeEach(() => { - useFakeTime("2015-10-21T07:28:00Z"); - applicationBuilder = getApplicationBuilder(); rendererDi = applicationBuilder.dis.rendererDi; @@ -265,21 +261,7 @@ describe("cluster - sidebar and tab navigation for core", () => { expect(rendered.getByTestId("some-child-page")).not.toBeNull(); }); - it("when not enough time passes, does not store state for expanded sidebar items to file system yet", async () => { - advanceFakeTime(250 - 1); - - const pathExistsFake = rendererDi.inject(pathExistsInjectable); - - const actual = await pathExistsFake( - "/some-directory-for-lens-local-storage/some-hosted-cluster-id.json", - ); - - expect(actual).toBe(false); - }); - - it("when enough time passes, stores state for expanded sidebar items to file system", async () => { - advanceFakeTime(250); - + it("stores state for expanded sidebar items to file system", async () => { const readJsonFileFake = rendererDi.inject(readJsonFileInjectable); const actual = await readJsonFileFake( diff --git a/src/behaviours/cluster/sidebar-and-tab-navigation-for-extensions.test.tsx b/src/behaviours/cluster/sidebar-and-tab-navigation-for-extensions.test.tsx index ff0bc402a8..30de1a2f99 100644 --- a/src/behaviours/cluster/sidebar-and-tab-navigation-for-extensions.test.tsx +++ b/src/behaviours/cluster/sidebar-and-tab-navigation-for-extensions.test.tsx @@ -11,13 +11,11 @@ import { matches } from "lodash/fp"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import writeJsonFileInjectable from "../../common/fs/write-json-file.injectable"; -import pathExistsInjectable from "../../common/fs/path-exists.injectable"; import readJsonFileInjectable from "../../common/fs/read-json-file.injectable"; import type { DiContainer } from "@ogre-tools/injectable"; import { navigateToRouteInjectionToken } from "../../common/front-end-routing/navigate-to-route-injection-token"; import assert from "assert"; import hostedClusterIdInjectable from "../../renderer/cluster-frame-context/hosted-cluster-id.injectable"; -import { advanceFakeTime, useFakeTime } from "../../common/test-utils/use-fake-time"; import { getExtensionFakeFor } from "../../renderer/components/test-utils/get-extension-fake"; import type { IObservableValue } from "mobx"; import { runInAction, computed, observable } from "mobx"; @@ -33,8 +31,6 @@ describe("cluster - sidebar and tab navigation for extensions", () => { let rendered: RenderResult; beforeEach(() => { - useFakeTime("2015-10-21T07:28:00Z"); - applicationBuilder = getApplicationBuilder(); rendererDi = applicationBuilder.dis.rendererDi; @@ -386,21 +382,7 @@ describe("cluster - sidebar and tab navigation for extensions", () => { expect(tabLink.dataset.isActiveTest).toBe("false"); }); - it("when not enough time passes, does not store state for expanded sidebar items to file system yet", async () => { - advanceFakeTime(250 - 1); - - const pathExistsFake = rendererDi.inject(pathExistsInjectable); - - const actual = await pathExistsFake( - "/some-directory-for-lens-local-storage/some-hosted-cluster-id.json", - ); - - expect(actual).toBe(false); - }); - - it("when enough time passes, stores state for expanded sidebar items to file system", async () => { - advanceFakeTime(250); - + it("stores state for expanded sidebar items to file system", async () => { const readJsonFileFake = rendererDi.inject(readJsonFileInjectable); const actual = await readJsonFileFake( diff --git a/src/renderer/getDiForUnitTesting.tsx b/src/renderer/getDiForUnitTesting.tsx index 1aad20d7f3..dbae2a575d 100644 --- a/src/renderer/getDiForUnitTesting.tsx +++ b/src/renderer/getDiForUnitTesting.tsx @@ -72,6 +72,7 @@ import { asyncComputed } from "@ogre-tools/injectable-react"; import forceUpdateModalRootFrameComponentInjectable from "./application-update/force-update-modal/force-update-modal-root-frame-component.injectable"; import legacyOnChannelListenInjectable from "./ipc/legacy-channel-listen.injectable"; import getEntitySettingCommandsInjectable from "./components/command-palette/registered-commands/get-entity-setting-commands.injectable"; +import storageSaveDelayInjectable from "./utils/create-storage/storage-save-delay.injectable"; export const getDiForUnitTesting = (opts: { doGeneralOverrides?: boolean } = {}) => { const { @@ -111,6 +112,9 @@ export const getDiForUnitTesting = (opts: { doGeneralOverrides?: boolean } = {}) di.override(historyInjectable, () => createMemoryHistory()); di.override(legacyOnChannelListenInjectable, () => () => noop); + + di.override(storageSaveDelayInjectable, () => 0); + di.override(requestAnimationFrameInjectable, () => (callback) => callback()); di.override(lensResourcesDirInjectable, () => "/irrelevant"); diff --git a/src/renderer/utils/create-storage/create-storage.injectable.ts b/src/renderer/utils/create-storage/create-storage.injectable.ts index f0bc54cd53..b40eef738c 100644 --- a/src/renderer/utils/create-storage/create-storage.injectable.ts +++ b/src/renderer/utils/create-storage/create-storage.injectable.ts @@ -11,6 +11,7 @@ import { observable } from "mobx"; import loggerInjectable from "../../../common/logger.injectable"; import getAbsolutePathInjectable from "../../../common/path/get-absolute-path.injectable"; import hostedClusterIdInjectable from "../../cluster-frame-context/hosted-cluster-id.injectable"; +import storageSaveDelayInjectable from "./storage-save-delay.injectable"; const createStorageInjectable = getInjectable({ id: "create-storage", @@ -27,6 +28,7 @@ const createStorageInjectable = getInjectable({ directoryForLensLocalStorage: di.inject(directoryForLensLocalStorageInjectable), getAbsolutePath: di.inject(getAbsolutePathInjectable), hostedClusterId: di.inject(hostedClusterIdInjectable), + saveDelay: di.inject(storageSaveDelayInjectable), }), }); diff --git a/src/renderer/utils/create-storage/create-storage.ts b/src/renderer/utils/create-storage/create-storage.ts index 0bc3de06e4..501e425161 100755 --- a/src/renderer/utils/create-storage/create-storage.ts +++ b/src/renderer/utils/create-storage/create-storage.ts @@ -21,6 +21,7 @@ interface Dependencies { writeJsonFile: (filePath: string, contentObject: JsonObject) => Promise; getAbsolutePath: GetAbsolutePath; hostedClusterId: string | undefined; + saveDelay: number; } export type CreateStorage = (key: string, defaultValue: T) => StorageLayer; @@ -36,6 +37,7 @@ export const createStorage = ({ readJsonFile, writeJsonFile, hostedClusterId, + saveDelay, }: Dependencies): CreateStorage => (key, defaultValue) => { const { logPrefix } = StorageHelper; @@ -59,7 +61,7 @@ export const createStorage = ({ // bind auto-saving data changes to %storage-file.json reaction(() => toJS(storage.data), saveFile, { - delay: 250, // lazy, avoid excessive writes to fs + delay: saveDelay, // lazy, avoid excessive writes to fs equals: comparer.structural, // save only when something really changed }); diff --git a/src/renderer/utils/create-storage/storage-save-delay.injectable.ts b/src/renderer/utils/create-storage/storage-save-delay.injectable.ts new file mode 100644 index 0000000000..57a680befc --- /dev/null +++ b/src/renderer/utils/create-storage/storage-save-delay.injectable.ts @@ -0,0 +1,12 @@ +/** + * 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 storageSaveDelayInjectable = getInjectable({ + id: "storage-save-delay", + instantiate: () => 250, +}); + +export default storageSaveDelayInjectable; diff --git a/src/renderer/utils/create-storage/storages-are-ready.ts b/src/renderer/utils/create-storage/storages-are-ready.ts new file mode 100644 index 0000000000..641c64cf8b --- /dev/null +++ b/src/renderer/utils/create-storage/storages-are-ready.ts @@ -0,0 +1,26 @@ +/** + * Copyright (c) OpenLens Authors. All rights reserved. + * Licensed under MIT License. See LICENSE in root directory for more information. + */ +import type { DiContainer } from "@ogre-tools/injectable"; +import type { CreateStorage } from "./create-storage"; +import createStorageInjectable from "./create-storage.injectable"; + +export const controlWhenStoragesAreReady = (di: DiContainer) => { + const storagesAreReady: Promise[] = []; + + const decorated = + (toBeDecorated: CreateStorage) => + (key: string, defaultValue: any) => { + const storage = toBeDecorated(key, defaultValue); + + storagesAreReady.push(storage.whenReady); + + return storage; + }; + + // TODO: Remove when typing is added to the library + (di as any).decorateFunction(createStorageInjectable, decorated); + + return async () => void await Promise.all(storagesAreReady); +};