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

- added initial tests for dock/__test__/dock-tab.store.test.ts

- fix: make DockTabStore.init() as public/async / handle opts.autoInit == false
- fix: increased terminal-tab window spacing

Signed-off-by: Roman <ixrock@gmail.com>
This commit is contained in:
Roman 2021-10-10 17:34:27 +03:00
parent 10a7db54d0
commit 59efe2a544
8 changed files with 137 additions and 17 deletions

View File

@ -0,0 +1,115 @@
/**
* 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 { jest } from "@jest/globals";
import { observable, reaction, toJS } from "mobx";
import { StorageHelper } from "../../../utils";
import { DockTabStore } from "../dock-tab.store";
import type { TabId } from "../dock.store";
type UtilsModule = typeof import("../../../utils");
jest.mock("../../../utils", () => {
const localStorageMock = observable.map<TabId, unknown>({});
const Utils = jest.requireActual("../../../utils") as UtilsModule;
// Partial module mocking
// https://jestjs.io/docs/mock-functions#mocking-partials
return {
...Utils,
createStorage: jest.fn((key: string, defaultValue: unknown) => {
return new StorageHelper(key, {
defaultValue,
storage: {
getItem(key: TabId) {
localStorageMock.get(key);
},
setItem(key: TabId, value: unknown) {
localStorageMock.set(key, value);
},
removeItem(key: TabId) {
localStorageMock.delete(key);
},
},
});
}),
};
});
// TODO: add more tests
describe(`[DockTabStore]: dock tabs data class-helper`, () => {
test("options.autoInit = true (default)", async () => {
const tabStorage = new DockTabStore({ autoInit: true });
expect(tabStorage.initialized).toBeFalsy();
expect(tabStorage.dataReady).toBeFalsy();
await tabStorage.whenReady;
expect(tabStorage.dataReady).toBeTruthy();
expect(tabStorage.initialized).toBeTruthy();
});
test("options.autoInit = false", async () => {
const tabStorage = new DockTabStore({ autoInit: false });
await tabStorage.whenReady;
expect(tabStorage.dataReady).toBeTruthy();
expect(tabStorage.initialized).toBeFalsy();
await tabStorage.init();
expect(tabStorage.initialized).toBeTruthy();
});
test(`dockTabStore.getData(tabId) is deeply observable`, async () => {
interface TabDataStorageShape {
[key: string]: any;
account: {
name: string;
description?: string;
}
}
const tabDataHistory: TabDataStorageShape[] = [];
const randomTabId = getRandomTabId();
const tabStorage = new DockTabStore<TabDataStorageShape>();
await tabStorage.whenReady;
reaction(() => toJS(tabStorage.getData(randomTabId)),
data => tabDataHistory.push(data),
);
tabStorage.setData(randomTabId, { account: { name: "test" } });
expect(tabStorage.getData(randomTabId)).toBe(tabStorage.data[randomTabId]);
expect(tabStorage.getData(randomTabId).account.name).toBe("test");
tabStorage.data[randomTabId].account.name = "updated"; // update deep in the tree
expect(tabDataHistory.length).toBe(2);
expect(tabDataHistory[1].account.name).toBe("updated");
});
});
export function getRandomTabId(): TabId {
return `tab-id-${(Math.random() * Date.now()).toString(16)}`;
}

View File

@ -57,7 +57,7 @@ export class CreateResourceStore extends DockTabStore<string> {
return path.resolve(os.homedir(), "~/.k8slens/templates"); return path.resolve(os.homedir(), "~/.k8slens/templates");
} }
protected async init() { async init() {
super.init(); super.init();
// scan all available templates immediately // scan all available templates immediately

View File

@ -24,18 +24,21 @@ import { autoBind, createStorage, disposer, StorageHelper } from "../../utils";
import { dockStore, TabId } from "./dock.store"; import { dockStore, TabId } from "./dock.store";
export interface DockTabStoreOptions { export interface DockTabStoreOptions {
autoInit?: boolean; // load data from storage when `storageKey` is provided and bind events, default: true autoInit?: boolean; // load data from storage when `storageKey` is provided and bind events (default: true)
storageKey?: string; // save data to persistent storage under the key storageKey?: string; // save data to persistent storage under the key
} }
export class DockTabStore<T extends {}> { export type DockTabStoreShape<T> = Record<TabId, T>;
@observable.ref private storage?: StorageHelper<Record<TabId, T>>; // available only with `options.storageKey`
@observable private _data: Record<TabId, T> = {}; export class DockTabStore<T> {
@observable.ref private storage?: StorageHelper<DockTabStoreShape<T>>; // available only with `options.storageKey`
@observable private _data: DockTabStoreShape<T> = {};
@observable dataReady = false; // dock-tab's data ready to interact, e.g. start editing resource @observable dataReady = false; // dock-tab's data ready to interact, e.g. start editing resource
@observable initialized = false;
protected dispose = disposer(); protected dispose = disposer();
get data() { get data(): DockTabStoreShape<T> {
if (this.options.storageKey) { if (this.options.storageKey) {
return this.storage.get(); return this.storage.get();
} }
@ -43,7 +46,7 @@ export class DockTabStore<T extends {}> {
return this._data; return this._data;
} }
set data(value: Record<TabId, T>) { set data(value: DockTabStoreShape<T>) {
if (this.options.storageKey) { if (this.options.storageKey) {
this.storage.set(value); this.storage.set(value);
} else { } else {
@ -51,7 +54,7 @@ export class DockTabStore<T extends {}> {
} }
} }
protected constructor(protected options: DockTabStoreOptions = {}) { constructor(protected options: DockTabStoreOptions = {}) {
makeObservable(this); // must be called *before* autoBind() when used with mobx's method decorators makeObservable(this); // must be called *before* autoBind() when used with mobx's method decorators
autoBind(this); autoBind(this);
@ -74,12 +77,13 @@ export class DockTabStore<T extends {}> {
return Promise.all([ return Promise.all([
dockStore.whenReady, dockStore.whenReady,
this.storage?.whenReady, this.storage?.whenReady,
]); ]).then(() => this.dataReady = true);
} }
@action @action
protected init() { async init(): Promise<any> {
this.dataReady = true; if (this.initialized) return;
this.initialized = true;
this.dispose.push( this.dispose.push(
dockStore.onTabClose(({ tabId }) => this.clearData(tabId)), dockStore.onTabClose(({ tabId }) => this.clearData(tabId)),
@ -102,8 +106,9 @@ export class DockTabStore<T extends {}> {
@action @action
reset() { reset() {
this.data = {}; this.data = {}; // clears json-file storage when initialized with `opts.storageKey`
this.dataReady = false; this.dataReady = false;
this.initialized = false;
} }
@action @action

View File

@ -40,7 +40,7 @@ export class EditResourceStore extends DockTabStore<EditingResource> {
autoBind(this); autoBind(this);
} }
protected init() { async init() {
super.init(); super.init();
this.dispose.push( this.dispose.push(

View File

@ -45,7 +45,7 @@ export class InstallChartStore extends DockTabStore<IChartInstallData> {
makeObservable(this); makeObservable(this);
} }
protected init() { async init() {
super.init(); super.init();
this.dispose.push( this.dispose.push(

View File

@ -59,7 +59,7 @@ export class LogTabStore extends DockTabStore<LogTabData> {
]); ]);
} }
protected init() { async init() {
super.init(); super.init();
this.dispose.push( this.dispose.push(

View File

@ -25,5 +25,5 @@
flex: 1; flex: 1;
height: 100%; height: 100%;
overflow: hidden; overflow: hidden;
margin: 10px; margin: $padding*2 $padding $padding $padding*2;
} }

View File

@ -41,7 +41,7 @@ export class UpgradeChartStore extends DockTabStore<IChartUpgradeData> {
makeObservable(this); makeObservable(this);
} }
protected async init() { async init() {
super.init(); super.init();
await releaseStore.loadFromContextNamespaces(); await releaseStore.loadFromContextNamespaces();