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

Replace static application window with ability to create many (#5979)

* Replace static application window with ability to create as many as you wish

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Adapt tests for replacing static application window with ability to create as many as you wish and separate starting of main and window in behaviours

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Make first render of application smaller in test that proves to be hard for CI

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Remove redundant code

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

* Simplify code

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
Janne Savolainen 2022-08-16 15:55:42 +03:00 committed by GitHub
parent 299922c8a7
commit 63d5a34379
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
98 changed files with 3283 additions and 2743 deletions

View File

@ -14,15 +14,10 @@ import { getApplicationBuilder } from "../../renderer/components/test-utils/get-
import type { DiContainer } from "@ogre-tools/injectable"; import type { DiContainer } from "@ogre-tools/injectable";
describe("app-paths", () => { describe("app-paths", () => {
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
let rendererDi: DiContainer;
let mainDi: DiContainer;
beforeEach(() => { beforeEach(() => {
applicationBuilder = getApplicationBuilder(); builder = getApplicationBuilder();
rendererDi = applicationBuilder.dis.rendererDi;
mainDi = applicationBuilder.dis.mainDi;
const defaultAppPathsStub: AppPaths = { const defaultAppPathsStub: AppPaths = {
appData: "some-app-data", appData: "some-app-data",
@ -43,7 +38,7 @@ describe("app-paths", () => {
userData: "some-irrelevant-user-data", userData: "some-irrelevant-user-data",
}; };
applicationBuilder.beforeApplicationStart(({ mainDi }) => { builder.beforeApplicationStart((mainDi) => {
mainDi.override( mainDi.override(
getElectronAppPathInjectable, getElectronAppPathInjectable,
() => () =>
@ -64,12 +59,18 @@ describe("app-paths", () => {
}); });
describe("normally", () => { describe("normally", () => {
let windowDi: DiContainer;
let mainDi: DiContainer;
beforeEach(async () => { beforeEach(async () => {
await applicationBuilder.render(); await builder.render();
windowDi = builder.applicationWindow.only.di;
mainDi = builder.mainDi;
}); });
it("given in renderer, when injecting app paths, returns application specific app paths", () => { it("given in renderer, when injecting app paths, returns application specific app paths", () => {
const actual = rendererDi.inject(appPathsInjectionToken); const actual = windowDi.inject(appPathsInjectionToken);
expect(actual).toEqual({ expect(actual).toEqual({
appData: "some-app-data", appData: "some-app-data",
@ -116,19 +117,23 @@ describe("app-paths", () => {
}); });
describe("when running integration tests", () => { describe("when running integration tests", () => {
let windowDi: DiContainer;
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.beforeApplicationStart(({ mainDi }) => { builder.beforeApplicationStart((mainDi) => {
mainDi.override( mainDi.override(
directoryForIntegrationTestingInjectable, directoryForIntegrationTestingInjectable,
() => "some-integration-testing-app-data", () => "some-integration-testing-app-data",
); );
}); });
await applicationBuilder.render(); await builder.render();
windowDi = builder.applicationWindow.only.di;
}); });
it("given in renderer, when injecting path for app data, has integration specific app data path", () => { it("given in renderer, when injecting path for app data, has integration specific app data path", () => {
const { appData, userData } = rendererDi.inject(appPathsInjectionToken); const { appData, userData } = windowDi.inject(appPathsInjectionToken);
expect({ appData, userData }).toEqual({ expect({ appData, userData }).toEqual({
appData: "some-integration-testing-app-data", appData: "some-integration-testing-app-data",
@ -137,7 +142,7 @@ describe("app-paths", () => {
}); });
it("given in main, when injecting path for app data, has integration specific app data path", () => { it("given in main, when injecting path for app data, has integration specific app data path", () => {
const { appData, userData } = rendererDi.inject(appPathsInjectionToken); const { appData, userData } = windowDi.inject(appPathsInjectionToken);
expect({ appData, userData }).toEqual({ expect({ appData, userData }).toEqual({
appData: "some-integration-testing-app-data", appData: "some-integration-testing-app-data",

View File

@ -0,0 +1,17 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getGlobalOverride } from "../test-utils/get-global-override";
import clusterStoreInjectable from "./cluster-store.injectable";
import type { Cluster } from "../cluster/cluster";
import type { ClusterStore } from "./cluster-store";
export default getGlobalOverride(
clusterStoreInjectable,
() =>
({
provideInitialFromMain: () => {},
getById: (id) => (void id, {}) as Cluster,
} as ClusterStore),
);

View File

@ -4,13 +4,11 @@
*/ */
import type { DiContainer } from "@ogre-tools/injectable"; import type { DiContainer } from "@ogre-tools/injectable";
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import type { LensWindow } from "../../../main/start-main-application/lens-window/application-window/lens-window-injection-token";
import { lensWindowInjectionToken } from "../../../main/start-main-application/lens-window/application-window/lens-window-injection-token";
import type { MessageToChannel } from "./message-to-channel-injection-token"; import type { MessageToChannel } from "./message-to-channel-injection-token";
import { messageToChannelInjectionToken } from "./message-to-channel-injection-token"; import { messageToChannelInjectionToken } from "./message-to-channel-injection-token";
import type { ApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
import createLensWindowInjectable from "../../../main/start-main-application/lens-window/application-window/create-lens-window.injectable"; import type { LensWindow } from "../../../main/start-main-application/lens-window/application-window/create-lens-window.injectable";
import closeAllWindowsInjectable from "../../../main/start-main-application/lens-window/hide-all-windows/close-all-windows.injectable";
import { messageChannelListenerInjectionToken } from "./message-channel-listener-injection-token"; import { messageChannelListenerInjectionToken } from "./message-channel-listener-injection-token";
import type { MessageChannel } from "./message-channel-injection-token"; import type { MessageChannel } from "./message-channel-injection-token";
import type { RequestFromChannel } from "./request-from-channel-injection-token"; import type { RequestFromChannel } from "./request-from-channel-injection-token";
@ -30,12 +28,10 @@ describe("channel", () => {
let messageListenerInWindowMock: jest.Mock; let messageListenerInWindowMock: jest.Mock;
let mainDi: DiContainer; let mainDi: DiContainer;
let messageToChannel: MessageToChannel; let messageToChannel: MessageToChannel;
let builder: ApplicationBuilder;
beforeEach(async () => { beforeEach(async () => {
const applicationBuilder = getApplicationBuilder(); builder = getApplicationBuilder();
mainDi = applicationBuilder.dis.mainDi;
const rendererDi = applicationBuilder.dis.rendererDi;
messageListenerInWindowMock = jest.fn(); messageListenerInWindowMock = jest.fn();
@ -44,37 +40,34 @@ describe("channel", () => {
instantiate: (di) => ({ instantiate: (di) => ({
channel: di.inject(testMessageChannelInjectable), channel: di.inject(testMessageChannelInjectable),
handler: messageListenerInWindowMock, handler: messageListenerInWindowMock,
}), }),
injectionToken: messageChannelListenerInjectionToken, injectionToken: messageChannelListenerInjectionToken,
}); });
rendererDi.register(testChannelListenerInTestWindowInjectable); builder.beforeApplicationStart((mainDi) => {
mainDi.register(testMessageChannelInjectable);
});
// Notice how test channel has presence in both DIs, being from common builder.beforeWindowStart((windowDi) => {
mainDi.register(testMessageChannelInjectable); windowDi.register(testChannelListenerInTestWindowInjectable);
rendererDi.register(testMessageChannelInjectable); windowDi.register(testMessageChannelInjectable);
});
mainDi = builder.mainDi;
await builder.startHidden();
testMessageChannel = mainDi.inject(testMessageChannelInjectable); testMessageChannel = mainDi.inject(testMessageChannelInjectable);
messageToChannel = mainDi.inject(messageToChannelInjectionToken);
messageToChannel = mainDi.inject(
messageToChannelInjectionToken,
);
await applicationBuilder.render();
const closeAllWindows = mainDi.inject(closeAllWindowsInjectable);
closeAllWindows();
}); });
describe("given window is started", () => { describe("given window is started", () => {
let someWindowFake: LensWindow; let someWindowFake: LensWindow;
beforeEach(async () => { beforeEach(async () => {
someWindowFake = createTestWindow(mainDi, "some-window"); someWindowFake = builder.applicationWindow.create("some-window");
await someWindowFake.start(); await someWindowFake.start();
}); });
@ -95,8 +88,8 @@ describe("channel", () => {
}); });
it("given multiple started windows, when sending message, triggers listeners in all windows", async () => { it("given multiple started windows, when sending message, triggers listeners in all windows", async () => {
const someWindowFake = createTestWindow(mainDi, "some-window"); const someWindowFake = builder.applicationWindow.create("some-window");
const someOtherWindowFake = createTestWindow(mainDi, "some-other-window"); const someOtherWindowFake = builder.applicationWindow.create("some-other-window");
await someWindowFake.start(); await someWindowFake.start();
await someOtherWindowFake.start(); await someOtherWindowFake.start();
@ -113,16 +106,11 @@ describe("channel", () => {
describe("messaging from renderer to main, given listener for channel in a main and application has started", () => { describe("messaging from renderer to main, given listener for channel in a main and application has started", () => {
let testMessageChannel: TestMessageChannel; let testMessageChannel: TestMessageChannel;
let messageListenerInMainMock: jest.Mock; let messageListenerInMainMock: jest.Mock;
let rendererDi: DiContainer;
let mainDi: DiContainer;
let messageToChannel: MessageToChannel; let messageToChannel: MessageToChannel;
beforeEach(async () => { beforeEach(async () => {
const applicationBuilder = getApplicationBuilder(); const applicationBuilder = getApplicationBuilder();
mainDi = applicationBuilder.dis.mainDi;
rendererDi = applicationBuilder.dis.rendererDi;
messageListenerInMainMock = jest.fn(); messageListenerInMainMock = jest.fn();
const testChannelListenerInMainInjectable = getInjectable({ const testChannelListenerInMainInjectable = getInjectable({
@ -137,19 +125,21 @@ describe("channel", () => {
injectionToken: messageChannelListenerInjectionToken, injectionToken: messageChannelListenerInjectionToken,
}); });
mainDi.register(testChannelListenerInMainInjectable); applicationBuilder.beforeApplicationStart((mainDi) => {
mainDi.register(testChannelListenerInMainInjectable);
mainDi.register(testMessageChannelInjectable);
});
// Notice how test channel has presence in both DIs, being from common applicationBuilder.beforeWindowStart((windowDi) => {
mainDi.register(testMessageChannelInjectable); windowDi.register(testMessageChannelInjectable);
rendererDi.register(testMessageChannelInjectable); });
testMessageChannel = rendererDi.inject(testMessageChannelInjectable);
messageToChannel = rendererDi.inject(
messageToChannelInjectionToken,
);
await applicationBuilder.render(); await applicationBuilder.render();
const windowDi = applicationBuilder.applicationWindow.only.di;
testMessageChannel = windowDi.inject(testMessageChannelInjectable);
messageToChannel = windowDi.inject(messageToChannelInjectionToken);
}); });
it("when sending message, triggers listener in main", () => { it("when sending message, triggers listener in main", () => {
@ -162,16 +152,11 @@ describe("channel", () => {
describe("requesting from main in renderer, given listener for channel in a main and application has started", () => { describe("requesting from main in renderer, given listener for channel in a main and application has started", () => {
let testRequestChannel: TestRequestChannel; let testRequestChannel: TestRequestChannel;
let requestListenerInMainMock: AsyncFnMock<(arg: string) => string>; let requestListenerInMainMock: AsyncFnMock<(arg: string) => string>;
let rendererDi: DiContainer;
let mainDi: DiContainer;
let requestFromChannel: RequestFromChannel; let requestFromChannel: RequestFromChannel;
beforeEach(async () => { beforeEach(async () => {
const applicationBuilder = getApplicationBuilder(); const applicationBuilder = getApplicationBuilder();
mainDi = applicationBuilder.dis.mainDi;
rendererDi = applicationBuilder.dis.rendererDi;
requestListenerInMainMock = asyncFn(); requestListenerInMainMock = asyncFn();
const testChannelListenerInMainInjectable = getInjectable({ const testChannelListenerInMainInjectable = getInjectable({
@ -186,19 +171,24 @@ describe("channel", () => {
injectionToken: requestChannelListenerInjectionToken, injectionToken: requestChannelListenerInjectionToken,
}); });
mainDi.register(testChannelListenerInMainInjectable); applicationBuilder.beforeApplicationStart((mainDi) => {
mainDi.register(testChannelListenerInMainInjectable);
mainDi.register(testRequestChannelInjectable);
});
// Notice how test channel has presence in both DIs, being from common applicationBuilder.beforeWindowStart((windowDi) => {
mainDi.register(testRequestChannelInjectable); windowDi.register(testRequestChannelInjectable);
rendererDi.register(testRequestChannelInjectable); });
testRequestChannel = rendererDi.inject(testRequestChannelInjectable);
requestFromChannel = rendererDi.inject(
requestFromChannelInjectionToken,
);
await applicationBuilder.render(); await applicationBuilder.render();
const windowDi = applicationBuilder.applicationWindow.only.di;
testRequestChannel = windowDi.inject(testRequestChannelInjectable);
requestFromChannel = windowDi.inject(
requestFromChannelInjectionToken,
);
}); });
describe("when requesting from channel", () => { describe("when requesting from channel", () => {
@ -245,29 +235,3 @@ const testRequestChannelInjectable = getInjectable({
}), }),
}); });
const createTestWindow = (di: DiContainer, id: string) => {
const testWindowInjectable = getInjectable({
id,
instantiate: (di) => {
const createLensWindow = di.inject(createLensWindowInjectable);
return createLensWindow({
id,
title: "Some test window",
defaultHeight: 42,
defaultWidth: 42,
getContentSource: () => ({ url: "some-content-url" }),
resizable: true,
windowFrameUtilitiesAreShown: false,
centered: false,
});
},
injectionToken: lensWindowInjectionToken,
});
di.register(testWindowInjectable);
return di.inject(testWindowInjectable);
};

View File

@ -2,13 +2,14 @@
* Copyright (c) OpenLens Authors. All rights reserved. * Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import type { DiContainer } from "@ogre-tools/injectable";
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { observe, runInAction } from "mobx"; import { observe, runInAction } from "mobx";
import type { ApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
import createSyncBoxInjectable from "./create-sync-box.injectable"; import createSyncBoxInjectable from "./create-sync-box.injectable";
import { flushPromises } from "../../test-utils/flush-promises";
import type { SyncBox } from "./sync-box-injection-token"; import type { SyncBox } from "./sync-box-injection-token";
import { syncBoxInjectionToken } from "./sync-box-injection-token";
describe("sync-box", () => { describe("sync-box", () => {
let applicationBuilder: ApplicationBuilder; let applicationBuilder: ApplicationBuilder;
@ -16,19 +17,23 @@ describe("sync-box", () => {
beforeEach(() => { beforeEach(() => {
applicationBuilder = getApplicationBuilder(); applicationBuilder = getApplicationBuilder();
applicationBuilder.dis.mainDi.register(someInjectable); applicationBuilder.beforeApplicationStart(mainDi => {
applicationBuilder.dis.rendererDi.register(someInjectable); mainDi.register(someInjectable);
});
applicationBuilder.beforeWindowStart((windowDi) => {
windowDi.register(someInjectable);
});
}); });
// TODO: Separate starting for main application and starting of window in application builder describe("given application is started, when value is set in main", () => {
xdescribe("given application is started, when value is set in main", () => {
let valueInMain: string; let valueInMain: string;
let syncBoxInMain: SyncBox<string>; let syncBoxInMain: SyncBox<string>;
beforeEach(async () => { beforeEach(async () => {
syncBoxInMain = applicationBuilder.dis.mainDi.inject(someInjectable); await applicationBuilder.startHidden();
// await applicationBuilder.start(); syncBoxInMain = applicationBuilder.mainDi.inject(someInjectable);
observe(syncBoxInMain.value, ({ newValue }) => { observe(syncBoxInMain.value, ({ newValue }) => {
valueInMain = newValue as string; valueInMain = newValue as string;
@ -46,48 +51,28 @@ describe("sync-box", () => {
describe("when window starts", () => { describe("when window starts", () => {
let valueInRenderer: string; let valueInRenderer: string;
let syncBoxInRenderer: SyncBox<string>; let syncBoxInRenderer: SyncBox<string>;
let rendererDi: DiContainer;
beforeEach(() => { beforeEach(async () => {
// applicationBuilder.renderWindow() const applicationWindow =
applicationBuilder.applicationWindow.create("some-window-id");
syncBoxInRenderer = applicationBuilder.dis.rendererDi.inject(someInjectable); await applicationWindow.start();
rendererDi = applicationWindow.di;
syncBoxInRenderer = rendererDi.inject(someInjectable);
observe(syncBoxInRenderer.value, ({ newValue }) => { observe(syncBoxInRenderer.value, ({ newValue }) => {
valueInRenderer = newValue as string; valueInRenderer = newValue as string;
}, true); }, true);
}); });
it("does not have the initial value yet", () => { it("has the value from main", () => {
expect(valueInRenderer).toBe(undefined); expect(valueInRenderer).toBe("some-value-from-main");
}); });
describe("when getting initial value resolves", () => { describe("when value is set from renderer", () => {
beforeEach(async () => {
await flushPromises();
});
it("has value in renderer", () => {
expect(valueInRenderer).toBe("some-value-from-main");
});
describe("when value is set from renderer", () => {
beforeEach(() => {
runInAction(() => {
syncBoxInRenderer.set("some-value-from-renderer");
});
});
it("has value in main", () => {
expect(valueInMain).toBe("some-value-from-renderer");
});
it("has value in renderer", () => {
expect(valueInRenderer).toBe("some-value-from-renderer");
});
});
});
describe("when value is set from renderer before getting initial value from main resolves", () => {
beforeEach(() => { beforeEach(() => {
runInAction(() => { runInAction(() => {
syncBoxInRenderer.set("some-value-from-renderer"); syncBoxInRenderer.set("some-value-from-renderer");
@ -112,11 +97,13 @@ describe("sync-box", () => {
let syncBoxInRenderer: SyncBox<string>; let syncBoxInRenderer: SyncBox<string>;
beforeEach(async () => { beforeEach(async () => {
syncBoxInMain = applicationBuilder.dis.mainDi.inject(someInjectable);
syncBoxInRenderer = applicationBuilder.dis.rendererDi.inject(someInjectable);
await applicationBuilder.render(); await applicationBuilder.render();
const applicationWindow = applicationBuilder.applicationWindow.only;
syncBoxInMain = applicationBuilder.mainDi.inject(someInjectable);
syncBoxInRenderer = applicationWindow.di.inject(someInjectable);
observe(syncBoxInRenderer.value, ({ newValue }) => { observe(syncBoxInRenderer.value, ({ newValue }) => {
valueInRenderer = newValue as string; valueInRenderer = newValue as string;
}, true); }, true);
@ -176,4 +163,6 @@ const someInjectable = getInjectable({
return createSyncBox("some-sync-box", "some-initial-value"); return createSyncBox("some-sync-box", "some-initial-value");
}, },
injectionToken: syncBoxInjectionToken,
}); });

View File

@ -21,7 +21,7 @@ import periodicalCheckForUpdatesInjectable from "../../main/application-update/p
import { advanceFakeTime, useFakeTime } from "../../common/test-utils/use-fake-time"; import { advanceFakeTime, useFakeTime } from "../../common/test-utils/use-fake-time";
describe("analytics for installing update", () => { describe("analytics for installing update", () => {
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
let checkForPlatformUpdatesMock: AsyncFnMock<CheckForPlatformUpdates>; let checkForPlatformUpdatesMock: AsyncFnMock<CheckForPlatformUpdates>;
let downloadPlatformUpdateMock: AsyncFnMock<DownloadPlatformUpdate>; let downloadPlatformUpdateMock: AsyncFnMock<DownloadPlatformUpdate>;
let analyticsListenerMock: jest.Mock; let analyticsListenerMock: jest.Mock;
@ -30,11 +30,11 @@ describe("analytics for installing update", () => {
beforeEach(async () => { beforeEach(async () => {
useFakeTime("2015-10-21T07:28:00Z"); useFakeTime("2015-10-21T07:28:00Z");
applicationBuilder = getApplicationBuilder(); builder = getApplicationBuilder();
analyticsListenerMock = jest.fn(); analyticsListenerMock = jest.fn();
applicationBuilder.beforeApplicationStart(({ mainDi }) => { builder.beforeApplicationStart(mainDi => {
mainDi.override(appVersionInjectable, () => "42.0.0"); mainDi.override(appVersionInjectable, () => "42.0.0");
checkForPlatformUpdatesMock = asyncFn(); checkForPlatformUpdatesMock = asyncFn();
@ -56,7 +56,7 @@ describe("analytics for installing update", () => {
eventBus.addListener(analyticsListenerMock); eventBus.addListener(analyticsListenerMock);
}); });
mainDi = applicationBuilder.dis.mainDi; mainDi = builder.mainDi;
}); });
describe("given application is started and checking updates periodically", () => { describe("given application is started and checking updates periodically", () => {
@ -64,7 +64,7 @@ describe("analytics for installing update", () => {
mainDi.unoverride(periodicalCheckForUpdatesInjectable); mainDi.unoverride(periodicalCheckForUpdatesInjectable);
mainDi.permitSideEffects(periodicalCheckForUpdatesInjectable); mainDi.permitSideEffects(periodicalCheckForUpdatesInjectable);
await applicationBuilder.render(); await builder.render();
}); });
@ -101,7 +101,7 @@ describe("analytics for installing update", () => {
beforeEach(async () => { beforeEach(async () => {
analyticsListenerMock.mockClear(); analyticsListenerMock.mockClear();
await applicationBuilder.render(); await builder.render();
}); });
it("sends event to analytics about the current version", () => { it("sends event to analytics about the current version", () => {
@ -119,7 +119,7 @@ describe("analytics for installing update", () => {
it("when checking for updates using tray, sends event to analytics for being checked from tray", async () => { it("when checking for updates using tray, sends event to analytics for being checked from tray", async () => {
analyticsListenerMock.mockClear(); analyticsListenerMock.mockClear();
applicationBuilder.tray.click("check-for-updates"); builder.tray.click("check-for-updates");
expect(analyticsListenerMock.mock.calls).toEqual([ expect(analyticsListenerMock.mock.calls).toEqual([
[ [
@ -140,7 +140,7 @@ describe("analytics for installing update", () => {
it("when checking for updates using application menu, sends event to analytics for being checked from application menu", async () => { it("when checking for updates using application menu, sends event to analytics for being checked from application menu", async () => {
analyticsListenerMock.mockClear(); analyticsListenerMock.mockClear();
applicationBuilder.applicationMenu.click("root.check-for-updates"); builder.applicationMenu.click("root.check-for-updates");
expect(analyticsListenerMock.mock.calls).toEqual([ expect(analyticsListenerMock.mock.calls).toEqual([
[ [

View File

@ -24,7 +24,7 @@ describe("downgrading version update", () => {
beforeEach(() => { beforeEach(() => {
applicationBuilder = getApplicationBuilder(); applicationBuilder = getApplicationBuilder();
applicationBuilder.beforeApplicationStart(({ mainDi }) => { applicationBuilder.beforeApplicationStart(mainDi => {
checkForPlatformUpdatesMock = asyncFn(); checkForPlatformUpdatesMock = asyncFn();
mainDi.override( mainDi.override(
@ -36,7 +36,7 @@ describe("downgrading version update", () => {
mainDi.override(publishIsConfiguredInjectable, () => true); mainDi.override(publishIsConfiguredInjectable, () => true);
}); });
mainDi = applicationBuilder.dis.mainDi; mainDi = applicationBuilder.mainDi;
}); });
[ [

View File

@ -35,10 +35,7 @@ describe("force user to update when too long since update was downloaded", () =>
applicationBuilder = getApplicationBuilder(); applicationBuilder = getApplicationBuilder();
applicationBuilder.beforeApplicationStart(({ mainDi, rendererDi }) => { applicationBuilder.beforeApplicationStart(mainDi => {
rendererDi.unoverride(forceUpdateModalRootFrameComponentInjectable);
rendererDi.permitSideEffects(forceUpdateModalRootFrameComponentInjectable);
checkForPlatformUpdatesMock = asyncFn(); checkForPlatformUpdatesMock = asyncFn();
mainDi.override(checkForPlatformUpdatesInjectable, () => checkForPlatformUpdatesMock); mainDi.override(checkForPlatformUpdatesInjectable, () => checkForPlatformUpdatesMock);
@ -50,13 +47,17 @@ describe("force user to update when too long since update was downloaded", () =>
quitAndInstallUpdateMock = jest.fn(); quitAndInstallUpdateMock = jest.fn();
mainDi.override(quitAndInstallUpdateInjectable, () => quitAndInstallUpdateMock); mainDi.override(quitAndInstallUpdateInjectable, () => quitAndInstallUpdateMock);
rendererDi.override(timeAfterUpdateMustBeInstalledInjectable, () => TIME_AFTER_UPDATE_MUST_BE_INSTALLED);
rendererDi.override(secondsAfterInstallStartsInjectable, () => TIME_AFTER_INSTALL_STARTS / 1000);
}); });
mainDi = applicationBuilder.dis.mainDi; applicationBuilder.beforeWindowStart(windowDi => {
windowDi.unoverride(forceUpdateModalRootFrameComponentInjectable);
windowDi.permitSideEffects(forceUpdateModalRootFrameComponentInjectable);
windowDi.override(timeAfterUpdateMustBeInstalledInjectable, () => TIME_AFTER_UPDATE_MUST_BE_INSTALLED);
windowDi.override(secondsAfterInstallStartsInjectable, () => TIME_AFTER_INSTALL_STARTS / 1000);
});
mainDi = applicationBuilder.mainDi;
}); });
describe("when application is started", () => { describe("when application is started", () => {

View File

@ -33,7 +33,7 @@ describe("encourage user to update when sufficient time passed since update was
applicationBuilder = getApplicationBuilder(); applicationBuilder = getApplicationBuilder();
applicationBuilder.beforeApplicationStart(({ mainDi }) => { applicationBuilder.beforeApplicationStart((mainDi) => {
checkForPlatformUpdatesMock = asyncFn(); checkForPlatformUpdatesMock = asyncFn();
downloadPlatformUpdateMock = asyncFn(); downloadPlatformUpdateMock = asyncFn();
@ -76,7 +76,7 @@ describe("encourage user to update when sufficient time passed since update was
let processCheckingForUpdates: (source: string) => Promise<{ updateIsReadyToBeInstalled: boolean }>; let processCheckingForUpdates: (source: string) => Promise<{ updateIsReadyToBeInstalled: boolean }>;
beforeEach(async () => { beforeEach(async () => {
processCheckingForUpdates = applicationBuilder.dis.mainDi.inject( processCheckingForUpdates = applicationBuilder.mainDi.inject(
processCheckingForUpdatesInjectable, processCheckingForUpdatesInjectable,
); );
@ -105,8 +105,15 @@ describe("encourage user to update when sufficient time passed since update was
expect(button).toHaveAttribute("data-warning-level", "light"); expect(button).toHaveAttribute("data-warning-level", "light");
}); });
// TODO: Implement after starting main and renderer is separated in ApplicationBuilder it("given closing the application window, when starting the application window again, still shows the button", async () => {
xit("given closing the application window, when starting the application window again, still shows the button", () => { applicationBuilder.applicationWindow.closeAll();
const window = applicationBuilder.applicationWindow.create("some-window-id");
await window.start();
const button = window.rendered.queryByTestId("update-button");
expect(button).toBeInTheDocument(); expect(button).toBeInTheDocument();
}); });

View File

@ -13,19 +13,18 @@ import type { AsyncFnMock } from "@async-fn/jest";
import asyncFn from "@async-fn/jest"; import asyncFn from "@async-fn/jest";
import type { DownloadPlatformUpdate } from "../../main/application-update/download-platform-update/download-platform-update.injectable"; import type { DownloadPlatformUpdate } from "../../main/application-update/download-platform-update/download-platform-update.injectable";
import downloadPlatformUpdateInjectable from "../../main/application-update/download-platform-update/download-platform-update.injectable"; import downloadPlatformUpdateInjectable from "../../main/application-update/download-platform-update/download-platform-update.injectable";
import closeAllWindowsInjectable from "../../main/start-main-application/lens-window/hide-all-windows/close-all-windows.injectable"; import type { LensWindow } from "../../main/start-main-application/lens-window/application-window/create-lens-window.injectable";
import applicationWindowInjectable from "../../main/start-main-application/lens-window/application-window/application-window.injectable"; import getCurrentApplicationWindowInjectable from "../../main/start-main-application/lens-window/application-window/get-current-application-window.injectable";
import type { LensWindow } from "../../main/start-main-application/lens-window/application-window/lens-window-injection-token";
describe("installing update using tray", () => { describe("installing update using tray", () => {
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
let checkForPlatformUpdatesMock: AsyncFnMock<CheckForPlatformUpdates>; let checkForPlatformUpdatesMock: AsyncFnMock<CheckForPlatformUpdates>;
let downloadPlatformUpdateMock: AsyncFnMock<DownloadPlatformUpdate>; let downloadPlatformUpdateMock: AsyncFnMock<DownloadPlatformUpdate>;
beforeEach(() => { beforeEach(() => {
applicationBuilder = getApplicationBuilder(); builder = getApplicationBuilder();
applicationBuilder.beforeApplicationStart(({ mainDi }) => { builder.beforeApplicationStart((mainDi) => {
checkForPlatformUpdatesMock = asyncFn(); checkForPlatformUpdatesMock = asyncFn();
downloadPlatformUpdateMock = asyncFn(); downloadPlatformUpdateMock = asyncFn();
@ -48,7 +47,7 @@ describe("installing update using tray", () => {
let rendered: RenderResult; let rendered: RenderResult;
beforeEach(async () => { beforeEach(async () => {
rendered = await applicationBuilder.render(); rendered = await builder.render();
}); });
it("renders", () => { it("renders", () => {
@ -56,23 +55,20 @@ describe("installing update using tray", () => {
}); });
it("user cannot install update yet", () => { it("user cannot install update yet", () => {
expect(applicationBuilder.tray.get("install-update")).toBeNull(); expect(builder.tray.get("install-update")).toBeNull();
}); });
describe("given all application windows are closed, when checking for updates", () => { describe("given all application windows are closed, when checking for updates", () => {
let applicationWindow: LensWindow; let getCurrentApplicationWindow: () => LensWindow | undefined;
let closeAllWindows: () => void;
beforeEach(() => { beforeEach(() => {
const mainDi = applicationBuilder.dis.mainDi; getCurrentApplicationWindow = builder.mainDi.inject(
getCurrentApplicationWindowInjectable,
);
closeAllWindows = mainDi.inject(closeAllWindowsInjectable); builder.applicationWindow.closeAll();
applicationWindow = mainDi.inject(applicationWindowInjectable); builder.tray.click("check-for-updates");
closeAllWindows();
applicationBuilder.tray.click("check-for-updates");
}); });
describe("when check for update resolves with new update", () => { describe("when check for update resolves with new update", () => {
@ -84,37 +80,44 @@ describe("installing update using tray", () => {
}); });
it("does not show application window yet", () => { it("does not show application window yet", () => {
expect(applicationWindow.isVisible).toBe(false); const actual = getCurrentApplicationWindow();
expect(actual).toBeUndefined();
}); });
describe("when download of update resolves with success", () => { describe("when download of update resolves with success", () => {
beforeEach(async () => { beforeEach(async () => {
await downloadPlatformUpdateMock.resolve({ downloadWasSuccessful: true }); await downloadPlatformUpdateMock.resolve({ downloadWasSuccessful: true });
}); });
it("shows the application window", () => { it("shows the application window", () => {
expect(applicationWindow.isVisible).toBe(true); const actual = getCurrentApplicationWindow();
expect(actual).not.toBeUndefined();
}); });
it("given closing application window again and checking for updates again using tray, when check resolves with same version that was earlier downloaded, shows the application window", async () => { it("given closing application window again and checking for updates again using tray, when check resolves with same version that was earlier downloaded, shows the application window", async () => {
closeAllWindows(); builder.applicationWindow.closeAll();
applicationBuilder.tray.click("check-for-updates"); builder.tray.click("check-for-updates");
await checkForPlatformUpdatesMock.resolve({ await checkForPlatformUpdatesMock.resolve({
updateWasDiscovered: true, updateWasDiscovered: true,
version: "some-version", version: "some-version",
}); });
expect(applicationWindow.isVisible).toBe(true); const actual = getCurrentApplicationWindow();
expect(actual).not.toBeUndefined();
}); });
}); });
it("when download of update resolves with failure, does not show the application window", async () => { it("when download of update resolves with failure, does not show the application window", async () => {
await downloadPlatformUpdateMock.resolve({ downloadWasSuccessful: false }); await downloadPlatformUpdateMock.resolve({ downloadWasSuccessful: false });
expect(applicationWindow.isVisible).toBe(false); const actual = getCurrentApplicationWindow();
expect(actual).toBeUndefined();
}); });
}); });
@ -123,29 +126,31 @@ describe("installing update using tray", () => {
updateWasDiscovered: false, updateWasDiscovered: false,
}); });
expect(applicationWindow.isVisible).toBe(false); const actual = getCurrentApplicationWindow();
expect(actual).toBeUndefined();
}); });
}); });
describe("when user checks for updates using tray", () => { describe("when user checks for updates using tray", () => {
beforeEach(() => { beforeEach(() => {
applicationBuilder.tray.click("check-for-updates"); builder.tray.click("check-for-updates");
}); });
it("user cannot check for updates again", () => { it("user cannot check for updates again", () => {
expect( expect(
applicationBuilder.tray.get("check-for-updates")?.enabled, builder.tray.get("check-for-updates")?.enabled,
).toBe(false); ).toBe(false);
}); });
it("name of tray item for checking updates indicates that checking is happening", () => { it("name of tray item for checking updates indicates that checking is happening", () => {
expect( expect(
applicationBuilder.tray.get("check-for-updates")?.label, builder.tray.get("check-for-updates")?.label,
).toBe("Checking for updates..."); ).toBe("Checking for updates...");
}); });
it("user cannot install update yet", () => { it("user cannot install update yet", () => {
expect(applicationBuilder.tray.get("install-update")).toBeNull(); expect(builder.tray.get("install-update")).toBeNull();
}); });
it("renders", () => { it("renders", () => {
@ -160,18 +165,18 @@ describe("installing update using tray", () => {
}); });
it("user cannot install update", () => { it("user cannot install update", () => {
expect(applicationBuilder.tray.get("install-update")).toBeNull(); expect(builder.tray.get("install-update")).toBeNull();
}); });
it("user can check for updates again", () => { it("user can check for updates again", () => {
expect( expect(
applicationBuilder.tray.get("check-for-updates")?.enabled, builder.tray.get("check-for-updates")?.enabled,
).toBe(true); ).toBe(true);
}); });
it("name of tray item for checking updates no longer indicates that checking is happening", () => { it("name of tray item for checking updates no longer indicates that checking is happening", () => {
expect( expect(
applicationBuilder.tray.get("check-for-updates")?.label, builder.tray.get("check-for-updates")?.label,
).toBe("Check for updates"); ).toBe("Check for updates");
}); });
@ -190,13 +195,13 @@ describe("installing update using tray", () => {
it("user cannot check for updates again yet", () => { it("user cannot check for updates again yet", () => {
expect( expect(
applicationBuilder.tray.get("check-for-updates")?.enabled, builder.tray.get("check-for-updates")?.enabled,
).toBe(false); ).toBe(false);
}); });
it("name of tray item for checking updates indicates that downloading is happening", () => { it("name of tray item for checking updates indicates that downloading is happening", () => {
expect( expect(
applicationBuilder.tray.get("check-for-updates")?.label, builder.tray.get("check-for-updates")?.label,
).toBe("Downloading update some-version (0%)..."); ).toBe("Downloading update some-version (0%)...");
}); });
@ -204,12 +209,12 @@ describe("installing update using tray", () => {
downloadPlatformUpdateMock.mock.calls[0][0]({ percentage: 42.424242 }); downloadPlatformUpdateMock.mock.calls[0][0]({ percentage: 42.424242 });
expect( expect(
applicationBuilder.tray.get("check-for-updates")?.label, builder.tray.get("check-for-updates")?.label,
).toBe("Downloading update some-version (42%)..."); ).toBe("Downloading update some-version (42%)...");
}); });
it("user still cannot install update", () => { it("user still cannot install update", () => {
expect(applicationBuilder.tray.get("install-update")).toBeNull(); expect(builder.tray.get("install-update")).toBeNull();
}); });
it("renders", () => { it("renders", () => {
@ -223,19 +228,19 @@ describe("installing update using tray", () => {
it("user cannot install update", () => { it("user cannot install update", () => {
expect( expect(
applicationBuilder.tray.get("install-update"), builder.tray.get("install-update"),
).toBeNull(); ).toBeNull();
}); });
it("user can check for updates again", () => { it("user can check for updates again", () => {
expect( expect(
applicationBuilder.tray.get("check-for-updates")?.enabled, builder.tray.get("check-for-updates")?.enabled,
).toBe(true); ).toBe(true);
}); });
it("name of tray item for checking updates no longer indicates that downloading is happening", () => { it("name of tray item for checking updates no longer indicates that downloading is happening", () => {
expect( expect(
applicationBuilder.tray.get("check-for-updates")?.label, builder.tray.get("check-for-updates")?.label,
).toBe("Check for updates"); ).toBe("Check for updates");
}); });
@ -251,19 +256,19 @@ describe("installing update using tray", () => {
it("user can install update", () => { it("user can install update", () => {
expect( expect(
applicationBuilder.tray.get("install-update")?.label, builder.tray.get("install-update")?.label,
).toBe("Install update some-version"); ).toBe("Install update some-version");
}); });
it("user can check for updates again", () => { it("user can check for updates again", () => {
expect( expect(
applicationBuilder.tray.get("check-for-updates")?.enabled, builder.tray.get("check-for-updates")?.enabled,
).toBe(true); ).toBe(true);
}); });
it("name of tray item for checking updates no longer indicates that downloading is happening", () => { it("name of tray item for checking updates no longer indicates that downloading is happening", () => {
expect( expect(
applicationBuilder.tray.get("check-for-updates")?.label, builder.tray.get("check-for-updates")?.label,
).toBe("Check for updates"); ).toBe("Check for updates");
}); });

View File

@ -20,7 +20,7 @@ import { useFakeTime } from "../../common/test-utils/use-fake-time";
import staticFilesDirectoryInjectable from "../../common/vars/static-files-directory.injectable"; import staticFilesDirectoryInjectable from "../../common/vars/static-files-directory.injectable";
describe("installing update", () => { describe("installing update", () => {
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
let quitAndInstallUpdateMock: jest.Mock; let quitAndInstallUpdateMock: jest.Mock;
let checkForPlatformUpdatesMock: AsyncFnMock<CheckForPlatformUpdates>; let checkForPlatformUpdatesMock: AsyncFnMock<CheckForPlatformUpdates>;
let downloadPlatformUpdateMock: AsyncFnMock<DownloadPlatformUpdate>; let downloadPlatformUpdateMock: AsyncFnMock<DownloadPlatformUpdate>;
@ -29,9 +29,9 @@ describe("installing update", () => {
beforeEach(() => { beforeEach(() => {
useFakeTime("2015-10-21T07:28:00Z"); useFakeTime("2015-10-21T07:28:00Z");
applicationBuilder = getApplicationBuilder(); builder = getApplicationBuilder();
applicationBuilder.beforeApplicationStart(({ mainDi }) => { builder.beforeApplicationStart((mainDi) => {
quitAndInstallUpdateMock = jest.fn(); quitAndInstallUpdateMock = jest.fn();
checkForPlatformUpdatesMock = asyncFn(); checkForPlatformUpdatesMock = asyncFn();
downloadPlatformUpdateMock = asyncFn(); downloadPlatformUpdateMock = asyncFn();
@ -66,9 +66,9 @@ describe("installing update", () => {
let processCheckingForUpdates: (source: string) => Promise<{ updateIsReadyToBeInstalled: boolean }>; let processCheckingForUpdates: (source: string) => Promise<{ updateIsReadyToBeInstalled: boolean }>;
beforeEach(async () => { beforeEach(async () => {
rendered = await applicationBuilder.render(); rendered = await builder.render();
processCheckingForUpdates = applicationBuilder.dis.mainDi.inject( processCheckingForUpdates = builder.mainDi.inject(
processCheckingForUpdatesInjectable, processCheckingForUpdatesInjectable,
); );
}); });
@ -78,7 +78,7 @@ describe("installing update", () => {
}); });
it("shows normal tray icon", () => { it("shows normal tray icon", () => {
expect(applicationBuilder.tray.getIconPath()).toBe( expect(builder.tray.getIconPath()).toBe(
"/some-static-files-directory/icons/trayIconTemplate.png", "/some-static-files-directory/icons/trayIconTemplate.png",
); );
}); });
@ -96,7 +96,7 @@ describe("installing update", () => {
}); });
it("shows tray icon for checking for updates", () => { it("shows tray icon for checking for updates", () => {
expect(applicationBuilder.tray.getIconPath()).toBe( expect(builder.tray.getIconPath()).toBe(
"/some-static-files-directory/icons/trayIconCheckingForUpdatesTemplate.png", "/some-static-files-directory/icons/trayIconCheckingForUpdatesTemplate.png",
); );
}); });
@ -113,7 +113,7 @@ describe("installing update", () => {
}); });
it("shows tray icon for normal", () => { it("shows tray icon for normal", () => {
expect(applicationBuilder.tray.getIconPath()).toBe( expect(builder.tray.getIconPath()).toBe(
"/some-static-files-directory/icons/trayIconTemplate.png", "/some-static-files-directory/icons/trayIconTemplate.png",
); );
}); });
@ -140,7 +140,7 @@ describe("installing update", () => {
}); });
it("still shows tray icon for downloading", () => { it("still shows tray icon for downloading", () => {
expect(applicationBuilder.tray.getIconPath()).toBe( expect(builder.tray.getIconPath()).toBe(
"/some-static-files-directory/icons/trayIconCheckingForUpdatesTemplate.png", "/some-static-files-directory/icons/trayIconCheckingForUpdatesTemplate.png",
); );
}); });
@ -159,7 +159,7 @@ describe("installing update", () => {
}); });
it("still shows normal tray icon", () => { it("still shows normal tray icon", () => {
expect(applicationBuilder.tray.getIconPath()).toBe( expect(builder.tray.getIconPath()).toBe(
"/some-static-files-directory/icons/trayIconTemplate.png", "/some-static-files-directory/icons/trayIconTemplate.png",
); );
}); });
@ -179,7 +179,7 @@ describe("installing update", () => {
}); });
it("shows tray icon for update being available", () => { it("shows tray icon for update being available", () => {
expect(applicationBuilder.tray.getIconPath()).toBe( expect(builder.tray.getIconPath()).toBe(
"/some-static-files-directory/icons/trayIconUpdateAvailableTemplate.png", "/some-static-files-directory/icons/trayIconUpdateAvailableTemplate.png",
); );
}); });
@ -196,7 +196,7 @@ describe("installing update", () => {
}); });
it("shows tray icon for checking for updates", () => { it("shows tray icon for checking for updates", () => {
expect(applicationBuilder.tray.getIconPath()).toBe( expect(builder.tray.getIconPath()).toBe(
"/some-static-files-directory/icons/trayIconCheckingForUpdatesTemplate.png", "/some-static-files-directory/icons/trayIconCheckingForUpdatesTemplate.png",
); );
}); });
@ -214,7 +214,7 @@ describe("installing update", () => {
}); });
it("shows tray icon for update being available", () => { it("shows tray icon for update being available", () => {
expect(applicationBuilder.tray.getIconPath()).toBe( expect(builder.tray.getIconPath()).toBe(
"/some-static-files-directory/icons/trayIconUpdateAvailableTemplate.png", "/some-static-files-directory/icons/trayIconUpdateAvailableTemplate.png",
); );
}); });
@ -233,7 +233,7 @@ describe("installing update", () => {
}); });
it("shows tray icon for downloading update", () => { it("shows tray icon for downloading update", () => {
expect(applicationBuilder.tray.getIconPath()).toBe( expect(builder.tray.getIconPath()).toBe(
"/some-static-files-directory/icons/trayIconCheckingForUpdatesTemplate.png", "/some-static-files-directory/icons/trayIconCheckingForUpdatesTemplate.png",
); );
}); });

View File

@ -14,15 +14,15 @@ import { advanceFakeTime, useFakeTime } from "../../common/test-utils/use-fake-t
const ENOUGH_TIME = 1000 * 60 * 60 * 2; const ENOUGH_TIME = 1000 * 60 * 60 * 2;
describe("periodical checking of updates", () => { describe("periodical checking of updates", () => {
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
let processCheckingForUpdatesMock: jest.Mock; let processCheckingForUpdatesMock: jest.Mock;
beforeEach(() => { beforeEach(() => {
useFakeTime("2015-10-21T07:28:00Z"); useFakeTime("2015-10-21T07:28:00Z");
applicationBuilder = getApplicationBuilder(); builder = getApplicationBuilder();
applicationBuilder.beforeApplicationStart(({ mainDi }) => { builder.beforeApplicationStart((mainDi) => {
mainDi.unoverride(periodicalCheckForUpdatesInjectable); mainDi.unoverride(periodicalCheckForUpdatesInjectable);
mainDi.permitSideEffects(periodicalCheckForUpdatesInjectable); mainDi.permitSideEffects(periodicalCheckForUpdatesInjectable);
@ -39,12 +39,12 @@ describe("periodical checking of updates", () => {
let rendered: RenderResult; let rendered: RenderResult;
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.beforeApplicationStart(({ mainDi }) => { builder.beforeApplicationStart((mainDi) => {
mainDi.override(electronUpdaterIsActiveInjectable, () => true); mainDi.override(electronUpdaterIsActiveInjectable, () => true);
mainDi.override(publishIsConfiguredInjectable, () => true); mainDi.override(publishIsConfiguredInjectable, () => true);
}); });
rendered = await applicationBuilder.render(); rendered = await builder.render();
}); });
it("renders", () => { it("renders", () => {
@ -74,12 +74,12 @@ describe("periodical checking of updates", () => {
describe("given updater is enabled but no configuration exist, when started", () => { describe("given updater is enabled but no configuration exist, when started", () => {
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.beforeApplicationStart(({ mainDi }) => { builder.beforeApplicationStart((mainDi) => {
mainDi.override(electronUpdaterIsActiveInjectable, () => true); mainDi.override(electronUpdaterIsActiveInjectable, () => true);
mainDi.override(publishIsConfiguredInjectable, () => false); mainDi.override(publishIsConfiguredInjectable, () => false);
}); });
await applicationBuilder.render(); await builder.render();
}); });
it("does not check for updates", () => { it("does not check for updates", () => {
@ -95,12 +95,12 @@ describe("periodical checking of updates", () => {
describe("given updater is not enabled but and configuration exist, when started", () => { describe("given updater is not enabled but and configuration exist, when started", () => {
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.beforeApplicationStart(({ mainDi }) => { builder.beforeApplicationStart((mainDi) => {
mainDi.override(electronUpdaterIsActiveInjectable, () => false); mainDi.override(electronUpdaterIsActiveInjectable, () => false);
mainDi.override(publishIsConfiguredInjectable, () => true); mainDi.override(publishIsConfiguredInjectable, () => true);
}); });
await applicationBuilder.render(); await builder.render();
}); });
it("does not check for updates", () => { it("does not check for updates", () => {

View File

@ -22,26 +22,25 @@ import setUpdateOnQuitInjectable from "../../main/electron-app/features/set-upda
import showInfoNotificationInjectable from "../../renderer/components/notifications/show-info-notification.injectable"; import showInfoNotificationInjectable from "../../renderer/components/notifications/show-info-notification.injectable";
import processCheckingForUpdatesInjectable from "../../main/application-update/check-for-updates/process-checking-for-updates.injectable"; import processCheckingForUpdatesInjectable from "../../main/application-update/check-for-updates/process-checking-for-updates.injectable";
import appVersionInjectable from "../../common/vars/app-version.injectable"; import appVersionInjectable from "../../common/vars/app-version.injectable";
import type { DiContainer } from "@ogre-tools/injectable";
describe("selection of update stability", () => { describe("selection of update stability", () => {
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
let quitAndInstallUpdateMock: jest.Mock; let quitAndInstallUpdateMock: jest.Mock;
let checkForPlatformUpdatesMock: AsyncFnMock<CheckForPlatformUpdates>; let checkForPlatformUpdatesMock: AsyncFnMock<CheckForPlatformUpdates>;
let downloadPlatformUpdateMock: AsyncFnMock<DownloadPlatformUpdate>; let downloadPlatformUpdateMock: AsyncFnMock<DownloadPlatformUpdate>;
let setUpdateOnQuitMock: jest.Mock; let setUpdateOnQuitMock: jest.Mock;
let showInfoNotificationMock: jest.Mock; let showInfoNotificationMock: jest.Mock;
let mainDi: DiContainer;
beforeEach(() => { beforeEach(() => {
applicationBuilder = getApplicationBuilder(); builder = getApplicationBuilder();
applicationBuilder.beforeApplicationStart(({ mainDi, rendererDi }) => { builder.beforeApplicationStart((mainDi) => {
quitAndInstallUpdateMock = jest.fn(); quitAndInstallUpdateMock = jest.fn();
checkForPlatformUpdatesMock = asyncFn(); checkForPlatformUpdatesMock = asyncFn();
downloadPlatformUpdateMock = asyncFn(); downloadPlatformUpdateMock = asyncFn();
setUpdateOnQuitMock = jest.fn(); setUpdateOnQuitMock = jest.fn();
showInfoNotificationMock = jest.fn(() => () => {});
rendererDi.override(showInfoNotificationInjectable, () => showInfoNotificationMock);
mainDi.override(setUpdateOnQuitInjectable, () => setUpdateOnQuitMock); mainDi.override(setUpdateOnQuitInjectable, () => setUpdateOnQuitMock);
@ -63,6 +62,14 @@ describe("selection of update stability", () => {
mainDi.override(electronUpdaterIsActiveInjectable, () => true); mainDi.override(electronUpdaterIsActiveInjectable, () => true);
mainDi.override(publishIsConfiguredInjectable, () => true); mainDi.override(publishIsConfiguredInjectable, () => true);
}); });
builder.beforeWindowStart((windowDi) => {
showInfoNotificationMock = jest.fn(() => () => {});
windowDi.override(showInfoNotificationInjectable, () => showInfoNotificationMock);
});
mainDi = builder.mainDi;
}); });
describe("when started", () => { describe("when started", () => {
@ -70,9 +77,9 @@ describe("selection of update stability", () => {
let processCheckingForUpdates: (source: string) => Promise<{ updateIsReadyToBeInstalled: boolean }>; let processCheckingForUpdates: (source: string) => Promise<{ updateIsReadyToBeInstalled: boolean }>;
beforeEach(async () => { beforeEach(async () => {
rendered = await applicationBuilder.render(); rendered = await builder.render();
processCheckingForUpdates = applicationBuilder.dis.mainDi.inject(processCheckingForUpdatesInjectable); processCheckingForUpdates = mainDi.inject(processCheckingForUpdatesInjectable);
}); });
it("renders", () => { it("renders", () => {
@ -86,7 +93,7 @@ describe("selection of update stability", () => {
}; };
beforeEach(() => { beforeEach(() => {
selectedUpdateChannel = applicationBuilder.dis.mainDi.inject( selectedUpdateChannel = mainDi.inject(
selectedUpdateChannelInjectable, selectedUpdateChannelInjectable,
); );
@ -177,7 +184,7 @@ describe("selection of update stability", () => {
}; };
beforeEach(() => { beforeEach(() => {
selectedUpdateChannel = applicationBuilder.dis.mainDi.inject( selectedUpdateChannel = mainDi.inject(
selectedUpdateChannelInjectable, selectedUpdateChannelInjectable,
); );
@ -224,7 +231,7 @@ describe("selection of update stability", () => {
}); });
it("given valid update channel selection is stored, when checking for updates, checks for updates from the update channel", async () => { it("given valid update channel selection is stored, when checking for updates, checks for updates from the update channel", async () => {
applicationBuilder.beforeApplicationStart(({ mainDi }) => { builder.beforeApplicationStart((mainDi) => {
// TODO: Switch to more natural way of setting initial value // TODO: Switch to more natural way of setting initial value
// TODO: UserStore is currently responsible for getting and setting initial value // TODO: UserStore is currently responsible for getting and setting initial value
const selectedUpdateChannel = mainDi.inject(selectedUpdateChannelInjectable); const selectedUpdateChannel = mainDi.inject(selectedUpdateChannelInjectable);
@ -232,9 +239,9 @@ describe("selection of update stability", () => {
selectedUpdateChannel.setValue(updateChannels.beta.id); selectedUpdateChannel.setValue(updateChannels.beta.id);
}); });
await applicationBuilder.render(); await builder.render();
const processCheckingForUpdates = applicationBuilder.dis.mainDi.inject(processCheckingForUpdatesInjectable); const processCheckingForUpdates = mainDi.inject(processCheckingForUpdatesInjectable);
processCheckingForUpdates("irrelevant"); processCheckingForUpdates("irrelevant");
@ -242,7 +249,7 @@ describe("selection of update stability", () => {
}); });
it("given invalid update channel selection is stored, when checking for updates, checks for updates from the update channel", async () => { it("given invalid update channel selection is stored, when checking for updates, checks for updates from the update channel", async () => {
applicationBuilder.beforeApplicationStart(({ mainDi }) => { builder.beforeApplicationStart((mainDi) => {
// TODO: Switch to more natural way of setting initial value // TODO: Switch to more natural way of setting initial value
// TODO: UserStore is currently responsible for getting and setting initial value // TODO: UserStore is currently responsible for getting and setting initial value
const selectedUpdateChannel = mainDi.inject(selectedUpdateChannelInjectable); const selectedUpdateChannel = mainDi.inject(selectedUpdateChannelInjectable);
@ -250,9 +257,9 @@ describe("selection of update stability", () => {
selectedUpdateChannel.setValue("something-invalid" as UpdateChannelId); selectedUpdateChannel.setValue("something-invalid" as UpdateChannelId);
}); });
await applicationBuilder.render(); await builder.render();
const processCheckingForUpdates = applicationBuilder.dis.mainDi.inject(processCheckingForUpdatesInjectable); const processCheckingForUpdates = mainDi.inject(processCheckingForUpdatesInjectable);
processCheckingForUpdates("irrelevant"); processCheckingForUpdates("irrelevant");
@ -260,13 +267,13 @@ describe("selection of update stability", () => {
}); });
it('given no update channel selection is stored and currently using stable release, when user checks for updates, checks for updates from "latest" update channel by default', async () => { it('given no update channel selection is stored and currently using stable release, when user checks for updates, checks for updates from "latest" update channel by default', async () => {
applicationBuilder.beforeApplicationStart(({ mainDi }) => { builder.beforeApplicationStart((mainDi) => {
mainDi.override(appVersionInjectable, () => "1.0.0"); mainDi.override(appVersionInjectable, () => "1.0.0");
}); });
await applicationBuilder.render(); await builder.render();
const processCheckingForUpdates = applicationBuilder.dis.mainDi.inject(processCheckingForUpdatesInjectable); const processCheckingForUpdates = mainDi.inject(processCheckingForUpdatesInjectable);
processCheckingForUpdates("irrelevant"); processCheckingForUpdates("irrelevant");
@ -277,13 +284,13 @@ describe("selection of update stability", () => {
}); });
it('given no update channel selection is stored and currently using alpha release, when checking for updates, checks for updates from "alpha" channel', async () => { it('given no update channel selection is stored and currently using alpha release, when checking for updates, checks for updates from "alpha" channel', async () => {
applicationBuilder.beforeApplicationStart(({ mainDi }) => { builder.beforeApplicationStart((mainDi) => {
mainDi.override(appVersionInjectable, () => "1.0.0-alpha"); mainDi.override(appVersionInjectable, () => "1.0.0-alpha");
}); });
await applicationBuilder.render(); await builder.render();
const processCheckingForUpdates = applicationBuilder.dis.mainDi.inject(processCheckingForUpdatesInjectable); const processCheckingForUpdates = mainDi.inject(processCheckingForUpdatesInjectable);
processCheckingForUpdates("irrelevant"); processCheckingForUpdates("irrelevant");
@ -291,13 +298,13 @@ describe("selection of update stability", () => {
}); });
it('given no update channel selection is stored and currently using beta release, when checking for updates, checks for updates from "beta" channel', async () => { it('given no update channel selection is stored and currently using beta release, when checking for updates, checks for updates from "beta" channel', async () => {
applicationBuilder.beforeApplicationStart(({ mainDi }) => { builder.beforeApplicationStart((mainDi) => {
mainDi.override(appVersionInjectable, () => "1.0.0-beta"); mainDi.override(appVersionInjectable, () => "1.0.0-beta");
}); });
await applicationBuilder.render(); await builder.render();
const processCheckingForUpdates = applicationBuilder.dis.mainDi.inject(processCheckingForUpdatesInjectable); const processCheckingForUpdates = mainDi.inject(processCheckingForUpdatesInjectable);
processCheckingForUpdates("irrelevant"); processCheckingForUpdates("irrelevant");
@ -305,7 +312,7 @@ describe("selection of update stability", () => {
}); });
it("given update channel selection is stored and currently using prerelease, when checking for updates, checks for updates from stored channel", async () => { it("given update channel selection is stored and currently using prerelease, when checking for updates, checks for updates from stored channel", async () => {
applicationBuilder.beforeApplicationStart(({ mainDi }) => { builder.beforeApplicationStart((mainDi) => {
mainDi.override(appVersionInjectable, () => "1.0.0-alpha"); mainDi.override(appVersionInjectable, () => "1.0.0-alpha");
// TODO: Switch to more natural way of setting initial value // TODO: Switch to more natural way of setting initial value
@ -315,9 +322,9 @@ describe("selection of update stability", () => {
selectedUpdateChannel.setValue(updateChannels.beta.id); selectedUpdateChannel.setValue(updateChannels.beta.id);
}); });
await applicationBuilder.render(); await builder.render();
const processCheckingForUpdates = applicationBuilder.dis.mainDi.inject(processCheckingForUpdatesInjectable); const processCheckingForUpdates = mainDi.inject(processCheckingForUpdatesInjectable);
processCheckingForUpdates("irrelevant"); processCheckingForUpdates("irrelevant");

View File

@ -8,7 +8,6 @@ import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
import type { TestExtensionRenderer } from "../../../renderer/components/test-utils/get-extension-fake"; import type { TestExtensionRenderer } from "../../../renderer/components/test-utils/get-extension-fake";
import { getExtensionFakeFor } from "../../../renderer/components/test-utils/get-extension-fake";
import type { KubernetesCluster } from "../../../common/catalog-entities"; import type { KubernetesCluster } from "../../../common/catalog-entities";
import React from "react"; import React from "react";
import extensionShouldBeEnabledForClusterFrameInjectable from "../../../renderer/extension-loader/extension-should-be-enabled-for-cluster-frame.injectable"; import extensionShouldBeEnabledForClusterFrameInjectable from "../../../renderer/extension-loader/extension-should-be-enabled-for-cluster-frame.injectable";
@ -24,13 +23,13 @@ describe("disable-cluster-pages-when-cluster-is-not-relevant", () => {
builder.setEnvironmentToClusterFrame(); builder.setEnvironmentToClusterFrame();
builder.dis.rendererDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable); builder.beforeWindowStart((windowDi) => {
windowDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable);
const getExtensionFake = getExtensionFakeFor(builder); });
isEnabledForClusterMock = asyncFn(); isEnabledForClusterMock = asyncFn();
const testExtension = getExtensionFake({ const testExtension = {
id: "test-extension-id", id: "test-extension-id",
name: "test-extension", name: "test-extension",
@ -43,13 +42,14 @@ describe("disable-cluster-pages-when-cluster-is-not-relevant", () => {
}, },
}], }],
}, },
}); };
rendererTestExtension = testExtension.renderer;
rendered = await builder.render(); rendered = await builder.render();
builder.extensions.enable(testExtension); builder.extensions.enable(testExtension);
rendererTestExtension =
builder.extensions.get("test-extension-id").applicationWindows.only;
}); });
describe("given not yet known if extension should be enabled for the cluster, when navigating", () => { describe("given not yet known if extension should be enabled for the cluster, when navigating", () => {

View File

@ -7,7 +7,6 @@ import asyncFn from "@async-fn/jest";
import type { RenderResult } from "@testing-library/react"; import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
import { getExtensionFakeFor } from "../../../renderer/components/test-utils/get-extension-fake";
import type { KubernetesCluster } from "../../../common/catalog-entities"; import type { KubernetesCluster } from "../../../common/catalog-entities";
import React from "react"; import React from "react";
import extensionShouldBeEnabledForClusterFrameInjectable from "../../../renderer/extension-loader/extension-should-be-enabled-for-cluster-frame.injectable"; import extensionShouldBeEnabledForClusterFrameInjectable from "../../../renderer/extension-loader/extension-should-be-enabled-for-cluster-frame.injectable";
@ -22,13 +21,13 @@ describe("disable sidebar items when cluster is not relevant", () => {
builder.setEnvironmentToClusterFrame(); builder.setEnvironmentToClusterFrame();
builder.dis.rendererDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable); builder.beforeWindowStart((windowDi) => {
windowDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable);
const getExtensionFake = getExtensionFakeFor(builder); });
isEnabledForClusterMock = asyncFn(); isEnabledForClusterMock = asyncFn();
const testExtension = getExtensionFake({ const testExtension = {
id: "test-extension-id", id: "test-extension-id",
name: "test-extension", name: "test-extension",
@ -52,7 +51,7 @@ describe("disable sidebar items when cluster is not relevant", () => {
}, },
], ],
}, },
}); };
rendered = await builder.render(); rendered = await builder.render();

View File

@ -9,24 +9,21 @@ import React from "react";
import type { TestExtensionRenderer } from "../../../renderer/components/test-utils/get-extension-fake"; import type { TestExtensionRenderer } from "../../../renderer/components/test-utils/get-extension-fake";
import type { ApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
import { getExtensionFakeFor } from "../../../renderer/components/test-utils/get-extension-fake";
describe("reactively disable cluster pages", () => { describe("reactively disable cluster pages", () => {
let builder: ApplicationBuilder; let builder: ApplicationBuilder;
let rendered: RenderResult; let rendered: RenderResult;
let someObservable: IObservableValue<boolean>; let someObservable: IObservableValue<boolean>;
let rendererTestExtension: TestExtensionRenderer; let testExtensionInstance: TestExtensionRenderer;
beforeEach(async () => { beforeEach(async () => {
builder = getApplicationBuilder(); builder = getApplicationBuilder();
builder.setEnvironmentToClusterFrame(); builder.setEnvironmentToClusterFrame();
const getExtensionFake = getExtensionFakeFor(builder);
someObservable = observable.box(false); someObservable = observable.box(false);
const testExtension = getExtensionFake({ const testExtensionOptions = {
id: "test-extension-id", id: "test-extension-id",
name: "test-extension", name: "test-extension",
@ -39,17 +36,18 @@ describe("reactively disable cluster pages", () => {
enabled: computed(() => someObservable.get()), enabled: computed(() => someObservable.get()),
}], }],
}, },
}); };
rendered = await builder.render(); rendered = await builder.render();
builder.extensions.enable(testExtension); builder.extensions.enable(testExtensionOptions);
rendererTestExtension = testExtension.renderer; testExtensionInstance =
builder.extensions.get("test-extension-id").applicationWindows.only;
}); });
it("when navigating to the page, does not show the page", () => { it("when navigating to the page, does not show the page", () => {
rendererTestExtension.navigate(); testExtensionInstance.navigate();
const actual = rendered.queryByTestId("some-test-page"); const actual = rendered.queryByTestId("some-test-page");
@ -61,7 +59,7 @@ describe("reactively disable cluster pages", () => {
someObservable.set(true); someObservable.set(true);
}); });
rendererTestExtension.navigate(); testExtensionInstance.navigate();
const actual = rendered.queryByTestId("some-test-page"); const actual = rendered.queryByTestId("some-test-page");

View File

@ -8,7 +8,6 @@ import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
import type { KubernetesCluster } from "../../../../common/catalog-entities"; import type { KubernetesCluster } from "../../../../common/catalog-entities";
import { getApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
import { getExtensionFakeFor } from "../../../../renderer/components/test-utils/get-extension-fake";
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { frontEndRouteInjectionToken } from "../../../../common/front-end-routing/front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../common/front-end-routing/front-end-route-injection-token";
import { computed } from "mobx"; import { computed } from "mobx";
@ -30,9 +29,10 @@ describe("disable kube object detail items when cluster is not relevant", () =>
beforeEach(async () => { beforeEach(async () => {
builder = getApplicationBuilder(); builder = getApplicationBuilder();
builder.setEnvironmentToClusterFrame();
builder.beforeApplicationStart(({ rendererDi }) => { builder.beforeWindowStart((windowDi) => {
rendererDi.override( windowDi.override(
apiManagerInjectable, apiManagerInjectable,
() => () =>
({ ({
@ -42,21 +42,15 @@ describe("disable kube object detail items when cluster is not relevant", () =>
}), }),
} as unknown as ApiManager), } as unknown as ApiManager),
); );
windowDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable);
windowDi.register(testRouteInjectable, testRouteComponentInjectable);
}); });
const rendererDi = builder.dis.rendererDi;
rendererDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable);
rendererDi.register(testRouteInjectable, testRouteComponentInjectable);
builder.setEnvironmentToClusterFrame();
const getExtensionFake = getExtensionFakeFor(builder);
isEnabledForClusterMock = asyncFn(); isEnabledForClusterMock = asyncFn();
const testExtension = getExtensionFake({ const testExtension = {
id: "test-extension-id", id: "test-extension-id",
name: "test-extension", name: "test-extension",
@ -77,12 +71,14 @@ describe("disable kube object detail items when cluster is not relevant", () =>
}, },
], ],
}, },
}); };
rendered = await builder.render(); rendered = await builder.render();
const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken); const windowDi = builder.applicationWindow.only.di;
const testRoute = rendererDi.inject(testRouteInjectable);
const navigateToRoute = windowDi.inject(navigateToRouteInjectionToken);
const testRoute = windowDi.inject(testRouteInjectable);
navigateToRoute(testRoute); navigateToRoute(testRoute);

View File

@ -5,7 +5,6 @@
import type { RenderResult } from "@testing-library/react"; import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
import { getExtensionFakeFor } from "../../../../renderer/components/test-utils/get-extension-fake";
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { frontEndRouteInjectionToken } from "../../../../common/front-end-routing/front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../common/front-end-routing/front-end-route-injection-token";
import type { IObservableValue } from "mobx"; import type { IObservableValue } from "mobx";
@ -26,8 +25,10 @@ describe("reactively hide kube object detail item", () => {
beforeEach(async () => { beforeEach(async () => {
builder = getApplicationBuilder(); builder = getApplicationBuilder();
builder.beforeApplicationStart(({ rendererDi }) => { builder.setEnvironmentToClusterFrame();
rendererDi.override(
builder.beforeWindowStart((windowDi) => {
windowDi.override(
apiManagerInjectable, apiManagerInjectable,
() => () =>
({ ({
@ -37,19 +38,13 @@ describe("reactively hide kube object detail item", () => {
}), }),
} as unknown as ApiManager), } as unknown as ApiManager),
); );
windowDi.register(testRouteInjectable, testRouteComponentInjectable);
}); });
const rendererDi = builder.dis.rendererDi;
rendererDi.register(testRouteInjectable, testRouteComponentInjectable);
builder.setEnvironmentToClusterFrame();
const getExtensionFake = getExtensionFakeFor(builder);
someObservable = observable.box(false); someObservable = observable.box(false);
const testExtension = getExtensionFake({ const testExtension = {
id: "test-extension-id", id: "test-extension-id",
name: "test-extension", name: "test-extension",
@ -71,12 +66,14 @@ describe("reactively hide kube object detail item", () => {
}, },
], ],
}, },
}); };
rendered = await builder.render(); rendered = await builder.render();
const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken); const windowDi = builder.applicationWindow.only.di;
const testRoute = rendererDi.inject(testRouteInjectable);
const navigateToRoute = windowDi.inject(navigateToRouteInjectionToken);
const testRoute = windowDi.inject(testRouteInjectable);
navigateToRoute(testRoute); navigateToRoute(testRoute);

View File

@ -8,7 +8,6 @@ import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
import type { KubernetesCluster } from "../../../../common/catalog-entities"; import type { KubernetesCluster } from "../../../../common/catalog-entities";
import { getApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
import { getExtensionFakeFor } from "../../../../renderer/components/test-utils/get-extension-fake";
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { frontEndRouteInjectionToken } from "../../../../common/front-end-routing/front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../common/front-end-routing/front-end-route-injection-token";
import { computed } from "mobx"; import { computed } from "mobx";
@ -29,19 +28,16 @@ describe("disable kube object menu items when cluster is not relevant", () => {
beforeEach(async () => { beforeEach(async () => {
builder = getApplicationBuilder(); builder = getApplicationBuilder();
const rendererDi = builder.dis.rendererDi;
rendererDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable);
rendererDi.register(testRouteInjectable, testRouteComponentInjectable);
builder.setEnvironmentToClusterFrame(); builder.setEnvironmentToClusterFrame();
const getExtensionFake = getExtensionFakeFor(builder); builder.beforeWindowStart((windowDi) => {
windowDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable);
windowDi.register(testRouteInjectable, testRouteComponentInjectable);
});
isEnabledForClusterMock = asyncFn(); isEnabledForClusterMock = asyncFn();
const testExtension = getExtensionFake({ const testExtension = {
id: "test-extension-id", id: "test-extension-id",
name: "test-extension", name: "test-extension",
@ -60,12 +56,14 @@ describe("disable kube object menu items when cluster is not relevant", () => {
}, },
], ],
}, },
}); };
rendered = await builder.render(); rendered = await builder.render();
const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken); const windowDi = builder.applicationWindow.only.di;
const testRoute = rendererDi.inject(testRouteInjectable);
const navigateToRoute = windowDi.inject(navigateToRouteInjectionToken);
const testRoute = windowDi.inject(testRouteInjectable);
navigateToRoute(testRoute); navigateToRoute(testRoute);

View File

@ -5,7 +5,6 @@
import type { RenderResult } from "@testing-library/react"; import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
import { getExtensionFakeFor } from "../../../../renderer/components/test-utils/get-extension-fake";
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { frontEndRouteInjectionToken } from "../../../../common/front-end-routing/front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../common/front-end-routing/front-end-route-injection-token";
import type { IObservableValue } from "mobx"; import type { IObservableValue } from "mobx";
@ -24,17 +23,15 @@ describe("reactively hide kube object menu item", () => {
beforeEach(async () => { beforeEach(async () => {
builder = getApplicationBuilder(); builder = getApplicationBuilder();
const rendererDi = builder.dis.rendererDi;
rendererDi.register(testRouteInjectable, testRouteComponentInjectable);
builder.setEnvironmentToClusterFrame(); builder.setEnvironmentToClusterFrame();
const getExtensionFake = getExtensionFakeFor(builder); builder.beforeWindowStart((windowDi) => {
windowDi.register(testRouteInjectable, testRouteComponentInjectable);
});
someObservable = observable.box(false); someObservable = observable.box(false);
const testExtension = getExtensionFake({ const testExtension = {
id: "test-extension-id", id: "test-extension-id",
name: "test-extension", name: "test-extension",
@ -53,12 +50,14 @@ describe("reactively hide kube object menu item", () => {
}, },
], ],
}, },
}); };
rendered = await builder.render(); rendered = await builder.render();
const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken); const windowDi = builder.applicationWindow.only.di;
const testRoute = rendererDi.inject(testRouteInjectable);
const navigateToRoute = windowDi.inject(navigateToRouteInjectionToken);
const testRoute = windowDi.inject(testRouteInjectable);
navigateToRoute(testRoute); navigateToRoute(testRoute);

View File

@ -8,7 +8,6 @@ import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
import type { KubernetesCluster } from "../../../../common/catalog-entities"; import type { KubernetesCluster } from "../../../../common/catalog-entities";
import { getApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
import { getExtensionFakeFor } from "../../../../renderer/components/test-utils/get-extension-fake";
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { frontEndRouteInjectionToken } from "../../../../common/front-end-routing/front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../common/front-end-routing/front-end-route-injection-token";
import { computed } from "mobx"; import { computed } from "mobx";
@ -30,19 +29,16 @@ describe("disable kube object statuses when cluster is not relevant", () => {
beforeEach(async () => { beforeEach(async () => {
builder = getApplicationBuilder(); builder = getApplicationBuilder();
const rendererDi = builder.dis.rendererDi;
rendererDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable);
rendererDi.register(testRouteInjectable, testRouteComponentInjectable);
builder.setEnvironmentToClusterFrame(); builder.setEnvironmentToClusterFrame();
const getExtensionFake = getExtensionFakeFor(builder); builder.beforeWindowStart((windowDi) => {
windowDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable);
windowDi.register(testRouteInjectable, testRouteComponentInjectable);
});
isEnabledForClusterMock = asyncFn(); isEnabledForClusterMock = asyncFn();
const testExtension = getExtensionFake({ const testExtension = {
id: "test-extension-id", id: "test-extension-id",
name: "test-extension", name: "test-extension",
@ -61,12 +57,14 @@ describe("disable kube object statuses when cluster is not relevant", () => {
}, },
], ],
}, },
}); };
rendered = await builder.render(); rendered = await builder.render();
const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken); const windowDi = builder.applicationWindow.only.di;
const testRoute = rendererDi.inject(testRouteInjectable);
const navigateToRoute = windowDi.inject(navigateToRouteInjectionToken);
const testRoute = windowDi.inject(testRouteInjectable);
navigateToRoute(testRoute); navigateToRoute(testRoute);

View File

@ -5,7 +5,6 @@
import type { RenderResult } from "@testing-library/react"; import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
import { getExtensionFakeFor } from "../../../../renderer/components/test-utils/get-extension-fake";
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { frontEndRouteInjectionToken } from "../../../../common/front-end-routing/front-end-route-injection-token"; import { frontEndRouteInjectionToken } from "../../../../common/front-end-routing/front-end-route-injection-token";
import type { IObservableValue } from "mobx"; import type { IObservableValue } from "mobx";
@ -26,19 +25,16 @@ describe("reactively hide kube object status", () => {
beforeEach(async () => { beforeEach(async () => {
builder = getApplicationBuilder(); builder = getApplicationBuilder();
const rendererDi = builder.dis.rendererDi;
rendererDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable);
rendererDi.register(testRouteInjectable, testRouteComponentInjectable);
builder.setEnvironmentToClusterFrame(); builder.setEnvironmentToClusterFrame();
const getExtensionFake = getExtensionFakeFor(builder); builder.beforeWindowStart((windowDi) => {
windowDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable);
windowDi.register(testRouteInjectable, testRouteComponentInjectable);
});
someObservable = observable.box(false); someObservable = observable.box(false);
const testExtension = getExtensionFake({ const testExtension = {
id: "test-extension-id", id: "test-extension-id",
name: "test-extension", name: "test-extension",
@ -57,12 +53,14 @@ describe("reactively hide kube object status", () => {
}, },
], ],
}, },
}); };
rendered = await builder.render(); rendered = await builder.render();
const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken); const windowDi = builder.applicationWindow.only.di;
const testRoute = rendererDi.inject(testRouteInjectable);
const navigateToRoute = windowDi.inject(navigateToRouteInjectionToken);
const testRoute = windowDi.inject(testRouteInjectable);
navigateToRoute(testRoute); navigateToRoute(testRoute);

View File

@ -32,8 +32,6 @@ describe("show status for a kube object", () => {
builder = getApplicationBuilder(); builder = getApplicationBuilder();
const rendererDi = builder.dis.rendererDi;
infoStatusIsShown = false; infoStatusIsShown = false;
const infoStatusInjectable = getInjectable({ const infoStatusInjectable = getInjectable({
@ -95,34 +93,36 @@ describe("show status for a kube object", () => {
}), }),
}); });
rendererDi.register( builder.beforeWindowStart((windowDi) => {
testRouteInjectable, windowDi.register(
testRouteComponentInjectable, testRouteInjectable,
infoStatusInjectable, testRouteComponentInjectable,
warningStatusInjectable, infoStatusInjectable,
criticalStatusInjectable, warningStatusInjectable,
someAtomInjectable, criticalStatusInjectable,
); someAtomInjectable,
);
});
builder.setEnvironmentToClusterFrame(); builder.setEnvironmentToClusterFrame();
}); });
describe("given application starts and in test page", () => { describe("given application starts and in test page", () => {
let rendererDi: DiContainer; let windowDi: DiContainer;
let rendered: RenderResult; let rendered: RenderResult;
let rerenderParent: () => void; let rerenderParent: () => void;
beforeEach(async () => { beforeEach(async () => {
rendered = await builder.render(); rendered = await builder.render();
rendererDi = builder.dis.rendererDi; windowDi = builder.applicationWindow.only.di;
const someAtom = rendererDi.inject(someAtomInjectable); const someAtom = windowDi.inject(someAtomInjectable);
rerenderParent = rerenderParentFor(someAtom); rerenderParent = rerenderParentFor(someAtom);
const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken); const navigateToRoute = windowDi.inject(navigateToRouteInjectionToken);
const testRoute = rendererDi.inject(testRouteInjectable); const testRoute = windowDi.inject(testRouteInjectable);
navigateToRoute(testRoute); navigateToRoute(testRoute);
}); });
@ -141,7 +141,7 @@ describe("show status for a kube object", () => {
describe("when status for irrelevant kube object kind emerges", () => { describe("when status for irrelevant kube object kind emerges", () => {
beforeEach(() => { beforeEach(() => {
rendererDi.register(statusForIrrelevantKubeObjectKindInjectable); windowDi.register(statusForIrrelevantKubeObjectKindInjectable);
rerenderParent(); rerenderParent();
}); });
@ -161,7 +161,7 @@ describe("show status for a kube object", () => {
describe("when status for irrelevant kube object api version emerges", () => { describe("when status for irrelevant kube object api version emerges", () => {
beforeEach(() => { beforeEach(() => {
rendererDi.register(statusForIrrelevantKubeObjectApiVersionInjectable); windowDi.register(statusForIrrelevantKubeObjectApiVersionInjectable);
rerenderParent(); rerenderParent();
}); });

View File

@ -44,34 +44,34 @@ describe("cluster/namespaces - edit namespace from new tab", () => {
showSuccessNotificationMock = jest.fn(); showSuccessNotificationMock = jest.fn();
showErrorNotificationMock = jest.fn(); showErrorNotificationMock = jest.fn();
builder.beforeApplicationStart(({ rendererDi }) => { builder.beforeWindowStart((windowDi) => {
rendererDi.override( windowDi.override(
directoryForLensLocalStorageInjectable, directoryForLensLocalStorageInjectable,
() => "/some-directory-for-lens-local-storage", () => "/some-directory-for-lens-local-storage",
); );
rendererDi.override(hostedClusterIdInjectable, () => "some-cluster-id"); windowDi.override(hostedClusterIdInjectable, () => "some-cluster-id");
storagesAreReady = controlWhenStoragesAreReady(rendererDi); storagesAreReady = controlWhenStoragesAreReady(windowDi);
rendererDi.override( windowDi.override(
showSuccessNotificationInjectable, showSuccessNotificationInjectable,
() => showSuccessNotificationMock, () => showSuccessNotificationMock,
); );
rendererDi.override( windowDi.override(
showErrorNotificationInjectable, showErrorNotificationInjectable,
() => showErrorNotificationMock, () => showErrorNotificationMock,
); );
rendererDi.override(getRandomIdForEditResourceTabInjectable, () => windowDi.override(getRandomIdForEditResourceTabInjectable, () =>
jest jest
.fn(() => "some-irrelevant-random-id") .fn(() => "some-irrelevant-random-id")
.mockReturnValueOnce("some-first-tab-id") .mockReturnValueOnce("some-first-tab-id")
.mockReturnValueOnce("some-second-tab-id"), .mockReturnValueOnce("some-second-tab-id"),
); );
rendererDi.override(callForResourceInjectable, () => async (selfLink: string) => { windowDi.override(callForResourceInjectable, () => async (selfLink: string) => {
if ( if (
[ [
"/apis/some-api-version/namespaces/some-uid", "/apis/some-api-version/namespaces/some-uid",
@ -84,7 +84,7 @@ describe("cluster/namespaces - edit namespace from new tab", () => {
return undefined; return undefined;
}); });
rendererDi.override(callForPatchResourceInjectable, () => async (namespace, ...args) => { windowDi.override(callForPatchResourceInjectable, () => async (namespace, ...args) => {
if ( if (
[ [
"/apis/some-api-version/namespaces/some-uid", "/apis/some-api-version/namespaces/some-uid",
@ -103,22 +103,22 @@ describe("cluster/namespaces - edit namespace from new tab", () => {
describe("when navigating to namespaces", () => { describe("when navigating to namespaces", () => {
let rendered: RenderResult; let rendered: RenderResult;
let rendererDi: DiContainer; let windowDi: DiContainer;
beforeEach(async () => { beforeEach(async () => {
rendered = await builder.render(); rendered = await builder.render();
await storagesAreReady(); await storagesAreReady();
rendererDi = builder.dis.rendererDi; windowDi = builder.applicationWindow.only.di;
const navigateToNamespaces = rendererDi.inject( const navigateToNamespaces = windowDi.inject(
navigateToNamespacesInjectable, navigateToNamespacesInjectable,
); );
navigateToNamespaces(); navigateToNamespaces();
const dockStore = rendererDi.inject(dockStoreInjectable); const dockStore = windowDi.inject(dockStoreInjectable);
// TODO: Make TerminalWindow unit testable to allow realistic behaviour // TODO: Make TerminalWindow unit testable to allow realistic behaviour
dockStore.closeTab("terminal"); dockStore.closeTab("terminal");
@ -168,7 +168,7 @@ describe("cluster/namespaces - edit namespace from new tab", () => {
// TODO: Make implementation match the description (tests above) // TODO: Make implementation match the description (tests above)
const namespaceStub = new Namespace(someNamespaceDataStub); const namespaceStub = new Namespace(someNamespaceDataStub);
const createEditResourceTab = rendererDi.inject(createEditResourceTabInjectable); const createEditResourceTab = windowDi.inject(createEditResourceTabInjectable);
createEditResourceTab(namespaceStub); createEditResourceTab(namespaceStub);
}); });
@ -510,7 +510,7 @@ metadata:
}); });
it("stores the changed configuration", async () => { it("stores the changed configuration", async () => {
const readJsonFile = rendererDi.inject( const readJsonFile = windowDi.inject(
readJsonFileInjectable, readJsonFileInjectable,
); );
@ -719,7 +719,7 @@ metadata:
// TODO: Make implementation match the description // TODO: Make implementation match the description
const namespaceStub = new Namespace(someOtherNamespaceDataStub); const namespaceStub = new Namespace(someOtherNamespaceDataStub);
const createEditResourceTab = rendererDi.inject(createEditResourceTabInjectable); const createEditResourceTab = windowDi.inject(createEditResourceTabInjectable);
createEditResourceTab(namespaceStub); createEditResourceTab(namespaceStub);
}); });

View File

@ -29,17 +29,17 @@ describe("cluster/namespaces - edit namespaces from previously opened tab", () =
callForNamespaceMock = asyncFn(); callForNamespaceMock = asyncFn();
builder.beforeApplicationStart(({ rendererDi }) => { builder.beforeWindowStart((windowDi) => {
rendererDi.override( windowDi.override(
directoryForLensLocalStorageInjectable, directoryForLensLocalStorageInjectable,
() => "/some-directory-for-lens-local-storage", () => "/some-directory-for-lens-local-storage",
); );
rendererDi.override(hostedClusterIdInjectable, () => "some-cluster-id"); windowDi.override(hostedClusterIdInjectable, () => "some-cluster-id");
storagesAreReady = controlWhenStoragesAreReady(rendererDi); storagesAreReady = controlWhenStoragesAreReady(windowDi);
rendererDi.override(callForResourceInjectable, () => callForNamespaceMock); windowDi.override(callForResourceInjectable, () => callForNamespaceMock);
}); });
builder.allowKubeResource("namespaces"); builder.allowKubeResource("namespaces");
@ -49,33 +49,35 @@ describe("cluster/namespaces - edit namespaces from previously opened tab", () =
let rendered: RenderResult; let rendered: RenderResult;
beforeEach(async () => { beforeEach(async () => {
const writeJsonFile = builder.dis.rendererDi.inject(writeJsonFileInjectable); builder.beforeWindowStart(async (windowDi) => {
const writeJsonFile = windowDi.inject(writeJsonFileInjectable);
await writeJsonFile( await writeJsonFile(
"/some-directory-for-lens-local-storage/some-cluster-id.json", "/some-directory-for-lens-local-storage/some-cluster-id.json",
{ {
dock: { dock: {
height: 300, height: 300,
tabs: [ tabs: [
{ {
id: "some-first-tab-id", id: "some-first-tab-id",
kind: TabKind.EDIT_RESOURCE, kind: TabKind.EDIT_RESOURCE,
title: "Namespace: some-namespace", title: "Namespace: some-namespace",
pinned: false, pinned: false,
},
],
isOpen: true,
},
edit_resource_store: {
"some-first-tab-id": {
resource: "/apis/some-api-version/namespaces/some-uid",
draft: "some-saved-configuration",
}, },
],
isOpen: true,
},
edit_resource_store: {
"some-first-tab-id": {
resource: "/apis/some-api-version/namespaces/some-uid",
draft: "some-saved-configuration",
}, },
}, },
}, );
); });
rendered = await builder.render(); rendered = await builder.render();

View File

@ -14,19 +14,21 @@ import { getApplicationBuilder } from "../../renderer/components/test-utils/get-
describe("cluster - order of sidebar items", () => { describe("cluster - order of sidebar items", () => {
let rendered: RenderResult; let rendered: RenderResult;
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
beforeEach(() => { beforeEach(() => {
applicationBuilder = getApplicationBuilder().setEnvironmentToClusterFrame(); builder = getApplicationBuilder();
applicationBuilder.beforeApplicationStart(({ rendererDi }) => { builder.setEnvironmentToClusterFrame();
rendererDi.register(testSidebarItemsInjectable);
builder.beforeWindowStart((windowDi) => {
windowDi.register(testSidebarItemsInjectable);
}); });
}); });
describe("when rendered", () => { describe("when rendered", () => {
beforeEach(async () => { beforeEach(async () => {
rendered = await applicationBuilder.render(); rendered = await builder.render();
}); });
it("renders", () => { it("renders", () => {

View File

@ -27,24 +27,21 @@ import { advanceFakeTime, useFakeTime } from "../../common/test-utils/use-fake-t
import storageSaveDelayInjectable from "../../renderer/utils/create-storage/storage-save-delay.injectable"; import storageSaveDelayInjectable from "../../renderer/utils/create-storage/storage-save-delay.injectable";
describe("cluster - sidebar and tab navigation for core", () => { describe("cluster - sidebar and tab navigation for core", () => {
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
let rendererDi: DiContainer;
let rendered: RenderResult; let rendered: RenderResult;
beforeEach(() => { beforeEach(() => {
useFakeTime("2015-10-21T07:28:00Z"); useFakeTime("2015-10-21T07:28:00Z");
applicationBuilder = getApplicationBuilder(); builder = getApplicationBuilder();
rendererDi = applicationBuilder.dis.rendererDi;
applicationBuilder.setEnvironmentToClusterFrame(); builder.setEnvironmentToClusterFrame();
applicationBuilder.beforeApplicationStart(({ rendererDi }) => { builder.beforeWindowStart((windowDi) => {
rendererDi.override(hostedClusterIdInjectable, () => "some-hosted-cluster-id"); windowDi.override(hostedClusterIdInjectable, () => "some-hosted-cluster-id");
windowDi.override(storageSaveDelayInjectable, () => 250);
rendererDi.override(storageSaveDelayInjectable, () => 250); windowDi.override(
rendererDi.override(
directoryForLensLocalStorageInjectable, directoryForLensLocalStorageInjectable,
() => "/some-directory-for-lens-local-storage", () => "/some-directory-for-lens-local-storage",
); );
@ -53,24 +50,23 @@ describe("cluster - sidebar and tab navigation for core", () => {
describe("given core registrations", () => { describe("given core registrations", () => {
beforeEach(() => { beforeEach(() => {
applicationBuilder.beforeApplicationStart(({ rendererDi }) => { builder.beforeWindowStart((windowDi) => {
rendererDi.register(testRouteInjectable); windowDi.register(testRouteInjectable);
rendererDi.register(testRouteComponentInjectable); windowDi.register(testRouteComponentInjectable);
rendererDi.register(testSidebarItemsInjectable); windowDi.register(testSidebarItemsInjectable);
}); });
}); });
describe("given no state for expanded sidebar items exists, and navigated to child sidebar item, when rendered", () => { describe("given no state for expanded sidebar items exists, and navigated to child sidebar item, when rendered", () => {
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.beforeRender(({ rendererDi }) => { rendered = await builder.render();
const route = rendererDi.inject(testRouteInjectable);
const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken); const windowDi = builder.applicationWindow.only.di;
navigateToRoute(route); const route = windowDi.inject(testRouteInjectable);
}); const navigateToRoute = windowDi.inject(navigateToRouteInjectionToken);
rendered = await applicationBuilder.render(); navigateToRoute(route);
}); });
it("renders", () => { it("renders", () => {
@ -96,8 +92,8 @@ describe("cluster - sidebar and tab navigation for core", () => {
describe("given state for expanded sidebar items already exists, when rendered", () => { describe("given state for expanded sidebar items already exists, when rendered", () => {
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.beforeRender(async ({ rendererDi }) => { builder.beforeWindowStart(async (windowDi) => {
const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable); const writeJsonFileFake = windowDi.inject(writeJsonFileInjectable);
await writeJsonFileFake( await writeJsonFileFake(
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json", "/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
@ -108,15 +104,13 @@ describe("cluster - sidebar and tab navigation for core", () => {
}, },
}, },
); );
});
applicationBuilder.beforeRender(async ({ rendererDi }) => { const sidebarStorage = windowDi.inject(sidebarStorageInjectable);
const sidebarStorage = rendererDi.inject(sidebarStorageInjectable);
await sidebarStorage.whenReady; await sidebarStorage.whenReady;
}); });
rendered = await applicationBuilder.render(); rendered = await builder.render();
}); });
it("renders", () => { it("renders", () => {
@ -138,8 +132,8 @@ describe("cluster - sidebar and tab navigation for core", () => {
describe("given state for expanded unknown sidebar items already exists, when rendered", () => { describe("given state for expanded unknown sidebar items already exists, when rendered", () => {
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.beforeRender(async ({ rendererDi }) => { builder.beforeWindowStart(async (windowDi) => {
const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable); const writeJsonFileFake = windowDi.inject(writeJsonFileInjectable);
await writeJsonFileFake( await writeJsonFileFake(
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json", "/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
@ -152,7 +146,7 @@ describe("cluster - sidebar and tab navigation for core", () => {
); );
}); });
rendered = await applicationBuilder.render(); rendered = await builder.render();
}); });
it("renders without errors", () => { it("renders without errors", () => {
@ -168,8 +162,8 @@ describe("cluster - sidebar and tab navigation for core", () => {
describe("given empty state for expanded sidebar items already exists, when rendered", () => { describe("given empty state for expanded sidebar items already exists, when rendered", () => {
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.beforeRender(async ({ rendererDi }) => { builder.beforeWindowStart(async (windowDi) => {
const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable); const writeJsonFileFake = windowDi.inject(writeJsonFileInjectable);
await writeJsonFileFake( await writeJsonFileFake(
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json", "/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
@ -179,7 +173,7 @@ describe("cluster - sidebar and tab navigation for core", () => {
); );
}); });
rendered = await applicationBuilder.render(); rendered = await builder.render();
}); });
it("renders without errors", () => { it("renders without errors", () => {
@ -194,8 +188,12 @@ describe("cluster - sidebar and tab navigation for core", () => {
}); });
describe("given no initially persisted state for sidebar items, when rendered", () => { describe("given no initially persisted state for sidebar items, when rendered", () => {
let windowDi: DiContainer;
beforeEach(async () => { beforeEach(async () => {
rendered = await applicationBuilder.render(); rendered = await builder.render();
windowDi = builder.applicationWindow.only.di;
}); });
it("renders", () => { it("renders", () => {
@ -271,7 +269,7 @@ describe("cluster - sidebar and tab navigation for core", () => {
it("when not enough time passes, does not store state for expanded sidebar items to file system yet", async () => { it("when not enough time passes, does not store state for expanded sidebar items to file system yet", async () => {
advanceFakeTime(250 - 1); advanceFakeTime(250 - 1);
const pathExistsFake = rendererDi.inject(pathExistsInjectable); const pathExistsFake = windowDi.inject(pathExistsInjectable);
const actual = await pathExistsFake( const actual = await pathExistsFake(
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json", "/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
@ -283,7 +281,7 @@ describe("cluster - sidebar and tab navigation for core", () => {
it("when enough time passes, stores state for expanded sidebar items to file system", async () => { it("when enough time passes, stores state for expanded sidebar items to file system", async () => {
advanceFakeTime(250); advanceFakeTime(250);
const readJsonFileFake = rendererDi.inject(readJsonFileInjectable); const readJsonFileFake = windowDi.inject(readJsonFileInjectable);
const actual = await readJsonFileFake( const actual = await readJsonFileFake(
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json", "/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",

View File

@ -13,35 +13,31 @@ import { getApplicationBuilder } from "../../renderer/components/test-utils/get-
import writeJsonFileInjectable from "../../common/fs/write-json-file.injectable"; import writeJsonFileInjectable from "../../common/fs/write-json-file.injectable";
import pathExistsInjectable from "../../common/fs/path-exists.injectable"; import pathExistsInjectable from "../../common/fs/path-exists.injectable";
import readJsonFileInjectable from "../../common/fs/read-json-file.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 { navigateToRouteInjectionToken } from "../../common/front-end-routing/navigate-to-route-injection-token";
import assert from "assert"; import assert from "assert";
import hostedClusterIdInjectable from "../../renderer/cluster-frame-context/hosted-cluster-id.injectable"; import hostedClusterIdInjectable from "../../renderer/cluster-frame-context/hosted-cluster-id.injectable";
import { advanceFakeTime, useFakeTime } from "../../common/test-utils/use-fake-time"; 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 type { IObservableValue } from "mobx";
import { runInAction, computed, observable } from "mobx"; import { runInAction, computed, observable } from "mobx";
import storageSaveDelayInjectable from "../../renderer/utils/create-storage/storage-save-delay.injectable"; import storageSaveDelayInjectable from "../../renderer/utils/create-storage/storage-save-delay.injectable";
import type { DiContainer } from "@ogre-tools/injectable";
describe("cluster - sidebar and tab navigation for extensions", () => { describe("cluster - sidebar and tab navigation for extensions", () => {
let applicationBuilder: ApplicationBuilder; let applicationBuilder: ApplicationBuilder;
let rendererDi: DiContainer;
let rendered: RenderResult; let rendered: RenderResult;
beforeEach(() => { beforeEach(() => {
useFakeTime("2015-10-21T07:28:00Z"); useFakeTime("2015-10-21T07:28:00Z");
applicationBuilder = getApplicationBuilder(); applicationBuilder = getApplicationBuilder();
rendererDi = applicationBuilder.dis.rendererDi;
applicationBuilder.setEnvironmentToClusterFrame(); applicationBuilder.setEnvironmentToClusterFrame();
applicationBuilder.beforeApplicationStart(({ rendererDi }) => { applicationBuilder.beforeWindowStart((windowDi) => {
rendererDi.override(hostedClusterIdInjectable, () => "some-hosted-cluster-id"); windowDi.override(hostedClusterIdInjectable, () => "some-hosted-cluster-id");
windowDi.override(storageSaveDelayInjectable, () => 250);
rendererDi.override(storageSaveDelayInjectable, () => 250); windowDi.override(
rendererDi.override(
directoryForLensLocalStorageInjectable, directoryForLensLocalStorageInjectable,
() => "/some-directory-for-lens-local-storage", () => "/some-directory-for-lens-local-storage",
); );
@ -54,9 +50,7 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
beforeEach(() => { beforeEach(() => {
someObservable = observable.box(false); someObservable = observable.box(false);
const getExtensionFake = getExtensionFakeFor(applicationBuilder); const testExtension = {
const testExtension = getExtensionFake({
id: "some-extension-id", id: "some-extension-id",
name: "some-extension-name", name: "some-extension-name",
@ -130,29 +124,31 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
}, },
], ],
}, },
}); };
applicationBuilder.extensions.enable(testExtension); applicationBuilder.extensions.enable(testExtension);
}); });
describe("given no state for expanded sidebar items exists, and navigated to child sidebar item, when rendered", () => { describe("given no state for expanded sidebar items exists, and navigated to child sidebar item, when rendered", () => {
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.beforeRender(({ rendererDi }) => {
const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken);
const route = rendererDi
.inject(routesInjectable)
.get()
.find(
matches({
path: "/extension/some-extension-name/some-child-page-id",
}),
);
assert(route);
navigateToRoute(route);
});
rendered = await applicationBuilder.render(); rendered = await applicationBuilder.render();
const windowDi = applicationBuilder.applicationWindow.only.di;
const navigateToRoute = windowDi.inject(navigateToRouteInjectionToken);
const route = windowDi
.inject(routesInjectable)
.get()
.find(
matches({
path: "/extension/some-extension-name/some-child-page-id",
}),
);
assert(route);
navigateToRoute(route);
}); });
it("renders", () => { it("renders", () => {
@ -178,8 +174,8 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
describe("given state for expanded sidebar items already exists, when rendered", () => { describe("given state for expanded sidebar items already exists, when rendered", () => {
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.beforeRender(async ({ rendererDi }) => { applicationBuilder.beforeWindowStart(async (windowDi) => {
const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable); const writeJsonFileFake = windowDi.inject(writeJsonFileInjectable);
await writeJsonFileFake( await writeJsonFileFake(
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json", "/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
@ -214,8 +210,8 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
describe("given state for expanded unknown sidebar items already exists, when rendered", () => { describe("given state for expanded unknown sidebar items already exists, when rendered", () => {
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.beforeRender(async ({ rendererDi }) => { applicationBuilder.beforeWindowStart(async (windowDi) => {
const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable); const writeJsonFileFake = windowDi.inject(writeJsonFileInjectable);
await writeJsonFileFake( await writeJsonFileFake(
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json", "/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
@ -244,8 +240,8 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
describe("given empty state for expanded sidebar items already exists, when rendered", () => { describe("given empty state for expanded sidebar items already exists, when rendered", () => {
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.beforeRender(async ({ rendererDi }) => { applicationBuilder.beforeWindowStart(async (windowDi) => {
const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable); const writeJsonFileFake = windowDi.inject(writeJsonFileInjectable);
await writeJsonFileFake( await writeJsonFileFake(
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json", "/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
@ -270,8 +266,12 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
}); });
describe("given no initially persisted state for sidebar items, when rendered", () => { describe("given no initially persisted state for sidebar items, when rendered", () => {
let windowDi: DiContainer;
beforeEach(async () => { beforeEach(async () => {
rendered = await applicationBuilder.render(); rendered = await applicationBuilder.render();
windowDi = applicationBuilder.applicationWindow.only.di;
}); });
it("renders", () => { it("renders", () => {
@ -387,7 +387,7 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
it("when not enough time passes, does not store state for expanded sidebar items to file system yet", async () => { it("when not enough time passes, does not store state for expanded sidebar items to file system yet", async () => {
advanceFakeTime(250 - 1); advanceFakeTime(250 - 1);
const pathExistsFake = rendererDi.inject(pathExistsInjectable); const pathExistsFake = windowDi.inject(pathExistsInjectable);
const actual = await pathExistsFake( const actual = await pathExistsFake(
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json", "/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
@ -399,7 +399,7 @@ describe("cluster - sidebar and tab navigation for extensions", () => {
it("when enough time passes, stores state for expanded sidebar items to file system", async () => { it("when enough time passes, stores state for expanded sidebar items to file system", async () => {
advanceFakeTime(250); advanceFakeTime(250);
const readJsonFileFake = rendererDi.inject(readJsonFileInjectable); const readJsonFileFake = windowDi.inject(readJsonFileInjectable);
const actual = await readJsonFileFake( const actual = await readJsonFileFake(
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json", "/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",

View File

@ -16,24 +16,24 @@ import { getApplicationBuilder } from "../../renderer/components/test-utils/get-
import { navigateToRouteInjectionToken } from "../../common/front-end-routing/navigate-to-route-injection-token"; import { navigateToRouteInjectionToken } from "../../common/front-end-routing/navigate-to-route-injection-token";
describe("cluster - visibility of sidebar items", () => { describe("cluster - visibility of sidebar items", () => {
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
let rendered: RenderResult; let rendered: RenderResult;
beforeEach(() => { beforeEach(() => {
applicationBuilder = getApplicationBuilder(); builder = getApplicationBuilder();
applicationBuilder.setEnvironmentToClusterFrame(); builder.setEnvironmentToClusterFrame();
applicationBuilder.beforeApplicationStart(({ rendererDi }) => { builder.beforeWindowStart((windowDi) => {
rendererDi.register(testRouteInjectable); windowDi.register(testRouteInjectable);
rendererDi.register(testRouteComponentInjectable); windowDi.register(testRouteComponentInjectable);
rendererDi.register(testSidebarItemsInjectable); windowDi.register(testSidebarItemsInjectable);
}); });
}); });
describe("given kube resource for route is not allowed", () => { describe("given kube resource for route is not allowed", () => {
beforeEach(async () => { beforeEach(async () => {
rendered = await applicationBuilder.render(); rendered = await builder.render();
}); });
it("renders", () => { it("renders", () => {
@ -48,7 +48,7 @@ describe("cluster - visibility of sidebar items", () => {
describe("when kube resource becomes allowed", () => { describe("when kube resource becomes allowed", () => {
beforeEach(() => { beforeEach(() => {
applicationBuilder.allowKubeResource("namespaces"); builder.allowKubeResource("namespaces");
}); });
it("renders", () => { it("renders", () => {

View File

@ -8,7 +8,6 @@ import type { RenderResult } from "@testing-library/react";
import type { ApplicationBuilder } from "../../../../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../../../../renderer/components/test-utils/get-application-builder";
import type { KubernetesCluster } from "../../../../../common/catalog-entities"; import type { KubernetesCluster } from "../../../../../common/catalog-entities";
import { getApplicationBuilder } from "../../../../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../../../../renderer/components/test-utils/get-application-builder";
import { getExtensionFakeFor } from "../../../../../renderer/components/test-utils/get-extension-fake";
import extensionShouldBeEnabledForClusterFrameInjectable from "../../../../../renderer/extension-loader/extension-should-be-enabled-for-cluster-frame.injectable"; import extensionShouldBeEnabledForClusterFrameInjectable from "../../../../../renderer/extension-loader/extension-should-be-enabled-for-cluster-frame.injectable";
import apiManagerInjectable from "../../../../../common/k8s-api/api-manager/manager.injectable"; import apiManagerInjectable from "../../../../../common/k8s-api/api-manager/manager.injectable";
import navigateToWorkloadsOverviewInjectable from "../../../../../common/front-end-routing/routes/cluster/workloads/overview/navigate-to-workloads-overview.injectable"; import navigateToWorkloadsOverviewInjectable from "../../../../../common/front-end-routing/routes/cluster/workloads/overview/navigate-to-workloads-overview.injectable";
@ -24,21 +23,19 @@ describe("disable workloads overview details when cluster is not relevant", () =
beforeEach(async () => { beforeEach(async () => {
builder = getApplicationBuilder(); builder = getApplicationBuilder();
builder.beforeApplicationStart(({ mainDi }) => { builder.setEnvironmentToClusterFrame();
builder.beforeApplicationStart((mainDi) => {
mainDi.override(apiManagerInjectable, () => ({})); mainDi.override(apiManagerInjectable, () => ({}));
}); });
const rendererDi = builder.dis.rendererDi; builder.beforeWindowStart((windowDi) => {
windowDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable);
rendererDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable); });
builder.setEnvironmentToClusterFrame();
const getExtensionFake = getExtensionFakeFor(builder);
isEnabledForClusterMock = asyncFn(); isEnabledForClusterMock = asyncFn();
const testExtension = getExtensionFake({ const testExtension = {
id: "test-extension-id", id: "test-extension-id",
name: "test-extension", name: "test-extension",
@ -55,11 +52,13 @@ describe("disable workloads overview details when cluster is not relevant", () =
}, },
], ],
}, },
}); };
rendered = await builder.render(); rendered = await builder.render();
const navigateToWorkloadsOverview = rendererDi.inject( const windowDi = builder.applicationWindow.only.di;
const navigateToWorkloadsOverview = windowDi.inject(
navigateToWorkloadsOverviewInjectable, navigateToWorkloadsOverviewInjectable,
); );

View File

@ -4,7 +4,6 @@
*/ */
import type { RenderResult } from "@testing-library/react"; import type { RenderResult } from "@testing-library/react";
import { getApplicationBuilder } from "../../../../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../../../../renderer/components/test-utils/get-application-builder";
import { getExtensionFakeFor } from "../../../../../renderer/components/test-utils/get-extension-fake";
import React from "react"; import React from "react";
import getRandomIdInjectable from "../../../../../common/utils/get-random-id.injectable"; import getRandomIdInjectable from "../../../../../common/utils/get-random-id.injectable";
import { workloadOverviewDetailInjectionToken } from "../../../../../renderer/components/+workloads-overview/workload-overview-details/workload-overview-detail-injection-token"; import { workloadOverviewDetailInjectionToken } from "../../../../../renderer/components/+workloads-overview/workload-overview-details/workload-overview-detail-injection-token";
@ -17,16 +16,22 @@ describe("order of workload overview details", () => {
beforeEach(async () => { beforeEach(async () => {
const builder = getApplicationBuilder(); const builder = getApplicationBuilder();
builder.beforeApplicationStart(({ rendererDi }) => { builder.beforeWindowStart((windowDi) => {
rendererDi.unoverride(getRandomIdInjectable); windowDi.unoverride(getRandomIdInjectable);
rendererDi.permitSideEffects(getRandomIdInjectable); windowDi.permitSideEffects(getRandomIdInjectable);
windowDi.register(
someCoreItemWithLowOrderNumberInjectable,
someCoreItemWithHighOrderNumberInjectable,
someCoreItemWithDefaultOrderNumberInjectable,
);
}); });
builder.setEnvironmentToClusterFrame(); builder.setEnvironmentToClusterFrame();
rendered = await builder.render(); rendered = await builder.render();
const testExtension = getExtensionFakeFor(builder)({ const testExtension = {
id: "some-extension-id", id: "some-extension-id",
name: "some-extension", name: "some-extension",
@ -66,16 +71,9 @@ describe("order of workload overview details", () => {
}, },
], ],
}, },
}); };
builder.extensions.enable(testExtension); builder.extensions.enable(testExtension);
builder.dis.rendererDi.register(
someCoreItemWithLowOrderNumberInjectable,
someCoreItemWithHighOrderNumberInjectable,
someCoreItemWithDefaultOrderNumberInjectable,
);
}); });
it("shows items in correct order", () => { it("shows items in correct order", () => {

View File

@ -9,7 +9,6 @@ import React from "react";
import navigateToWorkloadsOverviewInjectable from "../../../../../common/front-end-routing/routes/cluster/workloads/overview/navigate-to-workloads-overview.injectable"; import navigateToWorkloadsOverviewInjectable from "../../../../../common/front-end-routing/routes/cluster/workloads/overview/navigate-to-workloads-overview.injectable";
import type { ApplicationBuilder } from "../../../../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../../../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../../../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../../../../renderer/components/test-utils/get-application-builder";
import { getExtensionFakeFor } from "../../../../../renderer/components/test-utils/get-extension-fake";
describe("reactively hide workloads overview details item", () => { describe("reactively hide workloads overview details item", () => {
let builder: ApplicationBuilder; let builder: ApplicationBuilder;
@ -19,15 +18,11 @@ describe("reactively hide workloads overview details item", () => {
beforeEach(async () => { beforeEach(async () => {
builder = getApplicationBuilder(); builder = getApplicationBuilder();
const rendererDi = builder.dis.rendererDi;
builder.setEnvironmentToClusterFrame(); builder.setEnvironmentToClusterFrame();
const getExtensionFake = getExtensionFakeFor(builder);
someObservable = observable.box(false); someObservable = observable.box(false);
const testExtension = getExtensionFake({ const testExtension = {
id: "test-extension-id", id: "test-extension-id",
name: "test-extension", name: "test-extension",
@ -44,11 +39,13 @@ describe("reactively hide workloads overview details item", () => {
}, },
], ],
}, },
}); };
rendered = await builder.render(); rendered = await builder.render();
const navigateToWorkloadsOverview = rendererDi.inject( const windowDi = builder.applicationWindow.only.di;
const navigateToWorkloadsOverview = windowDi.inject(
navigateToWorkloadsOverviewInjectable, navigateToWorkloadsOverviewInjectable,
); );

View File

@ -9,17 +9,20 @@ import platformInjectable from "../../common/vars/platform.injectable";
import { type ApplicationBuilder, getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { type ApplicationBuilder, getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
describe("Command Pallet: keyboard shortcut tests", () => { describe("Command Pallet: keyboard shortcut tests", () => {
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
let rendered: RenderResult; let rendered: RenderResult;
beforeEach(async () => { beforeEach(async () => {
applicationBuilder = getApplicationBuilder(); builder = getApplicationBuilder();
}); });
describe("when on macOS", () => { describe("when on macOS", () => {
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.dis.rendererDi.override(platformInjectable, () => "darwin"); builder.beforeWindowStart((windowDi) => {
rendered = await applicationBuilder.render(); windowDi.override(platformInjectable, () => "darwin");
});
rendered = await builder.render();
}); });
it("renders", () => { it("renders", () => {
@ -83,8 +86,11 @@ describe("Command Pallet: keyboard shortcut tests", () => {
describe("when on linux", () => { describe("when on linux", () => {
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.dis.rendererDi.override(platformInjectable, () => "linux"); builder.beforeWindowStart((windowDi) => {
rendered = await applicationBuilder.render(); windowDi.override(platformInjectable, () => "linux");
});
rendered = await builder.render();
}); });
it("renders", () => { it("renders", () => {

View File

@ -2,30 +2,27 @@
* Copyright (c) OpenLens Authors. All rights reserved. * Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import type { FakeExtensionData, TestExtension } from "../renderer/components/test-utils/get-renderer-extension-fake";
import { getRendererExtensionFakeFor } from "../renderer/components/test-utils/get-renderer-extension-fake";
import React from "react"; import React from "react";
import type { RenderResult } from "@testing-library/react"; import type { RenderResult } from "@testing-library/react";
import currentPathInjectable from "../renderer/routes/current-path.injectable"; import currentPathInjectable from "../renderer/routes/current-path.injectable";
import type { ApplicationBuilder } from "../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../renderer/components/test-utils/get-application-builder";
import type { DiContainer } from "@ogre-tools/injectable";
import type { FakeExtensionOptions } from "../renderer/components/test-utils/get-extension-fake";
describe("extension special characters in page registrations", () => { describe("extension special characters in page registrations", () => {
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
let rendered: RenderResult; let rendered: RenderResult;
let testExtension: TestExtension; let windowDi: DiContainer;
beforeEach(async () => { beforeEach(async () => {
applicationBuilder = getApplicationBuilder(); builder = getApplicationBuilder();
const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder);
testExtension = getRendererExtensionFake( rendered = await builder.render();
extensionWithPagesHavingSpecialCharacters,
);
applicationBuilder.extensions.renderer.enable(testExtension); builder.extensions.enable(extensionWithPagesHavingSpecialCharacters);
rendered = await applicationBuilder.render(); windowDi = builder.applicationWindow.only.di;
}); });
it("renders", () => { it("renders", () => {
@ -34,6 +31,9 @@ describe("extension special characters in page registrations", () => {
describe("when navigating to route with ID having special characters", () => { describe("when navigating to route with ID having special characters", () => {
beforeEach(() => { beforeEach(() => {
const testExtension =
builder.extensions.get("some-extension-id").applicationWindows.only;
testExtension.navigate("/some-page-id/"); testExtension.navigate("/some-page-id/");
}); });
@ -42,22 +42,25 @@ describe("extension special characters in page registrations", () => {
}); });
it("knows URL", () => { it("knows URL", () => {
const currentPath = applicationBuilder.dis.rendererDi.inject(currentPathInjectable); const currentPath = windowDi.inject(currentPathInjectable);
expect(currentPath.get()).toBe("/extension/some-extension-name--/some-page-id"); expect(currentPath.get()).toBe("/extension/some-extension-name--/some-page-id");
}); });
}); });
}); });
const extensionWithPagesHavingSpecialCharacters: FakeExtensionData = { const extensionWithPagesHavingSpecialCharacters: FakeExtensionOptions = {
id: "some-extension-id", id: "some-extension-id",
name: "@some-extension-name/", name: "@some-extension-name/",
globalPages: [
{ rendererOptions: {
id: "/some-page-id/", globalPages: [
components: { {
Page: () => <div>Some page</div>, id: "/some-page-id/",
components: {
Page: () => <div>Some page</div>,
},
}, },
}, ],
], },
}; };

View File

@ -12,18 +12,20 @@ import focusWindowInjectable from "../../renderer/navigation/focus-window.inject
jest.mock("../../renderer/components/input/input"); jest.mock("../../renderer/components/input/input");
describe("extensions - navigation using application menu", () => { describe("extensions - navigation using application menu", () => {
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
let rendered: RenderResult; let rendered: RenderResult;
let focusWindowMock: jest.Mock; let focusWindowMock: jest.Mock;
beforeEach(async () => { beforeEach(async () => {
applicationBuilder = getApplicationBuilder().beforeApplicationStart(({ rendererDi }) => { builder = getApplicationBuilder();
builder.beforeWindowStart((windowDi) => {
focusWindowMock = jest.fn(); focusWindowMock = jest.fn();
rendererDi.override(focusWindowInjectable, () => focusWindowMock); windowDi.override(focusWindowInjectable, () => focusWindowMock);
}); });
rendered = await applicationBuilder.render(); rendered = await builder.render();
}); });
it("renders", () => { it("renders", () => {
@ -38,7 +40,7 @@ describe("extensions - navigation using application menu", () => {
describe("when navigating to extensions using application menu", () => { describe("when navigating to extensions using application menu", () => {
beforeEach(() => { beforeEach(() => {
applicationBuilder.applicationMenu.click("root.extensions"); builder.applicationMenu.click("root.extensions");
}); });
it("focuses the window", () => { it("focuses the window", () => {

View File

@ -19,7 +19,7 @@ import showErrorNotificationInjectable from "../../renderer/components/notificat
import type { AsyncResult } from "../../common/utils/async-result"; import type { AsyncResult } from "../../common/utils/async-result";
describe("add custom helm repository in preferences", () => { describe("add custom helm repository in preferences", () => {
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
let showSuccessNotificationMock: jest.Mock; let showSuccessNotificationMock: jest.Mock;
let showErrorNotificationMock: jest.Mock; let showErrorNotificationMock: jest.Mock;
let rendered: RenderResult; let rendered: RenderResult;
@ -31,41 +31,35 @@ describe("add custom helm repository in preferences", () => {
beforeEach(async () => { beforeEach(async () => {
jest.useFakeTimers(); jest.useFakeTimers();
applicationBuilder = getApplicationBuilder(); builder = getApplicationBuilder();
execFileMock = asyncFn(); execFileMock = asyncFn();
getActiveHelmRepositoriesMock = asyncFn(); getActiveHelmRepositoriesMock = asyncFn();
showSuccessNotificationMock = jest.fn();
showErrorNotificationMock = jest.fn();
applicationBuilder.beforeApplicationStart(({ mainDi, rendererDi }) => { builder.beforeApplicationStart((mainDi) => {
rendererDi.override(callForPublicHelmRepositoriesInjectable, () => async () => []); mainDi.override(getActiveHelmRepositoriesInjectable, () => getActiveHelmRepositoriesMock);
showSuccessNotificationMock = jest.fn();
rendererDi.override(showSuccessNotificationInjectable, () => showSuccessNotificationMock);
showErrorNotificationMock = jest.fn();
rendererDi.override(showErrorNotificationInjectable, () => showErrorNotificationMock);
// TODO: Figure out how to make async validators unit testable
rendererDi.override(isPathInjectable, () => ({ debounce: 0, validate: async () => {} }));
mainDi.override(
getActiveHelmRepositoriesInjectable,
() => getActiveHelmRepositoriesMock,
);
mainDi.override(execFileInjectable, () => execFileMock); mainDi.override(execFileInjectable, () => execFileMock);
mainDi.override(helmBinaryPathInjectable, () => "some-helm-binary-path"); mainDi.override(helmBinaryPathInjectable, () => "some-helm-binary-path");
}); });
rendered = await applicationBuilder.render(); builder.beforeWindowStart((windowDi) => {
windowDi.override(callForPublicHelmRepositoriesInjectable, () => async () => []);
windowDi.override(showSuccessNotificationInjectable, () => showSuccessNotificationMock);
windowDi.override(showErrorNotificationInjectable, () => showErrorNotificationMock);
// TODO: Figure out how to make async validators unit testable
windowDi.override(isPathInjectable, () => ({ debounce: 0, validate: async () => {} }));
});
rendered = await builder.render();
}); });
describe("when navigating to preferences containing helm repositories", () => { describe("when navigating to preferences containing helm repositories", () => {
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.preferences.navigate(); builder.preferences.navigate();
applicationBuilder.preferences.navigation.click("kubernetes"); builder.preferences.navigation.click("kubernetes");
}); });
it("renders", () => { it("renders", () => {

View File

@ -17,7 +17,7 @@ import showErrorNotificationInjectable from "../../renderer/components/notificat
import type { AsyncResult } from "../../common/utils/async-result"; import type { AsyncResult } from "../../common/utils/async-result";
describe("add helm repository from list in preferences", () => { describe("add helm repository from list in preferences", () => {
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
let showSuccessNotificationMock: jest.Mock; let showSuccessNotificationMock: jest.Mock;
let showErrorNotificationMock: jest.Mock; let showErrorNotificationMock: jest.Mock;
let rendered: RenderResult; let rendered: RenderResult;
@ -28,41 +28,33 @@ describe("add helm repository from list in preferences", () => {
let callForPublicHelmRepositoriesMock: AsyncFnMock<() => Promise<HelmRepo[]>>; let callForPublicHelmRepositoriesMock: AsyncFnMock<() => Promise<HelmRepo[]>>;
beforeEach(async () => { beforeEach(async () => {
applicationBuilder = getApplicationBuilder(); builder = getApplicationBuilder();
execFileMock = asyncFn(); execFileMock = asyncFn();
getActiveHelmRepositoriesMock = asyncFn(); getActiveHelmRepositoriesMock = asyncFn();
callForPublicHelmRepositoriesMock = asyncFn(); callForPublicHelmRepositoriesMock = asyncFn();
showSuccessNotificationMock = jest.fn();
showErrorNotificationMock = jest.fn();
applicationBuilder.beforeApplicationStart(({ mainDi, rendererDi }) => { builder.beforeApplicationStart((mainDi) => {
showSuccessNotificationMock = jest.fn(); mainDi.override(getActiveHelmRepositoriesInjectable, () => getActiveHelmRepositoriesMock);
rendererDi.override(showSuccessNotificationInjectable, () => showSuccessNotificationMock);
showErrorNotificationMock = jest.fn();
rendererDi.override(showErrorNotificationInjectable, () => showErrorNotificationMock);
rendererDi.override(
callForPublicHelmRepositoriesInjectable,
() => callForPublicHelmRepositoriesMock,
);
mainDi.override(
getActiveHelmRepositoriesInjectable,
() => getActiveHelmRepositoriesMock,
);
mainDi.override(execFileInjectable, () => execFileMock); mainDi.override(execFileInjectable, () => execFileMock);
mainDi.override(helmBinaryPathInjectable, () => "some-helm-binary-path"); mainDi.override(helmBinaryPathInjectable, () => "some-helm-binary-path");
}); });
rendered = await applicationBuilder.render(); builder.beforeWindowStart((windowDi) => {
windowDi.override(showSuccessNotificationInjectable, () => showSuccessNotificationMock);
windowDi.override(showErrorNotificationInjectable, () => showErrorNotificationMock);
windowDi.override(callForPublicHelmRepositoriesInjectable, () => callForPublicHelmRepositoriesMock);
});
rendered = await builder.render();
}); });
describe("when navigating to preferences containing helm repositories", () => { describe("when navigating to preferences containing helm repositories", () => {
beforeEach(async () => { beforeEach(() => {
applicationBuilder.preferences.navigate(); builder.preferences.navigate();
applicationBuilder.preferences.navigation.click("kubernetes"); builder.preferences.navigation.click("kubernetes");
}); });
it("renders", () => { it("renders", () => {
@ -100,7 +92,7 @@ describe("add helm repository from list in preferences", () => {
describe("when select for adding public repositories is clicked", () => { describe("when select for adding public repositories is clicked", () => {
beforeEach(() => { beforeEach(() => {
applicationBuilder.select.openMenu( builder.select.openMenu(
"selection-of-active-public-helm-repository", "selection-of-active-public-helm-repository",
); );
}); });
@ -113,7 +105,7 @@ describe("add helm repository from list in preferences", () => {
beforeEach(async () => { beforeEach(async () => {
getActiveHelmRepositoriesMock.mockClear(); getActiveHelmRepositoriesMock.mockClear();
applicationBuilder.select.selectOption( builder.select.selectOption(
"selection-of-active-public-helm-repository", "selection-of-active-public-helm-repository",
"Some to be added repository", "Some to be added repository",
); );
@ -207,7 +199,7 @@ describe("add helm repository from list in preferences", () => {
describe("when select for selecting active repositories is clicked", () => { describe("when select for selecting active repositories is clicked", () => {
beforeEach(() => { beforeEach(() => {
applicationBuilder.select.openMenu( builder.select.openMenu(
"selection-of-active-public-helm-repository", "selection-of-active-public-helm-repository",
); );
}); });
@ -221,7 +213,7 @@ describe("add helm repository from list in preferences", () => {
execFileMock.mockClear(); execFileMock.mockClear();
getActiveHelmRepositoriesMock.mockClear(); getActiveHelmRepositoriesMock.mockClear();
applicationBuilder.select.selectOption( builder.select.selectOption(
"selection-of-active-public-helm-repository", "selection-of-active-public-helm-repository",
"Some already active repository", "Some already active repository",
); );

View File

@ -1,6 +1,448 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started, when navigating to helm charts renders 1`] = ` exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started renders 1`] = `
<body>
<div>
<div
class="Notifications flex column align-flex-end"
/>
<div
class="mainLayout"
style="--sidebar-width: 200px;"
>
<div
class="sidebar"
>
<div
class="flex flex-col"
data-testid="cluster-sidebar"
>
<div
class="SidebarCluster"
>
<div
class="Avatar rounded loadingAvatar"
style="width: 40px; height: 40px;"
>
??
</div>
<div
class="loadingClusterName"
/>
</div>
<div
class="sidebarNav sidebar-active-status"
>
<div
class="SidebarItem"
data-is-active-test="true"
data-testid="sidebar-item-workloads"
>
<a
aria-current="page"
class="nav-item flex gaps align-center expandable active"
data-testid="sidebar-item-link-for-workloads"
href="/"
>
<i
class="Icon svg focusable"
>
<span
class="icon"
/>
</i>
<span
class="link-text box grow"
>
Workloads
</span>
<i
class="Icon expand-icon box right material focusable"
>
<span
class="icon"
data-icon-name="keyboard_arrow_down"
>
keyboard_arrow_down
</span>
</i>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-config"
>
<a
class="nav-item flex gaps align-center"
data-testid="sidebar-item-link-for-config"
href="/"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="list"
>
list
</span>
</i>
<span
class="link-text box grow"
>
Config
</span>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-network"
>
<a
class="nav-item flex gaps align-center expandable"
data-testid="sidebar-item-link-for-network"
href="/"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="device_hub"
>
device_hub
</span>
</i>
<span
class="link-text box grow"
>
Network
</span>
<i
class="Icon expand-icon box right material focusable"
>
<span
class="icon"
data-icon-name="keyboard_arrow_down"
>
keyboard_arrow_down
</span>
</i>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-storage"
>
<a
class="nav-item flex gaps align-center"
data-testid="sidebar-item-link-for-storage"
href="/"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="storage"
>
storage
</span>
</i>
<span
class="link-text box grow"
>
Storage
</span>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-helm"
>
<a
class="nav-item flex gaps align-center expandable"
data-testid="sidebar-item-link-for-helm"
href="/"
>
<i
class="Icon svg focusable"
>
<span
class="icon"
/>
</i>
<span
class="link-text box grow"
>
Helm
</span>
<i
class="Icon expand-icon box right material focusable"
>
<span
class="icon"
data-icon-name="keyboard_arrow_down"
>
keyboard_arrow_down
</span>
</i>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-user-management"
>
<a
class="nav-item flex gaps align-center"
data-testid="sidebar-item-link-for-user-management"
href="/"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="security"
>
security
</span>
</i>
<span
class="link-text box grow"
>
Access Control
</span>
</a>
</div>
<div
class="SidebarItem"
data-is-active-test="false"
data-testid="sidebar-item-custom-resources"
>
<a
class="nav-item flex gaps align-center expandable"
data-testid="sidebar-item-link-for-custom-resources"
href="/"
>
<i
class="Icon material focusable"
>
<span
class="icon"
data-icon-name="extension"
>
extension
</span>
</i>
<span
class="link-text box grow"
>
Custom Resources
</span>
<i
class="Icon expand-icon box right material focusable"
>
<span
class="icon"
data-icon-name="keyboard_arrow_down"
>
keyboard_arrow_down
</span>
</i>
</a>
</div>
</div>
</div>
<div
class="ResizingAnchor horizontal trailing"
/>
</div>
<div
class="contents"
>
<div
class="TabLayout"
data-testid="tab-layout"
>
<div
class="Tabs center scrollable"
>
<div
class="Tab flex gaps align-center active"
data-is-active-test="true"
data-testid="tab-link-for-overview"
role="tab"
tabindex="0"
>
<div
class="label"
>
Overview
</div>
</div>
</div>
<main>
<div
class="WorkloadsOverview flex column gaps"
>
<div
class="header flex gaps align-center"
>
<h5
class="box grow"
>
Overview
</h5>
<div
class="NamespaceSelectFilterParent"
data-testid="namespace-select-filter"
>
<div
class="Select theme-dark NamespaceSelect NamespaceSelectFilter css-b62m3t-container"
>
<span
class="css-1f43avz-a11yText-A11yText"
id="react-select-overview-namespace-select-filter-input-live-region"
/>
<span
aria-atomic="false"
aria-live="polite"
aria-relevant="additions text"
class="css-1f43avz-a11yText-A11yText"
/>
<div
class="Select__control css-1s2u09g-control"
>
<div
class="Select__value-container Select__value-container--is-multi css-319lph-ValueContainer"
>
<div
class="Select__placeholder css-14el2xx-placeholder"
id="react-select-overview-namespace-select-filter-input-placeholder"
>
All namespaces
</div>
<div
class="Select__input-container css-6j8wv5-Input"
data-value=""
>
<input
aria-autocomplete="list"
aria-describedby="react-select-overview-namespace-select-filter-input-placeholder"
aria-expanded="false"
aria-haspopup="true"
autocapitalize="none"
autocomplete="off"
autocorrect="off"
class="Select__input"
id="overview-namespace-select-filter-input"
role="combobox"
spellcheck="false"
style="opacity: 1; width: 100%; grid-area: 1 / 2; min-width: 2px; border: 0px; margin: 0px; outline: 0; padding: 0px;"
tabindex="0"
type="text"
value=""
/>
</div>
</div>
<div
class="Select__indicators css-1hb7zxy-IndicatorsContainer"
>
<span
class="Select__indicator-separator css-1okebmr-indicatorSeparator"
/>
<div
aria-hidden="true"
class="Select__indicator Select__dropdown-indicator css-tlfecz-indicatorContainer"
>
<svg
aria-hidden="true"
class="css-tj5bde-Svg"
focusable="false"
height="20"
viewBox="0 0 20 20"
width="20"
>
<path
d="M4.516 7.548c0.436-0.446 1.043-0.481 1.576 0l3.908 3.747 3.908-3.747c0.533-0.481 1.141-0.446 1.574 0 0.436 0.445 0.408 1.197 0 1.615-0.406 0.418-4.695 4.502-4.695 4.502-0.217 0.223-0.502 0.335-0.787 0.335s-0.57-0.112-0.789-0.335c0 0-4.287-4.084-4.695-4.502s-0.436-1.17 0-1.615z"
/>
</svg>
</div>
</div>
</div>
</div>
</div>
</div>
<div
class="OverviewStatuses"
>
<div
class="workloads"
/>
</div>
</div>
</main>
</div>
</div>
<div
class="footer"
>
<div
class="Dock"
tabindex="-1"
>
<div
class="ResizingAnchor vertical leading disabled"
/>
<div
class="tabs-container flex align-center"
>
<div
class="dockTabs"
role="tablist"
>
<div
class="Tabs tabs"
/>
</div>
<div
class="toolbar flex gaps align-center box grow pl-0"
>
<div
class="dock-menu box grow"
>
<i
class="Icon new-dock-tab material interactive focusable"
id="menu-actions-for-dock"
tabindex="0"
>
<span
class="icon"
data-icon-name="add"
>
add
</span>
</i>
<div>
New tab
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</body>
`;
exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started when navigating to helm charts renders 1`] = `
<body> <body>
<div> <div>
<div <div
@ -927,7 +1369,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
</body> </body>
`; `;
exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started, when navigating to helm charts when selecting to install the chart renders 1`] = ` exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started when navigating to helm charts when selecting to install the chart renders 1`] = `
<body> <body>
<div> <div>
<div <div
@ -1696,7 +2138,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
</body> </body>
`; `;
exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started, when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given changing version to be installed renders 1`] = ` exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given changing version to be installed renders 1`] = `
<body> <body>
<div> <div>
<div <div
@ -2709,7 +3151,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
</body> </body>
`; `;
exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started, when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given changing version to be installed when version is selected renders 1`] = ` exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given changing version to be installed when version is selected renders 1`] = `
<body> <body>
<div> <div>
<div <div
@ -3696,7 +4138,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
</body> </body>
`; `;
exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started, when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given changing version to be installed when version is selected when default configuration resolves renders 1`] = ` exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given changing version to be installed when version is selected when default configuration resolves renders 1`] = `
<body> <body>
<div> <div>
<div <div
@ -4678,7 +5120,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
</body> </body>
`; `;
exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started, when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given custom name is inputted renders 1`] = ` exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given custom name is inputted renders 1`] = `
<body> <body>
<div> <div>
<div <div
@ -5660,7 +6102,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
</body> </body>
`; `;
exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started, when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given invalid change in configuration renders 1`] = ` exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given invalid change in configuration renders 1`] = `
<body> <body>
<div> <div>
<div <div
@ -6664,7 +7106,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
</body> </body>
`; `;
exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started, when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given namespace selection is opened renders 1`] = ` exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given namespace selection is opened renders 1`] = `
<body> <body>
<div> <div>
<div <div
@ -7677,7 +8119,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
</body> </body>
`; `;
exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started, when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given namespace selection is opened when namespace is selected renders 1`] = ` exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given namespace selection is opened when namespace is selected renders 1`] = `
<body> <body>
<div> <div>
<div <div
@ -8659,7 +9101,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
</body> </body>
`; `;
exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started, when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given no changes in configuration, when installing the chart renders 1`] = ` exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given no changes in configuration, when installing the chart renders 1`] = `
<body> <body>
<div> <div>
<div <div
@ -9649,7 +10091,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
</body> </body>
`; `;
exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started, when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given no changes in configuration, when installing the chart when installation resolves renders 1`] = ` exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given no changes in configuration, when installing the chart when installation resolves renders 1`] = `
<body> <body>
<div> <div>
<div <div
@ -10498,7 +10940,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
</body> </body>
`; `;
exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started, when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given no changes in configuration, when installing the chart when installation resolves when selected to see the installed release renders 1`] = ` exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given no changes in configuration, when installing the chart when installation resolves when selected to see the installed release renders 1`] = `
<body> <body>
<div> <div>
<div <div
@ -11271,7 +11713,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
</body> </body>
`; `;
exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started, when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given no changes in configuration, when installing the chart when installation resolves when selected to show execution output renders 1`] = ` exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given no changes in configuration, when installing the chart when installation resolves when selected to show execution output renders 1`] = `
<body> <body>
<div> <div>
<div <div
@ -12180,7 +12622,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
</body> </body>
`; `;
exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started, when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given opening details for second chart, when details resolve renders 1`] = ` exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given opening details for second chart, when details resolve renders 1`] = `
<body> <body>
<div> <div>
<div <div
@ -13408,7 +13850,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
</body> </body>
`; `;
exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started, when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given opening details for second chart, when details resolve when selecting to install second chart renders 1`] = ` exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given opening details for second chart, when details resolve when selecting to install second chart renders 1`] = `
<body> <body>
<div> <div>
<div <div
@ -14226,7 +14668,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
</body> </body>
`; `;
exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started, when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given opening details for second chart, when details resolve when selecting to install second chart when configuration and versions resolve renders 1`] = ` exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given opening details for second chart, when details resolve when selecting to install second chart when configuration and versions resolve renders 1`] = `
<body> <body>
<div> <div>
<div <div
@ -15259,7 +15701,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
</body> </body>
`; `;
exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started, when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given opening details for second chart, when details resolve when selecting to install second chart when configuration and versions resolve when selecting the dock tab for installing first chart renders 1`] = ` exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given opening details for second chart, when details resolve when selecting to install second chart when configuration and versions resolve when selecting the dock tab for installing first chart renders 1`] = `
<body> <body>
<div> <div>
<div <div
@ -16290,7 +16732,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
</body> </body>
`; `;
exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started, when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given valid change in configuration renders 1`] = ` exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started when navigating to helm charts when selecting to install the chart when default configuration and versions resolve given valid change in configuration renders 1`] = `
<body> <body>
<div> <div>
<div <div
@ -17272,7 +17714,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
</body> </body>
`; `;
exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started, when navigating to helm charts when selecting to install the chart when default configuration and versions resolve renders 1`] = ` exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started when navigating to helm charts when selecting to install the chart when default configuration and versions resolve renders 1`] = `
<body> <body>
<div> <div>
<div <div
@ -18254,7 +18696,7 @@ exports[`installing helm chart from new tab given tab for installing chart was n
</body> </body>
`; `;
exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started, when navigating to helm charts when selecting to install the chart when default configuration and versions resolve when cancelled renders 1`] = ` exports[`installing helm chart from new tab given tab for installing chart was not previously opened and application is started when navigating to helm charts when selecting to install the chart when default configuration and versions resolve when cancelled renders 1`] = `
<body> <body>
<div> <div>
<div <div

View File

@ -15,18 +15,15 @@ import namespaceStoreInjectable from "../../../renderer/components/+namespaces/s
import type { NamespaceStore } from "../../../renderer/components/+namespaces/store"; import type { NamespaceStore } from "../../../renderer/components/+namespaces/store";
import type { CallForHelmChartVersions } from "../../../renderer/components/+helm-charts/details/versions/call-for-helm-chart-versions.injectable"; import type { CallForHelmChartVersions } from "../../../renderer/components/+helm-charts/details/versions/call-for-helm-chart-versions.injectable";
import callForHelmChartVersionsInjectable from "../../../renderer/components/+helm-charts/details/versions/call-for-helm-chart-versions.injectable"; import callForHelmChartVersionsInjectable from "../../../renderer/components/+helm-charts/details/versions/call-for-helm-chart-versions.injectable";
import { overrideFsWithFakes } from "../../../test-utils/override-fs-with-fakes";
import writeJsonFileInjectable from "../../../common/fs/write-json-file.injectable"; import writeJsonFileInjectable from "../../../common/fs/write-json-file.injectable";
import directoryForLensLocalStorageInjectable from "../../../common/directory-for-lens-local-storage/directory-for-lens-local-storage.injectable"; import directoryForLensLocalStorageInjectable from "../../../common/directory-for-lens-local-storage/directory-for-lens-local-storage.injectable";
import hostedClusterIdInjectable from "../../../renderer/cluster-frame-context/hosted-cluster-id.injectable"; import hostedClusterIdInjectable from "../../../renderer/cluster-frame-context/hosted-cluster-id.injectable";
import { TabKind } from "../../../renderer/components/dock/dock/store"; import { TabKind } from "../../../renderer/components/dock/dock/store";
import { controlWhenStoragesAreReady } from "../../../renderer/utils/create-storage/storages-are-ready"; import { controlWhenStoragesAreReady } from "../../../renderer/utils/create-storage/storages-are-ready";
import type { DiContainer } from "@ogre-tools/injectable";
import callForCreateHelmReleaseInjectable from "../../../renderer/components/+helm-releases/create-release/call-for-create-helm-release.injectable"; import callForCreateHelmReleaseInjectable from "../../../renderer/components/+helm-releases/create-release/call-for-create-helm-release.injectable";
describe("installing helm chart from previously opened tab", () => { describe("installing helm chart from previously opened tab", () => {
let builder: ApplicationBuilder; let builder: ApplicationBuilder;
let rendererDi: DiContainer;
let callForHelmChartVersionsMock: AsyncFnMock<CallForHelmChartVersions>; let callForHelmChartVersionsMock: AsyncFnMock<CallForHelmChartVersions>;
let callForHelmChartValuesMock: AsyncFnMock<CallForHelmChartValues>; let callForHelmChartValuesMock: AsyncFnMock<CallForHelmChartValues>;
let storagesAreReady: () => Promise<void>; let storagesAreReady: () => Promise<void>;
@ -34,45 +31,43 @@ describe("installing helm chart from previously opened tab", () => {
beforeEach(() => { beforeEach(() => {
builder = getApplicationBuilder(); builder = getApplicationBuilder();
rendererDi = builder.dis.rendererDi; builder.setEnvironmentToClusterFrame();
overrideFsWithFakes(rendererDi);
callForHelmChartVersionsMock = asyncFn(); callForHelmChartVersionsMock = asyncFn();
callForHelmChartValuesMock = asyncFn(); callForHelmChartValuesMock = asyncFn();
builder.beforeApplicationStart(({ rendererDi }) => { builder.beforeWindowStart((windowDi) => {
rendererDi.override( windowDi.override(
directoryForLensLocalStorageInjectable, directoryForLensLocalStorageInjectable,
() => "/some-directory-for-lens-local-storage", () => "/some-directory-for-lens-local-storage",
); );
rendererDi.override(hostedClusterIdInjectable, () => "some-cluster-id"); windowDi.override(hostedClusterIdInjectable, () => "some-cluster-id");
storagesAreReady = controlWhenStoragesAreReady(rendererDi); storagesAreReady = controlWhenStoragesAreReady(windowDi);
rendererDi.override( windowDi.override(
callForHelmChartVersionsInjectable, callForHelmChartVersionsInjectable,
() => callForHelmChartVersionsMock, () => callForHelmChartVersionsMock,
); );
rendererDi.override( windowDi.override(
callForHelmChartValuesInjectable, callForHelmChartValuesInjectable,
() => callForHelmChartValuesMock, () => callForHelmChartValuesMock,
); );
rendererDi.override( windowDi.override(
callForHelmChartValuesInjectable, callForHelmChartValuesInjectable,
() => callForHelmChartValuesMock, () => callForHelmChartValuesMock,
); );
rendererDi.override( windowDi.override(
callForCreateHelmReleaseInjectable, callForCreateHelmReleaseInjectable,
() => jest.fn(), () => jest.fn(),
); );
// TODO: Replace store mocking with mock for the actual side-effect (where the namespaces are coming from) // TODO: Replace store mocking with mock for the actual side-effect (where the namespaces are coming from)
rendererDi.override( windowDi.override(
namespaceStoreInjectable, namespaceStoreInjectable,
() => () =>
({ ({
@ -85,51 +80,51 @@ describe("installing helm chart from previously opened tab", () => {
} as unknown as NamespaceStore), } as unknown as NamespaceStore),
); );
rendererDi.override(getRandomInstallChartTabIdInjectable, () => windowDi.override(getRandomInstallChartTabIdInjectable, () =>
jest jest
.fn(() => "some-irrelevant-tab-id") .fn(() => "some-irrelevant-tab-id")
.mockReturnValueOnce("some-first-tab-id"), .mockReturnValueOnce("some-first-tab-id"),
); );
}); });
builder.setEnvironmentToClusterFrame();
}); });
describe("given tab for installing chart was previously opened, when application is started", () => { describe("given tab for installing chart was previously opened, when application is started", () => {
let rendered: RenderResult; let rendered: RenderResult;
beforeEach(async () => { beforeEach(async () => {
const writeJsonFile = rendererDi.inject(writeJsonFileInjectable); builder.beforeWindowStart(async (windowDi) => {
const writeJsonFile = windowDi.inject(writeJsonFileInjectable);
writeJsonFile( await writeJsonFile(
"/some-directory-for-lens-local-storage/some-cluster-id.json", "/some-directory-for-lens-local-storage/some-cluster-id.json",
{ {
dock: { dock: {
height: 300, height: 300,
tabs: [ tabs: [
{ {
id: "some-first-tab-id", id: "some-first-tab-id",
kind: TabKind.INSTALL_CHART, kind: TabKind.INSTALL_CHART,
title: "Helm Install: some-repository/some-name", title: "Helm Install: some-repository/some-name",
pinned: false, pinned: false,
},
],
isOpen: true,
},
install_charts: {
"some-first-tab-id": {
name: "some-name",
repo: "some-repository",
version: "some-other-version",
values: "some-stored-configuration",
releaseName: "some-stored-custom-name",
namespace: "some-other-namespace",
}, },
],
isOpen: true,
},
install_charts: {
"some-first-tab-id": {
name: "some-name",
repo: "some-repository",
version: "some-other-version",
values: "some-stored-configuration",
releaseName: "some-stored-custom-name",
namespace: "some-other-namespace",
}, },
}, },
}, );
); });
rendered = await builder.render(); rendered = await builder.render();

View File

@ -19,15 +19,12 @@ import callForHelmChartReadmeInjectable from "../../../renderer/components/+helm
import type { CallForHelmChartVersions } from "../../../renderer/components/+helm-charts/details/versions/call-for-helm-chart-versions.injectable"; import type { CallForHelmChartVersions } from "../../../renderer/components/+helm-charts/details/versions/call-for-helm-chart-versions.injectable";
import callForHelmChartVersionsInjectable from "../../../renderer/components/+helm-charts/details/versions/call-for-helm-chart-versions.injectable"; import callForHelmChartVersionsInjectable from "../../../renderer/components/+helm-charts/details/versions/call-for-helm-chart-versions.injectable";
import { flushPromises } from "../../../common/test-utils/flush-promises"; import { flushPromises } from "../../../common/test-utils/flush-promises";
import { overrideFsWithFakes } from "../../../test-utils/override-fs-with-fakes";
import directoryForLensLocalStorageInjectable from "../../../common/directory-for-lens-local-storage/directory-for-lens-local-storage.injectable"; import directoryForLensLocalStorageInjectable from "../../../common/directory-for-lens-local-storage/directory-for-lens-local-storage.injectable";
import hostedClusterIdInjectable from "../../../renderer/cluster-frame-context/hosted-cluster-id.injectable"; import hostedClusterIdInjectable from "../../../renderer/cluster-frame-context/hosted-cluster-id.injectable";
import dockStoreInjectable from "../../../renderer/components/dock/dock/store.injectable"; import dockStoreInjectable from "../../../renderer/components/dock/dock/store.injectable";
import type { DiContainer } from "@ogre-tools/injectable";
describe("opening dock tab for installing helm chart", () => { describe("opening dock tab for installing helm chart", () => {
let builder: ApplicationBuilder; let builder: ApplicationBuilder;
let rendererDi: DiContainer;
let callForHelmChartsMock: AsyncFnMock<CallForHelmCharts>; let callForHelmChartsMock: AsyncFnMock<CallForHelmCharts>;
let callForHelmChartVersionsMock: AsyncFnMock<CallForHelmChartVersions>; let callForHelmChartVersionsMock: AsyncFnMock<CallForHelmChartVersions>;
let callForHelmChartReadmeMock: AsyncFnMock<CallForHelmChartReadme>; let callForHelmChartReadmeMock: AsyncFnMock<CallForHelmChartReadme>;
@ -36,49 +33,45 @@ describe("opening dock tab for installing helm chart", () => {
beforeEach(() => { beforeEach(() => {
builder = getApplicationBuilder(); builder = getApplicationBuilder();
rendererDi = builder.dis.rendererDi;
overrideFsWithFakes(rendererDi);
callForHelmChartsMock = asyncFn(); callForHelmChartsMock = asyncFn();
callForHelmChartVersionsMock = asyncFn(); callForHelmChartVersionsMock = asyncFn();
callForHelmChartReadmeMock = asyncFn(); callForHelmChartReadmeMock = asyncFn();
callForHelmChartValuesMock = jest.fn(); callForHelmChartValuesMock = jest.fn();
builder.beforeApplicationStart(({ rendererDi }) => { builder.beforeWindowStart((windowDi) => {
rendererDi.override( windowDi.override(
directoryForLensLocalStorageInjectable, directoryForLensLocalStorageInjectable,
() => "/some-directory-for-lens-local-storage", () => "/some-directory-for-lens-local-storage",
); );
rendererDi.override(hostedClusterIdInjectable, () => "some-cluster-id"); windowDi.override(hostedClusterIdInjectable, () => "some-cluster-id");
rendererDi.override( windowDi.override(
callForHelmChartsInjectable, callForHelmChartsInjectable,
() => callForHelmChartsMock, () => callForHelmChartsMock,
); );
rendererDi.override( windowDi.override(
callForHelmChartVersionsInjectable, callForHelmChartVersionsInjectable,
() => callForHelmChartVersionsMock, () => callForHelmChartVersionsMock,
); );
rendererDi.override( windowDi.override(
callForHelmChartReadmeInjectable, callForHelmChartReadmeInjectable,
() => callForHelmChartReadmeMock, () => callForHelmChartReadmeMock,
); );
rendererDi.override( windowDi.override(
callForHelmChartValuesInjectable, callForHelmChartValuesInjectable,
() => callForHelmChartValuesMock, () => callForHelmChartValuesMock,
); );
rendererDi.override( windowDi.override(
callForCreateHelmReleaseInjectable, callForCreateHelmReleaseInjectable,
() => jest.fn(), () => jest.fn(),
); );
rendererDi.override(getRandomInstallChartTabIdInjectable, () => windowDi.override(getRandomInstallChartTabIdInjectable, () =>
jest jest
.fn(() => "some-irrelevant-tab-id") .fn(() => "some-irrelevant-tab-id")
.mockReturnValueOnce("some-tab-id"), .mockReturnValueOnce("some-tab-id"),
@ -96,7 +89,9 @@ describe("opening dock tab for installing helm chart", () => {
builder.helmCharts.navigate(); builder.helmCharts.navigate();
const dockStore = rendererDi.inject(dockStoreInjectable); const windowDi = builder.applicationWindow.only.di;
const dockStore = windowDi.inject(dockStoreInjectable);
// TODO: Make TerminalWindow unit testable to allow realistic behaviour // TODO: Make TerminalWindow unit testable to allow realistic behaviour
dockStore.closeTab("terminal"); dockStore.closeTab("terminal");

View File

@ -18,7 +18,7 @@ import callForPublicHelmRepositoriesInjectable from "../../renderer/components/+
import showErrorNotificationInjectable from "../../renderer/components/notifications/show-error-notification.injectable"; import showErrorNotificationInjectable from "../../renderer/components/notifications/show-error-notification.injectable";
describe("listing active helm repositories in preferences", () => { describe("listing active helm repositories in preferences", () => {
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
let rendered: RenderResult; let rendered: RenderResult;
let readYamlFileMock: AsyncFnMock<ReadYamlFile>; let readYamlFileMock: AsyncFnMock<ReadYamlFile>;
let execFileMock: AsyncFnMock<ReturnType<typeof execFileInjectable["instantiate"]>>; let execFileMock: AsyncFnMock<ReturnType<typeof execFileInjectable["instantiate"]>>;
@ -26,31 +26,33 @@ describe("listing active helm repositories in preferences", () => {
let showErrorNotificationMock: jest.Mock; let showErrorNotificationMock: jest.Mock;
beforeEach(async () => { beforeEach(async () => {
applicationBuilder = getApplicationBuilder(); builder = getApplicationBuilder();
readYamlFileMock = asyncFn(); readYamlFileMock = asyncFn();
execFileMock = asyncFn(); execFileMock = asyncFn();
showErrorNotificationMock = jest.fn();
loggerStub = { error: jest.fn() } as unknown as Logger; loggerStub = { error: jest.fn() } as unknown as Logger;
applicationBuilder.beforeApplicationStart(({ mainDi, rendererDi }) => { builder.beforeApplicationStart((mainDi) => {
showErrorNotificationMock = jest.fn();
rendererDi.override(showErrorNotificationInjectable, () => showErrorNotificationMock);
rendererDi.override(callForPublicHelmRepositoriesInjectable, () => async () => []);
mainDi.override(readYamlFileInjectable, () => readYamlFileMock); mainDi.override(readYamlFileInjectable, () => readYamlFileMock);
mainDi.override(execFileInjectable, () => execFileMock); mainDi.override(execFileInjectable, () => execFileMock);
mainDi.override(helmBinaryPathInjectable, () => "some-helm-binary-path"); mainDi.override(helmBinaryPathInjectable, () => "some-helm-binary-path");
mainDi.override(loggerInjectable, () => loggerStub); mainDi.override(loggerInjectable, () => loggerStub);
}); });
rendered = await applicationBuilder.render(); builder.beforeWindowStart((windowDi) => {
windowDi.override(showErrorNotificationInjectable, () => showErrorNotificationMock);
windowDi.override(callForPublicHelmRepositoriesInjectable, () => async () => []);
});
rendered = await builder.render();
}); });
describe("when navigating to preferences containing helm repositories", () => { describe("when navigating to preferences containing helm repositories", () => {
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.preferences.navigate(); builder.preferences.navigate();
applicationBuilder.preferences.navigation.click("kubernetes"); builder.preferences.navigation.click("kubernetes");
}); });
it("renders", () => { it("renders", () => {

View File

@ -16,7 +16,7 @@ import callForPublicHelmRepositoriesInjectable from "../../renderer/components/+
import type { AsyncResult } from "../../common/utils/async-result"; import type { AsyncResult } from "../../common/utils/async-result";
describe("remove helm repository from list of active repositories in preferences", () => { describe("remove helm repository from list of active repositories in preferences", () => {
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
let rendered: RenderResult; let rendered: RenderResult;
let getActiveHelmRepositoriesMock: AsyncFnMock<() => Promise<AsyncResult<HelmRepo[]>>>; let getActiveHelmRepositoriesMock: AsyncFnMock<() => Promise<AsyncResult<HelmRepo[]>>>;
let execFileMock: AsyncFnMock< let execFileMock: AsyncFnMock<
@ -24,30 +24,28 @@ describe("remove helm repository from list of active repositories in preferences
>; >;
beforeEach(async () => { beforeEach(async () => {
applicationBuilder = getApplicationBuilder(); builder = getApplicationBuilder();
execFileMock = asyncFn(); execFileMock = asyncFn();
getActiveHelmRepositoriesMock = asyncFn(); getActiveHelmRepositoriesMock = asyncFn();
applicationBuilder.beforeApplicationStart(({ mainDi, rendererDi }) => { builder.beforeApplicationStart((mainDi) => {
rendererDi.override(callForPublicHelmRepositoriesInjectable, () => async () => []); mainDi.override(getActiveHelmRepositoriesInjectable, () => getActiveHelmRepositoriesMock);
mainDi.override(
getActiveHelmRepositoriesInjectable,
() => getActiveHelmRepositoriesMock,
);
mainDi.override(execFileInjectable, () => execFileMock); mainDi.override(execFileInjectable, () => execFileMock);
mainDi.override(helmBinaryPathInjectable, () => "some-helm-binary-path"); mainDi.override(helmBinaryPathInjectable, () => "some-helm-binary-path");
}); });
rendered = await applicationBuilder.render(); builder.beforeWindowStart((windowDi) => {
windowDi.override(callForPublicHelmRepositoriesInjectable, () => async () => []);
});
rendered = await builder.render();
}); });
describe("when navigating to preferences containing helm repositories", () => { describe("when navigating to preferences containing helm repositories", () => {
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.preferences.navigate(); builder.preferences.navigate();
applicationBuilder.preferences.navigation.click("kubernetes"); builder.preferences.navigation.click("kubernetes");
}); });
it("renders", () => { it("renders", () => {

View File

@ -48,43 +48,43 @@ describe("showing details for helm release", () => {
showSuccessNotificationMock = jest.fn(); showSuccessNotificationMock = jest.fn();
showCheckedErrorNotificationMock = jest.fn(); showCheckedErrorNotificationMock = jest.fn();
builder.beforeApplicationStart(({ rendererDi }) => { builder.beforeWindowStart((windowDi) => {
rendererDi.override( windowDi.override(
getRandomUpgradeChartTabIdInjectable, getRandomUpgradeChartTabIdInjectable,
() => () => "some-tab-id", () => () => "some-tab-id",
); );
rendererDi.override( windowDi.override(
showSuccessNotificationInjectable, showSuccessNotificationInjectable,
() => showSuccessNotificationMock, () => showSuccessNotificationMock,
); );
rendererDi.override( windowDi.override(
showCheckedErrorInjectable, showCheckedErrorInjectable,
() => showCheckedErrorNotificationMock, () => showCheckedErrorNotificationMock,
); );
rendererDi.override( windowDi.override(
callForHelmReleasesInjectable, callForHelmReleasesInjectable,
() => callForHelmReleasesMock, () => callForHelmReleasesMock,
); );
rendererDi.override( windowDi.override(
callForHelmReleaseInjectable, callForHelmReleaseInjectable,
() => callForHelmReleaseMock, () => callForHelmReleaseMock,
); );
rendererDi.override( windowDi.override(
callForHelmReleaseConfigurationInjectable, callForHelmReleaseConfigurationInjectable,
() => callForHelmReleaseConfigurationMock, () => callForHelmReleaseConfigurationMock,
); );
rendererDi.override( windowDi.override(
callForHelmReleaseUpdateInjectable, callForHelmReleaseUpdateInjectable,
() => callForHelmReleaseUpdateMock, () => callForHelmReleaseUpdateMock,
); );
rendererDi.override( windowDi.override(
namespaceStoreInjectable, namespaceStoreInjectable,
() => () =>
({ ({
@ -105,9 +105,9 @@ describe("showing details for helm release", () => {
describe("when navigating to helm releases", () => { describe("when navigating to helm releases", () => {
beforeEach(() => { beforeEach(() => {
const rendererDi = builder.dis.rendererDi; const windowDi = builder.applicationWindow.only.di;
const navigateToHelmReleases = rendererDi.inject( const navigateToHelmReleases = windowDi.inject(
navigateToHelmReleasesInjectable, navigateToHelmReleasesInjectable,
); );

View File

@ -2,8 +2,6 @@
* Copyright (c) OpenLens Authors. All rights reserved. * Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import type { FakeExtensionData, TestExtension } from "../renderer/components/test-utils/get-renderer-extension-fake";
import { getRendererExtensionFakeFor } from "../renderer/components/test-utils/get-renderer-extension-fake";
import React from "react"; import React from "react";
import type { RenderResult } from "@testing-library/react"; import type { RenderResult } from "@testing-library/react";
import { fireEvent } from "@testing-library/react"; import { fireEvent } from "@testing-library/react";
@ -12,29 +10,29 @@ import queryParametersInjectable from "../renderer/routes/query-parameters.injec
import currentPathInjectable from "../renderer/routes/current-path.injectable"; import currentPathInjectable from "../renderer/routes/current-path.injectable";
import type { IComputedValue } from "mobx"; import type { IComputedValue } from "mobx";
import { getApplicationBuilder } from "../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../renderer/components/test-utils/get-application-builder";
import type { FakeExtensionOptions } from "../renderer/components/test-utils/get-extension-fake";
import type { LensRendererExtension } from "../extensions/lens-renderer-extension";
describe("navigate to extension page", () => { describe("navigate to extension page", () => {
let rendered: RenderResult; let rendered: RenderResult;
let testExtension: TestExtension; let testExtension: LensRendererExtension;
let queryParameters: IComputedValue<object>; let queryParameters: IComputedValue<object>;
let currentPath: IComputedValue<string>; let currentPath: IComputedValue<string>;
beforeEach(async () => { beforeEach(async () => {
const applicationBuilder = getApplicationBuilder(); const builder = getApplicationBuilder();
const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder);
testExtension = getRendererExtensionFake( builder.extensions.enable(extensionWithPagesHavingParameters);
extensionWithPagesHavingParameters,
);
applicationBuilder.extensions.renderer.enable(testExtension); rendered = await builder.render();
rendered = await applicationBuilder.render(); const windowDi = builder.applicationWindow.only.di;
const rendererDi = applicationBuilder.dis.rendererDi; testExtension =
builder.extensions.get("some-extension-id").applicationWindows.only;
queryParameters = rendererDi.inject(queryParametersInjectable); queryParameters = windowDi.inject(queryParametersInjectable);
currentPath = rendererDi.inject(currentPathInjectable); currentPath = windowDi.inject(currentPathInjectable);
}); });
it("renders", () => { it("renders", () => {
@ -125,57 +123,60 @@ describe("navigate to extension page", () => {
}); });
}); });
const extensionWithPagesHavingParameters: FakeExtensionData = { const extensionWithPagesHavingParameters: FakeExtensionOptions = {
id: "some-extension-id", id: "some-extension-id",
name: "some-extension-name", name: "some-extension-name",
globalPages: [
{
components: {
Page: ({ params }) => (
<div>
<ul>
<li>{params.someStringParameter.get()}</li>
<li>{params.someNumberParameter.get()}</li>
<li>{params.someArrayParameter.get().join(",")}</li>
</ul>
<button rendererOptions: {
type="button" globalPages: [
data-testid="button-to-change-page-parameters" {
onClick={() => { components: {
params.someStringParameter.set("some-changed-string-value"); Page: ({ params }) => (
params.someNumberParameter.set(84); <div>
params.someArrayParameter.set([ <ul>
"some-changed-array-value", <li>{params.someStringParameter.get()}</li>
"some-other-changed-array-value", <li>{params.someNumberParameter.get()}</li>
]); <li>{params.someArrayParameter.get().join(",")}</li>
}} </ul>
>
Some button
</button>
</div>
),
},
params: { <button
someStringParameter: "some-string-value", type="button"
someNumberParameter: { data-testid="button-to-change-page-parameters"
defaultValue: 42, onClick={() => {
stringify: (value) => value.toString(), params.someStringParameter.set("some-changed-string-value");
parse: (value) => (value ? Number(value) : undefined), params.someNumberParameter.set(84);
params.someArrayParameter.set([
"some-changed-array-value",
"some-other-changed-array-value",
]);
}}
>
Some button
</button>
</div>
),
}, },
someArrayParameter: {
defaultValue: ["some-array-value", "some-other-array-value"], params: {
stringify: (value) => value.join(","), someStringParameter: "some-string-value",
parse: (value: string[]) => (!isEmpty(value) ? value : undefined), someNumberParameter: {
defaultValue: 42,
stringify: (value) => value.toString(),
parse: (value) => (value ? Number(value) : undefined),
},
someArrayParameter: {
defaultValue: ["some-array-value", "some-other-array-value"],
stringify: (value) => value.join(","),
parse: (value: string[]) => (!isEmpty(value) ? value : undefined),
},
}, },
}, },
}, {
{ id: "some-child-page-id",
id: "some-child-page-id", components: {
components: { Page: () => <div>Child page</div>,
Page: () => <div>Child page</div>, },
}, },
}, ],
], },
}; };

View File

@ -20,32 +20,34 @@ import { navigateToRouteInjectionToken } from "../common/front-end-routing/navig
import routePathParametersInjectable from "../renderer/routes/route-path-parameters.injectable"; import routePathParametersInjectable from "../renderer/routes/route-path-parameters.injectable";
describe("navigating between routes", () => { describe("navigating between routes", () => {
let rendererDi: DiContainer;
let rendered: RenderResult; let rendered: RenderResult;
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
beforeEach(async () => { beforeEach(async () => {
applicationBuilder = getApplicationBuilder(); builder = getApplicationBuilder();
rendererDi = applicationBuilder.dis.rendererDi;
}); });
describe("given route without path parameters", () => { describe("given route without path parameters", () => {
let windowDi: DiContainer;
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.beforeApplicationStart(({ rendererDi }) => { builder.beforeWindowStart((windowDi) => {
rendererDi.register(testRouteWithoutPathParametersInjectable); windowDi.register(testRouteWithoutPathParametersInjectable);
rendererDi.register(testRouteWithoutPathParametersComponentInjectable); windowDi.register(testRouteWithoutPathParametersComponentInjectable);
}); });
rendered = await applicationBuilder.render(); rendered = await builder.render();
windowDi = builder.applicationWindow.only.di;
}); });
describe("when navigating to route", () => { describe("when navigating to route", () => {
let route: Route; let route: Route;
beforeEach(() => { beforeEach(() => {
const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken); const navigateToRoute = windowDi.inject(navigateToRouteInjectionToken);
route = rendererDi.inject(testRouteWithoutPathParametersInjectable); route = windowDi.inject(testRouteWithoutPathParametersInjectable);
navigateToRoute(route); navigateToRoute(route);
}); });
@ -55,35 +57,35 @@ describe("navigating between routes", () => {
}); });
it("knows current route", () => { it("knows current route", () => {
const currentRoute = rendererDi.inject(currentRouteInjectable); const currentRoute = windowDi.inject(currentRouteInjectable);
expect(currentRoute.get()).toBe(route); expect(currentRoute.get()).toBe(route);
}); });
it("knows current path", () => { it("knows current path", () => {
const currentPath = rendererDi.inject(currentPathInjectable); const currentPath = windowDi.inject(currentPathInjectable);
expect(currentPath.get()).toBe("/some-path"); expect(currentPath.get()).toBe("/some-path");
}); });
it("does not have query parameters", () => { it("does not have query parameters", () => {
const queryParameters = rendererDi.inject(queryParametersInjectable); const queryParameters = windowDi.inject(queryParametersInjectable);
expect(queryParameters.get()).toEqual({}); expect(queryParameters.get()).toEqual({});
}); });
it("does not have path parameters", () => { it("does not have path parameters", () => {
const pathParameters = rendererDi.inject(routePathParametersInjectable, route); const pathParameters = windowDi.inject(routePathParametersInjectable, route);
expect(pathParameters.get()).toEqual({}); expect(pathParameters.get()).toEqual({});
}); });
}); });
it("when navigating to route with query parameters, knows query parameters", () => { it("when navigating to route with query parameters, knows query parameters", () => {
const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken); const navigateToRoute = windowDi.inject(navigateToRouteInjectionToken);
const queryParameters = rendererDi.inject(queryParametersInjectable); const queryParameters = windowDi.inject(queryParametersInjectable);
const route = rendererDi.inject(testRouteWithoutPathParametersInjectable); const route = windowDi.inject(testRouteWithoutPathParametersInjectable);
navigateToRoute(route, { navigateToRoute(route, {
query: { query: {
@ -100,23 +102,26 @@ describe("navigating between routes", () => {
}); });
describe("given route with optional path parameters", () => { describe("given route with optional path parameters", () => {
let windowDi: DiContainer;
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.beforeApplicationStart(({ rendererDi }) => { builder.beforeWindowStart((windowDi) => {
rendererDi.register(routeWithOptionalPathParametersInjectable); windowDi.register(routeWithOptionalPathParametersInjectable);
rendererDi.register(routeWithOptionalPathParametersComponentInjectable); windowDi.register(routeWithOptionalPathParametersComponentInjectable);
}); });
rendered = await builder.render();
rendered = await applicationBuilder.render(); windowDi = builder.applicationWindow.only.di;
}); });
describe("when navigating to route with path parameters", () => { describe("when navigating to route with path parameters", () => {
let route: Route<any>; let route: Route<any>;
beforeEach(() => { beforeEach(() => {
route = rendererDi.inject(routeWithOptionalPathParametersInjectable); route = windowDi.inject(routeWithOptionalPathParametersInjectable);
const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken); const navigateToRoute = windowDi.inject(navigateToRouteInjectionToken);
navigateToRoute(route, { navigateToRoute(route, {
parameters: { parameters: {
@ -131,13 +136,13 @@ describe("navigating between routes", () => {
}); });
it("knows current route", () => { it("knows current route", () => {
const currentRoute = rendererDi.inject(currentRouteInjectable); const currentRoute = windowDi.inject(currentRouteInjectable);
expect(currentRoute.get()).toBe(route); expect(currentRoute.get()).toBe(route);
}); });
it("knows current path", () => { it("knows current path", () => {
const currentPath = rendererDi.inject(currentPathInjectable); const currentPath = windowDi.inject(currentPathInjectable);
expect(currentPath.get()).toBe( expect(currentPath.get()).toBe(
"/some-path/some-value/some-other-value", "/some-path/some-value/some-other-value",
@ -145,7 +150,7 @@ describe("navigating between routes", () => {
}); });
it("knows path parameters", () => { it("knows path parameters", () => {
const pathParameters = rendererDi.inject(routePathParametersInjectable, route); const pathParameters = windowDi.inject(routePathParametersInjectable, route);
expect(pathParameters.get()).toEqual({ expect(pathParameters.get()).toEqual({
someParameter: "some-value", someParameter: "some-value",
@ -158,27 +163,27 @@ describe("navigating between routes", () => {
let route: Route<any>; let route: Route<any>;
beforeEach(() => { beforeEach(() => {
route = rendererDi.inject(routeWithOptionalPathParametersInjectable); route = windowDi.inject(routeWithOptionalPathParametersInjectable);
const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken); const navigateToRoute = windowDi.inject(navigateToRouteInjectionToken);
navigateToRoute(route); navigateToRoute(route);
}); });
it("knows current route", () => { it("knows current route", () => {
const currentRoute = rendererDi.inject(currentRouteInjectable); const currentRoute = windowDi.inject(currentRouteInjectable);
expect(currentRoute.get()).toBe(route); expect(currentRoute.get()).toBe(route);
}); });
it("knows current path", () => { it("knows current path", () => {
const currentPath = rendererDi.inject(currentPathInjectable); const currentPath = windowDi.inject(currentPathInjectable);
expect(currentPath.get()).toBe("/some-path"); expect(currentPath.get()).toBe("/some-path");
}); });
it("knows path parameters", () => { it("knows path parameters", () => {
const pathParameters = rendererDi.inject(routePathParametersInjectable, route); const pathParameters = windowDi.inject(routePathParametersInjectable, route);
expect(pathParameters.get()).toEqual({ expect(pathParameters.get()).toEqual({
someParameter: undefined, someParameter: undefined,

View File

@ -24,19 +24,19 @@ import navigateToFrontPageInjectable from "../../common/front-end-routing/naviga
import { navigateToRouteInjectionToken } from "../../common/front-end-routing/navigate-to-route-injection-token"; import { navigateToRouteInjectionToken } from "../../common/front-end-routing/navigate-to-route-injection-token";
describe("preferences - closing-preferences", () => { describe("preferences - closing-preferences", () => {
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
beforeEach(() => { beforeEach(() => {
applicationBuilder = getApplicationBuilder(); builder = getApplicationBuilder();
applicationBuilder.beforeApplicationStart(({ rendererDi }) => { builder.beforeWindowStart((windowDi) => {
rendererDi.register(testPreferencesRouteInjectable); windowDi.register(testPreferencesRouteInjectable);
rendererDi.register(testPreferencesRouteComponentInjectable); windowDi.register(testPreferencesRouteComponentInjectable);
rendererDi.register(testFrontPageRouteInjectable); windowDi.register(testFrontPageRouteInjectable);
rendererDi.register(testFrontPageRouteComponentInjectable); windowDi.register(testFrontPageRouteComponentInjectable);
rendererDi.register(testNavigationItemInjectable); windowDi.register(testNavigationItemInjectable);
rendererDi.override(navigateToFrontPageInjectable, (di) => { windowDi.override(navigateToFrontPageInjectable, (di) => {
const navigateToRoute = di.inject(navigateToRouteInjectionToken); const navigateToRoute = di.inject(navigateToRouteInjectionToken);
const testFrontPage = di.inject(testFrontPageRouteInjectable); const testFrontPage = di.inject(testFrontPageRouteInjectable);
@ -49,11 +49,11 @@ describe("preferences - closing-preferences", () => {
describe("given already in a page and then navigated to preferences", () => { describe("given already in a page and then navigated to preferences", () => {
let rendered: RenderResult; let rendered: RenderResult;
let rendererDi: DiContainer; let windowDi: DiContainer;
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.beforeApplicationStart(({ rendererDi }) => { builder.beforeWindowStart((windowDi) => {
rendererDi.override(observableHistoryInjectable, () => { windowDi.override(observableHistoryInjectable, () => {
const historyFake = createMemoryHistory({ const historyFake = createMemoryHistory({
initialEntries: ["/some-test-path"], initialEntries: ["/some-test-path"],
initialIndex: 0, initialIndex: 0,
@ -65,10 +65,10 @@ describe("preferences - closing-preferences", () => {
}); });
}); });
rendered = await applicationBuilder.render(); rendered = await builder.render();
rendererDi = applicationBuilder.dis.rendererDi; windowDi = builder.applicationWindow.only.di;
applicationBuilder.preferences.navigate(); builder.preferences.navigate();
}); });
it("renders", () => { it("renders", () => {
@ -77,7 +77,7 @@ describe("preferences - closing-preferences", () => {
describe("when preferences are closed", () => { describe("when preferences are closed", () => {
beforeEach(() => { beforeEach(() => {
applicationBuilder.preferences.close(); builder.preferences.close();
}); });
it("renders", () => { it("renders", () => {
@ -85,7 +85,7 @@ describe("preferences - closing-preferences", () => {
}); });
it("navigates back to the original page", () => { it("navigates back to the original page", () => {
const currentPath = rendererDi.inject(currentPathInjectable).get(); const currentPath = windowDi.inject(currentPathInjectable).get();
expect(currentPath).toBe("/some-test-path"); expect(currentPath).toBe("/some-test-path");
}); });
@ -93,7 +93,7 @@ describe("preferences - closing-preferences", () => {
describe("when navigating to a tab in preferences", () => { describe("when navigating to a tab in preferences", () => {
beforeEach(() => { beforeEach(() => {
applicationBuilder.preferences.navigation.click( builder.preferences.navigation.click(
"some-test-preference-navigation-item-id", "some-test-preference-navigation-item-id",
); );
}); });
@ -104,7 +104,7 @@ describe("preferences - closing-preferences", () => {
describe("when preferences are closed", () => { describe("when preferences are closed", () => {
beforeEach(() => { beforeEach(() => {
applicationBuilder.preferences.close(); builder.preferences.close();
}); });
it("renders", () => { it("renders", () => {
@ -112,7 +112,7 @@ describe("preferences - closing-preferences", () => {
}); });
it("navigates back to the original page", () => { it("navigates back to the original page", () => {
const currentPath = rendererDi.inject(currentPathInjectable).get(); const currentPath = windowDi.inject(currentPathInjectable).get();
expect(currentPath).toBe("/some-test-path"); expect(currentPath).toBe("/some-test-path");
}); });
@ -122,11 +122,11 @@ describe("preferences - closing-preferences", () => {
describe("given accessing preferences directly", () => { describe("given accessing preferences directly", () => {
let rendered: RenderResult; let rendered: RenderResult;
let rendererDi: DiContainer; let windowDi: DiContainer;
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.beforeApplicationStart(({ rendererDi }) => { builder.beforeWindowStart((windowDi) => {
rendererDi.override(observableHistoryInjectable, () => { windowDi.override(observableHistoryInjectable, () => {
const historyFake = createMemoryHistory({ const historyFake = createMemoryHistory({
initialEntries: ["/preferences/app"], initialEntries: ["/preferences/app"],
initialIndex: 0, initialIndex: 0,
@ -138,9 +138,9 @@ describe("preferences - closing-preferences", () => {
}); });
}); });
rendered = await applicationBuilder.render(); rendered = await builder.render();
rendererDi = applicationBuilder.dis.rendererDi; windowDi = builder.applicationWindow.only.di;
}); });
it("renders", () => { it("renders", () => {
@ -149,7 +149,7 @@ describe("preferences - closing-preferences", () => {
describe("when preferences are closed", () => { describe("when preferences are closed", () => {
beforeEach(() => { beforeEach(() => {
applicationBuilder.preferences.close(); builder.preferences.close();
}); });
it("renders", () => { it("renders", () => {
@ -157,7 +157,7 @@ describe("preferences - closing-preferences", () => {
}); });
it("navigates back to the front page", () => { it("navigates back to the front page", () => {
const currentPath = rendererDi.inject(currentPathInjectable).get(); const currentPath = windowDi.inject(currentPathInjectable).get();
expect(currentPath).toBe("/some-front-page"); expect(currentPath).toBe("/some-front-page");
}); });
@ -165,7 +165,7 @@ describe("preferences - closing-preferences", () => {
describe("when navigating to a tab in preferences", () => { describe("when navigating to a tab in preferences", () => {
beforeEach(() => { beforeEach(() => {
applicationBuilder.preferences.navigation.click( builder.preferences.navigation.click(
"some-test-preference-navigation-item-id", "some-test-preference-navigation-item-id",
); );
}); });
@ -176,7 +176,7 @@ describe("preferences - closing-preferences", () => {
describe("when preferences are closed", () => { describe("when preferences are closed", () => {
beforeEach(() => { beforeEach(() => {
applicationBuilder.preferences.close(); builder.preferences.close();
}); });
it("renders", () => { it("renders", () => {
@ -184,7 +184,7 @@ describe("preferences - closing-preferences", () => {
}); });
it("navigates back to the front page", () => { it("navigates back to the front page", () => {
const currentPath = rendererDi.inject(currentPathInjectable).get(); const currentPath = windowDi.inject(currentPathInjectable).get();
expect(currentPath).toBe("/some-front-page"); expect(currentPath).toBe("/some-front-page");
}); });

View File

@ -7,7 +7,6 @@ import type { IObservableValue } from "mobx";
import { runInAction, computed, observable } from "mobx"; import { runInAction, computed, observable } from "mobx";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getExtensionFakeFor } from "../../renderer/components/test-utils/get-extension-fake";
describe("preferences: extension adding preference tabs", () => { describe("preferences: extension adding preference tabs", () => {
let builder: ApplicationBuilder; let builder: ApplicationBuilder;
@ -25,11 +24,9 @@ describe("preferences: extension adding preference tabs", () => {
builder.preferences.navigate(); builder.preferences.navigate();
const getExtensionFake = getExtensionFakeFor(builder);
someObservable = observable.box(false); someObservable = observable.box(false);
const testExtension = getExtensionFake({ const testExtension = {
id: "some-extension-id", id: "some-extension-id",
name: "some-extension", name: "some-extension",
@ -53,7 +50,7 @@ describe("preferences: extension adding preference tabs", () => {
}, },
], ],
}, },
}); };
builder.extensions.enable(testExtension); builder.extensions.enable(testExtension);

View File

@ -8,23 +8,23 @@ import { getApplicationBuilder } from "../../renderer/components/test-utils/get-
import navigateToProxyPreferencesInjectable from "../../common/front-end-routing/routes/preferences/proxy/navigate-to-proxy-preferences.injectable"; import navigateToProxyPreferencesInjectable from "../../common/front-end-routing/routes/preferences/proxy/navigate-to-proxy-preferences.injectable";
describe("preferences - navigation to application preferences", () => { describe("preferences - navigation to application preferences", () => {
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
beforeEach(() => { beforeEach(() => {
applicationBuilder = getApplicationBuilder(); builder = getApplicationBuilder();
}); });
describe("given in some child page of preferences, when rendered", () => { describe("given in some child page of preferences, when rendered", () => {
let rendered: RenderResult; let rendered: RenderResult;
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.beforeRender(({ rendererDi }) => { builder.beforeWindowStart((windowDi) => {
const navigateToProxyPreferences = rendererDi.inject(navigateToProxyPreferencesInjectable); const navigateToProxyPreferences = windowDi.inject(navigateToProxyPreferencesInjectable);
navigateToProxyPreferences(); navigateToProxyPreferences();
}); });
rendered = await applicationBuilder.render(); rendered = await builder.render();
}); });
it("renders", () => { it("renders", () => {
@ -39,7 +39,7 @@ describe("preferences - navigation to application preferences", () => {
describe("when navigating to application preferences using navigation", () => { describe("when navigating to application preferences using navigation", () => {
beforeEach(() => { beforeEach(() => {
applicationBuilder.preferences.navigation.click("application"); builder.preferences.navigation.click("application");
}); });
it("renders", () => { it("renders", () => {

View File

@ -17,7 +17,7 @@ describe("preferences - navigation to editor preferences", () => {
let rendered: RenderResult; let rendered: RenderResult;
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.beforeRender(() => { applicationBuilder.beforeWindowStart(() => {
applicationBuilder.preferences.navigate(); applicationBuilder.preferences.navigate();
}); });

View File

@ -7,29 +7,25 @@ import type { ApplicationBuilder } from "../../renderer/components/test-utils/ge
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import React from "react"; import React from "react";
import "@testing-library/jest-dom/extend-expect"; import "@testing-library/jest-dom/extend-expect";
import type { FakeExtensionData, TestExtension } from "../../renderer/components/test-utils/get-renderer-extension-fake";
import { getRendererExtensionFakeFor } from "../../renderer/components/test-utils/get-renderer-extension-fake";
import type { DiContainer } from "@ogre-tools/injectable";
import { getDiForUnitTesting } from "../../renderer/getDiForUnitTesting";
import extensionPreferencesRouteInjectable from "../../common/front-end-routing/routes/preferences/extension/extension-preferences-route.injectable"; import extensionPreferencesRouteInjectable from "../../common/front-end-routing/routes/preferences/extension/extension-preferences-route.injectable";
import type { FakeExtensionOptions } from "../../renderer/components/test-utils/get-extension-fake";
describe("preferences - navigation to extension specific preferences", () => { describe("preferences - navigation to extension specific preferences", () => {
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
beforeEach(() => { beforeEach(() => {
applicationBuilder = getApplicationBuilder(); builder = getApplicationBuilder();
}); });
describe("given in preferences, when rendered", () => { describe("given in preferences, when rendered", () => {
let rendered: RenderResult; let rendered: RenderResult;
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.beforeRender(() => { builder.beforeWindowStart(() => {
applicationBuilder.preferences.navigate(); builder.preferences.navigate();
}); });
rendered = await applicationBuilder.render(); rendered = await builder.render();
}); });
it("renders", () => { it("renders", () => {
@ -49,13 +45,15 @@ describe("preferences - navigation to extension specific preferences", () => {
}); });
describe("given multiple extensions with specific preferences, when navigating to extension specific preferences page", () => { describe("given multiple extensions with specific preferences, when navigating to extension specific preferences page", () => {
beforeEach(async () => { beforeEach(() => {
const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder); builder.extensions.enable(
const someTestExtension = getRendererExtensionFake(extensionStubWithExtensionSpecificPreferenceItems); extensionStubWithExtensionSpecificPreferenceItems,
const someOtherTestExtension = getRendererExtensionFake(someOtherExtensionStubWithExtensionSpecificPreferenceItems); someOtherExtensionStubWithExtensionSpecificPreferenceItems,
);
await applicationBuilder.extensions.renderer.enable(someTestExtension, someOtherTestExtension); builder.preferences.navigation.click(
applicationBuilder.preferences.navigation.click("extension-some-test-extension-id"); "extension-some-test-extension-id",
);
}); });
it("renders", () => { it("renders", () => {
@ -76,13 +74,12 @@ describe("preferences - navigation to extension specific preferences", () => {
}); });
describe("given multiple extensions with and without specific preferences", () => { describe("given multiple extensions with and without specific preferences", () => {
beforeEach(async () => { beforeEach(() => {
const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder); builder.extensions.enable(
const someTestExtension = getRendererExtensionFake(extensionStubWithExtensionSpecificPreferenceItems); extensionStubWithExtensionSpecificPreferenceItems,
const extensionWithoutPreferences = getRendererExtensionFake(extensionStubWithoutPreferences); extensionStubWithoutPreferences,
const extensionWithSpecificTab = getRendererExtensionFake(extensionStubWithShowInPreferencesTab); extensionStubWithShowInPreferencesTab,
);
await applicationBuilder.extensions.renderer.enable(someTestExtension, extensionWithoutPreferences, extensionWithSpecificTab);
}); });
it("doesn't show link for extension without preferences", () => { it("doesn't show link for extension without preferences", () => {
@ -99,16 +96,8 @@ describe("preferences - navigation to extension specific preferences", () => {
}); });
describe("when extension with specific preferences is enabled", () => { describe("when extension with specific preferences is enabled", () => {
let testExtension: TestExtension;
beforeEach(() => { beforeEach(() => {
const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder); builder.extensions.enable(extensionStubWithExtensionSpecificPreferenceItems);
testExtension = getRendererExtensionFake(
extensionStubWithExtensionSpecificPreferenceItems,
);
applicationBuilder.extensions.renderer.enable(testExtension);
}); });
it("renders", () => { it("renders", () => {
@ -129,7 +118,7 @@ describe("preferences - navigation to extension specific preferences", () => {
describe("when navigating to extension preferences using navigation", () => { describe("when navigating to extension preferences using navigation", () => {
beforeEach(() => { beforeEach(() => {
applicationBuilder.preferences.navigation.click("extension-some-test-extension-id"); builder.preferences.navigation.click("extension-some-test-extension-id");
}); });
it("renders", () => { it("renders", () => {
@ -168,7 +157,7 @@ describe("preferences - navigation to extension specific preferences", () => {
describe("when extension is disabled", () => { describe("when extension is disabled", () => {
beforeEach(() => { beforeEach(() => {
applicationBuilder.extensions.renderer.disable(testExtension); builder.extensions.disable(extensionStubWithExtensionSpecificPreferenceItems);
}); });
it("renders", () => { it("renders", () => {
@ -180,7 +169,7 @@ describe("preferences - navigation to extension specific preferences", () => {
}); });
it("when extension is enabled again, does not show the error message anymore", () => { it("when extension is enabled again, does not show the error message anymore", () => {
applicationBuilder.extensions.renderer.enable(testExtension); builder.extensions.enable(extensionStubWithExtensionSpecificPreferenceItems);
expect(rendered.queryByTestId("error-for-extension-not-being-present")).not.toBeInTheDocument(); expect(rendered.queryByTestId("error-for-extension-not-being-present")).not.toBeInTheDocument();
}); });
@ -189,11 +178,8 @@ describe("preferences - navigation to extension specific preferences", () => {
}); });
describe("given extension with registered tab", () => { describe("given extension with registered tab", () => {
beforeEach(async () => { beforeEach(() => {
const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder); builder.extensions.enable(extensionStubWithWithRegisteredTab);
const extension = getRendererExtensionFake(extensionStubWithWithRegisteredTab);
await applicationBuilder.extensions.renderer.enable(extension);
}); });
it("shows extension tab in general area", () => { it("shows extension tab in general area", () => {
@ -210,7 +196,7 @@ describe("preferences - navigation to extension specific preferences", () => {
describe("when navigating to specific extension tab", () => { describe("when navigating to specific extension tab", () => {
beforeEach(() => { beforeEach(() => {
applicationBuilder.preferences.navigation.click("extension-registered-tab-page-id-nav-item-metrics-extension-tab"); builder.preferences.navigation.click("extension-registered-tab-page-id-nav-item-metrics-extension-tab");
}); });
it("renders", () => { it("renders", () => {
expect(rendered.container).toMatchSnapshot(); expect(rendered.container).toMatchSnapshot();
@ -232,7 +218,7 @@ describe("preferences - navigation to extension specific preferences", () => {
}); });
it("shows page title same as tab title", () => { it("shows page title same as tab title", () => {
const pageTitle = rendered.queryByTestId("extension-preferences-page-title"); const pageTitle = rendered.queryByTestId("extension-preferences-page-title");
const tabs = extensionStubWithWithRegisteredTab.appPreferenceTabs; const tabs = extensionStubWithWithRegisteredTab.rendererOptions?.appPreferenceTabs;
const tabTitle = tabs && tabs[0].title; const tabTitle = tabs && tabs[0].title;
expect(pageTitle?.innerHTML).toBe(tabTitle); expect(pageTitle?.innerHTML).toBe(tabTitle);
@ -246,11 +232,8 @@ describe("preferences - navigation to extension specific preferences", () => {
"tab-link-for-extension-hello-world-tab-page-id-nav-item-logs-extension-tab", "tab-link-for-extension-hello-world-tab-page-id-nav-item-logs-extension-tab",
]; ];
beforeEach(async () => { beforeEach(() => {
const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder); builder.extensions.enable(extensionStubWithWithRegisteredTabs);
const extension = getRendererExtensionFake(extensionStubWithWithRegisteredTabs);
await applicationBuilder.extensions.renderer.enable(extension);
}); });
it.each(tabs)("shows '%s' tab in general area", (tab) => { it.each(tabs)("shows '%s' tab in general area", (tab) => {
@ -261,12 +244,8 @@ describe("preferences - navigation to extension specific preferences", () => {
}); });
describe("given extensions with tabs having same id", () => { describe("given extensions with tabs having same id", () => {
beforeEach(async () => { beforeEach(() => {
const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder); builder.extensions.enable(extensionStubWithWithRegisteredTab, extensionStubWithWithSameRegisteredTab);
const extension = getRendererExtensionFake(extensionStubWithWithRegisteredTab);
const otherExtension = getRendererExtensionFake(extensionStubWithWithSameRegisteredTab);
await applicationBuilder.extensions.renderer.enable(extension, otherExtension);
}); });
it("shows tab from the first extension", () => { it("shows tab from the first extension", () => {
@ -283,7 +262,7 @@ describe("preferences - navigation to extension specific preferences", () => {
describe("when navigating to first extension tab", () => { describe("when navigating to first extension tab", () => {
beforeEach(() => { beforeEach(() => {
applicationBuilder.preferences.navigation.click("extension-registered-tab-page-id-nav-item-metrics-extension-tab"); builder.preferences.navigation.click("extension-registered-tab-page-id-nav-item-metrics-extension-tab");
}); });
it("renders", () => { it("renders", () => {
@ -305,7 +284,7 @@ describe("preferences - navigation to extension specific preferences", () => {
describe("when navigating to second extension tab", () => { describe("when navigating to second extension tab", () => {
beforeEach(() => { beforeEach(() => {
applicationBuilder.preferences.navigation.click("extension-duplicated-tab-page-id-nav-item-metrics-extension-tab"); builder.preferences.navigation.click("extension-duplicated-tab-page-id-nav-item-metrics-extension-tab");
}); });
it("renders", () => { it("renders", () => {
@ -329,27 +308,21 @@ describe("preferences - navigation to extension specific preferences", () => {
describe("when navigating to extension specific tab", () => { describe("when navigating to extension specific tab", () => {
let rendered: RenderResult; let rendered: RenderResult;
let di: DiContainer;
beforeEach(async () => { beforeEach(async () => {
di = getDiForUnitTesting({ doGeneralOverrides: true }); builder.beforeWindowStart((windowDi) => {
const extensionRoute = windowDi.inject(extensionPreferencesRouteInjectable);
const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder);
const extension = getRendererExtensionFake(extensionStubWithWithSameRegisteredTab);
const otherExtension = getRendererExtensionFake(extensionUsingSomeoneElseTab);
applicationBuilder.beforeRender(() => {
const extensionRoute = di.inject(extensionPreferencesRouteInjectable);
const params = { parameters: { const params = { parameters: {
extensionId: "duplicated-tab-page-id", extensionId: "duplicated-tab-page-id",
tabId: "metrics-extension-tab", tabId: "metrics-extension-tab",
}}; }};
applicationBuilder.preferences.navigateTo(extensionRoute, params); builder.preferences.navigateTo(extensionRoute, params);
}); });
await applicationBuilder.extensions.renderer.enable(extension, otherExtension); builder.extensions.enable(extensionStubWithWithSameRegisteredTab, extensionUsingSomeoneElseTab);
rendered = await applicationBuilder.render(); rendered = await builder.render();
}); });
it("renders", () => { it("renders", () => {
@ -367,27 +340,20 @@ describe("preferences - navigation to extension specific preferences", () => {
describe("when navigating to someone else extension specific tab", () => { describe("when navigating to someone else extension specific tab", () => {
let rendered: RenderResult; let rendered: RenderResult;
let di: DiContainer;
beforeEach(async () => { beforeEach(async () => {
di = getDiForUnitTesting({ doGeneralOverrides: true }); builder.beforeWindowStart((windowDi) => {
const extensionRoute = windowDi.inject(extensionPreferencesRouteInjectable);
const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder);
const extension = getRendererExtensionFake(extensionStubWithWithSameRegisteredTab);
const extensionUsingOtherTab = getRendererExtensionFake(extensionUsingSomeoneElseTab);
applicationBuilder.beforeRender(() => {
const extensionRoute = di.inject(extensionPreferencesRouteInjectable);
const params = { parameters: { const params = { parameters: {
extensionId: "extension-using-someone-else-tab-id", extensionId: "extension-using-someone-else-tab-id",
tabId: "metrics-extension-tab", tabId: "metrics-extension-tab",
}}; }};
applicationBuilder.preferences.navigateTo(extensionRoute, params); builder.preferences.navigateTo(extensionRoute, params);
}); });
await applicationBuilder.extensions.renderer.enable(extension, extensionUsingOtherTab); builder.extensions.enable(extensionStubWithWithSameRegisteredTab, extensionUsingSomeoneElseTab);
rendered = await applicationBuilder.render(); rendered = await builder.render();
}); });
it("renders", () => { it("renders", () => {
@ -396,193 +362,208 @@ describe("preferences - navigation to extension specific preferences", () => {
}); });
}); });
const extensionStubWithExtensionSpecificPreferenceItems: FakeExtensionData = { const extensionStubWithExtensionSpecificPreferenceItems: FakeExtensionOptions = {
id: "some-test-extension-id", id: "some-test-extension-id",
name: "some-test-extension-id", name: "some-test-extension-id",
appPreferences: [
{
title: "Some preference item",
id: "some-preference-item-id",
components: { rendererOptions: {
Hint: () => <div data-testid="some-preference-item-hint" />, appPreferences: [
Input: () => <div data-testid="some-preference-item-input" />, {
title: "Some preference item",
id: "some-preference-item-id",
components: {
Hint: () => <div data-testid="some-preference-item-hint" />,
Input: () => <div data-testid="some-preference-item-input" />,
},
}, },
},
{ {
title: "irrelevant", title: "irrelevant",
id: "some-unrelated-preference-item-id", id: "some-unrelated-preference-item-id",
showInPreferencesTab: "some-tab", showInPreferencesTab: "some-tab",
components: { components: {
Hint: () => <div />, Hint: () => <div />,
Input: () => <div />, Input: () => <div />,
},
}, },
}, ],
], },
}; };
const someOtherExtensionStubWithExtensionSpecificPreferenceItems: FakeExtensionData = { const someOtherExtensionStubWithExtensionSpecificPreferenceItems: FakeExtensionOptions = {
id: "some-other-test-extension-id", id: "some-other-test-extension-id",
name: "some-other-test-extension-id", name: "some-other-test-extension-id",
appPreferences: [ rendererOptions: {
{ appPreferences: [
title: "Test preference item", {
id: "some-other-preference-item-id", title: "Test preference item",
id: "some-other-preference-item-id",
components: { components: {
Hint: () => <div data-testid="some-other-preference-item-hint" />, Hint: () => <div data-testid="some-other-preference-item-hint" />,
Input: () => <div data-testid="some-other-preference-item-input" />, Input: () => <div data-testid="some-other-preference-item-input" />,
},
}, },
}, ],
], },
}; };
const extensionStubWithoutPreferences: FakeExtensionData = { const extensionStubWithoutPreferences: FakeExtensionOptions = {
id: "without-preferences-id", id: "without-preferences-id",
name: "without-preferences-id", name: "without-preferences-id",
}; };
const extensionStubWithShowInPreferencesTab: FakeExtensionData = { const extensionStubWithShowInPreferencesTab: FakeExtensionOptions = {
id: "specified-preferences-page-id", id: "specified-preferences-page-id",
name: "specified-preferences-page-name", name: "specified-preferences-page-name",
appPreferences: [ rendererOptions: {
{ appPreferences: [
title: "Test preference item", {
id: "very-other-preference-item-id", title: "Test preference item",
showInPreferencesTab: "some-tab", id: "very-other-preference-item-id",
showInPreferencesTab: "some-tab",
components: { components: {
Hint: () => <div data-testid="very-other-preference-item-hint" />, Hint: () => <div data-testid="very-other-preference-item-hint" />,
Input: () => <div data-testid="very-other-preference-item-input" />, Input: () => <div data-testid="very-other-preference-item-input" />,
},
}, },
}, ],
], },
}; };
const extensionStubWithWithRegisteredTab: FakeExtensionData = { const extensionStubWithWithRegisteredTab: FakeExtensionOptions = {
id: "registered-tab-page-id", id: "registered-tab-page-id",
name: "registered-tab-page-id", name: "registered-tab-page-id",
appPreferences: [ rendererOptions: {
{ appPreferences: [
title: "License item", {
id: "metrics-preference-item-id", title: "License item",
showInPreferencesTab: "metrics-extension-tab", id: "metrics-preference-item-id",
showInPreferencesTab: "metrics-extension-tab",
components: { components: {
Hint: () => <div data-testid="metrics-preference-item-hint" />, Hint: () => <div data-testid="metrics-preference-item-hint" />,
Input: () => <div data-testid="metrics-preference-item-input" />, Input: () => <div data-testid="metrics-preference-item-input" />,
},
}, },
}, {
{ title: "Menu item",
title: "Menu item", id: "menu-preference-item-id",
id: "menu-preference-item-id", showInPreferencesTab: "menu-extension-tab",
showInPreferencesTab: "menu-extension-tab",
components: { components: {
Hint: () => <div data-testid="menu-preference-item-hint" />, Hint: () => <div data-testid="menu-preference-item-hint" />,
Input: () => <div data-testid="menu-preference-item-input" />, Input: () => <div data-testid="menu-preference-item-input" />,
},
}, },
}, {
{ title: "Survey item",
title: "Survey item", id: "survey-preference-item-id",
id: "survey-preference-item-id", showInPreferencesTab: "survey-extension-tab",
showInPreferencesTab: "survey-extension-tab",
components: { components: {
Hint: () => <div data-testid="survey-preference-item-hint" />, Hint: () => <div data-testid="survey-preference-item-hint" />,
Input: () => <div data-testid="survey-preference-item-input" />, Input: () => <div data-testid="survey-preference-item-input" />,
},
}, },
}, ],
],
appPreferenceTabs: [{ appPreferenceTabs: [{
title: "Metrics tab", title: "Metrics tab",
id: "metrics-extension-tab", id: "metrics-extension-tab",
orderNumber: 100, orderNumber: 100,
}], }],
},
}; };
const extensionStubWithWithRegisteredTabs: FakeExtensionData = { const extensionStubWithWithRegisteredTabs: FakeExtensionOptions = {
id: "hello-world-tab-page-id", id: "hello-world-tab-page-id",
name: "hello-world-tab-page-id", name: "hello-world-tab-page-id",
appPreferences: [ rendererOptions: {
{ appPreferences: [
title: "Hello world", {
id: "hello-preference-item-id", title: "Hello world",
showInPreferencesTab: "hello-extension-tab", id: "hello-preference-item-id",
showInPreferencesTab: "hello-extension-tab",
components: { components: {
Hint: () => <div data-testid="hello-preference-item-hint" />, Hint: () => <div data-testid="hello-preference-item-hint" />,
Input: () => <div data-testid="hello-preference-item-input" />, Input: () => <div data-testid="hello-preference-item-input" />,
},
}, },
}, {
{ title: "Logs",
title: "Logs", id: "logs-preference-item-id",
id: "logs-preference-item-id", showInPreferencesTab: "logs-extension-tab",
showInPreferencesTab: "logs-extension-tab",
components: { components: {
Hint: () => <div data-testid="logs-preference-item-hint" />, Hint: () => <div data-testid="logs-preference-item-hint" />,
Input: () => <div data-testid="logs-preference-item-input" />, Input: () => <div data-testid="logs-preference-item-input" />,
},
}, },
}, ],
],
appPreferenceTabs: [{ appPreferenceTabs: [{
title: "Metrics tab", title: "Metrics tab",
id: "hello-extension-tab", id: "hello-extension-tab",
orderNumber: 100, orderNumber: 100,
}, { }, {
title: "Logs tab", title: "Logs tab",
id: "logs-extension-tab", id: "logs-extension-tab",
orderNumber: 200, orderNumber: 200,
}], }],
},
}; };
const extensionStubWithWithSameRegisteredTab: FakeExtensionData = { const extensionStubWithWithSameRegisteredTab: FakeExtensionOptions = {
id: "duplicated-tab-page-id", id: "duplicated-tab-page-id",
name: "duplicated-tab-page-id", name: "duplicated-tab-page-id",
appPreferences: [ rendererOptions: {
{ appPreferences: [
title: "Another metrics", {
id: "another-metrics-preference-item-id", title: "Another metrics",
showInPreferencesTab: "metrics-extension-tab", id: "another-metrics-preference-item-id",
showInPreferencesTab: "metrics-extension-tab",
components: { components: {
Hint: () => <div data-testid="another-metrics-preference-item-hint" />, Hint: () => <div data-testid="another-metrics-preference-item-hint" />,
Input: () => <div data-testid="another-metrics-preference-item-input" />, Input: () => <div data-testid="another-metrics-preference-item-input" />,
},
}, },
}, ],
],
appPreferenceTabs: [{ appPreferenceTabs: [{
title: "Metrics tab", title: "Metrics tab",
id: "metrics-extension-tab", id: "metrics-extension-tab",
orderNumber: 100, orderNumber: 100,
}], }],
},
}; };
const extensionUsingSomeoneElseTab: FakeExtensionData = { const extensionUsingSomeoneElseTab: FakeExtensionOptions = {
id: "extension-using-someone-else-tab-id", id: "extension-using-someone-else-tab-id",
name: "extension-using-someone-else-tab-id", name: "extension-using-someone-else-tab-id",
appPreferences: [ rendererOptions: {
{ appPreferences: [
title: "My preferences", {
id: "my-preferences-item-id", title: "My preferences",
showInPreferencesTab: "metrics-extension-tab", id: "my-preferences-item-id",
showInPreferencesTab: "metrics-extension-tab",
components: { components: {
Hint: () => <div data-testid="my-preferences-item-hint" />, Hint: () => <div data-testid="my-preferences-item-hint" />,
Input: () => <div data-testid="my-preferences-item-input" />, Input: () => <div data-testid="my-preferences-item-input" />,
},
}, },
}, ],
], },
}; };

View File

@ -9,30 +9,32 @@ import callForPublicHelmRepositoriesInjectable from "../../renderer/components/+
import getActiveHelmRepositoriesInjectable from "../../main/helm/repositories/get-active-helm-repositories/get-active-helm-repositories.injectable"; import getActiveHelmRepositoriesInjectable from "../../main/helm/repositories/get-active-helm-repositories/get-active-helm-repositories.injectable";
describe("preferences - navigation to kubernetes preferences", () => { describe("preferences - navigation to kubernetes preferences", () => {
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
beforeEach(() => { beforeEach(() => {
applicationBuilder = getApplicationBuilder(); builder = getApplicationBuilder();
}); });
describe("given in preferences, when rendered", () => { describe("given in preferences, when rendered", () => {
let rendered: RenderResult; let rendered: RenderResult;
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.beforeApplicationStart(({ rendererDi, mainDi }) => { builder.beforeApplicationStart((mainDi) => {
rendererDi.override(callForPublicHelmRepositoriesInjectable, () => async () => []);
mainDi.override( mainDi.override(
getActiveHelmRepositoriesInjectable, getActiveHelmRepositoriesInjectable,
() => async () => ({ callWasSuccessful: true, response: [] }), () => async () => ({ callWasSuccessful: true, response: [] }),
); );
}); });
applicationBuilder.beforeRender(() => { builder.beforeWindowStart((windowDi) => {
applicationBuilder.preferences.navigate(); windowDi.override(callForPublicHelmRepositoriesInjectable, () => async () => []);
}); });
rendered = await applicationBuilder.render(); builder.beforeWindowStart(() => {
builder.preferences.navigate();
});
rendered = await builder.render();
}); });
it("renders", () => { it("renders", () => {
@ -47,7 +49,7 @@ describe("preferences - navigation to kubernetes preferences", () => {
describe("when navigating to kubernetes preferences using navigation", () => { describe("when navigating to kubernetes preferences using navigation", () => {
beforeEach(() => { beforeEach(() => {
applicationBuilder.preferences.navigation.click("kubernetes"); builder.preferences.navigation.click("kubernetes");
}); });
it("renders", () => { it("renders", () => {

View File

@ -17,7 +17,7 @@ describe("preferences - navigation to proxy preferences", () => {
let rendered: RenderResult; let rendered: RenderResult;
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.beforeRender(() => { applicationBuilder.beforeWindowStart(() => {
applicationBuilder.preferences.navigate(); applicationBuilder.preferences.navigate();
}); });

View File

@ -6,27 +6,26 @@ import type { RenderResult } from "@testing-library/react";
import React from "react"; import React from "react";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import type { FakeExtensionData } from "../../renderer/components/test-utils/get-renderer-extension-fake";
import { getRendererExtensionFakeFor } from "../../renderer/components/test-utils/get-renderer-extension-fake";
import navigateToTelemetryPreferencesInjectable from "../../common/front-end-routing/routes/preferences/telemetry/navigate-to-telemetry-preferences.injectable"; import navigateToTelemetryPreferencesInjectable from "../../common/front-end-routing/routes/preferences/telemetry/navigate-to-telemetry-preferences.injectable";
import sentryDnsUrlInjectable from "../../renderer/components/+preferences/sentry-dns-url.injectable"; import sentryDnsUrlInjectable from "../../renderer/components/+preferences/sentry-dns-url.injectable";
import type { FakeExtensionOptions } from "../../renderer/components/test-utils/get-extension-fake";
describe("preferences - navigation to telemetry preferences", () => { describe("preferences - navigation to telemetry preferences", () => {
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
beforeEach(() => { beforeEach(() => {
applicationBuilder = getApplicationBuilder(); builder = getApplicationBuilder();
}); });
describe("given in preferences, when rendered", () => { describe("given in preferences, when rendered", () => {
let rendered: RenderResult; let rendered: RenderResult;
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.beforeRender(() => { builder.beforeWindowStart(() => {
applicationBuilder.preferences.navigate(); builder.preferences.navigate();
}); });
rendered = await applicationBuilder.render(); rendered = await builder.render();
}); });
it("renders", () => { it("renders", () => {
@ -47,11 +46,8 @@ describe("preferences - navigation to telemetry preferences", () => {
describe("when extension with telemetry preference items gets enabled", () => { describe("when extension with telemetry preference items gets enabled", () => {
beforeEach(() => { beforeEach(() => {
const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder); builder.extensions.enable(
const testExtensionWithTelemetryPreferenceItems = getRendererExtensionFake(extensionStubWithTelemetryPreferenceItems); extensionStubWithTelemetryPreferenceItems,
applicationBuilder.extensions.renderer.enable(
testExtensionWithTelemetryPreferenceItems,
); );
}); });
@ -67,7 +63,7 @@ describe("preferences - navigation to telemetry preferences", () => {
describe("when clicking link to telemetry preferences from navigation", () => { describe("when clicking link to telemetry preferences from navigation", () => {
beforeEach(() => { beforeEach(() => {
applicationBuilder.preferences.navigation.click("telemetry"); builder.preferences.navigation.click("telemetry");
}); });
it("renders", () => { it("renders", () => {
@ -91,23 +87,21 @@ describe("preferences - navigation to telemetry preferences", () => {
}); });
it("given extensions but no telemetry preference items, does not show link for telemetry preferences", () => { it("given extensions but no telemetry preference items, does not show link for telemetry preferences", () => {
const getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder); builder.extensions.enable({
const testExtensionWithTelemetryPreferenceItems = getRendererExtensionFake({
id: "some-test-extension-id", id: "some-test-extension-id",
name: "some-test-extension-name", name: "some-test-extension-name",
appPreferences: [
{
title: "irrelevant",
id: "irrelevant",
showInPreferencesTab: "not-telemetry",
components: { Hint: () => <div />, Input: () => <div /> },
},
],
});
applicationBuilder.extensions.renderer.enable( rendererOptions: {
testExtensionWithTelemetryPreferenceItems, appPreferences: [
); {
title: "irrelevant",
id: "irrelevant",
showInPreferencesTab: "not-telemetry",
components: { Hint: () => <div />, Input: () => <div /> },
},
],
},
});
const actual = rendered.queryByTestId("tab-link-for-telemetry"); const actual = rendered.queryByTestId("tab-link-for-telemetry");
@ -119,18 +113,18 @@ describe("preferences - navigation to telemetry preferences", () => {
let rendered: RenderResult; let rendered: RenderResult;
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.beforeApplicationStart(({ rendererDi }) => { builder.beforeWindowStart((windowDi) => {
rendererDi.override(sentryDnsUrlInjectable, () => "some-sentry-dns-url"); windowDi.override(sentryDnsUrlInjectable, () => "some-sentry-dns-url");
}); });
rendered = await applicationBuilder.render(); rendered = await builder.render();
applicationBuilder.preferences.navigate(); builder.preferences.navigate();
}); });
describe("when navigating to telemetry preferences", () => { describe("when navigating to telemetry preferences", () => {
beforeEach(() => { beforeEach(() => {
applicationBuilder.preferences.navigation.click("telemetry"); builder.preferences.navigation.click("telemetry");
}); });
it("renders", () => { it("renders", () => {
@ -149,13 +143,15 @@ describe("preferences - navigation to telemetry preferences", () => {
let rendered: RenderResult; let rendered: RenderResult;
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.beforeApplicationStart(({ rendererDi }) => { builder.beforeWindowStart((windowDi) => {
rendererDi.override(sentryDnsUrlInjectable, () => null); windowDi.override(sentryDnsUrlInjectable, () => null);
}); });
rendered = await applicationBuilder.render(); rendered = await builder.render();
const navigateToTelemetryPreferences = applicationBuilder.dis.rendererDi.inject(navigateToTelemetryPreferencesInjectable); const windowDi = builder.applicationWindow.only.di;
const navigateToTelemetryPreferences = windowDi.inject(navigateToTelemetryPreferencesInjectable);
navigateToTelemetryPreferences(); navigateToTelemetryPreferences();
}); });
@ -172,19 +168,22 @@ describe("preferences - navigation to telemetry preferences", () => {
}); });
}); });
const extensionStubWithTelemetryPreferenceItems: FakeExtensionData = { const extensionStubWithTelemetryPreferenceItems: FakeExtensionOptions = {
id: "some-test-extension-id", id: "some-test-extension-id",
name: "some-test-extension-name", name: "some-test-extension-name",
appPreferences: [
{
title: "Some telemetry-preference item",
id: "some-telemetry-preference-item-id",
showInPreferencesTab: "telemetry",
components: { rendererOptions: {
Hint: () => <div data-testid="some-preference-item-hint" />, appPreferences: [
Input: () => <div data-testid="some-preference-item-input" />, {
title: "Some telemetry-preference item",
id: "some-telemetry-preference-item-id",
showInPreferencesTab: "telemetry",
components: {
Hint: () => <div data-testid="some-preference-item-hint" />,
Input: () => <div data-testid="some-preference-item-input" />,
},
}, },
}, ],
], },
}; };

View File

@ -17,7 +17,7 @@ describe("preferences - navigation to terminal preferences", () => {
let rendered: RenderResult; let rendered: RenderResult;
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.beforeRender(() => { applicationBuilder.beforeWindowStart(() => {
applicationBuilder.preferences.navigate(); applicationBuilder.preferences.navigate();
}); });

View File

@ -5,19 +5,18 @@
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { lensWindowInjectionToken } from "../../main/start-main-application/lens-window/application-window/lens-window-injection-token";
import applicationWindowInjectable from "../../main/start-main-application/lens-window/application-window/application-window.injectable";
import createElectronWindowForInjectable from "../../main/start-main-application/lens-window/application-window/create-electron-window.injectable";
import type { AsyncFnMock } from "@async-fn/jest"; import type { AsyncFnMock } from "@async-fn/jest";
import asyncFn from "@async-fn/jest"; import asyncFn from "@async-fn/jest";
import type { ElectronWindow, LensWindowConfiguration } from "../../main/start-main-application/lens-window/application-window/create-lens-window.injectable"; import type { LensWindow } from "../../main/start-main-application/lens-window/application-window/create-lens-window.injectable";
import type { DiContainer } from "@ogre-tools/injectable";
import lensResourcesDirInjectable from "../../common/vars/lens-resources-dir.injectable"; import lensResourcesDirInjectable from "../../common/vars/lens-resources-dir.injectable";
import focusApplicationInjectable from "../../main/electron-app/features/focus-application.injectable"; import focusApplicationInjectable from "../../main/electron-app/features/focus-application.injectable";
import type { CreateElectronWindow } from "../../main/start-main-application/lens-window/application-window/create-electron-window.injectable";
import createElectronWindowInjectable from "../../main/start-main-application/lens-window/application-window/create-electron-window.injectable";
import splashWindowInjectable from "../../main/start-main-application/lens-window/splash-window/splash-window.injectable";
describe("opening application window using tray", () => { describe("opening application window using tray", () => {
describe("given application has started", () => { describe("given application has started", () => {
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
let createElectronWindowMock: jest.Mock; let createElectronWindowMock: jest.Mock;
let expectWindowsToBeOpen: (windowIds: string[]) => void; let expectWindowsToBeOpen: (windowIds: string[]) => void;
let callForSplashWindowHtmlMock: AsyncFnMock<() => Promise<void>>; let callForSplashWindowHtmlMock: AsyncFnMock<() => Promise<void>>;
@ -30,71 +29,66 @@ describe("opening application window using tray", () => {
focusApplicationMock = jest.fn(); focusApplicationMock = jest.fn();
applicationBuilder = getApplicationBuilder().beforeApplicationStart( builder = getApplicationBuilder();
({ mainDi }) => {
mainDi.override(focusApplicationInjectable, () => focusApplicationMock);
mainDi.override(lensResourcesDirInjectable, () => "some-lens-resources-directory"); builder.beforeApplicationStart((mainDi) => {
mainDi.override(focusApplicationInjectable, () => focusApplicationMock);
const loadFileMock = jest mainDi.override(
.fn(callForSplashWindowHtmlMock) lensResourcesDirInjectable,
.mockImplementationOnce(() => Promise.resolve()); () => "some-lens-resources-directory",
);
const loadUrlMock = jest const loadFileMock = jest
.fn(callForApplicationWindowHtmlMock) .fn(callForSplashWindowHtmlMock)
.mockImplementationOnce(() => Promise.resolve()); .mockImplementationOnce(() => Promise.resolve());
createElectronWindowMock = jest.fn((configuration: LensWindowConfiguration) => const loadUrlMock = jest
({ .fn(callForApplicationWindowHtmlMock)
splash: { .mockImplementationOnce(() => Promise.resolve());
send: () => {},
close: () => {},
show: () => {},
loadFile: loadFileMock,
loadUrl: () => { throw new Error("Should never come here"); },
},
"only-application-window": { createElectronWindowMock = jest.fn((toBeDecorated): CreateElectronWindow => (configuration) => {
send: () => {}, const browserWindow = toBeDecorated(configuration);
close: () => {},
show: () => {},
loadFile: () => { throw new Error("Should never come here"); },
loadUrl: loadUrlMock,
},
}[configuration.id] as ElectronWindow));
mainDi.override( if (configuration.id === "splash") {
createElectronWindowForInjectable, return { ...browserWindow, loadFile: loadFileMock };
}
() => createElectronWindowMock, if (configuration.id === "first-application-window") {
); return { ...browserWindow, loadUrl: loadUrlMock };
}
expectWindowsToBeOpen = expectWindowsToBeOpenFor(mainDi); return browserWindow;
}, });
);
await applicationBuilder.render(); (mainDi as any).decorateFunction(
createElectronWindowInjectable,
createElectronWindowMock,
);
expectWindowsToBeOpen = expectWindowsToBeOpenFor(builder);
});
await builder.render();
}); });
it("only an application window is open", () => { it("only the first application window is open", () => {
expectWindowsToBeOpen(["only-application-window"]); expectWindowsToBeOpen(["first-application-window"]);
}); });
describe("when an attempt to reopen the already started application is made using tray", () => { describe("when an attempt to reopen the already started application is made using tray", () => {
beforeEach(() => { beforeEach(() => {
applicationBuilder.tray.click("open-app"); builder.tray.click("open-app");
}); });
it("still shows only the application window", () => { it("still shows only the application window", () => {
expectWindowsToBeOpen(["only-application-window"]); expectWindowsToBeOpen(["first-application-window"]);
}); });
}); });
describe("when the application window is closed", () => { describe("when the first application window is closed", () => {
beforeEach(() => { beforeEach(() => {
const applicationWindow = applicationBuilder.dis.mainDi.inject( const applicationWindow = builder.applicationWindow.only;
applicationWindowInjectable,
);
applicationWindow.close(); applicationWindow.close();
}); });
@ -110,7 +104,7 @@ describe("opening application window using tray", () => {
callForSplashWindowHtmlMock.mockClear(); callForSplashWindowHtmlMock.mockClear();
callForApplicationWindowHtmlMock.mockClear(); callForApplicationWindowHtmlMock.mockClear();
applicationBuilder.tray.click("open-app"); builder.tray.click("open-app");
}); });
it("focuses the application", () => { it("focuses the application", () => {
@ -143,7 +137,7 @@ describe("opening application window using tray", () => {
callForApplicationWindowHtmlMock.mockClear(); callForApplicationWindowHtmlMock.mockClear();
callForSplashWindowHtmlMock.mockClear(); callForSplashWindowHtmlMock.mockClear();
applicationBuilder.tray.click("open-app"); builder.tray.click("open-app");
}); });
it("does not load contents of splash window again", () => { it("does not load contents of splash window again", () => {
@ -155,7 +149,7 @@ describe("opening application window using tray", () => {
}); });
it("shows just the blank application window to permit developer tool access", () => { it("shows just the blank application window to permit developer tool access", () => {
expectWindowsToBeOpen(["only-application-window"]); expectWindowsToBeOpen(["first-application-window"]);
}); });
}); });
@ -165,7 +159,7 @@ describe("opening application window using tray", () => {
}); });
it("shows just the application window", () => { it("shows just the application window", () => {
expectWindowsToBeOpen(["only-application-window"]); expectWindowsToBeOpen(["first-application-window"]);
}); });
describe("when reopening the application using tray", () => { describe("when reopening the application using tray", () => {
@ -173,11 +167,11 @@ describe("opening application window using tray", () => {
callForSplashWindowHtmlMock.mockClear(); callForSplashWindowHtmlMock.mockClear();
callForApplicationWindowHtmlMock.mockClear(); callForApplicationWindowHtmlMock.mockClear();
applicationBuilder.tray.click("open-app"); builder.tray.click("open-app");
}); });
it("still shows just the application window", () => { it("still shows just the application window", () => {
expectWindowsToBeOpen(["only-application-window"]); expectWindowsToBeOpen(["first-application-window"]);
}); });
it("does not load HTML for splash window again", () => { it("does not load HTML for splash window again", () => {
@ -195,7 +189,7 @@ describe("opening application window using tray", () => {
beforeEach(() => { beforeEach(() => {
createElectronWindowMock.mockClear(); createElectronWindowMock.mockClear();
applicationBuilder.tray.click("open-app"); builder.tray.click("open-app");
}); });
it("does not open any new windows", () => { it("does not open any new windows", () => {
@ -215,14 +209,14 @@ describe("opening application window using tray", () => {
it("when opening of application window finishes, only an application window is open", async () => { it("when opening of application window finishes, only an application window is open", async () => {
await callForApplicationWindowHtmlMock.resolve(); await callForApplicationWindowHtmlMock.resolve();
expectWindowsToBeOpen(["only-application-window"]); expectWindowsToBeOpen(["first-application-window"]);
}); });
describe("given opening of application window has not finished yet, but another attempt to open the application is made", () => { describe("given opening of application window has not finished yet, but another attempt to open the application is made", () => {
beforeEach(() => { beforeEach(() => {
createElectronWindowMock.mockClear(); createElectronWindowMock.mockClear();
applicationBuilder.tray.click("open-app"); builder.tray.click("open-app");
}); });
it("does not open any new windows", () => { it("does not open any new windows", () => {
@ -232,7 +226,7 @@ describe("opening application window using tray", () => {
it("when opening finishes, only an application window is open", async () => { it("when opening finishes, only an application window is open", async () => {
await callForApplicationWindowHtmlMock.resolve(); await callForApplicationWindowHtmlMock.resolve();
expectWindowsToBeOpen(["only-application-window"]); expectWindowsToBeOpen(["first-application-window"]);
}); });
}); });
}); });
@ -241,10 +235,14 @@ describe("opening application window using tray", () => {
}); });
}); });
const expectWindowsToBeOpenFor = (di: DiContainer) => (windowIds: string[]) => { const expectWindowsToBeOpenFor =
const windows = di.injectMany(lensWindowInjectionToken); (builder: ApplicationBuilder) => (windowIds: string[]) => {
const windows: LensWindow[] = [
builder.mainDi.inject(splashWindowInjectable),
...builder.applicationWindow.getAll(),
];
expect( expect(
windows.filter((window) => window.isVisible).map((window) => window.id), windows.filter((window) => window.isVisible).map((window) => window.id),
).toEqual(windowIds); ).toEqual(windowIds);
}; };

View File

@ -6,7 +6,6 @@
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import type { ClusterManager } from "../../main/cluster-manager"; import type { ClusterManager } from "../../main/cluster-manager";
import { lensWindowInjectionToken } from "../../main/start-main-application/lens-window/application-window/lens-window-injection-token";
import exitAppInjectable from "../../main/electron-app/features/exit-app.injectable"; import exitAppInjectable from "../../main/electron-app/features/exit-app.injectable";
import clusterManagerInjectable from "../../main/cluster-manager.injectable"; import clusterManagerInjectable from "../../main/cluster-manager.injectable";
import stopServicesAndExitAppInjectable from "../../main/stop-services-and-exit-app.injectable"; import stopServicesAndExitAppInjectable from "../../main/stop-services-and-exit-app.injectable";
@ -14,15 +13,17 @@ import { advanceFakeTime, useFakeTime } from "../../common/test-utils/use-fake-t
describe("quitting the app using application menu", () => { describe("quitting the app using application menu", () => {
describe("given application has started", () => { describe("given application has started", () => {
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
let clusterManagerStub: ClusterManager; let clusterManagerStub: ClusterManager;
let exitAppMock: jest.Mock; let exitAppMock: jest.Mock;
beforeEach(async () => { beforeEach(async () => {
useFakeTime("2015-10-21T07:28:00Z"); useFakeTime("2015-10-21T07:28:00Z");
applicationBuilder = getApplicationBuilder().beforeApplicationStart( builder = getApplicationBuilder();
({ mainDi }) => {
builder.beforeApplicationStart(
(mainDi) => {
mainDi.unoverride(stopServicesAndExitAppInjectable); mainDi.unoverride(stopServicesAndExitAppInjectable);
clusterManagerStub = { stop: jest.fn() } as unknown as ClusterManager; clusterManagerStub = { stop: jest.fn() } as unknown as ClusterManager;
@ -33,38 +34,24 @@ describe("quitting the app using application menu", () => {
}, },
); );
await applicationBuilder.render(); await builder.render();
}); });
it("only an application window is open", () => { it("first application window is open", () => {
const windows = applicationBuilder.dis.mainDi.injectMany( const windows = builder.applicationWindow.getAll();
lensWindowInjectionToken,
);
expect( expect(windows.map((window) => window.id)).toEqual(["first-application-window"]);
windows.map((window) => ({ id: window.id, visible: window.isVisible })),
).toEqual([
{ id: "only-application-window", visible: true },
{ id: "splash", visible: false },
]);
}); });
describe("when application is quit", () => { describe("when application is quit", () => {
beforeEach(() => { beforeEach(() => {
applicationBuilder.applicationMenu.click("root.quit"); builder.applicationMenu.click("root.quit");
}); });
it("closes all windows", () => { it("closes all windows", () => {
const windows = applicationBuilder.dis.mainDi.injectMany( const windows = builder.applicationWindow.getAll();
lensWindowInjectionToken,
);
expect( expect(windows).toEqual([]);
windows.map((window) => ({ id: window.id, visible: window.isVisible })),
).toEqual([
{ id: "only-application-window", visible: false },
{ id: "splash", visible: false },
]);
}); });
it("disconnects all clusters", () => { it("disconnects all clusters", () => {

View File

@ -12,28 +12,28 @@ import resolveSystemProxyFromElectronInjectable from "../../main/utils/resolve-s
import { getPromiseStatus } from "../../common/test-utils/get-promise-status"; import { getPromiseStatus } from "../../common/test-utils/get-promise-status";
describe("resolve-system-proxy", () => { describe("resolve-system-proxy", () => {
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
let actualPromise: Promise<string>; let actualPromise: Promise<string>;
let resolveSystemProxyFromElectronMock: AsyncFnMock<ResolveSystemProxy>; let resolveSystemProxyFromElectronMock: AsyncFnMock<ResolveSystemProxy>;
beforeEach(async () => { beforeEach(async () => {
applicationBuilder = getApplicationBuilder(); builder = getApplicationBuilder();
resolveSystemProxyFromElectronMock = asyncFn(); resolveSystemProxyFromElectronMock = asyncFn();
applicationBuilder.beforeApplicationStart(({ mainDi }) => { builder.beforeApplicationStart((mainDi) => {
mainDi.override( mainDi.override(
resolveSystemProxyFromElectronInjectable, resolveSystemProxyFromElectronInjectable,
() => resolveSystemProxyFromElectronMock, () => resolveSystemProxyFromElectronMock,
); );
}); });
await applicationBuilder.render(); await builder.render();
}); });
describe("given in main, when called with URL", () => { describe("given in main, when called with URL", () => {
beforeEach(async () => { beforeEach(async () => {
const resolveSystemProxyInMain = applicationBuilder.dis.mainDi.inject( const resolveSystemProxyInMain = builder.mainDi.inject(
resolveSystemProxyInjectionToken, resolveSystemProxyInjectionToken,
); );
@ -59,7 +59,9 @@ describe("resolve-system-proxy", () => {
describe("given in renderer, when called with URL", () => { describe("given in renderer, when called with URL", () => {
beforeEach(async () => { beforeEach(async () => {
const resolveSystemProxyInRenderer = applicationBuilder.dis.rendererDi.inject( const windowDi = builder.applicationWindow.only.di;
const resolveSystemProxyInRenderer = windowDi.inject(
resolveSystemProxyInjectionToken, resolveSystemProxyInjectionToken,
); );

View File

@ -9,7 +9,6 @@ import React from "react";
import type { TestExtensionRenderer } from "../../../renderer/components/test-utils/get-extension-fake"; import type { TestExtensionRenderer } from "../../../renderer/components/test-utils/get-extension-fake";
import type { ApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
import { getExtensionFakeFor } from "../../../renderer/components/test-utils/get-extension-fake";
describe("reactively disable global pages", () => { describe("reactively disable global pages", () => {
let builder: ApplicationBuilder; let builder: ApplicationBuilder;
@ -20,11 +19,9 @@ describe("reactively disable global pages", () => {
beforeEach(async () => { beforeEach(async () => {
builder = getApplicationBuilder(); builder = getApplicationBuilder();
const getExtensionFake = getExtensionFakeFor(builder);
someObservable = observable.box(false); someObservable = observable.box(false);
const testExtension = getExtensionFake({ const testExtension = {
id: "test-extension-id", id: "test-extension-id",
name: "test-extension", name: "test-extension",
@ -37,13 +34,13 @@ describe("reactively disable global pages", () => {
enabled: computed(() => someObservable.get()), enabled: computed(() => someObservable.get()),
}], }],
}, },
}); };
rendered = await builder.render(); rendered = await builder.render();
builder.extensions.enable(testExtension); builder.extensions.enable(testExtension);
rendererTestExtension = testExtension.renderer; rendererTestExtension = builder.extensions.get("test-extension-id").applicationWindows.only;
}); });
it("when navigating to the page, does not show the page", () => { it("when navigating to the page, does not show the page", () => {

View File

@ -4,11 +4,10 @@
*/ */
import type { RenderResult } from "@testing-library/react"; import type { RenderResult } from "@testing-library/react";
import React from "react"; import React from "react";
import type { GetRendererExtensionFake, TestExtension } from "../../renderer/components/test-utils/get-renderer-extension-fake";
import { getRendererExtensionFakeFor } from "../../renderer/components/test-utils/get-renderer-extension-fake";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import getRandomIdInjectable from "../../common/utils/get-random-id.injectable"; import getRandomIdInjectable from "../../common/utils/get-random-id.injectable";
import type { FakeExtensionOptions } from "../../renderer/components/test-utils/get-extension-fake";
describe("status-bar-items-originating-from-extensions", () => { describe("status-bar-items-originating-from-extensions", () => {
let applicationBuilder: ApplicationBuilder; let applicationBuilder: ApplicationBuilder;
@ -16,50 +15,53 @@ describe("status-bar-items-originating-from-extensions", () => {
beforeEach(() => { beforeEach(() => {
applicationBuilder = getApplicationBuilder(); applicationBuilder = getApplicationBuilder();
applicationBuilder.beforeApplicationStart(({ rendererDi }) => { applicationBuilder.beforeWindowStart((windowDi) => {
rendererDi.unoverride(getRandomIdInjectable); windowDi.unoverride(getRandomIdInjectable);
rendererDi.permitSideEffects(getRandomIdInjectable); windowDi.permitSideEffects(getRandomIdInjectable);
}); });
}); });
describe("when application starts", () => { describe("when application starts", () => {
let rendered: RenderResult; let rendered: RenderResult;
let getRendererExtensionFake: GetRendererExtensionFake;
beforeEach(async () => { beforeEach(async () => {
rendered = await applicationBuilder.render(); rendered = await applicationBuilder.render();
getRendererExtensionFake = getRendererExtensionFakeFor(applicationBuilder);
}); });
it("when multiple extensions with status bar items are loaded, shows items in correct order", () => { it("when multiple extensions with status bar items are loaded, shows items in correct order", () => {
const testExtension1 = getRendererExtensionFake({ const testExtension1 = {
id: "some-id", id: "some-id",
name: "some-name", name: "some-name",
statusBarItems: [ rendererOptions: {
{ statusBarItems: [
components: { {
Item: () => <div data-testid="some-testId">extension1</div>, components: {
position: "right", Item: () => <div data-testid="some-testId">extension1</div>,
position: "right" as const,
},
}, },
}, ],
], },
}); };
const testExtension2 = getRendererExtensionFake({ const testExtension2 = {
id: "some-other-id", id: "some-other-id",
name: "some-other-name", name: "some-other-name",
statusBarItems: [
{
components: {
Item: () => <div data-testid="some-testId">extension2</div>,
position: "right",
},
},
],
});
applicationBuilder.extensions.renderer.enable(testExtension1, testExtension2); rendererOptions: {
statusBarItems: [
{
components: {
Item: () => <div data-testid="some-testId">extension2</div>,
position: "right" as const,
},
},
],
},
};
applicationBuilder.extensions.enable(testExtension1, testExtension2);
const rightSide = rendered.getByTestId("status-bar-right"); const rightSide = rendered.getByTestId("status-bar-right");
@ -72,41 +74,44 @@ describe("status-bar-items-originating-from-extensions", () => {
}); });
describe("when extension with status bar items is loaded", () => { describe("when extension with status bar items is loaded", () => {
let testExtension: TestExtension; let testExtensionOptions: FakeExtensionOptions;
beforeEach(() => { beforeEach(() => {
testExtension = getRendererExtensionFake({ testExtensionOptions = {
id: "some-id", id: "some-id",
name: "some-name", name: "some-name",
statusBarItems: [
{
item: () => <span data-testid="some-testId">right1</span>,
},
{
item: () => <span data-testid="some-testId">right2</span>,
},
{
components: {
Item: () => <div data-testid="some-testId">right3</div>,
position: "right",
},
},
{
components: {
Item: () => <div data-testid="some-testId">left1</div>,
position: "left",
},
},
{
components: {
Item: () => <div data-testid="some-testId">left2</div>,
position: "left",
},
},
],
});
applicationBuilder.extensions.renderer.enable(testExtension); rendererOptions: {
statusBarItems: [
{
item: () => <span data-testid="some-testId">right1</span>,
},
{
item: () => <span data-testid="some-testId">right2</span>,
},
{
components: {
Item: () => <div data-testid="some-testId">right3</div>,
position: "right" as const,
},
},
{
components: {
Item: () => <div data-testid="some-testId">left1</div>,
position: "left" as const,
},
},
{
components: {
Item: () => <div data-testid="some-testId">left2</div>,
position: "left" as const,
},
},
],
},
};
applicationBuilder.extensions.enable(testExtensionOptions);
}); });
it("renders", () => { it("renders", () => {
@ -134,7 +139,7 @@ describe("status-bar-items-originating-from-extensions", () => {
}); });
it("when the extension is removed, shows there are no extension status bar items", () => { it("when the extension is removed, shows there are no extension status bar items", () => {
applicationBuilder.extensions.renderer.disable(testExtension); applicationBuilder.extensions.disable(testExtensionOptions);
const actual = rendered.queryAllByTestId("some-testId"); const actual = rendered.queryAllByTestId("some-testId");

View File

@ -2,49 +2,51 @@
* Copyright (c) OpenLens Authors. All rights reserved. * Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import { LensMainExtension } from "../../extensions/lens-main-extension";
import type { TrayMenuRegistration } from "../../main/tray/tray-menu-registration";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import loggerInjectable from "../../common/logger.injectable"; import loggerInjectable from "../../common/logger.injectable";
import type { Logger } from "../../common/logger"; import type { Logger } from "../../common/logger";
import type { FakeExtensionOptions } from "../../renderer/components/test-utils/get-extension-fake";
import getRandomIdInjectable from "../../common/utils/get-random-id.injectable"; import getRandomIdInjectable from "../../common/utils/get-random-id.injectable";
describe("clicking tray menu item originating from extension", () => { describe("clicking tray menu item originating from extension", () => {
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
let logErrorMock: jest.Mock; let logErrorMock: jest.Mock;
beforeEach(async () => { beforeEach(async () => {
applicationBuilder = getApplicationBuilder(); builder = getApplicationBuilder();
applicationBuilder.beforeApplicationStart(({ mainDi }) => { builder.beforeApplicationStart((mainDi) => {
logErrorMock = jest.fn(); logErrorMock = jest.fn();
mainDi.override(loggerInjectable, () => ({ error: logErrorMock }) as unknown as Logger); mainDi.override(loggerInjectable, () => ({ error: logErrorMock }) as unknown as Logger);
mainDi.override(getRandomIdInjectable, () => () => "some-random-id"); mainDi.override(getRandomIdInjectable, () => () => "some-random-id");
}); });
await applicationBuilder.render(); await builder.render();
}); });
describe("when extension is enabled", () => { describe("when extension is enabled", () => {
let someExtension: SomeTestExtension; let someExtension: FakeExtensionOptions;
let clickMock: jest.Mock; let clickMock: jest.Mock;
beforeEach(() => { beforeEach(() => {
clickMock = jest.fn(); clickMock = jest.fn();
someExtension = new SomeTestExtension({ someExtension = {
id: "some-extension-id", id: "some-extension-id",
trayMenus: [{ label: "some-label", click: clickMock }], name: "some-extension-name",
}); mainOptions: {
trayMenus: [{ label: "some-label", click: clickMock }],
},
};
applicationBuilder.extensions.main.enable(someExtension); builder.extensions.enable(someExtension);
}); });
it("when item is clicked, triggers the click handler", () => { it("when item is clicked, triggers the click handler", () => {
applicationBuilder.tray.click( builder.tray.click(
"some-random-id-tray-menu-item-for-extension-some-extension-id", "some-random-id-tray-menu-item-for-extension-some-extension-name",
); );
expect(clickMock).toHaveBeenCalled(); expect(clickMock).toHaveBeenCalled();
@ -56,14 +58,14 @@ describe("clicking tray menu item originating from extension", () => {
throw new Error("some-error"); throw new Error("some-error");
}); });
applicationBuilder.tray.click( builder.tray.click(
"some-random-id-tray-menu-item-for-extension-some-extension-id", "some-random-id-tray-menu-item-for-extension-some-extension-name",
); );
}); });
it("logs the error", () => { it("logs the error", () => {
expect(logErrorMock).toHaveBeenCalledWith( expect(logErrorMock).toHaveBeenCalledWith(
'[TRAY]: Clicking of tray item "some-random-id" from extension "some-extension-id" failed.', '[TRAY]: Clicking of tray item "some-random-id" from extension "some-extension-name" failed.',
expect.any(Error), expect.any(Error),
); );
}); });
@ -73,14 +75,14 @@ describe("clicking tray menu item originating from extension", () => {
beforeEach(() => { beforeEach(() => {
clickMock.mockImplementation(() => Promise.reject("some-rejection")); clickMock.mockImplementation(() => Promise.reject("some-rejection"));
applicationBuilder.tray.click( builder.tray.click(
"some-random-id-tray-menu-item-for-extension-some-extension-id", "some-random-id-tray-menu-item-for-extension-some-extension-name",
); );
}); });
it("logs the error", () => { it("logs the error", () => {
expect(logErrorMock).toHaveBeenCalledWith( expect(logErrorMock).toHaveBeenCalledWith(
'[TRAY]: Clicking of tray item "some-random-id" from extension "some-extension-id" failed.', '[TRAY]: Clicking of tray item "some-random-id" from extension "some-extension-name" failed.',
"some-rejection", "some-rejection",
); );
}); });
@ -88,47 +90,27 @@ describe("clicking tray menu item originating from extension", () => {
describe("when extension is disabled", () => { describe("when extension is disabled", () => {
beforeEach(() => { beforeEach(() => {
applicationBuilder.extensions.main.disable(someExtension); builder.extensions.disable(someExtension);
}); });
it("does not have the tray menu item from extension", () => { it("does not have the tray menu item from extension", () => {
expect( expect(
applicationBuilder.tray.get( builder.tray.get(
"some-random-id-tray-menu-item-for-extension-some-extension-id", "some-random-id-tray-menu-item-for-extension-some-extension-name",
), ),
).toBeNull(); ).toBeNull();
}); });
// Note: Motivation here is to make sure that enabling same extension does not throw // Note: Motivation here is to make sure that enabling same extension does not throw
it("when extension is re-enabled, has the tray menu item from extension", async () => { it("when extension is re-enabled, has the tray menu item from extension", async () => {
await applicationBuilder.extensions.main.enable(someExtension); await builder.extensions.enable(someExtension);
expect( expect(
applicationBuilder.tray.get( builder.tray.get(
"some-random-id-tray-menu-item-for-extension-some-extension-id", "some-random-id-tray-menu-item-for-extension-some-extension-name",
), ),
).not.toBeNull(); ).not.toBeNull();
}); });
}); });
}); });
}); });
class SomeTestExtension extends LensMainExtension {
constructor({ id, trayMenus }: {
id: string;
trayMenus: TrayMenuRegistration[];
}) {
super({
id,
absolutePath: "irrelevant",
isBundled: false,
isCompatible: false,
isEnabled: false,
manifest: { name: id, version: "some-version", engines: { lens: "^5.5.0" }},
manifestPath: "irrelevant",
});
this.trayMenus = trayMenus;
}
}

View File

@ -6,7 +6,6 @@ import type { IObservableValue } from "mobx";
import { computed, runInAction, observable } from "mobx"; import { computed, runInAction, observable } from "mobx";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getExtensionFakeFor } from "../../renderer/components/test-utils/get-extension-fake";
describe("preferences: extension adding tray items", () => { describe("preferences: extension adding tray items", () => {
describe("when extension with tray items is enabled", () => { describe("when extension with tray items is enabled", () => {
@ -22,13 +21,11 @@ describe("preferences: extension adding tray items", () => {
builder.preferences.navigate(); builder.preferences.navigate();
const getExtensionFake = getExtensionFakeFor(builder);
someObservableForVisibility = observable.box(false); someObservableForVisibility = observable.box(false);
someObservableForEnabled = observable.box(false); someObservableForEnabled = observable.box(false);
someObservableLabel = observable.box("Some label"); someObservableLabel = observable.box("Some label");
const testExtension = getExtensionFake({ const testExtension = {
id: "some-extension-id", id: "some-extension-id",
name: "some-extension", name: "some-extension",
@ -82,7 +79,7 @@ describe("preferences: extension adding tray items", () => {
}, },
], ],
}, },
}); };
builder.extensions.enable(testExtension); builder.extensions.enable(testExtension);
}); });

View File

@ -2,53 +2,36 @@
* Copyright (c) OpenLens Authors. All rights reserved. * Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import { LensMainExtension } from "../../extensions/lens-main-extension";
import type { TrayMenuRegistration } from "../../main/tray/tray-menu-registration";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import getRandomIdInjectable from "../../common/utils/get-random-id.injectable"; import getRandomIdInjectable from "../../common/utils/get-random-id.injectable";
describe("multiple separators originating from extension", () => { describe("multiple separators originating from extension", () => {
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
beforeEach(async () => { beforeEach(async () => {
applicationBuilder = getApplicationBuilder(); builder = getApplicationBuilder();
applicationBuilder.beforeApplicationStart(({ mainDi }) => { builder.beforeApplicationStart((mainDi) => {
mainDi.unoverride(getRandomIdInjectable); mainDi.unoverride(getRandomIdInjectable);
mainDi.permitSideEffects(getRandomIdInjectable); mainDi.permitSideEffects(getRandomIdInjectable);
}); });
await applicationBuilder.render(); await builder.render();
}); });
it("given extension with multiple separators, when extension is enabled, does not throw", () => { it("given extension with multiple separators, when extension is enabled, does not throw", () => {
const someExtension = new SomeTestExtension({ const someExtension = {
id: "some-extension-id", id: "some-extension-id",
trayMenus: [{ type: "separator" }, { type: "separator" } ], name: "some-extension",
});
mainOptions: {
trayMenus: [{ type: "separator" as const }, { type: "separator" as const } ],
},
};
expect(() => { expect(() => {
applicationBuilder.extensions.main.enable(someExtension); builder.extensions.enable(someExtension);
}).not.toThrow(); }).not.toThrow();
}); });
}); });
class SomeTestExtension extends LensMainExtension {
constructor({ id, trayMenus }: {
id: string;
trayMenus: TrayMenuRegistration[];
}) {
super({
id,
absolutePath: "irrelevant",
isBundled: false,
isCompatible: false,
isEnabled: false,
manifest: { name: id, version: "some-version", engines: { lens: "^5.5.0" }},
manifestPath: "irrelevant",
});
this.trayMenus = trayMenus;
}
}

View File

@ -17,9 +17,6 @@ import extensionsStoreInjectable from "../extensions/extensions-store/extensions
import type { ExtensionsStore } from "../extensions/extensions-store/extensions-store"; import type { ExtensionsStore } from "../extensions/extensions-store/extensions-store";
import fileSystemProvisionerStoreInjectable from "../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable"; import fileSystemProvisionerStoreInjectable from "../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable";
import type { FileSystemProvisionerStore } from "../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store"; import type { FileSystemProvisionerStore } from "../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store";
import clusterStoreInjectable from "../common/cluster-store/cluster-store.injectable";
import type { ClusterStore } from "../common/cluster-store/cluster-store";
import type { Cluster } from "../common/cluster/cluster";
import userStoreInjectable from "../common/user-store/user-store.injectable"; import userStoreInjectable from "../common/user-store/user-store.injectable";
import type { UserStore } from "../common/user-store"; import type { UserStore } from "../common/user-store";
import getAbsolutePathInjectable from "../common/path/get-absolute-path.injectable"; import getAbsolutePathInjectable from "../common/path/get-absolute-path.injectable";
@ -62,9 +59,7 @@ import { observable } from "mobx";
import waitForElectronToBeReadyInjectable from "./electron-app/features/wait-for-electron-to-be-ready.injectable"; import waitForElectronToBeReadyInjectable from "./electron-app/features/wait-for-electron-to-be-ready.injectable";
import setupListenerForCurrentClusterFrameInjectable from "./start-main-application/lens-window/current-cluster-frame/setup-listener-for-current-cluster-frame.injectable"; import setupListenerForCurrentClusterFrameInjectable from "./start-main-application/lens-window/current-cluster-frame/setup-listener-for-current-cluster-frame.injectable";
import ipcMainInjectable from "./utils/channel/ipc-main/ipc-main.injectable"; import ipcMainInjectable from "./utils/channel/ipc-main/ipc-main.injectable";
import createElectronWindowForInjectable from "./start-main-application/lens-window/application-window/create-electron-window.injectable";
import setupRunnablesAfterWindowIsOpenedInjectable from "./electron-app/runnables/setup-runnables-after-window-is-opened.injectable"; import setupRunnablesAfterWindowIsOpenedInjectable from "./electron-app/runnables/setup-runnables-after-window-is-opened.injectable";
import sendToChannelInElectronBrowserWindowInjectable from "./start-main-application/lens-window/application-window/send-to-channel-in-electron-browser-window.injectable";
import broadcastMessageInjectable from "../common/ipc/broadcast-message.injectable"; import broadcastMessageInjectable from "../common/ipc/broadcast-message.injectable";
import getElectronThemeInjectable from "./electron-app/features/get-electron-theme.injectable"; import getElectronThemeInjectable from "./electron-app/features/get-electron-theme.injectable";
import syncThemeFromOperatingSystemInjectable from "./electron-app/features/sync-theme-from-operating-system.injectable"; import syncThemeFromOperatingSystemInjectable from "./electron-app/features/sync-theme-from-operating-system.injectable";
@ -144,7 +139,6 @@ export function getDiForUnitTesting(opts: { doGeneralOverrides?: boolean } = {})
di.override(userStoreInjectable, () => ({ startMainReactions: () => {}, extensionRegistryUrl: { customUrl: "some-custom-url" }}) as UserStore); di.override(userStoreInjectable, () => ({ startMainReactions: () => {}, extensionRegistryUrl: { customUrl: "some-custom-url" }}) as UserStore);
di.override(extensionsStoreInjectable, () => ({ isEnabled: (opts) => (void opts, false) }) as ExtensionsStore); di.override(extensionsStoreInjectable, () => ({ isEnabled: (opts) => (void opts, false) }) as ExtensionsStore);
di.override(clusterStoreInjectable, () => ({ provideInitialFromMain: () => {}, getById: (id) => (void id, {}) as Cluster }) as ClusterStore);
di.override(fileSystemProvisionerStoreInjectable, () => ({}) as FileSystemProvisionerStore); di.override(fileSystemProvisionerStoreInjectable, () => ({}) as FileSystemProvisionerStore);
overrideOperatingSystem(di); overrideOperatingSystem(di);
@ -270,21 +264,6 @@ const overrideElectronFeatures = (di: DiContainer) => {
throw new Error("Tried to check for platform updates without explicit override."); throw new Error("Tried to check for platform updates without explicit override.");
}); });
di.override(createElectronWindowForInjectable, () => () => ({
show: () => {},
close: () => {},
send: (arg) => {
const sendFake = di.inject(sendToChannelInElectronBrowserWindowInjectable) as any;
sendFake(null, arg);
},
loadFile: async () => {},
loadUrl: async () => {},
}));
di.override( di.override(
getElectronAppPathInjectable, getElectronAppPathInjectable,
() => (name: string) => `some-electron-app-path-for-${kebabCase(name)}`, () => (name: string) => `some-electron-app-path-for-${kebabCase(name)}`,

View File

@ -10,12 +10,15 @@ import * as LensExtensionsCommonApi from "../extensions/common-api";
import * as LensExtensionsMainApi from "../extensions/main-api"; import * as LensExtensionsMainApi from "../extensions/main-api";
import { getDi } from "./getDi"; import { getDi } from "./getDi";
import startMainApplicationInjectable from "./start-main-application/start-main-application.injectable"; import startMainApplicationInjectable from "./start-main-application/start-main-application.injectable";
import shouldStartHiddenInjectable from "./electron-app/features/should-start-hidden.injectable";
const di = getDi(); const di = getDi();
const shouldStartHidden = di.inject(shouldStartHiddenInjectable);
const startApplication = di.inject(startMainApplicationInjectable); const startApplication = di.inject(startMainApplicationInjectable);
void startApplication(); void startApplication(!shouldStartHidden);
/** /**
* Exports for virtual package "@k8slens/extensions" for main-process. * Exports for virtual package "@k8slens/extensions" for main-process.

View File

@ -20,8 +20,7 @@ import stopServicesAndExitAppInjectable from "../stop-services-and-exit-app.inje
import isMacInjectable from "../../common/vars/is-mac.injectable"; import isMacInjectable from "../../common/vars/is-mac.injectable";
import { computed } from "mobx"; import { computed } from "mobx";
import showAboutInjectable from "./show-about.injectable"; import showAboutInjectable from "./show-about.injectable";
import applicationWindowInjectable from "../start-main-application/lens-window/application-window/application-window.injectable"; import reloadCurrentApplicationWindowInjectable from "../start-main-application/lens-window/reload-current-application-window.injectable";
import reloadWindowInjectable from "../start-main-application/lens-window/reload-window.injectable";
import showApplicationWindowInjectable from "../start-main-application/lens-window/show-application-window.injectable"; import showApplicationWindowInjectable from "../start-main-application/lens-window/show-application-window.injectable";
import processCheckingForUpdatesInjectable from "../application-update/check-for-updates/process-checking-for-updates.injectable"; import processCheckingForUpdatesInjectable from "../application-update/check-for-updates/process-checking-for-updates.injectable";
import openLinkInBrowserInjectable from "../../common/utils/open-link-in-browser.injectable"; import openLinkInBrowserInjectable from "../../common/utils/open-link-in-browser.injectable";
@ -44,9 +43,8 @@ const applicationMenuItemsInjectable = getInjectable({
const updatingIsEnabled = di.inject(updatingIsEnabledInjectable); const updatingIsEnabled = di.inject(updatingIsEnabledInjectable);
const electronMenuItems = di.inject(electronMenuItemsInjectable); const electronMenuItems = di.inject(electronMenuItemsInjectable);
const showAbout = di.inject(showAboutInjectable); const showAbout = di.inject(showAboutInjectable);
const applicationWindow = di.inject(applicationWindowInjectable);
const showApplicationWindow = di.inject(showApplicationWindowInjectable); const showApplicationWindow = di.inject(showApplicationWindowInjectable);
const reloadApplicationWindow = di.inject(reloadWindowInjectable, applicationWindow); const reloadApplicationWindow = di.inject(reloadCurrentApplicationWindowInjectable);
const navigateToPreferences = di.inject(navigateToPreferencesInjectable); const navigateToPreferences = di.inject(navigateToPreferencesInjectable);
const navigateToExtensions = di.inject(navigateToExtensionsInjectable); const navigateToExtensions = di.inject(navigateToExtensionsInjectable);
const navigateToCatalog = di.inject(navigateToCatalogInjectable); const navigateToCatalog = di.inject(navigateToCatalogInjectable);

View File

@ -0,0 +1,10 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectionToken } from "@ogre-tools/injectable";
import type { LensWindow } from "./create-lens-window.injectable";
export const applicationWindowInjectionToken = getInjectionToken<LensWindow>({
id: "application-window-injection-token",
});

View File

@ -1,53 +0,0 @@
/**
* 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 { lensWindowInjectionToken } from "./lens-window-injection-token";
import createLensWindowInjectable from "./create-lens-window.injectable";
import lensProxyPortInjectable from "../../../lens-proxy/lens-proxy-port.injectable";
import isMacInjectable from "../../../../common/vars/is-mac.injectable";
import appNameInjectable from "../../../app-paths/app-name/app-name.injectable";
import appEventBusInjectable from "../../../../common/app-event-bus/app-event-bus.injectable";
import waitUntilBundledExtensionsAreLoadedInjectable from "./wait-until-bundled-extensions-are-loaded.injectable";
const applicationWindowInjectable = getInjectable({
id: "application-window",
instantiate: (di) => {
const createLensWindow = di.inject(createLensWindowInjectable);
const isMac = di.inject(isMacInjectable);
const applicationName = di.inject(appNameInjectable);
const appEventBus = di.inject(appEventBusInjectable);
const waitUntilBundledExtensionsAreLoaded = di.inject(waitUntilBundledExtensionsAreLoadedInjectable);
const lensProxyPort = di.inject(lensProxyPortInjectable);
return createLensWindow({
id: "only-application-window",
title: applicationName,
defaultHeight: 900,
defaultWidth: 1440,
getContentSource: () => ({
url: `http://localhost:${lensProxyPort.get()}`,
}),
resizable: true,
windowFrameUtilitiesAreShown: isMac,
titleBarStyle: isMac ? "hiddenInset" : "hidden",
centered: false,
onFocus: () => {
appEventBus.emit({ name: "app", action: "focus" });
},
onBlur: () => {
appEventBus.emit({ name: "app", action: "blur" });
},
onDomReady: () => {
appEventBus.emit({ name: "app", action: "dom-ready" });
},
beforeOpen: waitUntilBundledExtensionsAreLoaded,
});
},
injectionToken: lensWindowInjectionToken,
});
export default applicationWindowInjectable;

View File

@ -0,0 +1,68 @@
/**
* 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 createLensWindowInjectable from "./create-lens-window.injectable";
import lensProxyPortInjectable from "../../../lens-proxy/lens-proxy-port.injectable";
import isMacInjectable from "../../../../common/vars/is-mac.injectable";
import appNameInjectable from "../../../app-paths/app-name/app-name.injectable";
import appEventBusInjectable from "../../../../common/app-event-bus/app-event-bus.injectable";
import waitUntilBundledExtensionsAreLoadedInjectable from "./wait-until-bundled-extensions-are-loaded.injectable";
import { applicationWindowInjectionToken } from "./application-window-injection-token";
const createApplicationWindowInjectable = getInjectable({
id: "create-application-window",
instantiate: (parentDi) => (id: string) => {
const windowInjectable = getInjectable({
id: `application-window-for-${id}`,
instantiate: (di) => {
const createLensWindow = di.inject(createLensWindowInjectable);
const isMac = di.inject(isMacInjectable);
const applicationName = di.inject(appNameInjectable);
const appEventBus = di.inject(appEventBusInjectable);
const waitUntilBundledExtensionsAreLoaded = di.inject(waitUntilBundledExtensionsAreLoadedInjectable);
const lensProxyPort = di.inject(lensProxyPortInjectable);
return createLensWindow({
id,
title: applicationName,
defaultHeight: 900,
defaultWidth: 1440,
getContentSource: () => ({
url: `http://localhost:${lensProxyPort.get()}`,
}),
resizable: true,
windowFrameUtilitiesAreShown: isMac,
titleBarStyle: isMac ? "hiddenInset" : "hidden",
centered: false,
onFocus: () => {
appEventBus.emit({ name: "app", action: "focus" });
},
onBlur: () => {
appEventBus.emit({ name: "app", action: "blur" });
},
onDomReady: () => {
appEventBus.emit({ name: "app", action: "dom-ready" });
},
onClose: () => {
parentDi.deregister(windowInjectable);
},
beforeOpen: waitUntilBundledExtensionsAreLoaded,
});
},
injectionToken: applicationWindowInjectionToken,
});
parentDi.register(windowInjectable);
return parentDi.inject(windowInjectable);
},
});
export default createApplicationWindowInjectable;

View File

@ -0,0 +1,15 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getGlobalOverride } from "../../../../common/test-utils/get-global-override";
import createElectronWindowInjectable from "./create-electron-window.injectable";
export default getGlobalOverride(createElectronWindowInjectable, () => () => ({
loadFile: async () => {},
loadUrl: async () => {},
show: () => {},
close: () => {},
send: () => {},
reload: () => {},
}));

View File

@ -140,7 +140,14 @@ const createElectronWindowInjectable = getInjectable({
show: () => browserWindow.show(), show: () => browserWindow.show(),
close: () => browserWindow.close(), close: () => browserWindow.close(),
send: (args) => sendToChannelInLensWindow(browserWindow, args), send: (args) => sendToChannelInLensWindow(configuration.id, browserWindow, args),
reload: () => {
const wc = browserWindow.webContents;
wc.reload();
wc.clearHistory();
},
}; };
}; };
}, },

View File

@ -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 createApplicationWindowInjectable from "./create-application-window.injectable";
// Note: Motivation is to create the window with same ID to use stored dimensions
const createFirstApplicationWindowInjectable = getInjectable({
id: "create-first-application-window",
instantiate: (di) => {
const createApplicationWindow = di.inject(createApplicationWindowInjectable);
return () => createApplicationWindow("first-application-window");
},
});
export default createFirstApplicationWindowInjectable;

View File

@ -3,10 +3,10 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import type { LensWindow, SendToViewArgs } from "./lens-window-injection-token";
import type { ContentSource, ElectronWindowTitleBarStyle } from "./create-electron-window.injectable"; import type { ContentSource, ElectronWindowTitleBarStyle } from "./create-electron-window.injectable";
import createElectronWindowForInjectable from "./create-electron-window.injectable"; import createElectronWindowForInjectable from "./create-electron-window.injectable";
import assert from "assert"; import assert from "assert";
import type { ClusterFrameInfo } from "../../../../common/cluster-frames";
export interface ElectronWindow { export interface ElectronWindow {
show: () => void; show: () => void;
@ -14,6 +14,24 @@ export interface ElectronWindow {
send: (args: SendToViewArgs) => void; send: (args: SendToViewArgs) => void;
loadFile: (filePath: string) => Promise<void>; loadFile: (filePath: string) => Promise<void>;
loadUrl: (url: string) => Promise<void>; loadUrl: (url: string) => Promise<void>;
reload: () => void;
}
export interface SendToViewArgs {
channel: string;
frameInfo?: ClusterFrameInfo;
data?: unknown[];
}
export interface LensWindow {
id: string;
start: () => Promise<void>;
close: () => void;
show: () => void;
send: (args: SendToViewArgs) => void;
isVisible: boolean;
isStarting: boolean;
reload: () => void;
} }
export interface LensWindowConfiguration { export interface LensWindowConfiguration {
@ -30,6 +48,7 @@ export interface LensWindowConfiguration {
onFocus?: () => void; onFocus?: () => void;
onBlur?: () => void; onBlur?: () => void;
onDomReady?: () => void; onDomReady?: () => void;
onClose?: () => void;
} }
const createLensWindowInjectable = getInjectable({ const createLensWindowInjectable = getInjectable({
@ -97,6 +116,7 @@ const createLensWindowInjectable = getInjectable({
browserWindow?.close(); browserWindow?.close();
browserWindow = undefined; browserWindow = undefined;
windowIsShown = false; windowIsShown = false;
configuration.onClose?.();
}, },
send: (args: SendToViewArgs) => { send: (args: SendToViewArgs) => {
@ -106,6 +126,14 @@ const createLensWindowInjectable = getInjectable({
return browserWindow.send(args); return browserWindow.send(args);
}, },
reload: () => {
if (!browserWindow) {
throw new Error(`Tried to reload window "${configuration.id}" but the window was closed`);
}
return browserWindow.reload();
},
}; };
}; };
}, },

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 { first } from "lodash/fp";
import { applicationWindowInjectionToken } from "./application-window-injection-token";
const getCurrentApplicationWindowInjectable = getInjectable({
id: "get-current-application-window",
instantiate: (di) => () =>
first(di.injectMany(applicationWindowInjectionToken)),
});
export default getCurrentApplicationWindowInjectable;

View File

@ -1,26 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectionToken } from "@ogre-tools/injectable";
import type { ClusterFrameInfo } from "../../../../common/cluster-frames";
export interface SendToViewArgs {
channel: string;
frameInfo?: ClusterFrameInfo;
data?: unknown[];
}
export interface LensWindow {
id: string;
start: () => Promise<void>;
close: () => void;
show: () => void;
send: (args: SendToViewArgs) => void;
isVisible: boolean;
isStarting: boolean;
}
export const lensWindowInjectionToken = getInjectionToken<LensWindow>({
id: "lens-window",
});

View File

@ -4,7 +4,7 @@
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import type { BrowserWindow } from "electron"; import type { BrowserWindow } from "electron";
import type { SendToViewArgs } from "./lens-window-injection-token"; import type { SendToViewArgs } from "./create-lens-window.injectable";
const sendToChannelInElectronBrowserWindowInjectable = getInjectable({ const sendToChannelInElectronBrowserWindowInjectable = getInjectable({
id: "send-to-channel-in-electron-browser-window", id: "send-to-channel-in-electron-browser-window",
@ -12,6 +12,7 @@ const sendToChannelInElectronBrowserWindowInjectable = getInjectable({
instantiate: instantiate:
() => () =>
( (
windowId: string,
browserWindow: BrowserWindow, browserWindow: BrowserWindow,
{ channel, frameInfo, data = [] }: SendToViewArgs, { channel, frameInfo, data = [] }: SendToViewArgs,
) => { ) => {

View File

@ -5,13 +5,13 @@
import { pipeline } from "@ogre-tools/fp"; import { pipeline } from "@ogre-tools/fp";
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { filter } from "lodash/fp"; import { filter } from "lodash/fp";
import { lensWindowInjectionToken } from "./application-window/lens-window-injection-token"; import { applicationWindowInjectionToken } from "./application-window/application-window-injection-token";
const getVisibleWindowsInjectable = getInjectable({ const getVisibleWindowsInjectable = getInjectable({
id: "get-visible-windows", id: "get-visible-windows",
instantiate: (di) => { instantiate: (di) => {
const getAllLensWindows = () => di.injectMany(lensWindowInjectionToken); const getAllLensWindows = () => di.injectMany(applicationWindowInjectionToken);
return () => return () =>
pipeline( pipeline(

View File

@ -3,13 +3,13 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { lensWindowInjectionToken } from "../application-window/lens-window-injection-token"; import { applicationWindowInjectionToken } from "../application-window/application-window-injection-token";
const closeAllWindowsInjectable = getInjectable({ const closeAllWindowsInjectable = getInjectable({
id: "close-all-windows", id: "close-all-windows",
instantiate: (di) => () => { instantiate: (di) => () => {
const lensWindows = di.injectMany(lensWindowInjectionToken); const lensWindows = di.injectMany(applicationWindowInjectionToken);
lensWindows.forEach((lensWindow) => { lensWindows.forEach((lensWindow) => {
lensWindow.close(); lensWindow.close();

View File

@ -6,7 +6,8 @@ import { getInjectable } from "@ogre-tools/injectable";
import { iter } from "../../../common/utils"; import { iter } from "../../../common/utils";
import clusterFramesInjectable from "../../../common/cluster-frames.injectable"; import clusterFramesInjectable from "../../../common/cluster-frames.injectable";
import showApplicationWindowInjectable from "./show-application-window.injectable"; import showApplicationWindowInjectable from "./show-application-window.injectable";
import applicationWindowInjectable from "./application-window/application-window.injectable"; import getCurrentApplicationWindowInjectable from "./application-window/get-current-application-window.injectable";
import assert from "assert";
export type NavigateForExtension = ( export type NavigateForExtension = (
extId: string, extId: string,
@ -19,7 +20,7 @@ const navigateForExtensionInjectable = getInjectable({
id: "navigate-for-extension", id: "navigate-for-extension",
instantiate: (di): NavigateForExtension => { instantiate: (di): NavigateForExtension => {
const applicationWindow = di.inject(applicationWindowInjectable); const getApplicationWindow = di.inject(getCurrentApplicationWindowInjectable);
const clusterFrames = di.inject(clusterFramesInjectable); const clusterFrames = di.inject(clusterFramesInjectable);
const showApplicationWindow = di.inject(showApplicationWindowInjectable); const showApplicationWindow = di.inject(showApplicationWindowInjectable);
@ -31,6 +32,10 @@ const navigateForExtensionInjectable = getInjectable({
) => { ) => {
await showApplicationWindow(); await showApplicationWindow();
const applicationWindow = getApplicationWindow();
assert(applicationWindow);
const frameInfo = iter.find( const frameInfo = iter.find(
clusterFrames.values(), clusterFrames.values(),
(frameInfo) => frameInfo.frameId === frameId, (frameInfo) => frameInfo.frameId === frameId,

View File

@ -4,22 +4,27 @@
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { iter } from "../../../common/utils"; import { iter } from "../../../common/utils";
import applicationWindowInjectable from "./application-window/application-window.injectable";
import clusterFramesInjectable from "../../../common/cluster-frames.injectable"; import clusterFramesInjectable from "../../../common/cluster-frames.injectable";
import { IpcRendererNavigationEvents } from "../../../renderer/navigation/events"; import { IpcRendererNavigationEvents } from "../../../renderer/navigation/events";
import showApplicationWindowInjectable from "./show-application-window.injectable"; import showApplicationWindowInjectable from "./show-application-window.injectable";
import getCurrentApplicationWindowInjectable from "./application-window/get-current-application-window.injectable";
import assert from "assert";
const navigateInjectable = getInjectable({ const navigateInjectable = getInjectable({
id: "navigate", id: "navigate",
instantiate: (di) => { instantiate: (di) => {
const applicationWindow = di.inject(applicationWindowInjectable); const getApplicationWindow = di.inject(getCurrentApplicationWindowInjectable);
const showApplicationWindow = di.inject(showApplicationWindowInjectable); const showApplicationWindow = di.inject(showApplicationWindowInjectable);
const clusterFrames = di.inject(clusterFramesInjectable); const clusterFrames = di.inject(clusterFramesInjectable);
return async (url: string, frameId?: number) => { return async (url: string, frameId?: number) => {
await showApplicationWindow(); await showApplicationWindow();
const applicationWindow = getApplicationWindow();
assert(applicationWindow);
const frameInfo = iter.find( const frameInfo = iter.find(
clusterFrames.values(), clusterFrames.values(),
(frameInfo) => frameInfo.frameId === frameId, (frameInfo) => frameInfo.frameId === frameId,

View File

@ -1,24 +0,0 @@
/**
* 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 { webContents } from "electron";
const reloadAllWindowsInjectable = getInjectable({
id: "reload-all-windows",
instantiate: () => () => {
webContents
.getAllWebContents()
.filter((wc) => wc.getType() === "window")
.forEach((wc) => {
wc.reload();
wc.clearHistory();
});
},
causesSideEffects: true,
});
export default reloadAllWindowsInjectable;

View File

@ -0,0 +1,38 @@
/**
* 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 { IpcRendererNavigationEvents } from "../../../renderer/navigation/events";
import currentClusterFrameInjectable from "./current-cluster-frame/current-cluster-frame.injectable";
import getCurrentApplicationWindowInjectable from "./application-window/get-current-application-window.injectable";
const reloadCurrentApplicationWindowInjectable = getInjectable({
id: "reload-current-application-window",
instantiate: (di) => {
const getCurrentApplicationWindow = di.inject(getCurrentApplicationWindowInjectable);
const currentClusterIframe = di.inject(currentClusterFrameInjectable);
return () => {
const lensWindow = getCurrentApplicationWindow();
if (!lensWindow) {
return;
}
const frameInfo = currentClusterIframe.get();
if (frameInfo) {
lensWindow.send({
channel: IpcRendererNavigationEvents.RELOAD_PAGE,
frameInfo,
});
} else {
lensWindow.reload();
}
};
},
});
export default reloadCurrentApplicationWindowInjectable;

View File

@ -1,33 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
import type { LensWindow } from "./application-window/lens-window-injection-token";
import { IpcRendererNavigationEvents } from "../../../renderer/navigation/events";
import currentClusterFrameInjectable from "./current-cluster-frame/current-cluster-frame.injectable";
import reloadAllWindowsInjectable from "./reload-all-windows.injectable";
const reloadWindowInjectable = getInjectable({
id: "reload-window",
instantiate: (di, lensWindow: LensWindow) => () => {
const currentClusterIframe = di.inject(currentClusterFrameInjectable);
const reloadAllWindows = di.inject(reloadAllWindowsInjectable);
const frameInfo = currentClusterIframe.get();
if (frameInfo) {
lensWindow.send({
channel: IpcRendererNavigationEvents.RELOAD_PAGE,
frameInfo,
});
} else {
reloadAllWindows();
}
},
lifecycle: lifecycleEnum.transient,
});
export default reloadWindowInjectable;

View File

@ -4,22 +4,26 @@
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import splashWindowInjectable from "./splash-window/splash-window.injectable"; import splashWindowInjectable from "./splash-window/splash-window.injectable";
import applicationWindowInjectable from "./application-window/application-window.injectable";
import { identity, some } from "lodash/fp"; import { identity, some } from "lodash/fp";
import focusApplicationInjectable from "../../electron-app/features/focus-application.injectable"; import focusApplicationInjectable from "../../electron-app/features/focus-application.injectable";
import getCurrentApplicationWindowInjectable from "./application-window/get-current-application-window.injectable";
import createFirstApplicationWindowInjectable from "./application-window/create-first-application-window.injectable";
const someIsTruthy = some(identity); const someIsTruthy = some(identity);
const showApplicationWindowInjectable = getInjectable({ const showApplicationWindowInjectable = getInjectable({
id: "show-application-window", id: "show-application-window",
instantiate: (di) => { instantiate: (di) => {
const applicationWindow = di.inject(applicationWindowInjectable); const getApplicationWindow = di.inject(getCurrentApplicationWindowInjectable);
const createFirstApplicationWindow = di.inject(createFirstApplicationWindowInjectable);
const splashWindow = di.inject(splashWindowInjectable); const splashWindow = di.inject(splashWindowInjectable);
const focusApplication = di.inject(focusApplicationInjectable); const focusApplication = di.inject(focusApplicationInjectable);
return async () => { return async () => {
focusApplication(); focusApplication();
const applicationWindow = getApplicationWindow() ?? createFirstApplicationWindow();
if (applicationWindow.isStarting) { if (applicationWindow.isStarting) {
applicationWindow.show(); applicationWindow.show();
splashWindow.close(); splashWindow.close();

View File

@ -3,7 +3,6 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { lensWindowInjectionToken } from "../application-window/lens-window-injection-token";
import createLensWindowInjectable from "../application-window/create-lens-window.injectable"; import createLensWindowInjectable from "../application-window/create-lens-window.injectable";
import staticFilesDirectoryInjectable from "../../../../common/vars/static-files-directory.injectable"; import staticFilesDirectoryInjectable from "../../../../common/vars/static-files-directory.injectable";
import getAbsolutePathInjectable from "../../../../common/path/get-absolute-path.injectable"; import getAbsolutePathInjectable from "../../../../common/path/get-absolute-path.injectable";
@ -30,8 +29,6 @@ const splashWindowInjectable = getInjectable({
centered: true, centered: true,
}); });
}, },
injectionToken: lensWindowInjectionToken,
}); });
export default splashWindowInjectable; export default splashWindowInjectable;

View File

@ -12,13 +12,12 @@ import { onLoadOfApplicationInjectionToken } from "./runnable-tokens/on-load-of-
import { afterApplicationIsLoadedInjectionToken } from "./runnable-tokens/after-application-is-loaded-injection-token"; import { afterApplicationIsLoadedInjectionToken } from "./runnable-tokens/after-application-is-loaded-injection-token";
import splashWindowInjectable from "./lens-window/splash-window/splash-window.injectable"; import splashWindowInjectable from "./lens-window/splash-window/splash-window.injectable";
import applicationWindowInjectable from "./lens-window/application-window/application-window.injectable";
import shouldStartHiddenInjectable from "../electron-app/features/should-start-hidden.injectable";
import openDeepLinkInjectable from "../protocol-handler/lens-protocol-router-main/open-deep-link-for-url/open-deep-link.injectable"; import openDeepLinkInjectable from "../protocol-handler/lens-protocol-router-main/open-deep-link-for-url/open-deep-link.injectable";
import { pipeline } from "@ogre-tools/fp"; import { pipeline } from "@ogre-tools/fp";
import { find, map, startsWith, toLower } from "lodash/fp"; import { find, map, startsWith, toLower } from "lodash/fp";
import commandLineArgumentsInjectable from "../utils/command-line-arguments.injectable"; import commandLineArgumentsInjectable from "../utils/command-line-arguments.injectable";
import waitForElectronToBeReadyInjectable from "../electron-app/features/wait-for-electron-to-be-ready.injectable"; import waitForElectronToBeReadyInjectable from "../electron-app/features/wait-for-electron-to-be-ready.injectable";
import createFirstApplicationWindowInjectable from "./lens-window/application-window/create-first-application-window.injectable";
const startMainApplicationInjectable = getInjectable({ const startMainApplicationInjectable = getInjectable({
id: "start-main-application", id: "start-main-application",
@ -27,9 +26,8 @@ const startMainApplicationInjectable = getInjectable({
const runMany = runManyFor(di); const runMany = runManyFor(di);
const runManySync = runManySyncFor(di); const runManySync = runManySyncFor(di);
const waitForElectronToBeReady = di.inject(waitForElectronToBeReadyInjectable); const waitForElectronToBeReady = di.inject(waitForElectronToBeReadyInjectable);
const applicationWindow = di.inject(applicationWindowInjectable); const createFirstApplicationWindow = di.inject(createFirstApplicationWindowInjectable);
const splashWindow = di.inject(splashWindowInjectable); const splashWindow = di.inject(splashWindowInjectable);
const shouldStartHidden = di.inject(shouldStartHiddenInjectable);
const openDeepLink = di.inject(openDeepLinkInjectable); const openDeepLink = di.inject(openDeepLinkInjectable);
const commandLineArguments = di.inject(commandLineArgumentsInjectable); const commandLineArguments = di.inject(commandLineArgumentsInjectable);
@ -38,7 +36,7 @@ const startMainApplicationInjectable = getInjectable({
const onLoadOfApplication = runMany(onLoadOfApplicationInjectionToken); const onLoadOfApplication = runMany(onLoadOfApplicationInjectionToken);
const afterApplicationIsLoaded = runMany(afterApplicationIsLoadedInjectionToken); const afterApplicationIsLoaded = runMany(afterApplicationIsLoadedInjectionToken);
return () => { return (shouldStartWindow: boolean) => {
// Stuff happening before application is ready needs to be synchronous because of // Stuff happening before application is ready needs to be synchronous because of
// https://github.com/electron/electron/issues/21370 // https://github.com/electron/electron/issues/21370
beforeElectronIsReady(); beforeElectronIsReady();
@ -48,18 +46,20 @@ const startMainApplicationInjectable = getInjectable({
await beforeApplicationIsLoading(); await beforeApplicationIsLoading();
if (!shouldStartHidden) { if (shouldStartWindow) {
await splashWindow.start(); await splashWindow.start();
} }
await onLoadOfApplication(); await onLoadOfApplication();
if (!shouldStartHidden) { if (shouldStartWindow) {
const deepLinkUrl = getDeepLinkUrl(commandLineArguments); const deepLinkUrl = getDeepLinkUrl(commandLineArguments);
if (deepLinkUrl) { if (deepLinkUrl) {
await openDeepLink(deepLinkUrl); await openDeepLink(deepLinkUrl);
} else { } else {
const applicationWindow = createFirstApplicationWindow();
await applicationWindow.start(); await applicationWindow.start();
} }

View File

@ -5,15 +5,10 @@
import type { MessageToChannel } from "../../../common/utils/channel/message-to-channel-injection-token"; import type { MessageToChannel } from "../../../common/utils/channel/message-to-channel-injection-token";
import { messageToChannelInjectionToken } from "../../../common/utils/channel/message-to-channel-injection-token"; import { messageToChannelInjectionToken } from "../../../common/utils/channel/message-to-channel-injection-token";
import closeAllWindowsInjectable from "../../start-main-application/lens-window/hide-all-windows/close-all-windows.injectable";
import type { MessageChannel } from "../../../common/utils/channel/message-channel-injection-token"; import type { MessageChannel } from "../../../common/utils/channel/message-channel-injection-token";
import { getDiForUnitTesting } from "../../getDiForUnitTesting"; import type { LensWindow } from "../../start-main-application/lens-window/application-window/create-lens-window.injectable";
import createLensWindowInjectable from "../../start-main-application/lens-window/application-window/create-lens-window.injectable";
import type { LensWindow } from "../../start-main-application/lens-window/application-window/lens-window-injection-token";
import { lensWindowInjectionToken } from "../../start-main-application/lens-window/application-window/lens-window-injection-token";
import type { DiContainer } from "@ogre-tools/injectable";
import { getInjectable } from "@ogre-tools/injectable";
import sendToChannelInElectronBrowserWindowInjectable from "../../start-main-application/lens-window/application-window/send-to-channel-in-electron-browser-window.injectable"; import sendToChannelInElectronBrowserWindowInjectable from "../../start-main-application/lens-window/application-window/send-to-channel-in-electron-browser-window.injectable";
import { getApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
describe("message to channel from main", () => { describe("message to channel from main", () => {
let messageToChannel: MessageToChannel; let messageToChannel: MessageToChannel;
@ -21,20 +16,21 @@ describe("message to channel from main", () => {
let someOtherTestWindow: LensWindow; let someOtherTestWindow: LensWindow;
let sendToChannelInBrowserMock: jest.Mock; let sendToChannelInBrowserMock: jest.Mock;
beforeEach(() => { beforeEach(async () => {
const di = getDiForUnitTesting({ doGeneralOverrides: true }); const builder = getApplicationBuilder();
sendToChannelInBrowserMock = jest.fn(); sendToChannelInBrowserMock = jest.fn();
di.override(sendToChannelInElectronBrowserWindowInjectable, () => sendToChannelInBrowserMock);
someTestWindow = createTestWindow(di, "some-test-window-id"); builder.beforeApplicationStart(mainDi => {
someOtherTestWindow = createTestWindow(di, "some-other-test-window-id"); mainDi.override(sendToChannelInElectronBrowserWindowInjectable, () => sendToChannelInBrowserMock);
});
messageToChannel = di.inject(messageToChannelInjectionToken); await builder.startHidden();
const closeAllWindows = di.inject(closeAllWindowsInjectable); someTestWindow = builder.applicationWindow.create("some-test-window-id");
someOtherTestWindow = builder.applicationWindow.create("some-other-test-window-id");
closeAllWindows(); messageToChannel = builder.mainDi.inject(messageToChannelInjectionToken);
}); });
it("given no visible windows, when messaging to channel, does not message to any window", () => { it("given no visible windows, when messaging to channel, does not message to any window", () => {
@ -53,6 +49,8 @@ describe("message to channel from main", () => {
expect(sendToChannelInBrowserMock.mock.calls).toEqual([ expect(sendToChannelInBrowserMock.mock.calls).toEqual([
[ [
"some-test-window-id",
null, null,
{ {
@ -68,6 +66,8 @@ describe("message to channel from main", () => {
expect(sendToChannelInBrowserMock.mock.calls).toEqual([ expect(sendToChannelInBrowserMock.mock.calls).toEqual([
[ [
"some-test-window-id",
null, null,
{ {
@ -83,6 +83,8 @@ describe("message to channel from main", () => {
expect(sendToChannelInBrowserMock.mock.calls).toEqual([ expect(sendToChannelInBrowserMock.mock.calls).toEqual([
[ [
"some-test-window-id",
null, null,
{ {
@ -98,6 +100,8 @@ describe("message to channel from main", () => {
expect(sendToChannelInBrowserMock.mock.calls).toEqual([ expect(sendToChannelInBrowserMock.mock.calls).toEqual([
[ [
"some-test-window-id",
null, null,
{ {
@ -117,6 +121,8 @@ describe("message to channel from main", () => {
expect(sendToChannelInBrowserMock.mock.calls).toEqual([ expect(sendToChannelInBrowserMock.mock.calls).toEqual([
[ [
"some-test-window-id",
null, null,
{ {
@ -126,6 +132,8 @@ describe("message to channel from main", () => {
], ],
[ [
"some-other-test-window-id",
null, null,
{ {
@ -138,30 +146,3 @@ describe("message to channel from main", () => {
}); });
const someChannel: MessageChannel<any> = { id: "some-channel" }; const someChannel: MessageChannel<any> = { id: "some-channel" };
const createTestWindow = (di: DiContainer, id: string) => {
const testWindowInjectable = getInjectable({
id,
instantiate: (di) => {
const createLensWindow = di.inject(createLensWindowInjectable);
return createLensWindow({
id,
title: "Some test window",
defaultHeight: 42,
defaultWidth: 42,
getContentSource: () => ({ url: "some-content-url" }),
resizable: true,
windowFrameUtilitiesAreShown: false,
centered: false,
});
},
injectionToken: lensWindowInjectionToken,
});
di.register(testWindowInjectable);
return di.inject(testWindowInjectable);
};

View File

@ -13,10 +13,10 @@ import type { PreferenceNavigationItem } from "../preference-navigation-items.in
import preferenceNavigationItemsInjectable from "../preference-navigation-items.injectable"; import preferenceNavigationItemsInjectable from "../preference-navigation-items.injectable";
describe.only("preferences - navigation block with links", () => { describe.only("preferences - navigation block with links", () => {
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
beforeEach(() => { beforeEach(() => {
applicationBuilder = getApplicationBuilder(); builder = getApplicationBuilder();
}); });
describe("given in preferences, when rendered", () => { describe("given in preferences, when rendered", () => {
@ -24,17 +24,15 @@ describe.only("preferences - navigation block with links", () => {
describe("when general navigation items passed", () => { describe("when general navigation items passed", () => {
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.beforeApplicationStart(({ rendererDi }) => { builder.beforeWindowStart((windowDi) => {
rendererDi.override(preferenceNavigationItemsInjectable, () => windowDi.override(preferenceNavigationItemsInjectable, () =>
computed(() => generalNavItems), computed(() => generalNavItems),
); );
builder.preferences.navigate();
}); });
applicationBuilder.beforeRender(() => { renderer = await builder.render();
applicationBuilder.preferences.navigate();
});
renderer = await applicationBuilder.render();
}); });
const links = ["General", "Proxy"]; const links = ["General", "Proxy"];
@ -52,17 +50,15 @@ describe.only("preferences - navigation block with links", () => {
describe("when general + extension navigation items passed", () => { describe("when general + extension navigation items passed", () => {
beforeEach(async () => { beforeEach(async () => {
applicationBuilder.beforeApplicationStart(({ rendererDi }) => { builder.beforeWindowStart((windowDi) => {
rendererDi.override(preferenceNavigationItemsInjectable, () => windowDi.override(preferenceNavigationItemsInjectable, () =>
computed(() => [...generalNavItems, ...extensionNavItems]), computed(() => [...generalNavItems, ...extensionNavItems]),
); );
builder.preferences.navigate();
}); });
applicationBuilder.beforeRender(() => { renderer = await builder.render();
applicationBuilder.preferences.navigate();
});
renderer = await applicationBuilder.render();
}); });
const generalLinks = ["General", "Proxy"]; const generalLinks = ["General", "Proxy"];

View File

@ -6,13 +6,10 @@ import "@testing-library/jest-dom/extend-expect";
import { KubeConfig } from "@kubernetes/client-node"; import { KubeConfig } from "@kubernetes/client-node";
import { fireEvent } from "@testing-library/react"; import { fireEvent } from "@testing-library/react";
import type { RenderResult } from "@testing-library/react"; import type { RenderResult } from "@testing-library/react";
import mockFs from "mock-fs";
import * as selectEvent from "react-select-event"; import * as selectEvent from "react-select-event";
import type { CreateCluster } from "../../../../common/cluster/create-cluster-injection-token"; import type { CreateCluster } from "../../../../common/cluster/create-cluster-injection-token";
import { createClusterInjectionToken } from "../../../../common/cluster/create-cluster-injection-token"; import { createClusterInjectionToken } from "../../../../common/cluster/create-cluster-injection-token";
import createContextHandlerInjectable from "../../../../main/context-handler/create-context-handler.injectable"; import createContextHandlerInjectable from "../../../../main/context-handler/create-context-handler.injectable";
import type { OpenDeleteClusterDialog } from "../open.injectable";
import openDeleteClusterDialogInjectable from "../open.injectable";
import storesAndApisCanBeCreatedInjectable from "../../../stores-apis-can-be-created.injectable"; import storesAndApisCanBeCreatedInjectable from "../../../stores-apis-can-be-created.injectable";
import createKubeconfigManagerInjectable from "../../../../main/kubeconfig-manager/create-kubeconfig-manager.injectable"; import createKubeconfigManagerInjectable from "../../../../main/kubeconfig-manager/create-kubeconfig-manager.injectable";
import type { ApplicationBuilder } from "../../test-utils/get-application-builder"; import type { ApplicationBuilder } from "../../test-utils/get-application-builder";
@ -20,22 +17,8 @@ import { getApplicationBuilder } from "../../test-utils/get-application-builder"
import normalizedPlatformInjectable from "../../../../common/vars/normalized-platform.injectable"; import normalizedPlatformInjectable from "../../../../common/vars/normalized-platform.injectable";
import kubectlBinaryNameInjectable from "../../../../main/kubectl/binary-name.injectable"; import kubectlBinaryNameInjectable from "../../../../main/kubectl/binary-name.injectable";
import kubectlDownloadingNormalizedArchInjectable from "../../../../main/kubectl/normalized-arch.injectable"; import kubectlDownloadingNormalizedArchInjectable from "../../../../main/kubectl/normalized-arch.injectable";
import type { OpenDeleteClusterDialog } from "../open.injectable";
jest.mock("electron", () => ({ import openDeleteClusterDialogInjectable from "../open.injectable";
app: {
getVersion: () => "99.99.99",
getName: () => "lens",
setName: jest.fn(),
setPath: jest.fn(),
getPath: () => "tmp",
getLocale: () => "en",
setLoginItemSettings: jest.fn(),
},
ipcMain: {
on: jest.fn(),
handle: jest.fn(),
},
}));
const currentClusterServerUrl = "https://localhost"; const currentClusterServerUrl = "https://localhost";
const nonCurrentClusterServerUrl = "http://localhost"; const nonCurrentClusterServerUrl = "http://localhost";
@ -87,65 +70,50 @@ users:
token: kubeconfig-user-q4lm4:xxxyyyy token: kubeconfig-user-q4lm4:xxxyyyy
`; `;
let config: KubeConfig;
describe("<DeleteClusterDialog />", () => { describe("<DeleteClusterDialog />", () => {
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
let createCluster: CreateCluster;
let openDeleteClusterDialog: OpenDeleteClusterDialog;
beforeEach(async () => { beforeEach(() => {
applicationBuilder = getApplicationBuilder(); builder = getApplicationBuilder();
applicationBuilder.beforeApplicationStart(({ mainDi, rendererDi }) => { builder.beforeApplicationStart((mainDi) => {
mainDi.override(createContextHandlerInjectable, () => () => undefined as never); mainDi.override(createContextHandlerInjectable, () => () => undefined as never);
mainDi.override(createKubeconfigManagerInjectable, () => () => undefined as never); mainDi.override(createKubeconfigManagerInjectable, () => () => undefined as never);
mainDi.override(kubectlBinaryNameInjectable, () => "kubectl"); mainDi.override(kubectlBinaryNameInjectable, () => "kubectl");
mainDi.override(kubectlDownloadingNormalizedArchInjectable, () => "amd64"); mainDi.override(kubectlDownloadingNormalizedArchInjectable, () => "amd64");
mainDi.override(normalizedPlatformInjectable, () => "darwin"); mainDi.override(normalizedPlatformInjectable, () => "darwin");
rendererDi.override(storesAndApisCanBeCreatedInjectable, () => true);
}); });
mockFs(); builder.beforeWindowStart((windowDi) => {
windowDi.override(storesAndApisCanBeCreatedInjectable, () => true);
applicationBuilder.beforeRender(({ rendererDi }) => {
openDeleteClusterDialog = rendererDi.inject(openDeleteClusterDialogInjectable);
createCluster = rendererDi.inject(createClusterInjectionToken);
}); });
}); });
afterEach(() => {
mockFs.restore();
});
it("shows context switcher when deleting current cluster", async () => { it("shows context switcher when deleting current cluster", async () => {
const mockOpts = { const config = new KubeConfig();
"temp-kube-config": multiClusterConfig,
};
mockFs(mockOpts);
config = new KubeConfig();
config.loadFromString(multiClusterConfig); config.loadFromString(multiClusterConfig);
applicationBuilder.beforeRender(({ rendererDi }) => { const rendered = await builder.render();
const createCluster = rendererDi.inject(createClusterInjectionToken);
const cluster = createCluster({ const windowDi = builder.applicationWindow.only.di;
id: "some-current-context-cluster",
contextName: "some-current-context",
preferences: {
clusterName: "some-current-context-cluster",
},
kubeConfigPath: "./temp-kube-config",
}, {
clusterServerUrl: currentClusterServerUrl,
});
openDeleteClusterDialog({ cluster, config }); const createCluster = windowDi.inject(createClusterInjectionToken);
const cluster = createCluster({
id: "some-current-context-cluster",
contextName: "some-current-context",
preferences: {
clusterName: "some-current-context-cluster",
},
kubeConfigPath: "./temp-kube-config",
}, {
clusterServerUrl: currentClusterServerUrl,
}); });
const rendered = await applicationBuilder.render(); const openDeleteClusterDialog = windowDi.inject(openDeleteClusterDialogInjectable);
openDeleteClusterDialog({ cluster, config });
const { getByText } = rendered; const { getByText } = rendered;
@ -158,21 +126,23 @@ describe("<DeleteClusterDialog />", () => {
expect(getByText("some-non-current-context")).toBeInTheDocument(); expect(getByText("some-non-current-context")).toBeInTheDocument();
}); });
describe("Kubeconfig with different clusters", () => { describe("Kubeconfig with different clusters", () => {
let rendered: RenderResult; let rendered: RenderResult;
let openDeleteClusterDialog: OpenDeleteClusterDialog;
let createCluster: CreateCluster;
let config: KubeConfig;
beforeEach(async () => { beforeEach(async () => {
const mockOpts = {
"temp-kube-config": multiClusterConfig,
};
mockFs(mockOpts);
config = new KubeConfig(); config = new KubeConfig();
config.loadFromString(multiClusterConfig); config.loadFromString(multiClusterConfig);
rendered = await applicationBuilder.render(); rendered = await builder.render();
const windowDi = builder.applicationWindow.only.di;
openDeleteClusterDialog = windowDi.inject(openDeleteClusterDialogInjectable);
createCluster = windowDi.inject(createClusterInjectionToken);
}); });
it("renders w/o errors", () => { it("renders w/o errors", () => {
@ -268,18 +238,21 @@ describe("<DeleteClusterDialog />", () => {
describe("Kubeconfig with single cluster", () => { describe("Kubeconfig with single cluster", () => {
let rendered: RenderResult; let rendered: RenderResult;
let openDeleteClusterDialog: OpenDeleteClusterDialog;
let createCluster: CreateCluster;
let config: KubeConfig;
beforeEach(async () => { beforeEach(async () => {
const mockOpts = {
"temp-kube-config": singleClusterConfig,
};
mockFs(mockOpts);
config = new KubeConfig(); config = new KubeConfig();
config.loadFromString(singleClusterConfig); config.loadFromString(singleClusterConfig);
rendered = await applicationBuilder.render(); rendered = await builder.render();
const windowDi = builder.applicationWindow.only.di;
openDeleteClusterDialog = windowDi.inject(openDeleteClusterDialogInjectable);
createCluster = windowDi.inject(createClusterInjectionToken);
}); });
it("shows warning if no other contexts left", () => { it("shows warning if no other contexts left", () => {

View File

@ -14,6 +14,7 @@ import { cssNames, noop, stopPropagation } from "../../utils";
import type { ObservableHistory } from "mobx-observable-history"; import type { ObservableHistory } from "mobx-observable-history";
import { withInjectables } from "@ogre-tools/injectable-react"; import { withInjectables } from "@ogre-tools/injectable-react";
import observableHistoryInjectable from "../../navigation/observable-history.injectable"; import observableHistoryInjectable from "../../navigation/observable-history.injectable";
import requestAnimationFrameInjectable from "../animate/request-animation-frame.injectable";
// todo: refactor + handle animation-end in props.onClose()? // todo: refactor + handle animation-end in props.onClose()?
@ -37,6 +38,7 @@ interface DialogState {
interface Dependencies { interface Dependencies {
navigation: ObservableHistory<unknown>; navigation: ObservableHistory<unknown>;
requestAnimationFrame: (callback: () => void) => void;
} }
@observer @observer
@ -95,7 +97,7 @@ class NonInjectedDialog extends React.PureComponent<DialogProps & Dependencies &
} }
open() { open() {
requestAnimationFrame(this.onOpen); // wait for render(), bind close-event to this.elem this.props.requestAnimationFrame(this.onOpen); // wait for render(), bind close-event to this.elem
this.setState({ isOpen: true }); this.setState({ isOpen: true });
this.props.open?.(); this.props.open?.();
} }
@ -182,5 +184,6 @@ export const Dialog = withInjectables<Dependencies, DialogProps>((props) => <Non
getProps: (di, props) => ({ getProps: (di, props) => ({
...props, ...props,
navigation: di.inject(observableHistoryInjectable), navigation: di.inject(observableHistoryInjectable),
requestAnimationFrame: di.inject(requestAnimationFrameInjectable),
}), }),
}); });

View File

@ -7,55 +7,40 @@ import React from "react";
import "@testing-library/jest-dom/extend-expect"; import "@testing-library/jest-dom/extend-expect";
import type { IObservableArray } from "mobx"; import type { IObservableArray } from "mobx";
import { computed, observable } from "mobx"; import { computed, observable } from "mobx";
import type { DiContainer } from "@ogre-tools/injectable";
import type { StatusBarItems } from "./status-bar-items.injectable"; import type { StatusBarItems } from "./status-bar-items.injectable";
import statusBarItemsInjectable from "./status-bar-items.injectable"; import statusBarItemsInjectable from "./status-bar-items.injectable";
import { LensRendererExtension } from "../../../extensions/lens-renderer-extension";
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
import type { ApplicationBuilder } from "../test-utils/get-application-builder"; import type { ApplicationBuilder } from "../test-utils/get-application-builder";
import { getApplicationBuilder } from "../test-utils/get-application-builder"; import { getApplicationBuilder } from "../test-utils/get-application-builder";
import getRandomIdInjectable from "../../../common/utils/get-random-id.injectable"; import getRandomIdInjectable from "../../../common/utils/get-random-id.injectable";
class SomeTestExtension extends LensRendererExtension {
constructor(statusBarItems: IObservableArray<any>) {
super({
id: "some-id",
absolutePath: "irrelevant",
isBundled: false,
isCompatible: false,
isEnabled: false,
manifest: { name: "some-id", version: "some-version", engines: { lens: "^5.5.0" }},
manifestPath: "irrelevant",
});
this.statusBarItems = statusBarItems;
}
}
describe("<StatusBar />", () => { describe("<StatusBar />", () => {
let di: DiContainer;
let statusBarItems: IObservableArray<any>; let statusBarItems: IObservableArray<any>;
let applicationBuilder: ApplicationBuilder; let builder: ApplicationBuilder;
beforeEach(async () => { beforeEach(async () => {
statusBarItems = observable.array([]); statusBarItems = observable.array([]);
applicationBuilder = getApplicationBuilder(); builder = getApplicationBuilder();
applicationBuilder.beforeApplicationStart(({ rendererDi }) => { builder.beforeWindowStart((windowDi) => {
rendererDi.unoverride(getRandomIdInjectable); windowDi.unoverride(getRandomIdInjectable);
rendererDi.permitSideEffects(getRandomIdInjectable); windowDi.permitSideEffects(getRandomIdInjectable);
windowDi.override(directoryForUserDataInjectable, () => "some-directory-for-user-data");
}); });
applicationBuilder.extensions.renderer.enable(new SomeTestExtension(statusBarItems)); builder.extensions.enable({
id: "some-id",
name: "some-name",
di = applicationBuilder.dis.rendererDi; rendererOptions: {
statusBarItems,
di.override(directoryForUserDataInjectable, () => "some-directory-for-user-data"); },
});
}); });
it("renders w/o errors", async () => { it("renders w/o errors", async () => {
const { container } = await applicationBuilder.render(); const { container } = await builder.render();
expect(container).toBeInstanceOf(HTMLElement); expect(container).toBeInstanceOf(HTMLElement);
}); });
@ -71,19 +56,21 @@ describe("<StatusBar />", () => {
])("renders w/o errors when registrations are not type compliant (%p)", async val => { ])("renders w/o errors when registrations are not type compliant (%p)", async val => {
statusBarItems.replace([val]); statusBarItems.replace([val]);
await expect(applicationBuilder.render()).resolves.toBeTruthy(); await expect(builder.render()).resolves.toBeTruthy();
}); });
it("renders items [{item: React.ReactNode}] (4.0.0-rc.1)", async () => { it("renders items [{item: React.ReactNode}] (4.0.0-rc.1)", async () => {
const testId = "testId"; const testId = "testId";
const text = "heee"; const text = "heee";
di.override(statusBarItemsInjectable, () => computed(() => ({ builder.beforeWindowStart((windowDi) => {
right: [ () => <span data-testid={testId} >{text}</span> ], windowDi.override(statusBarItemsInjectable, () => computed(() => ({
left: [], right: [ () => <span data-testid={testId} >{text}</span> ],
}) as StatusBarItems)); left: [],
}) as StatusBarItems));
});
const { getByTestId } = await applicationBuilder.render(); const { getByTestId } = await builder.render();
expect(getByTestId(testId)).toHaveTextContent(text); expect(getByTestId(testId)).toHaveTextContent(text);
}); });
@ -96,7 +83,7 @@ describe("<StatusBar />", () => {
item: () => <span data-testid={testId} >{text}</span>, item: () => <span data-testid={testId} >{text}</span>,
}]); }]);
const { getByTestId } = await applicationBuilder.render(); const { getByTestId } = await builder.render();
expect(getByTestId(testId)).toHaveTextContent(text); expect(getByTestId(testId)).toHaveTextContent(text);
}); });
@ -129,7 +116,7 @@ describe("<StatusBar />", () => {
}, },
]); ]);
const { getAllByTestId } = await applicationBuilder.render(); const { getAllByTestId } = await builder.render();
const elems = getAllByTestId("sortedElem"); const elems = getAllByTestId("sortedElem");
const positions = elems.map(elem => elem.textContent); const positions = elems.map(elem => elem.textContent);

View File

@ -5,27 +5,24 @@
import type { LensRendererExtension } from "../../../extensions/lens-renderer-extension"; import type { LensRendererExtension } from "../../../extensions/lens-renderer-extension";
import rendererExtensionsInjectable from "../../../extensions/renderer-extensions.injectable"; import rendererExtensionsInjectable from "../../../extensions/renderer-extensions.injectable";
import currentlyInClusterFrameInjectable from "../../routes/currently-in-cluster-frame.injectable"; import currentlyInClusterFrameInjectable from "../../routes/currently-in-cluster-frame.injectable";
import type { ObservableSet } from "mobx"; import type { IComputedValue, ObservableMap } from "mobx";
import { computed, observable, runInAction } from "mobx"; import { computed, observable, runInAction } from "mobx";
import React from "react"; import React from "react";
import { Router } from "react-router"; import { Router } from "react-router";
import subscribeStoresInjectable from "../../kube-watch-api/subscribe-stores.injectable";
import allowedResourcesInjectable from "../../cluster-frame-context/allowed-resources.injectable"; import allowedResourcesInjectable from "../../cluster-frame-context/allowed-resources.injectable";
import type { RenderResult } from "@testing-library/react"; import type { RenderResult } from "@testing-library/react";
import { queryByText, fireEvent } from "@testing-library/react"; import { fireEvent, queryByText } from "@testing-library/react";
import type { KubeResource } from "../../../common/rbac"; import type { KubeResource } from "../../../common/rbac";
import type { DiContainer } from "@ogre-tools/injectable"; import type { DiContainer, Injectable } from "@ogre-tools/injectable";
import clusterStoreInjectable from "../../../common/cluster-store/cluster-store.injectable"; import { getInjectable } from "@ogre-tools/injectable";
import type { ClusterStore } from "../../../common/cluster-store/cluster-store";
import mainExtensionsInjectable from "../../../extensions/main-extensions.injectable"; import mainExtensionsInjectable from "../../../extensions/main-extensions.injectable";
import { pipeline } from "@ogre-tools/fp"; import { pipeline } from "@ogre-tools/fp";
import { flatMap, compact, join, get, filter, map, matches, last } from "lodash/fp"; import { compact, filter, first, flatMap, get, join, last, map, matches } from "lodash/fp";
import preferenceNavigationItemsInjectable from "../+preferences/preferences-navigation/preference-navigation-items.injectable"; import preferenceNavigationItemsInjectable from "../+preferences/preferences-navigation/preference-navigation-items.injectable";
import navigateToPreferencesInjectable from "../../../common/front-end-routing/routes/preferences/navigate-to-preferences.injectable"; import navigateToPreferencesInjectable from "../../../common/front-end-routing/routes/preferences/navigate-to-preferences.injectable";
import type { MenuItemOpts } from "../../../main/menu/application-menu-items.injectable"; import type { MenuItemOpts } from "../../../main/menu/application-menu-items.injectable";
import applicationMenuItemsInjectable from "../../../main/menu/application-menu-items.injectable"; import applicationMenuItemsInjectable from "../../../main/menu/application-menu-items.injectable";
import type { MenuItemConstructorOptions, MenuItem } from "electron"; import type { MenuItem, MenuItemConstructorOptions } from "electron";
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
import type { NavigateToHelmCharts } from "../../../common/front-end-routing/routes/cluster/helm/charts/navigate-to-helm-charts.injectable"; import type { NavigateToHelmCharts } from "../../../common/front-end-routing/routes/cluster/helm/charts/navigate-to-helm-charts.injectable";
import navigateToHelmChartsInjectable from "../../../common/front-end-routing/routes/cluster/helm/charts/navigate-to-helm-charts.injectable"; import navigateToHelmChartsInjectable from "../../../common/front-end-routing/routes/cluster/helm/charts/navigate-to-helm-charts.injectable";
import hostedClusterInjectable from "../../cluster-frame-context/hosted-cluster.injectable"; import hostedClusterInjectable from "../../cluster-frame-context/hosted-cluster.injectable";
@ -39,7 +36,6 @@ import type { NamespaceStore } from "../+namespaces/store";
import historyInjectable from "../../navigation/history.injectable"; import historyInjectable from "../../navigation/history.injectable";
import type { MinimalTrayMenuItem } from "../../../main/tray/electron-tray/electron-tray.injectable"; import type { MinimalTrayMenuItem } from "../../../main/tray/electron-tray/electron-tray.injectable";
import electronTrayInjectable from "../../../main/tray/electron-tray/electron-tray.injectable"; import electronTrayInjectable from "../../../main/tray/electron-tray/electron-tray.injectable";
import applicationWindowInjectable from "../../../main/start-main-application/lens-window/application-window/application-window.injectable";
import { getDiForUnitTesting as getRendererDi } from "../../getDiForUnitTesting"; import { getDiForUnitTesting as getRendererDi } from "../../getDiForUnitTesting";
import { getDiForUnitTesting as getMainDi } from "../../../main/getDiForUnitTesting"; import { getDiForUnitTesting as getMainDi } from "../../../main/getDiForUnitTesting";
import { overrideChannels } from "../../../test-utils/channel-fakes/override-channels"; import { overrideChannels } from "../../../test-utils/channel-fakes/override-channels";
@ -52,7 +48,6 @@ import type { NavigateToRouteOptions } from "../../../common/front-end-routing/n
import { navigateToRouteInjectionToken } from "../../../common/front-end-routing/navigate-to-route-injection-token"; import { navigateToRouteInjectionToken } from "../../../common/front-end-routing/navigate-to-route-injection-token";
import type { LensMainExtension } from "../../../extensions/lens-main-extension"; import type { LensMainExtension } from "../../../extensions/lens-main-extension";
import type { LensExtension } from "../../../extensions/lens-extension"; import type { LensExtension } from "../../../extensions/lens-extension";
import extensionInjectable from "../../../extensions/extension-loader/extension/extension.injectable"; import extensionInjectable from "../../../extensions/extension-loader/extension/extension.injectable";
import { renderFor } from "./renderFor"; import { renderFor } from "./renderFor";
import { RootFrame } from "../../frames/root-frame/root-frame"; import { RootFrame } from "../../frames/root-frame/root-frame";
@ -62,34 +57,50 @@ import activeKubernetesClusterInjectable from "../../cluster-frame-context/activ
import { catalogEntityFromCluster } from "../../../main/cluster-manager"; import { catalogEntityFromCluster } from "../../../main/cluster-manager";
import namespaceStoreInjectable from "../+namespaces/store.injectable"; import namespaceStoreInjectable from "../+namespaces/store.injectable";
import { isAllowedResource } from "../../../common/cluster/is-allowed-resource"; import { isAllowedResource } from "../../../common/cluster/is-allowed-resource";
import createApplicationWindowInjectable from "../../../main/start-main-application/lens-window/application-window/create-application-window.injectable";
import type { CreateElectronWindow } from "../../../main/start-main-application/lens-window/application-window/create-electron-window.injectable";
import createElectronWindowInjectable from "../../../main/start-main-application/lens-window/application-window/create-electron-window.injectable";
import { applicationWindowInjectionToken } from "../../../main/start-main-application/lens-window/application-window/application-window-injection-token";
import sendToChannelInElectronBrowserWindowInjectable from "../../../main/start-main-application/lens-window/application-window/send-to-channel-in-electron-browser-window.injectable";
import closeAllWindowsInjectable from "../../../main/start-main-application/lens-window/hide-all-windows/close-all-windows.injectable";
import type { LensWindow } from "../../../main/start-main-application/lens-window/application-window/create-lens-window.injectable";
import type { FakeExtensionOptions } from "./get-extension-fake";
import { getExtensionFakeForMain, getExtensionFakeForRenderer } from "./get-extension-fake";
type Callback = (dis: DiContainers) => void | Promise<void>; type Callback = (di: DiContainer) => void | Promise<void>;
type EnableExtensions<T> = (...extensions: T[]) => void; type LensWindowWithHelpers = LensWindow & { rendered: RenderResult; di: DiContainer };
type DisableExtensions<T> = (...extensions: T[]) => void;
export interface ApplicationBuilder { export interface ApplicationBuilder {
dis: DiContainers; mainDi: DiContainer;
setEnvironmentToClusterFrame: () => ApplicationBuilder; setEnvironmentToClusterFrame: () => ApplicationBuilder;
extensions: { extensions: {
renderer: { enable: (...extensions: FakeExtensionOptions[]) => void;
enable: EnableExtensions<LensRendererExtension>; disable: (...extensions: FakeExtensionOptions[]) => void;
disable: DisableExtensions<LensRendererExtension>;
};
main: { get: (id: string) => {
enable: EnableExtensions<LensMainExtension>; main: LensMainExtension;
disable: DisableExtensions<LensMainExtension>;
};
enable: (...extensions: { renderer: LensRendererExtension; main: LensMainExtension }[]) => void; applicationWindows: Record<string, LensRendererExtension> & {
disable: (...extensions: { renderer: LensRendererExtension; main: LensMainExtension }[]) => void; only: LensRendererExtension;
};
};
};
applicationWindow: {
closeAll: () => void;
only: LensWindowWithHelpers;
get: (id: string) => LensWindowWithHelpers;
getAll: () => LensWindowWithHelpers[];
create: (id: string) => LensWindowWithHelpers;
}; };
allowKubeResource: (resourceName: KubeResource) => ApplicationBuilder; allowKubeResource: (resourceName: KubeResource) => ApplicationBuilder;
beforeApplicationStart: (callback: Callback) => ApplicationBuilder; beforeApplicationStart: (callback: Callback) => ApplicationBuilder;
beforeRender: (callback: Callback) => ApplicationBuilder; beforeWindowStart: (callback: Callback) => ApplicationBuilder;
startHidden: () => Promise<void>;
render: () => Promise<RenderResult>; render: () => Promise<RenderResult>;
tray: { tray: {
@ -116,17 +127,12 @@ export interface ApplicationBuilder {
}; };
select: { select: {
openMenu: (id: string) => ({ selectOption: (labelText: string) => void }); openMenu: (id: string) => { selectOption: (labelText: string) => void };
selectOption: (menuId: string, labelText: string) => void; selectOption: (menuId: string, labelText: string) => void;
getValue: (menuId: string) => string; getValue: (menuId: string) => string;
}; };
} }
interface DiContainers {
rendererDi: DiContainer;
mainDi: DiContainer;
}
interface Environment { interface Environment {
RootComponent: React.ElementType; RootComponent: React.ElementType;
onAllowKubeResource: () => void; onAllowKubeResource: () => void;
@ -137,64 +143,22 @@ export const getApplicationBuilder = () => {
doGeneralOverrides: true, doGeneralOverrides: true,
}); });
mainDi.register(mainExtensionsStateInjectable);
const overrideChannelsForWindow = overrideChannels(mainDi); const overrideChannelsForWindow = overrideChannels(mainDi);
const rendererDi = getRendererDi({
doGeneralOverrides: true,
});
overrideChannelsForWindow(rendererDi);
const dis = { rendererDi, mainDi };
const clusterStoreStub = {
provideInitialFromMain: () => {},
getById: (): null => null,
} as unknown as ClusterStore;
rendererDi.override(clusterStoreInjectable, () => clusterStoreStub);
rendererDi.override(storesAndApisCanBeCreatedInjectable, () => true);
mainDi.override(clusterStoreInjectable, () => clusterStoreStub);
const beforeApplicationStartCallbacks: Callback[] = []; const beforeApplicationStartCallbacks: Callback[] = [];
const beforeRenderCallbacks: Callback[] = []; const beforeWindowStartCallbacks: Callback[] = [];
const rendererExtensionsState = observable.set<LensRendererExtension>();
const mainExtensionsState = observable.set<LensMainExtension>();
rendererDi.override(subscribeStoresInjectable, () => () => () => {});
const environments = {
application: {
RootComponent: RootFrame,
onAllowKubeResource: () => {
throw new Error(
"Tried to allow kube resource when environment is not cluster frame.",
);
},
} as Environment,
clusterFrame: {
RootComponent: ClusterFrame,
onAllowKubeResource: () => {},
} as Environment,
};
let environment = environments.application; let environment = environments.application;
rendererDi.override( mainDi.override(mainExtensionsInjectable, (di) => {
currentlyInClusterFrameInjectable, const mainExtensionsState = di.inject(mainExtensionsStateInjectable);
() => environment === environments.clusterFrame,
);
rendererDi.override(rendererExtensionsInjectable, () => return computed(() =>
computed(() => [...rendererExtensionsState]), [...mainExtensionsState.values()],
); );
});
mainDi.override(mainExtensionsInjectable, () =>
computed(() => [...mainExtensionsState]),
);
let trayMenuIconPath: string; let trayMenuIconPath: string;
@ -209,60 +173,135 @@ export const getApplicationBuilder = () => {
}, },
})); }));
let allowedResourcesState: KubeResource[]; const allowedResourcesState = observable.array<KubeResource>();
let rendered: RenderResult;
const enableExtensionsFor = <T extends ObservableSet>( const windowHelpers = new Map<string, { di: DiContainer; getRendered: () => RenderResult }>();
extensionState: T,
di: DiContainer,
) => {
const getExtension = (extension: LensExtension) =>
di.inject(extensionInjectable, extension);
return (...extensionInstances: LensExtension[]) => { const createElectronWindowFake: CreateElectronWindow = (configuration) => {
const addAndEnableExtensions = () => { const windowId = configuration.id;
extensionInstances.forEach(instance => {
const extension = getExtension(instance);
extension.register(); const windowDi = getRendererDi({ doGeneralOverrides: true });
});
runInAction(() => { overrideChannelsForWindow(windowDi, windowId);
extensionInstances.forEach((extension) => {
extensionState.add(extension);
});
});
};
if (rendered) { windowDi.register(rendererExtensionsStateInjectable);
addAndEnableExtensions();
} else { windowDi.override(
builder.beforeRender(addAndEnableExtensions); currentlyInClusterFrameInjectable,
} () => environment === environments.clusterFrame,
);
windowDi.override(rendererExtensionsInjectable, (di) => {
const rendererExtensionState = di.inject(rendererExtensionsStateInjectable);
return computed(() => [...rendererExtensionState.values()]);
});
let rendered: RenderResult;
windowHelpers.set(windowId, { di: windowDi, getRendered: () => rendered });
return {
show: () => {},
close: () => {},
loadFile: async () => {},
loadUrl: async () => {
for (const callback of beforeWindowStartCallbacks) {
await callback(windowDi);
}
const startFrame = windowDi.inject(startFrameInjectable);
await startFrame();
const history = windowDi.inject(historyInjectable);
const render = renderFor(windowDi);
rendered = render(
<Router history={history}>
<environment.RootComponent />
</Router>,
);
},
send: (arg) => {
const sendFake = mainDi.inject(sendToChannelInElectronBrowserWindowInjectable) as any;
sendFake(windowId, null, arg);
},
reload: () => {
throw new Error("Tried to reload application window which is not implemented yet.");
},
}; };
}; };
const enableRendererExtension = enableExtensionsFor(rendererExtensionsState, rendererDi); mainDi.override(createElectronWindowInjectable, () => createElectronWindowFake);
const enableMainExtension = enableExtensionsFor(mainExtensionsState, mainDi);
const disableRendererExtension = disableExtensionsFor(rendererExtensionsState, rendererDi);
const disableMainExtension = disableExtensionsFor(mainExtensionsState, mainDi);
const selectOptionFor = (menuId: string) => (labelText: string) => { let applicationHasStarted = false;
const menuOptions = rendered.baseElement.querySelector<HTMLElement>(
`.${menuId}-options`,
);
assert(menuOptions, `Could not find select options for menu with ID "${menuId}"`);
const option = queryByText(menuOptions, labelText);
assert(option, `Could not find select option with label "${labelText}" for menu with ID "${menuId}"`);
userEvent.click(option);
};
const builder: ApplicationBuilder = { const builder: ApplicationBuilder = {
dis, mainDi,
applicationWindow: {
closeAll: () => {
const closeAll = mainDi.inject(closeAllWindowsInjectable);
closeAll();
document.documentElement.innerHTML = "";
},
get only() {
const applicationWindows = builder.applicationWindow.getAll();
if (applicationWindows.length > 1) {
throw new Error(
"Tried to get only application window when there are multiple windows.",
);
}
const applicationWindow = first(applicationWindows);
if (!applicationWindow) {
throw new Error(
"Tried to get only application window when there are no windows.",
);
}
return applicationWindow;
},
getAll: () =>
mainDi
.injectMany(applicationWindowInjectionToken)
.map(toWindowWithHelpersFor(windowHelpers)),
get: (id) => {
const applicationWindows = builder.applicationWindow.getAll();
const applicationWindow = applicationWindows.find(
(window) => window.id === id,
);
if (!applicationWindow) {
throw new Error(`Tried to get application window with ID "${id}" but it was not found.`);
}
return applicationWindow;
},
create: (id) => {
const createApplicationWindow = mainDi.inject(
createApplicationWindowInjectable,
);
createApplicationWindow(id);
return builder.applicationWindow.get(id);
},
},
applicationMenu: { applicationMenu: {
click: (path: string) => { click: (path: string) => {
@ -340,29 +379,39 @@ export const getApplicationBuilder = () => {
preferences: { preferences: {
close: () => { close: () => {
const rendered = builder.applicationWindow.only.rendered;
const link = rendered.getByTestId("close-preferences"); const link = rendered.getByTestId("close-preferences");
fireEvent.click(link); fireEvent.click(link);
}, },
navigate: () => { navigate: () => {
const navigateToPreferences = rendererDi.inject(navigateToPreferencesInjectable); const windowDi = builder.applicationWindow.only.di;
const navigateToPreferences = windowDi.inject(
navigateToPreferencesInjectable,
);
navigateToPreferences(); navigateToPreferences();
}, },
navigateTo: (route: Route<any>, params: Partial<NavigateToRouteOptions<any>>) => { navigateTo: (route: Route<any>, params: Partial<NavigateToRouteOptions<any>>) => {
const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken); const windowDi = builder.applicationWindow.only.di;
const navigateToRoute = windowDi.inject(navigateToRouteInjectionToken);
navigateToRoute(route, params); navigateToRoute(route, params);
}, },
navigation: { navigation: {
click: (id: string) => { click: (id: string) => {
const { di: windowDi, rendered } = builder.applicationWindow.only;
const link = rendered.queryByTestId(`tab-link-for-${id}`); const link = rendered.queryByTestId(`tab-link-for-${id}`);
if (!link) { if (!link) {
const preferencesNavigationItems = rendererDi.inject( const preferencesNavigationItems = windowDi.inject(
preferenceNavigationItemsInjectable, preferenceNavigationItemsInjectable,
); );
@ -382,7 +431,11 @@ export const getApplicationBuilder = () => {
helmCharts: { helmCharts: {
navigate: (parameters) => { navigate: (parameters) => {
const navigateToHelmCharts = rendererDi.inject(navigateToHelmChartsInjectable); const windowDi = builder.applicationWindow.only.di;
const navigateToHelmCharts = windowDi.inject(
navigateToHelmChartsInjectable,
);
navigateToHelmCharts(parameters); navigateToHelmCharts(parameters);
}, },
@ -391,81 +444,129 @@ export const getApplicationBuilder = () => {
setEnvironmentToClusterFrame: () => { setEnvironmentToClusterFrame: () => {
environment = environments.clusterFrame; environment = environments.clusterFrame;
allowedResourcesState = observable.array(); builder.beforeWindowStart((windowDi) => {
windowDi.override(allowedResourcesInjectable, () =>
computed(() => new Set([...allowedResourcesState])),
);
rendererDi.override(allowedResourcesInjectable, () => const clusterStub = {
computed(() => new Set([...allowedResourcesState])), accessibleNamespaces: [],
); isAllowedResource: isAllowedResource(allowedResourcesState),
} as unknown as Cluster;
const clusterStub = { windowDi.override(activeKubernetesClusterInjectable, () =>
accessibleNamespaces: [], computed(() => catalogEntityFromCluster(clusterStub)),
isAllowedResource: isAllowedResource(allowedResourcesState), );
} as unknown as Cluster;
rendererDi.override(activeKubernetesClusterInjectable, () => // TODO: Figure out a way to remove this stub.
computed(() => catalogEntityFromCluster(clusterStub)), const namespaceStoreStub = {
); isLoaded: true,
contextNamespaces: [],
contextItems: [],
api: {
kind: "Namespace",
},
items: [],
selectNamespaces: () => {},
getByPath: () => undefined,
pickOnlySelected: () => [],
isSelectedAll: () => false,
getTotalCount: () => 0,
} as unknown as NamespaceStore;
// TODO: Figure out a way to remove this stub. const clusterFrameContextFake = new ClusterFrameContext(
const namespaceStoreStub = { clusterStub,
isLoaded: true,
contextNamespaces: [],
contextItems: [],
api: {
kind: "Namespace",
},
items: [],
selectNamespaces: () => {},
getByPath: () => undefined,
pickOnlySelected: () => [],
isSelectedAll: () => false,
getTotalCount: () => 0,
} as unknown as NamespaceStore;
const clusterFrameContextFake = new ClusterFrameContext( {
clusterStub, namespaceStore: namespaceStoreStub,
},
);
{ windowDi.override(namespaceStoreInjectable, () => namespaceStoreStub);
namespaceStore: namespaceStoreStub, windowDi.override(hostedClusterInjectable, () => clusterStub);
}, windowDi.override(hostedClusterIdInjectable, () => "irrelevant-hosted-cluster-id");
); windowDi.override(clusterFrameContextInjectable, () => clusterFrameContextFake);
rendererDi.override(namespaceStoreInjectable, () => namespaceStoreStub); // Todo: get rid of global state.
rendererDi.override(hostedClusterInjectable, () => clusterStub); KubeObjectStore.defaultContext.set(clusterFrameContextFake);
rendererDi.override(hostedClusterIdInjectable, () => "irrelevant-hosted-cluster-id"); });
rendererDi.override(clusterFrameContextInjectable, () => clusterFrameContextFake);
// Todo: get rid of global state.
KubeObjectStore.defaultContext.set(clusterFrameContextFake);
return builder; return builder;
}, },
extensions: { extensions: {
renderer: { get: (id: string) => {
enable: enableRendererExtension, const windowInstances = pipeline(
disable: disableRendererExtension, builder.applicationWindow.getAll(),
},
main: { map((window): [string, LensRendererExtension] => [
enable: enableMainExtension, window.id,
disable: disableMainExtension, findExtensionInstance(window.di, rendererExtensionsInjectable, id),
]),
items => Object.fromEntries(items),
);
return {
main: findExtensionInstance(mainDi, mainExtensionsInjectable, id),
applicationWindows: {
get only() {
return findExtensionInstance(
builder.applicationWindow.only.di,
rendererExtensionsInjectable,
id,
);
},
...windowInstances,
},
};
}, },
enable: (...extensions) => { enable: (...extensions) => {
const rendererExtensions = extensions.map(extension => extension.renderer); builder.beforeWindowStart((windowDi) => {
const mainExtensions = extensions.map(extension => extension.main); const rendererExtensionInstances = extensions.map((options) =>
getExtensionFakeForRenderer(
windowDi,
options.id,
options.name,
options.rendererOptions || {},
),
);
enableRendererExtension(...rendererExtensions); rendererExtensionInstances.forEach(
enableMainExtension(...mainExtensions); enableExtensionFor(windowDi, rendererExtensionsStateInjectable),
);
});
builder.beforeApplicationStart((mainDi) => {
const mainExtensionInstances = extensions.map((extension) =>
getExtensionFakeForMain(mainDi, extension.id, extension.name, extension.mainOptions || {}),
);
mainExtensionInstances.forEach(
enableExtensionFor(mainDi, mainExtensionsStateInjectable),
);
});
}, },
disable: (...extensions) => { disable: (...extensions) => {
const rendererExtensions = extensions.map(extension => extension.renderer); builder.beforeWindowStart(windowDi => {
const mainExtensions = extensions.map(extension => extension.main); extensions
.map((ext) => ext.id)
.forEach(
disableExtensionFor(windowDi, rendererExtensionsStateInjectable),
);
});
disableRendererExtension(...rendererExtensions); builder.beforeApplicationStart(mainDi => {
disableMainExtension(...mainExtensions); extensions
.map((ext) => ext.id)
.forEach(
disableExtensionFor(mainDi, mainExtensionsStateInjectable),
);
});
}, },
}, },
@ -479,56 +580,72 @@ export const getApplicationBuilder = () => {
return builder; return builder;
}, },
beforeApplicationStart(callback: (dis: DiContainers) => void) { beforeApplicationStart(callback) {
if (applicationHasStarted) {
callback(mainDi);
}
beforeApplicationStartCallbacks.push(callback); beforeApplicationStartCallbacks.push(callback);
return builder; return builder;
}, },
beforeRender(callback: (dis: DiContainers) => void) { beforeWindowStart(callback) {
beforeRenderCallbacks.push(callback); const alreadyRenderedWindows = builder.applicationWindow.getAll();
alreadyRenderedWindows.forEach((window) => {
callback(window.di);
});
beforeWindowStartCallbacks.push(callback);
return builder; return builder;
}, },
startHidden: async () => {
mainDi.inject(lensProxyPortInjectable).set(42);
for (const callback of beforeApplicationStartCallbacks) {
await callback(mainDi);
}
const startMainApplication = mainDi.inject(
startMainApplicationInjectable,
);
await startMainApplication(false);
applicationHasStarted = true;
},
async render() { async render() {
mainDi.inject(lensProxyPortInjectable).set(42); mainDi.inject(lensProxyPortInjectable).set(42);
for (const callback of beforeApplicationStartCallbacks) { for (const callback of beforeApplicationStartCallbacks) {
await callback(dis); await callback(mainDi);
} }
const startMainApplication = mainDi.inject(startMainApplicationInjectable); const startMainApplication = mainDi.inject(
startMainApplicationInjectable,
await startMainApplication();
const applicationWindow = mainDi.inject(applicationWindowInjectable);
await applicationWindow.start();
const startFrame = rendererDi.inject(startFrameInjectable);
await startFrame();
for (const callback of beforeRenderCallbacks) {
await callback(dis);
}
const history = rendererDi.inject(historyInjectable);
const render = renderFor(rendererDi);
rendered = render(
<Router history={history}>
<environment.RootComponent />
</Router>,
); );
return rendered; await startMainApplication(true);
applicationHasStarted = true;
const applicationWindow = builder.applicationWindow.get(
"first-application-window",
);
assert(applicationWindow);
return applicationWindow.rendered;
}, },
select: { select: {
openMenu: (menuId) => { openMenu: (menuId) => {
const rendered = builder.applicationWindow.only.rendered;
const select = rendered.baseElement.querySelector<HTMLElement>( const select = rendered.baseElement.querySelector<HTMLElement>(
`#${menuId}`, `#${menuId}`,
); );
@ -538,13 +655,15 @@ export const getApplicationBuilder = () => {
openMenu(select); openMenu(select);
return { return {
selectOption: selectOptionFor(menuId), selectOption: selectOptionFor(builder, menuId),
}; };
}, },
selectOption: (menuId, labelText) => selectOptionFor(menuId)(labelText), selectOption: (menuId, labelText) => selectOptionFor(builder, menuId)(labelText),
getValue: (menuId) => { getValue: (menuId) => {
const rendered = builder.applicationWindow.only.rendered;
const select = rendered.baseElement.querySelector<HTMLInputElement>( const select = rendered.baseElement.querySelector<HTMLInputElement>(
`#${menuId}`, `#${menuId}`,
); );
@ -582,22 +701,134 @@ function toFlatChildren(parentId: string | null | undefined): ToFlatChildren {
]; ];
} }
const disableExtensionsFor = <T extends ObservableSet>( export const rendererExtensionsStateInjectable = getInjectable({
extensionState: T, id: "renderer-extensions-state",
instantiate: () => observable.map<string, LensRendererExtension>(),
});
const mainExtensionsStateInjectable = getInjectable({
id: "main-extensions-state",
instantiate: () => observable.map<string, LensMainExtension>(),
});
const findExtensionInstance = <T extends LensExtension> (di: DiContainer, injectable: Injectable<IComputedValue<T[]>, any, any>, id: string) => {
const instance = di.inject(injectable).get().find(ext => ext.id === id);
if (!instance) {
throw new Error(`Tried to get extension with ID ${id}, but it didn't exist`);
}
return instance;
};
type ApplicationWindowHelpers = Map<string, { di: DiContainer; getRendered: () => RenderResult }>;
const toWindowWithHelpersFor =
(windowHelpers: ApplicationWindowHelpers) => (applicationWindow: LensWindow) => ({
...applicationWindow,
get rendered() {
const helpers = windowHelpers.get(applicationWindow.id);
if (!helpers) {
throw new Error(
`Tried to get rendered for application window "${applicationWindow.id}" before it was started.`,
);
}
return helpers.getRendered();
},
get di() {
const helpers = windowHelpers.get(applicationWindow.id);
if (!helpers) {
throw new Error(
`Tried to get di for application window "${applicationWindow.id}" before it was started.`,
);
}
return helpers.di;
},
});
const environments = {
application: {
RootComponent: RootFrame,
onAllowKubeResource: () => {
throw new Error(
"Tried to allow kube resource when environment is not cluster frame.",
);
},
} as Environment,
clusterFrame: {
RootComponent: ClusterFrame,
onAllowKubeResource: () => {},
} as Environment,
};
const selectOptionFor = (builder: ApplicationBuilder, menuId: string) => (labelText: string) => {
const rendered = builder.applicationWindow.only.rendered;
const menuOptions = rendered.baseElement.querySelector<HTMLElement>(
`.${menuId}-options`,
);
assert(menuOptions, `Could not find select options for menu with ID "${menuId}"`);
const option = queryByText(menuOptions, labelText);
assert(option, `Could not find select option with label "${labelText}" for menu with ID "${menuId}"`);
userEvent.click(option);
};
const enableExtensionFor = (
di: DiContainer, di: DiContainer,
stateInjectable: Injectable<ObservableMap<string, any>, any, any>,
) => { ) => {
const getExtension = (instance: LensExtension) => const extensionState = di.inject(stateInjectable);
di.inject(extensionInjectable, instance);
return (...extensionInstances: LensExtension[]) => { const getExtension = (extension: LensExtension) =>
extensionInstances.forEach((instance) => { di.inject(extensionInjectable, extension);
const extension = getExtension(instance);
runInAction(() => { return (extensionInstance: LensExtension) => {
extension.deregister(); const extension = getExtension(extensionInstance);
extensionState.delete(instance); runInAction(() => {
}); extension.register();
extensionState.set(extensionInstance.id, extensionInstance);
}); });
}; };
}; };
const disableExtensionFor =
(
di: DiContainer,
stateInjectable: Injectable<ObservableMap<string, any>, unknown, void>,
) =>
(id: string) => {
const getExtension = (extension: LensExtension) =>
di.inject(extensionInjectable, extension);
const extensionsState = di.inject(stateInjectable);
const instance = extensionsState.get(id);
if (!instance) {
throw new Error(
`Tried to disable extension with ID "${id}", but it wasn't enabled`,
);
}
const injectable = getExtension(instance);
runInAction(() => {
injectable.deregister();
extensionsState.delete(id);
});
};

View File

@ -5,7 +5,6 @@
import type { Mutable } from "type-fest"; import type { Mutable } from "type-fest";
import fileSystemProvisionerStoreInjectable from "../../../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable"; import fileSystemProvisionerStoreInjectable from "../../../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable";
import { lensExtensionDependencies } from "../../../extensions/lens-extension"; import { lensExtensionDependencies } from "../../../extensions/lens-extension";
import type { ApplicationBuilder } from "./get-application-builder";
import { LensMainExtension } from "../../../extensions/lens-main-extension"; import { LensMainExtension } from "../../../extensions/lens-main-extension";
import navigateForExtensionInjectable from "../../../main/start-main-application/lens-window/navigate-for-extension.injectable"; import navigateForExtensionInjectable from "../../../main/start-main-application/lens-window/navigate-for-extension.injectable";
import { LensRendererExtension } from "../../../extensions/lens-renderer-extension"; import { LensRendererExtension } from "../../../extensions/lens-renderer-extension";
@ -27,21 +26,7 @@ export interface FakeExtensionOptions {
mainOptions?: Partial<LensMainExtension>; mainOptions?: Partial<LensMainExtension>;
} }
export type GetExtensionFake = (arg: FakeExtensionOptions) => { export const getExtensionFakeForMain = (di: DiContainer, id: string, name: string, options: Partial<LensMainExtension>) => {
main: TestExtensionMain;
renderer: TestExtensionRenderer;
};
export const getExtensionFakeFor =
(builder: ApplicationBuilder): GetExtensionFake =>
({ id, name, mainOptions = {}, rendererOptions = {}}) => {
const mainInstance = getExtensionFakeForMain(builder.dis.mainDi, id, name, mainOptions);
const rendererInstance = getExtensionFakeForRenderer(builder.dis.rendererDi, id, name, rendererOptions);
return { main: mainInstance, renderer: rendererInstance };
};
const getExtensionFakeForMain = (di: DiContainer, id: string, name: string, options: Partial<LensMainExtension>) => {
const instance = new TestExtensionMain({ const instance = new TestExtensionMain({
id, id,
absolutePath: "irrelevant", absolutePath: "irrelevant",
@ -71,7 +56,7 @@ const getExtensionFakeForMain = (di: DiContainer, id: string, name: string, opti
return instance; return instance;
}; };
const getExtensionFakeForRenderer = (di: DiContainer, id: string, name: string, options: Partial<LensRendererExtension>) => { export const getExtensionFakeForRenderer = (di: DiContainer, id: string, name: string, options: Partial<LensRendererExtension>) => {
const instance = new TestExtensionRenderer({ const instance = new TestExtensionRenderer({
id, id,
absolutePath: "irrelevant", absolutePath: "irrelevant",

View File

@ -1,28 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { SetRequired } from "type-fest";
import { LensRendererExtension } from "../../../extensions/lens-renderer-extension";
import type { ApplicationBuilder } from "./get-application-builder";
import { getExtensionFakeFor } from "./get-extension-fake";
export class TestExtension extends LensRendererExtension {}
export type FakeExtensionData = SetRequired<Partial<LensRendererExtension>, "id" | "name">;
export type GetRendererExtensionFake = (fakeExtensionData: FakeExtensionData) => TestExtension;
export const getRendererExtensionFakeFor = (
builder: ApplicationBuilder,
): GetRendererExtensionFake => {
const getExtensionFake = getExtensionFakeFor(builder);
return ({ id, name, ...rest }) =>
getExtensionFake({
id,
name,
rendererOptions: rest,
}).renderer;
};

View File

@ -18,9 +18,6 @@ import extensionsStoreInjectable from "../extensions/extensions-store/extensions
import type { ExtensionsStore } from "../extensions/extensions-store/extensions-store"; import type { ExtensionsStore } from "../extensions/extensions-store/extensions-store";
import fileSystemProvisionerStoreInjectable from "../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable"; import fileSystemProvisionerStoreInjectable from "../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store.injectable";
import type { FileSystemProvisionerStore } from "../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store"; import type { FileSystemProvisionerStore } from "../extensions/extension-loader/file-system-provisioner-store/file-system-provisioner-store";
import clusterStoreInjectable from "../common/cluster-store/cluster-store.injectable";
import type { ClusterStore } from "../common/cluster-store/cluster-store";
import type { Cluster } from "../common/cluster/cluster";
import userStoreInjectable from "../common/user-store/user-store.injectable"; import userStoreInjectable from "../common/user-store/user-store.injectable";
import type { UserStore } from "../common/user-store"; import type { UserStore } from "../common/user-store";
import getAbsolutePathInjectable from "../common/path/get-absolute-path.injectable"; import getAbsolutePathInjectable from "../common/path/get-absolute-path.injectable";
@ -41,7 +38,6 @@ import setupOnApiErrorListenersInjectable from "./api/setup-on-api-errors.inject
import { observable, computed } from "mobx"; import { observable, computed } from "mobx";
import defaultShellInjectable from "./components/+preferences/default-shell.injectable"; import defaultShellInjectable from "./components/+preferences/default-shell.injectable";
import appVersionInjectable from "../common/vars/app-version.injectable"; import appVersionInjectable from "../common/vars/app-version.injectable";
import provideInitialValuesForSyncBoxesInjectable from "./utils/sync-box/provide-initial-values-for-sync-boxes.injectable";
import requestAnimationFrameInjectable from "./components/animate/request-animation-frame.injectable"; import requestAnimationFrameInjectable from "./components/animate/request-animation-frame.injectable";
import getRandomIdInjectable from "../common/utils/get-random-id.injectable"; import getRandomIdInjectable from "../common/utils/get-random-id.injectable";
import getFilePathsInjectable from "./components/+preferences/kubernetes/helm-charts/adding-of-custom-helm-repository/helm-file-input/get-file-paths.injectable"; import getFilePathsInjectable from "./components/+preferences/kubernetes/helm-charts/adding-of-custom-helm-repository/helm-file-input/get-file-paths.injectable";
@ -189,12 +185,8 @@ export const getDiForUnitTesting = (opts: { doGeneralOverrides?: boolean } = {})
di.override(fileSystemProvisionerStoreInjectable, () => ({}) as FileSystemProvisionerStore); di.override(fileSystemProvisionerStoreInjectable, () => ({}) as FileSystemProvisionerStore);
// eslint-disable-next-line unused-imports/no-unused-vars-ts
di.override(clusterStoreInjectable, () => ({ getById: (id): Cluster => ({}) as Cluster }) as ClusterStore);
di.override(setupSystemCaInjectable, () => ({ run: () => {} })); di.override(setupSystemCaInjectable, () => ({ run: () => {} }));
di.override(setupOnApiErrorListenersInjectable, () => ({ run: () => {} })); di.override(setupOnApiErrorListenersInjectable, () => ({ run: () => {} }));
di.override(provideInitialValuesForSyncBoxesInjectable, () => ({ run: () => {} }));
di.override(defaultShellInjectable, () => "some-default-shell"); di.override(defaultShellInjectable, () => "some-default-shell");

View File

@ -0,0 +1,11 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getGlobalOverride } from "../../common/test-utils/get-global-override";
import subscribeStoresInjectable from "./subscribe-stores.injectable";
export default getGlobalOverride(
subscribeStoresInjectable,
() => () => () => {},
);

View File

@ -4,11 +4,17 @@
*/ */
import { getInjectable } from "@ogre-tools/injectable"; import { getInjectable } from "@ogre-tools/injectable";
import { storesAndApisCanBeCreatedInjectionToken } from "../common/k8s-api/stores-apis-can-be-created.token"; import { storesAndApisCanBeCreatedInjectionToken } from "../common/k8s-api/stores-apis-can-be-created.token";
import { getClusterIdFromHost } from "./utils"; import hostedClusterIdInjectable from "./cluster-frame-context/hosted-cluster-id.injectable";
const storesAndApisCanBeCreatedInjectable = getInjectable({ const storesAndApisCanBeCreatedInjectable = getInjectable({
id: "create-stores-and-apis", id: "create-stores-and-apis",
instantiate: () => Boolean(getClusterIdFromHost(location.host)),
instantiate: (di) => {
const hostedClusterId = di.inject(hostedClusterIdInjectable);
return !!hostedClusterId;
},
injectionToken: storesAndApisCanBeCreatedInjectionToken, injectionToken: storesAndApisCanBeCreatedInjectionToken,
}); });

View File

@ -12,8 +12,8 @@ export const overrideChannels = (mainDi: DiContainer) => {
const overrideMessagingFromWindowToForWindow = overrideMessagingFromWindowToMain(mainDi); const overrideMessagingFromWindowToForWindow = overrideMessagingFromWindowToMain(mainDi);
const overrideRequestingFromWindowToMainForWindow = overrideRequestingFromWindowToMain(mainDi); const overrideRequestingFromWindowToMainForWindow = overrideRequestingFromWindowToMain(mainDi);
return (windowDi: DiContainer) => { return (windowDi: DiContainer, windowId: string) => {
overrideMessagingFromMainToWindowForWindow(windowDi); overrideMessagingFromMainToWindowForWindow(windowDi, windowId);
overrideMessagingFromWindowToForWindow(windowDi); overrideMessagingFromWindowToForWindow(windowDi);
overrideRequestingFromWindowToMainForWindow(windowDi); overrideRequestingFromWindowToMainForWindow(windowDi);
}; };

View File

@ -3,30 +3,44 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * Licensed under MIT License. See LICENSE in root directory for more information.
*/ */
import type { MessageChannelListener } from "../../common/utils/channel/message-channel-listener-injection-token"; import type { MessageChannelListener } from "../../common/utils/channel/message-channel-listener-injection-token";
import type { MessageChannel } from "../../common/utils/channel/message-channel-injection-token";
import sendToChannelInElectronBrowserWindowInjectable from "../../main/start-main-application/lens-window/application-window/send-to-channel-in-electron-browser-window.injectable"; import sendToChannelInElectronBrowserWindowInjectable from "../../main/start-main-application/lens-window/application-window/send-to-channel-in-electron-browser-window.injectable";
import type { SendToViewArgs } from "../../main/start-main-application/lens-window/application-window/lens-window-injection-token"; import type { SendToViewArgs } from "../../main/start-main-application/lens-window/application-window/create-lens-window.injectable";
import enlistMessageChannelListenerInjectableInRenderer from "../../renderer/utils/channel/channel-listeners/enlist-message-channel-listener.injectable"; import enlistMessageChannelListenerInjectableInRenderer from "../../renderer/utils/channel/channel-listeners/enlist-message-channel-listener.injectable";
import type { DiContainer } from "@ogre-tools/injectable"; import type { DiContainer } from "@ogre-tools/injectable";
import assert from "assert";
import { tentativeParseJson } from "../../common/utils/tentative-parse-json"; import { tentativeParseJson } from "../../common/utils/tentative-parse-json";
import { getOrInsert } from "../../common/utils";
type ListenerSet = Set<MessageChannelListener<any>>;
type WindowListenerMap = Map<string, ListenerSet>;
type ListenerFakeMap = Map<string, WindowListenerMap>;
export const overrideMessagingFromMainToWindow = (mainDi: DiContainer) => { export const overrideMessagingFromMainToWindow = (mainDi: DiContainer) => {
const messageChannelListenerFakesForRenderer = new Map< const messageChannelListenerFakesForRenderer: ListenerFakeMap = new Map();
string,
Set<MessageChannelListener<MessageChannel<any>>> const getWindowListeners = (channelId: string, windowId: string) => {
>(); const channelListeners = getOrInsert<string, WindowListenerMap>(
messageChannelListenerFakesForRenderer,
channelId,
new Map(),
);
return getOrInsert<string, ListenerSet>(
channelListeners,
windowId,
new Set(),
);
};
mainDi.override( mainDi.override(
sendToChannelInElectronBrowserWindowInjectable, sendToChannelInElectronBrowserWindowInjectable,
() => () =>
( (
windowId: string,
browserWindow, browserWindow,
{ channel: channelId, frameInfo, data = [] }: SendToViewArgs, { channel: channelId, frameInfo, data = [] }: SendToViewArgs,
) => { ) => {
const listeners = const windowListeners = getWindowListeners(channelId, windowId);
messageChannelListenerFakesForRenderer.get(channelId) || new Set();
if (frameInfo) { if (frameInfo) {
throw new Error( throw new Error(
@ -40,7 +54,7 @@ export const overrideMessagingFromMainToWindow = (mainDi: DiContainer) => {
); );
} }
if (listeners.size === 0) { if (windowListeners.size === 0) {
throw new Error( throw new Error(
`Tried to send message to channel "${channelId}" but there where no listeners. Current channels with listeners: "${[ `Tried to send message to channel "${channelId}" but there where no listeners. Current channels with listeners: "${[
...messageChannelListenerFakesForRenderer.keys(), ...messageChannelListenerFakesForRenderer.keys(),
@ -50,40 +64,26 @@ export const overrideMessagingFromMainToWindow = (mainDi: DiContainer) => {
const message = tentativeParseJson(data[0]); const message = tentativeParseJson(data[0]);
listeners.forEach((listener) => listener.handler(message)); windowListeners.forEach((listener) =>
listener.handler(message),
);
}, },
); );
return (windowDi: DiContainer) => { return (windowDi: DiContainer, windowId: string) => {
windowDi.override( windowDi.override(
enlistMessageChannelListenerInjectableInRenderer, enlistMessageChannelListenerInjectableInRenderer,
() => (listener) => { () => (listener) => {
if (!messageChannelListenerFakesForRenderer.has(listener.channel.id)) { const windowListeners = getWindowListeners(
messageChannelListenerFakesForRenderer.set(
listener.channel.id,
new Set(),
);
}
const listeners = messageChannelListenerFakesForRenderer.get(
listener.channel.id, listener.channel.id,
windowId,
); );
assert(listeners); windowListeners.add(listener);
// TODO: Figure out typing
listeners.add(
listener as unknown as MessageChannelListener<MessageChannel<any>>,
);
return () => { return () => {
// TODO: Figure out typing windowListeners.delete(listener);
listeners.delete(
listener as unknown as MessageChannelListener<
MessageChannel<any>
>,
);
}; };
}, },
); );