mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Fix memory leak in unit tests (#5597)
This commit is contained in:
1 parent
2eb585e88e
commit
3058bea88f
37 files changed
+1502
-1777
No files matched your search
@@ -134,7 +134,7 @@ class NonInjectedAddCluster extends React.Component<Dependencies> {
|
||||
{this.allErrors.length > 0 && (
|
||||
<>
|
||||
<h3>KubeConfig Yaml Validation Errors:</h3>
|
||||
{...this.allErrors.map(error => <div key={error} className="error">{error}</div>)}
|
||||
{this.allErrors.map(error => <div key={error} className="error">{error}</div>)}
|
||||
</>
|
||||
)}
|
||||
<div className="actions-panel">
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* 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 { observable } from "mobx";
|
||||
|
||||
const badgeHasTextSelectedStateInjectable = getInjectable({
|
||||
id: "badge-has-text-selected-state",
|
||||
instantiate: () => observable.box(false),
|
||||
});
|
||||
|
||||
export default badgeHasTextSelectedStateInjectable;
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* 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 { WindowAction } from "../../../../common/ipc/window";
|
||||
import { requestWindowAction } from "../../../ipc";
|
||||
|
||||
const closeWindowInjectable = getInjectable({
|
||||
id: "close-window",
|
||||
instantiate: () => () => requestWindowAction(WindowAction.CLOSE),
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default closeWindowInjectable;
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* 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 { WindowAction } from "../../../../common/ipc/window";
|
||||
import { requestWindowAction } from "../../../ipc";
|
||||
|
||||
const goBackInjectable = getInjectable({
|
||||
id: "go-back",
|
||||
instantiate: () => () => requestWindowAction(WindowAction.GO_BACK),
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default goBackInjectable;
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* 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 { WindowAction } from "../../../../common/ipc/window";
|
||||
import { requestWindowAction } from "../../../ipc";
|
||||
|
||||
const goForwardInjectable = getInjectable({
|
||||
id: "go-forward",
|
||||
instantiate: () => () => requestWindowAction(WindowAction.GO_FORWARD),
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default goForwardInjectable;
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* 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 { WindowAction } from "../../../../common/ipc/window";
|
||||
import { requestWindowAction } from "../../../ipc";
|
||||
|
||||
const maximizeWindowInjectable = getInjectable({
|
||||
id: "maximize-window",
|
||||
instantiate: () => () => requestWindowAction(WindowAction.MINIMIZE),
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default maximizeWindowInjectable;
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { computed } from "mobx";
|
||||
import topBarStateInjectable from "./state.injectable";
|
||||
|
||||
const topBarNextEnabledInjectable = getInjectable({
|
||||
id: "top-bar-next-enabled",
|
||||
instantiate: (di) => {
|
||||
const state = di.inject(topBarStateInjectable);
|
||||
|
||||
return computed(() => state.nextEnabled);
|
||||
},
|
||||
});
|
||||
|
||||
export default topBarNextEnabledInjectable;
|
||||
@@ -0,0 +1,14 @@
|
||||
/**
|
||||
* 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 { emitOpenAppMenuAsContextMenu } from "../../../ipc";
|
||||
|
||||
const openAppContextMenuInjectable = getInjectable({
|
||||
id: "open-app-context-menu",
|
||||
instantiate: () => emitOpenAppMenuAsContextMenu,
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default openAppContextMenuInjectable;
|
||||
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { computed } from "mobx";
|
||||
import topBarStateInjectable from "./state.injectable";
|
||||
|
||||
const topBarPrevEnabledInjectable = getInjectable({
|
||||
id: "top-bar-prev-enabled",
|
||||
instantiate: (di) => {
|
||||
const state = di.inject(topBarStateInjectable);
|
||||
|
||||
return computed(() => state.prevEnabled);
|
||||
},
|
||||
});
|
||||
|
||||
export default topBarPrevEnabledInjectable;
|
||||
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* 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 { action } from "mobx";
|
||||
import { beforeFrameStartsInjectionToken } from "../../../before-frame-starts/before-frame-starts-injection-token";
|
||||
import ipcRendererInjectable from "../../../utils/channel/ipc-renderer.injectable";
|
||||
import topBarStateInjectable from "./state.injectable";
|
||||
|
||||
// TODO: replace with a SyncBox
|
||||
const startTopbarStateSyncInjectable = getInjectable({
|
||||
id: "start-topbar-state-sync",
|
||||
instantiate: (di) => {
|
||||
const state = di.inject(topBarStateInjectable);
|
||||
const ipcRenderer = di.inject(ipcRendererInjectable);
|
||||
|
||||
return {
|
||||
run: () => {
|
||||
ipcRenderer.on("history:can-go-back", action((event, canGoBack: boolean) => {
|
||||
state.prevEnabled = canGoBack;
|
||||
}));
|
||||
|
||||
ipcRenderer.on("history:can-go-forward", action((event, canGoForward: boolean) => {
|
||||
state.nextEnabled = canGoForward;
|
||||
}));
|
||||
},
|
||||
};
|
||||
},
|
||||
injectionToken: beforeFrameStartsInjectionToken,
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default startTopbarStateSyncInjectable;
|
||||
@@ -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 { observable } from "mobx";
|
||||
|
||||
const topBarStateInjectable = getInjectable({
|
||||
id: "top-bar-state",
|
||||
instantiate: () => observable.object({
|
||||
prevEnabled: false,
|
||||
nextEnabled: false,
|
||||
}),
|
||||
});
|
||||
|
||||
export default topBarStateInjectable;
|
||||
@@ -0,0 +1,15 @@
|
||||
/**
|
||||
* 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 { WindowAction } from "../../../../common/ipc/window";
|
||||
import { requestWindowAction } from "../../../ipc";
|
||||
|
||||
const toggleMaximizeWindowInjectable = getInjectable({
|
||||
id: "toggle-maximize-window",
|
||||
instantiate: () => () => requestWindowAction(WindowAction.TOGGLE_MAXIMIZE),
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default toggleMaximizeWindowInjectable;
|
||||
@@ -1,88 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
import { fireEvent } from "@testing-library/react";
|
||||
import "@testing-library/jest-dom/extend-expect";
|
||||
import { TopBar } from "./top-bar";
|
||||
import { getDiForUnitTesting } from "../../../getDiForUnitTesting";
|
||||
import type { DiRender } from "../../test-utils/renderFor";
|
||||
import { renderFor } from "../../test-utils/renderFor";
|
||||
import directoryForUserDataInjectable from "../../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||
import mockFs from "mock-fs";
|
||||
import { emitOpenAppMenuAsContextMenu, requestWindowAction } from "../../../ipc";
|
||||
import isLinuxInjectable from "../../../../common/vars/is-linux.injectable";
|
||||
import isMacInjectable from "../../../../common/vars/is-mac.injectable";
|
||||
import isWindowsInjectable from "../../../../common/vars/is-windows.injectable";
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
|
||||
jest.mock("../../../../common/ipc");
|
||||
jest.mock("../../../ipc");
|
||||
|
||||
describe("<TopBar/> in Windows and Linux", () => {
|
||||
let render: DiRender;
|
||||
let di: DiContainer;
|
||||
|
||||
beforeEach(() => {
|
||||
di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
di.override(isMacInjectable, () => false);
|
||||
|
||||
di.override(directoryForUserDataInjectable, () => "some-directory-for-user-data");
|
||||
|
||||
mockFs();
|
||||
|
||||
render = renderFor(di);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mockFs.restore();
|
||||
});
|
||||
|
||||
it("shows window controls on Windows", () => {
|
||||
di.override(isWindowsInjectable, () => true);
|
||||
|
||||
const { getByTestId } = render(<TopBar />);
|
||||
|
||||
expect(getByTestId("window-menu")).toBeInTheDocument();
|
||||
expect(getByTestId("window-minimize")).toBeInTheDocument();
|
||||
expect(getByTestId("window-maximize")).toBeInTheDocument();
|
||||
expect(getByTestId("window-close")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows window controls on Linux", () => {
|
||||
di.override(isLinuxInjectable, () => true);
|
||||
|
||||
const { getByTestId } = render(<TopBar />);
|
||||
|
||||
expect(getByTestId("window-menu")).toBeInTheDocument();
|
||||
expect(getByTestId("window-minimize")).toBeInTheDocument();
|
||||
expect(getByTestId("window-maximize")).toBeInTheDocument();
|
||||
expect(getByTestId("window-close")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("triggers ipc events on click", () => {
|
||||
di.override(isWindowsInjectable, () => true);
|
||||
|
||||
const { getByTestId } = render(<TopBar />);
|
||||
|
||||
const menu = getByTestId("window-menu");
|
||||
const minimize = getByTestId("window-minimize");
|
||||
const maximize = getByTestId("window-maximize");
|
||||
const close = getByTestId("window-close");
|
||||
|
||||
fireEvent.click(menu);
|
||||
expect(emitOpenAppMenuAsContextMenu).toHaveBeenCalledWith();
|
||||
|
||||
fireEvent.click(minimize);
|
||||
expect(requestWindowAction).toHaveBeenCalledWith("minimize");
|
||||
|
||||
fireEvent.click(maximize);
|
||||
expect(requestWindowAction).toHaveBeenCalledWith("toggle-maximize");
|
||||
|
||||
fireEvent.click(close);
|
||||
expect(requestWindowAction).toHaveBeenCalledWith("close");
|
||||
});
|
||||
});
|
||||
@@ -12,163 +12,191 @@ import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import type { DiRender } from "../../test-utils/renderFor";
|
||||
import { renderFor } from "../../test-utils/renderFor";
|
||||
import topBarItemsInjectable from "./top-bar-items/top-bar-items.injectable";
|
||||
import { computed } from "mobx";
|
||||
import directoryForUserDataInjectable from "../../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
|
||||
import mockFs from "mock-fs";
|
||||
import isLinuxInjectable from "../../../../common/vars/is-linux.injectable";
|
||||
import isWindowsInjectable from "../../../../common/vars/is-windows.injectable";
|
||||
|
||||
jest.mock("../../../../common/vars", () => {
|
||||
const { SemVer } = require("semver");
|
||||
|
||||
return {
|
||||
...jest.requireActual<{}>("../../../../common/vars"),
|
||||
appSemVer: new SemVer("1.0.0"),
|
||||
};
|
||||
});
|
||||
|
||||
const goBack = jest.fn();
|
||||
const goForward = jest.fn();
|
||||
|
||||
jest.mock(
|
||||
"electron",
|
||||
() => ({
|
||||
ipcRenderer: {
|
||||
on: jest.fn(
|
||||
(channel: string, listener: (event: any, ...args: any[]) => void) => {
|
||||
if (channel === "history:can-go-back") {
|
||||
listener({}, true);
|
||||
}
|
||||
|
||||
if (channel === "history:can-go-forward") {
|
||||
listener({}, true);
|
||||
}
|
||||
},
|
||||
),
|
||||
invoke: jest.fn(
|
||||
(channel: string, action: string) => {
|
||||
console.log("channel", channel, action);
|
||||
|
||||
if (channel !== "window:window-action") return;
|
||||
|
||||
switch(action) {
|
||||
case "back": {
|
||||
goBack();
|
||||
break;
|
||||
}
|
||||
|
||||
case "forward": {
|
||||
goForward();
|
||||
break;
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
},
|
||||
}),
|
||||
);
|
||||
|
||||
jest.mock("../../+catalog", () => ({
|
||||
previousActiveTab: jest.fn(),
|
||||
}));
|
||||
import { computed, observable } from "mobx";
|
||||
import rendererExtensionsInjectable from "../../../../extensions/renderer-extensions.injectable";
|
||||
import closeWindowInjectable from "./close-window.injectable";
|
||||
import goBackInjectable from "./go-back.injectable";
|
||||
import goForwardInjectable from "./go-forward.injectable";
|
||||
import maximizeWindowInjectable from "./maximize-window.injectable";
|
||||
import openAppContextMenuInjectable from "./open-app-context-menu.injectable";
|
||||
import toggleMaximizeWindowInjectable from "./toggle-maximize-window.injectable";
|
||||
import topBarStateInjectable from "./state.injectable";
|
||||
import platformInjectable from "../../../../common/vars/platform.injectable";
|
||||
|
||||
describe("<TopBar/>", () => {
|
||||
let di: DiContainer;
|
||||
let render: DiRender;
|
||||
let goBack: jest.MockedFunction<() => void>;
|
||||
let goForward: jest.MockedFunction<() => void>;
|
||||
let openAppContextMenu: jest.MockedFunction<() => void>;
|
||||
let closeWindow: jest.MockedFunction<() => void>;
|
||||
let maximizeWindow: jest.MockedFunction<() => void>;
|
||||
let toggleMaximizeWindow: jest.MockedFunction<() => void>;
|
||||
|
||||
beforeEach(() => {
|
||||
di = getDiForUnitTesting({ doGeneralOverrides: true });
|
||||
|
||||
mockFs();
|
||||
|
||||
di.override(directoryForUserDataInjectable, () => "some-directory-for-user-data");
|
||||
di.override(rendererExtensionsInjectable, () => computed(() => []));
|
||||
di.override(openAppContextMenuInjectable, () => openAppContextMenu = jest.fn());
|
||||
di.override(goBackInjectable, () => goBack = jest.fn());
|
||||
di.override(goForwardInjectable, () => goForward = jest.fn());
|
||||
di.override(closeWindowInjectable, () => closeWindow = jest.fn());
|
||||
di.override(maximizeWindowInjectable, () => maximizeWindow = jest.fn());
|
||||
di.override(toggleMaximizeWindowInjectable, () => toggleMaximizeWindow = jest.fn());
|
||||
|
||||
render = renderFor(di);
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
mockFs.restore();
|
||||
});
|
||||
describe("with both previous and next history enabled", () => {
|
||||
beforeEach(() => {
|
||||
di.override(topBarStateInjectable, () => observable.object({
|
||||
prevEnabled: true,
|
||||
nextEnabled: true,
|
||||
}));
|
||||
});
|
||||
it("renders w/o errors", () => {
|
||||
const { container } = render(<TopBar/>);
|
||||
|
||||
it("renders w/o errors", () => {
|
||||
const { container } = render(<TopBar/>);
|
||||
expect(container).toBeInstanceOf(HTMLElement);
|
||||
});
|
||||
|
||||
expect(container).toBeInstanceOf(HTMLElement);
|
||||
});
|
||||
it("renders home button", async () => {
|
||||
const { findByTestId } = render(<TopBar/>);
|
||||
|
||||
it("renders home button", async () => {
|
||||
const { findByTestId } = render(<TopBar/>);
|
||||
expect(await findByTestId("home-button")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
expect(await findByTestId("home-button")).toBeInTheDocument();
|
||||
});
|
||||
it("renders history arrows", async () => {
|
||||
const { findByTestId } = render(<TopBar/>);
|
||||
|
||||
it("renders history arrows", async () => {
|
||||
const { findByTestId } = render(<TopBar/>);
|
||||
expect(await findByTestId("history-back")).toBeInTheDocument();
|
||||
expect(await findByTestId("history-forward")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
expect(await findByTestId("history-back")).toBeInTheDocument();
|
||||
expect(await findByTestId("history-forward")).toBeInTheDocument();
|
||||
});
|
||||
it("enables arrow by ipc event", async () => {
|
||||
const { findByTestId } = render(<TopBar/>);
|
||||
|
||||
it("enables arrow by ipc event", async () => {
|
||||
const { findByTestId } = render(<TopBar/>);
|
||||
expect(await findByTestId("history-back")).not.toHaveClass("disabled");
|
||||
expect(await findByTestId("history-forward")).not.toHaveClass("disabled");
|
||||
});
|
||||
|
||||
expect(await findByTestId("history-back")).not.toHaveClass("disabled");
|
||||
expect(await findByTestId("history-forward")).not.toHaveClass("disabled");
|
||||
});
|
||||
it("triggers browser history back and forward", async () => {
|
||||
const { findByTestId } = render(<TopBar/>);
|
||||
|
||||
it("triggers browser history back and forward", async () => {
|
||||
const { findByTestId } = render(<TopBar/>);
|
||||
const prevButton = await findByTestId("history-back");
|
||||
const nextButton = await findByTestId("history-forward");
|
||||
|
||||
const prevButton = await findByTestId("history-back");
|
||||
const nextButton = await findByTestId("history-forward");
|
||||
fireEvent.click(prevButton);
|
||||
|
||||
fireEvent.click(prevButton);
|
||||
expect(goBack).toBeCalled();
|
||||
|
||||
expect(goBack).toBeCalled();
|
||||
fireEvent.click(nextButton);
|
||||
|
||||
fireEvent.click(nextButton);
|
||||
expect(goForward).toBeCalled();
|
||||
});
|
||||
|
||||
expect(goForward).toBeCalled();
|
||||
});
|
||||
it("renders items", async () => {
|
||||
const testId = "testId";
|
||||
const text = "an item";
|
||||
|
||||
it("renders items", async () => {
|
||||
const testId = "testId";
|
||||
const text = "an item";
|
||||
|
||||
di.override(topBarItemsInjectable, () => computed(() => [
|
||||
{
|
||||
components: {
|
||||
Item: () => <span data-testid={testId}>{text}</span>,
|
||||
di.override(topBarItemsInjectable, () => computed(() => [
|
||||
{
|
||||
components: {
|
||||
Item: () => <span data-testid={testId}>{text}</span>,
|
||||
},
|
||||
},
|
||||
},
|
||||
]));
|
||||
]));
|
||||
|
||||
const { findByTestId } = render(<TopBar/>);
|
||||
const { findByTestId } = render(<TopBar/>);
|
||||
|
||||
expect(await findByTestId(testId)).toHaveTextContent(text);
|
||||
});
|
||||
expect(await findByTestId(testId)).toHaveTextContent(text);
|
||||
});
|
||||
|
||||
it("doesn't show windows title buttons on macos", () => {
|
||||
di.override(isLinuxInjectable, () => false);
|
||||
di.override(isWindowsInjectable, () => false);
|
||||
describe("on macos", () => {
|
||||
beforeEach(() => {
|
||||
di.override(platformInjectable, () => "darwin");
|
||||
});
|
||||
|
||||
const { queryByTestId } = render(<TopBar/>);
|
||||
it("doesn't show windows title", () => {
|
||||
const { queryByTestId } = render(<TopBar/>);
|
||||
|
||||
expect(queryByTestId("window-menu")).not.toBeInTheDocument();
|
||||
expect(queryByTestId("window-minimize")).not.toBeInTheDocument();
|
||||
expect(queryByTestId("window-maximize")).not.toBeInTheDocument();
|
||||
expect(queryByTestId("window-close")).not.toBeInTheDocument();
|
||||
});
|
||||
expect(queryByTestId("window-menu")).not.toBeInTheDocument();
|
||||
expect(queryByTestId("window-minimize")).not.toBeInTheDocument();
|
||||
expect(queryByTestId("window-maximize")).not.toBeInTheDocument();
|
||||
expect(queryByTestId("window-close")).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it("does show windows title buttons on linux", () => {
|
||||
di.override(isLinuxInjectable, () => true);
|
||||
di.override(isWindowsInjectable, () => false);
|
||||
describe("on linux", () => {
|
||||
beforeEach(() => {
|
||||
di.override(platformInjectable, () => "linux");
|
||||
});
|
||||
|
||||
const { queryByTestId } = render(<TopBar/>);
|
||||
it("does show windows title buttons", () => {
|
||||
const { queryByTestId } = render(<TopBar/>);
|
||||
|
||||
expect(queryByTestId("window-menu")).toBeInTheDocument();
|
||||
expect(queryByTestId("window-minimize")).toBeInTheDocument();
|
||||
expect(queryByTestId("window-maximize")).toBeInTheDocument();
|
||||
expect(queryByTestId("window-close")).toBeInTheDocument();
|
||||
expect(queryByTestId("window-menu")).toBeInTheDocument();
|
||||
expect(queryByTestId("window-minimize")).toBeInTheDocument();
|
||||
expect(queryByTestId("window-maximize")).toBeInTheDocument();
|
||||
expect(queryByTestId("window-close")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("triggers ipc events on click", () => {
|
||||
const { getByTestId } = render(<TopBar />);
|
||||
|
||||
const menu = getByTestId("window-menu");
|
||||
const minimize = getByTestId("window-minimize");
|
||||
const maximize = getByTestId("window-maximize");
|
||||
const close = getByTestId("window-close");
|
||||
|
||||
fireEvent.click(menu);
|
||||
expect(openAppContextMenu).toBeCalled();
|
||||
|
||||
fireEvent.click(minimize);
|
||||
expect(maximizeWindow).toBeCalled();
|
||||
|
||||
fireEvent.click(maximize);
|
||||
expect(toggleMaximizeWindow).toBeCalled();
|
||||
|
||||
fireEvent.click(close);
|
||||
expect(closeWindow).toBeCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("on windows", () => {
|
||||
beforeEach(() => {
|
||||
di.override(platformInjectable, () => "win32");
|
||||
});
|
||||
|
||||
it("does show windows title buttons", () => {
|
||||
const { queryByTestId } = render(<TopBar/>);
|
||||
|
||||
expect(queryByTestId("window-menu")).toBeInTheDocument();
|
||||
expect(queryByTestId("window-minimize")).toBeInTheDocument();
|
||||
expect(queryByTestId("window-maximize")).toBeInTheDocument();
|
||||
expect(queryByTestId("window-close")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("triggers ipc events on click", () => {
|
||||
const { getByTestId } = render(<TopBar />);
|
||||
|
||||
const menu = getByTestId("window-menu");
|
||||
const minimize = getByTestId("window-minimize");
|
||||
const maximize = getByTestId("window-maximize");
|
||||
const close = getByTestId("window-close");
|
||||
|
||||
fireEvent.click(menu);
|
||||
expect(openAppContextMenu).toBeCalled();
|
||||
|
||||
fireEvent.click(minimize);
|
||||
expect(maximizeWindow).toBeCalled();
|
||||
|
||||
fireEvent.click(maximize);
|
||||
expect(toggleMaximizeWindow).toBeCalled();
|
||||
|
||||
fireEvent.click(close);
|
||||
expect(closeWindow).toBeCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -8,15 +8,11 @@ import React, { useEffect, useRef } from "react";
|
||||
import { observer } from "mobx-react";
|
||||
import type { IComputedValue } from "mobx";
|
||||
import { Icon } from "../../icon";
|
||||
import { observable } from "mobx";
|
||||
import { ipcRendererOn } from "../../../../common/ipc";
|
||||
import { watchHistoryState } from "../../../remote-helpers/history-updater";
|
||||
import { cssNames, noop } from "../../../utils";
|
||||
import topBarItemsInjectable from "./top-bar-items/top-bar-items.injectable";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import type { TopBarRegistration } from "./top-bar-registration";
|
||||
import { emitOpenAppMenuAsContextMenu, requestWindowAction } from "../../../ipc";
|
||||
import { WindowAction } from "../../../../common/ipc/window";
|
||||
import isLinuxInjectable from "../../../../common/vars/is-linux.injectable";
|
||||
import isWindowsInjectable from "../../../../common/vars/is-windows.injectable";
|
||||
import type { NavigateToCatalog } from "../../../../common/front-end-routing/routes/catalog/navigate-to-catalog.injectable";
|
||||
@@ -24,6 +20,14 @@ import navigateToCatalogInjectable from "../../../../common/front-end-routing/ro
|
||||
import catalogRouteInjectable from "../../../../common/front-end-routing/routes/catalog/catalog-route.injectable";
|
||||
import routeIsActiveInjectable from "../../../routes/route-is-active.injectable";
|
||||
import { UpdateButton } from "../../update-button";
|
||||
import topBarPrevEnabledInjectable from "./prev-enabled.injectable";
|
||||
import topBarNextEnabledInjectable from "./next-enabled.injectable";
|
||||
import openAppContextMenuInjectable from "./open-app-context-menu.injectable";
|
||||
import goBackInjectable from "./go-back.injectable";
|
||||
import goForwardInjectable from "./go-forward.injectable";
|
||||
import closeWindowInjectable from "./close-window.injectable";
|
||||
import maximizeWindowInjectable from "./maximize-window.injectable";
|
||||
import toggleMaximizeWindowInjectable from "./toggle-maximize-window.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
navigateToCatalog: NavigateToCatalog;
|
||||
@@ -31,62 +35,43 @@ interface Dependencies {
|
||||
items: IComputedValue<TopBarRegistration[]>;
|
||||
isWindows: boolean;
|
||||
isLinux: boolean;
|
||||
prevEnabled: IComputedValue<Boolean>;
|
||||
nextEnabled: IComputedValue<Boolean>;
|
||||
openAppContextMenu: () => void;
|
||||
goBack: () => void;
|
||||
goForward: () => void;
|
||||
minimizeWindow: () => void;
|
||||
toggleMaximizeWindow: () => void;
|
||||
closeWindow: () => void;
|
||||
}
|
||||
|
||||
const prevEnabled = observable.box(false);
|
||||
const nextEnabled = observable.box(false);
|
||||
|
||||
ipcRendererOn("history:can-go-back", (event, state: boolean) => {
|
||||
prevEnabled.set(state);
|
||||
});
|
||||
|
||||
ipcRendererOn("history:can-go-forward", (event, state: boolean) => {
|
||||
nextEnabled.set(state);
|
||||
});
|
||||
|
||||
const NonInjectedTopBar = observer(({
|
||||
items,
|
||||
navigateToCatalog,
|
||||
catalogRouteIsActive,
|
||||
isWindows,
|
||||
isLinux,
|
||||
prevEnabled,
|
||||
nextEnabled,
|
||||
openAppContextMenu,
|
||||
goBack,
|
||||
goForward,
|
||||
closeWindow,
|
||||
minimizeWindow,
|
||||
toggleMaximizeWindow,
|
||||
}: Dependencies) => {
|
||||
const elem = useRef<HTMLDivElement | null>(null);
|
||||
|
||||
const openAppContextMenu = () => {
|
||||
emitOpenAppMenuAsContextMenu();
|
||||
};
|
||||
|
||||
const goHome = () => {
|
||||
navigateToCatalog();
|
||||
};
|
||||
|
||||
const goBack = () => {
|
||||
requestWindowAction(WindowAction.GO_BACK);
|
||||
};
|
||||
|
||||
const goForward = () => {
|
||||
requestWindowAction(WindowAction.GO_FORWARD);
|
||||
};
|
||||
|
||||
const windowSizeToggle = (evt: React.MouseEvent) => {
|
||||
if (elem.current === evt.target) {
|
||||
toggleMaximize();
|
||||
toggleMaximizeWindow();
|
||||
}
|
||||
};
|
||||
|
||||
const minimizeWindow = () => {
|
||||
requestWindowAction(WindowAction.MINIMIZE);
|
||||
};
|
||||
|
||||
const toggleMaximize = () => {
|
||||
requestWindowAction(WindowAction.TOGGLE_MAXIMIZE);
|
||||
};
|
||||
|
||||
const closeWindow = () => {
|
||||
requestWindowAction(WindowAction.CLOSE);
|
||||
};
|
||||
|
||||
useEffect(() => watchHistoryState(), []);
|
||||
|
||||
return (
|
||||
@@ -147,14 +132,14 @@ const NonInjectedTopBar = observer(({
|
||||
width="10"
|
||||
height="1"
|
||||
x="1"
|
||||
y="9"
|
||||
y="9"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
<div
|
||||
className={styles.maximize}
|
||||
data-testid="window-maximize"
|
||||
onClick={toggleMaximize}
|
||||
onClick={toggleMaximizeWindow}
|
||||
>
|
||||
<svg shapeRendering="crispEdges" viewBox="0 0 12 12">
|
||||
<rect
|
||||
@@ -163,7 +148,7 @@ const NonInjectedTopBar = observer(({
|
||||
x="1.5"
|
||||
y="1.5"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
</div>
|
||||
@@ -193,23 +178,23 @@ const renderRegisteredItems = (items: TopBarRegistration[]) => (
|
||||
})
|
||||
);
|
||||
|
||||
export const TopBar = withInjectables<Dependencies>(
|
||||
NonInjectedTopBar,
|
||||
{
|
||||
getProps: (di) => {
|
||||
const catalogRoute = di.inject(catalogRouteInjectable);
|
||||
|
||||
return {
|
||||
navigateToCatalog: di.inject(navigateToCatalogInjectable),
|
||||
items: di.inject(topBarItemsInjectable),
|
||||
isLinux: di.inject(isLinuxInjectable),
|
||||
isWindows: di.inject(isWindowsInjectable),
|
||||
|
||||
catalogRouteIsActive: di.inject(
|
||||
routeIsActiveInjectable,
|
||||
catalogRoute,
|
||||
),
|
||||
};
|
||||
},
|
||||
},
|
||||
);
|
||||
export const TopBar = withInjectables<Dependencies>(NonInjectedTopBar, {
|
||||
getProps: (di) => ({
|
||||
navigateToCatalog: di.inject(navigateToCatalogInjectable),
|
||||
items: di.inject(topBarItemsInjectable),
|
||||
isLinux: di.inject(isLinuxInjectable),
|
||||
isWindows: di.inject(isWindowsInjectable),
|
||||
prevEnabled: di.inject(topBarPrevEnabledInjectable),
|
||||
nextEnabled: di.inject(topBarNextEnabledInjectable),
|
||||
catalogRouteIsActive: di.inject(
|
||||
routeIsActiveInjectable,
|
||||
di.inject(catalogRouteInjectable),
|
||||
),
|
||||
openAppContextMenu: di.inject(openAppContextMenuInjectable),
|
||||
goBack: di.inject(goBackInjectable),
|
||||
goForward: di.inject(goForwardInjectable),
|
||||
closeWindow: di.inject(closeWindowInjectable),
|
||||
minimizeWindow: di.inject(maximizeWindowInjectable),
|
||||
toggleMaximizeWindow: di.inject(toggleMaximizeWindowInjectable),
|
||||
}),
|
||||
});
|
||||
@@ -18,6 +18,7 @@ exports[`<Tooltip /> renders to DOM when forced to by visibile prop 1`] = `
|
||||
<div
|
||||
class="Tooltip visible"
|
||||
role="tooltip"
|
||||
style="left: 10px; top: 0px;"
|
||||
>
|
||||
I am a tooltip
|
||||
</div>
|
||||
@@ -34,7 +35,7 @@ exports[`<Tooltip /> renders to DOM when hovering over target 1`] = `
|
||||
<body>
|
||||
<div>
|
||||
<div
|
||||
class="Tooltip right"
|
||||
class="Tooltip visible"
|
||||
role="tooltip"
|
||||
style="left: 10px; top: 0px;"
|
||||
>
|
||||
|
||||
@@ -10,6 +10,23 @@ import React from "react";
|
||||
import { Tooltip } from "./tooltip";
|
||||
|
||||
describe("<Tooltip />", () => {
|
||||
let requestAnimationFrameSpy: jest.SpyInstance<number, [callback: FrameRequestCallback]>;
|
||||
|
||||
beforeEach(() => {
|
||||
requestAnimationFrameSpy = jest.spyOn(window, "requestAnimationFrame");
|
||||
|
||||
requestAnimationFrameSpy.mockImplementation(cb => {
|
||||
cb(0);
|
||||
|
||||
return 0;
|
||||
});
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
requestAnimationFrameSpy.mockRestore();
|
||||
});
|
||||
|
||||
|
||||
it("does not render to DOM if not visibile", () => {
|
||||
const result = render((
|
||||
<>
|
||||
|
||||
@@ -79,6 +79,7 @@ export class Tooltip extends React.Component<TooltipProps> {
|
||||
componentDidMount() {
|
||||
this.hoverTarget?.addEventListener("mouseenter", this.onEnterTarget);
|
||||
this.hoverTarget?.addEventListener("mouseleave", this.onLeaveTarget);
|
||||
this.refreshPosition();
|
||||
}
|
||||
|
||||
componentDidUpdate() {
|
||||
@@ -110,7 +111,8 @@ export class Tooltip extends React.Component<TooltipProps> {
|
||||
return;
|
||||
}
|
||||
|
||||
let positions = new Set<TooltipPosition>([
|
||||
const positions = new Set<TooltipPosition>([
|
||||
...[preferredPositions ?? []].flat(),
|
||||
TooltipPosition.RIGHT,
|
||||
TooltipPosition.BOTTOM,
|
||||
TooltipPosition.TOP,
|
||||
@@ -121,13 +123,6 @@ export class Tooltip extends React.Component<TooltipProps> {
|
||||
TooltipPosition.BOTTOM_LEFT,
|
||||
]);
|
||||
|
||||
if (preferredPositions) {
|
||||
positions = new Set([
|
||||
...[preferredPositions].flat(),
|
||||
...positions,
|
||||
]);
|
||||
}
|
||||
|
||||
// reset position first and get all possible client-rect area for tooltip element
|
||||
this.setPosition(elem, { left: 0, top: 0 });
|
||||
|
||||
|
||||
@@ -26,9 +26,6 @@ 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 type { UserStore } from "../common/user-store";
|
||||
import isMacInjectable from "../common/vars/is-mac.injectable";
|
||||
import isWindowsInjectable from "../common/vars/is-windows.injectable";
|
||||
import isLinuxInjectable from "../common/vars/is-linux.injectable";
|
||||
import getAbsolutePathInjectable from "../common/path/get-absolute-path.injectable";
|
||||
import { getAbsolutePathFake } from "../common/test-utils/get-absolute-path-fake";
|
||||
import joinPathsInjectable from "../common/path/join-paths.injectable";
|
||||
@@ -52,6 +49,8 @@ import requestAnimationFrameInjectable from "./components/animate/request-animat
|
||||
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 callForPublicHelmRepositoriesInjectable from "./components/+preferences/kubernetes/helm-charts/adding-of-public-helm-repository/public-helm-repositories/call-for-public-helm-repositories.injectable";
|
||||
import platformInjectable from "../common/vars/platform.injectable";
|
||||
import startTopbarStateSyncInjectable from "./components/layout/top-bar/start-state-sync.injectable";
|
||||
|
||||
export const getDiForUnitTesting = (opts: { doGeneralOverrides?: boolean } = {}) => {
|
||||
const {
|
||||
@@ -75,9 +74,10 @@ export const getDiForUnitTesting = (opts: { doGeneralOverrides?: boolean } = {})
|
||||
|
||||
if (doGeneralOverrides) {
|
||||
di.override(getRandomIdInjectable, () => () => "some-irrelevant-random-id");
|
||||
di.override(isMacInjectable, () => true);
|
||||
di.override(isWindowsInjectable, () => false);
|
||||
di.override(isLinuxInjectable, () => false);
|
||||
di.override(platformInjectable, () => "darwin");
|
||||
di.override(startTopbarStateSyncInjectable, () => ({
|
||||
run: () => {},
|
||||
}));
|
||||
|
||||
di.override(terminalSpawningPoolInjectable, () => document.createElement("div"));
|
||||
di.override(hostedClusterIdInjectable, () => undefined);
|
||||
|
||||
Reference in new issue
Block a user