mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
fix delete-cluster-dialog.test.tsx
Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
977c83502d
commit
203580ad92
@ -58,14 +58,14 @@ export class Cluster implements ClusterModel, ClusterState {
|
|||||||
|
|
||||||
public get contextHandler() {
|
public get contextHandler() {
|
||||||
// TODO: remove these once main/renderer are seperate classes
|
// TODO: remove these once main/renderer are seperate classes
|
||||||
assert(this._contextHandler);
|
assert(this._contextHandler, "contextHandler is only defined in the main environment");
|
||||||
|
|
||||||
return this._contextHandler;
|
return this._contextHandler;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected get proxyKubeconfigManager() {
|
protected get proxyKubeconfigManager() {
|
||||||
// TODO: remove these once main/renderer are seperate classes
|
// TODO: remove these once main/renderer are seperate classes
|
||||||
assert(this._proxyKubeconfigManager);
|
assert(this._proxyKubeconfigManager, "proxyKubeconfigManager is only defined in the main environment");
|
||||||
|
|
||||||
return this._proxyKubeconfigManager;
|
return this._proxyKubeconfigManager;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -17,7 +17,7 @@ const createContextHandlerInjectable = getInjectable({
|
|||||||
instantiate: (di) => {
|
instantiate: (di) => {
|
||||||
const createKubeAuthProxy = di.inject(createKubeAuthProxyInjectable);
|
const createKubeAuthProxy = di.inject(createKubeAuthProxyInjectable);
|
||||||
|
|
||||||
return (cluster: Cluster): ClusterContextHandler => {
|
return (cluster: Cluster): ClusterContextHandler | undefined => {
|
||||||
const clusterUrl = new URLParse(cluster.apiUrl);
|
const clusterUrl = new URLParse(cluster.apiUrl);
|
||||||
|
|
||||||
return new ContextHandler(
|
return new ContextHandler(
|
||||||
|
|||||||
@ -13,16 +13,18 @@ export interface KubeConfigManagerInstantiationParameter {
|
|||||||
cluster: Cluster;
|
cluster: Cluster;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type CreateKubeconfigManager = (cluster: Cluster) => KubeconfigManager | undefined;
|
||||||
|
|
||||||
const createKubeconfigManagerInjectable = getInjectable({
|
const createKubeconfigManagerInjectable = getInjectable({
|
||||||
id: "create-kubeconfig-manager",
|
id: "create-kubeconfig-manager",
|
||||||
|
|
||||||
instantiate: (di) => {
|
instantiate: (di): CreateKubeconfigManager => {
|
||||||
const dependencies: KubeconfigManagerDependencies = {
|
const dependencies: KubeconfigManagerDependencies = {
|
||||||
directoryForTemp: di.inject(directoryForTempInjectable),
|
directoryForTemp: di.inject(directoryForTempInjectable),
|
||||||
logger: di.inject(loggerInjectable),
|
logger: di.inject(loggerInjectable),
|
||||||
};
|
};
|
||||||
|
|
||||||
return (cluster: Cluster) => new KubeconfigManager(dependencies, cluster);
|
return (cluster) => new KubeconfigManager(dependencies, cluster);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
*/
|
*/
|
||||||
import "@testing-library/jest-dom/extend-expect";
|
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, screen } from "@testing-library/react";
|
||||||
import mockFs from "mock-fs";
|
import mockFs from "mock-fs";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import * as selectEvent from "react-select-event";
|
import * as selectEvent from "react-select-event";
|
||||||
@ -16,9 +16,10 @@ import { createClusterInjectionToken } from "../../../../common/cluster/create-c
|
|||||||
import createContextHandlerInjectable from "../../../../main/context-handler/create-context-handler.injectable";
|
import createContextHandlerInjectable from "../../../../main/context-handler/create-context-handler.injectable";
|
||||||
import type { DiRender } from "../../test-utils/renderFor";
|
import type { DiRender } from "../../test-utils/renderFor";
|
||||||
import { renderFor } from "../../test-utils/renderFor";
|
import { renderFor } from "../../test-utils/renderFor";
|
||||||
import hotbarStoreInjectable from "../../../../common/hotbars/store.injectable";
|
|
||||||
import type { OpenDeleteClusterDialog } from "../open.injectable";
|
import type { OpenDeleteClusterDialog } from "../open.injectable";
|
||||||
import openDeleteClusterDialogInjectable from "../open.injectable";
|
import openDeleteClusterDialogInjectable from "../open.injectable";
|
||||||
|
import createStoresAndApisInjectable from "../../../create-stores-apis.injectable";
|
||||||
|
import createKubeconfigManagerInjectable from "../../../../main/kubeconfig-manager/create-kubeconfig-manager.injectable";
|
||||||
|
|
||||||
jest.mock("electron", () => ({
|
jest.mock("electron", () => ({
|
||||||
app: {
|
app: {
|
||||||
@ -98,12 +99,11 @@ describe("<DeleteClusterDialog />", () => {
|
|||||||
const { mainDi, rendererDi, runSetups } = getDisForUnitTesting({ doGeneralOverrides: true });
|
const { mainDi, rendererDi, runSetups } = getDisForUnitTesting({ doGeneralOverrides: true });
|
||||||
|
|
||||||
render = renderFor(rendererDi);
|
render = renderFor(rendererDi);
|
||||||
|
mainDi.override(createContextHandlerInjectable, () => () => undefined);
|
||||||
mainDi.override(createContextHandlerInjectable, () => () => undefined as never);
|
mainDi.override(createKubeconfigManagerInjectable, () => () => undefined);
|
||||||
|
|
||||||
mockFs();
|
mockFs();
|
||||||
|
|
||||||
rendererDi.override(hotbarStoreInjectable, () => ({}));
|
rendererDi.override(createStoresAndApisInjectable, () => true);
|
||||||
|
|
||||||
await runSetups();
|
await runSetups();
|
||||||
|
|
||||||
@ -137,7 +137,7 @@ describe("<DeleteClusterDialog />", () => {
|
|||||||
expect(container).toBeInstanceOf(HTMLElement);
|
expect(container).toBeInstanceOf(HTMLElement);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("shows warning when deleting non-current-context cluster", () => {
|
it("shows warning when deleting non-current-context cluster", async () => {
|
||||||
const cluster = createCluster({
|
const cluster = createCluster({
|
||||||
id: "test",
|
id: "test",
|
||||||
contextName: "test",
|
contextName: "test",
|
||||||
@ -148,14 +148,14 @@ describe("<DeleteClusterDialog />", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
openDeleteClusterDialog({ cluster, config });
|
openDeleteClusterDialog({ cluster, config });
|
||||||
const { getByText } = render(<DeleteClusterDialog />);
|
|
||||||
|
|
||||||
|
render(<DeleteClusterDialog />);
|
||||||
const message = "The contents of kubeconfig file will be changed!";
|
const message = "The contents of kubeconfig file will be changed!";
|
||||||
|
|
||||||
expect(getByText(message)).toBeInstanceOf(HTMLElement);
|
expect(await screen.findByText(message)).toBeInstanceOf(HTMLElement);
|
||||||
});
|
});
|
||||||
|
|
||||||
it("shows warning when deleting current-context cluster", () => {
|
it("shows warning when deleting current-context cluster", async () => {
|
||||||
const cluster = createCluster({
|
const cluster = createCluster({
|
||||||
id: "other-cluster",
|
id: "other-cluster",
|
||||||
contextName: "other-context",
|
contextName: "other-context",
|
||||||
@ -166,10 +166,9 @@ describe("<DeleteClusterDialog />", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
openDeleteClusterDialog({ cluster, config });
|
openDeleteClusterDialog({ cluster, config });
|
||||||
|
render(<DeleteClusterDialog />);
|
||||||
|
|
||||||
const { getByTestId } = render(<DeleteClusterDialog />);
|
expect(await screen.findByTestId("current-context-warning")).toBeInstanceOf(HTMLElement);
|
||||||
|
|
||||||
expect(getByTestId("current-context-warning")).toBeInstanceOf(HTMLElement);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
it("shows context switcher when deleting current cluster", async () => {
|
it("shows context switcher when deleting current cluster", async () => {
|
||||||
@ -183,14 +182,15 @@ describe("<DeleteClusterDialog />", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
openDeleteClusterDialog({ cluster, config });
|
openDeleteClusterDialog({ cluster, config });
|
||||||
|
render(<DeleteClusterDialog />);
|
||||||
|
|
||||||
const { getByText } = render(<DeleteClusterDialog />);
|
const menu = await screen.findByText("Select new context...");
|
||||||
|
|
||||||
expect(getByText("Select...")).toBeInTheDocument();
|
expect(menu).toBeInTheDocument();
|
||||||
selectEvent.openMenu(getByText("Select..."));
|
selectEvent.openMenu(menu);
|
||||||
|
|
||||||
expect(getByText("test")).toBeInTheDocument();
|
expect(await screen.findByText("test")).toBeInTheDocument();
|
||||||
expect(getByText("test2")).toBeInTheDocument();
|
expect(await screen.findByText("test2")).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("shows context switcher after checkbox click", async () => {
|
it("shows context switcher after checkbox click", async () => {
|
||||||
@ -204,21 +204,23 @@ describe("<DeleteClusterDialog />", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
openDeleteClusterDialog({ cluster, config });
|
openDeleteClusterDialog({ cluster, config });
|
||||||
|
render(<DeleteClusterDialog />);
|
||||||
|
|
||||||
const { getByText, getByTestId } = render(<DeleteClusterDialog />);
|
const link = await screen.findByTestId("context-switch");
|
||||||
const link = getByTestId("context-switch");
|
|
||||||
|
|
||||||
expect(link).toBeInstanceOf(HTMLElement);
|
expect(link).toBeInstanceOf(HTMLElement);
|
||||||
fireEvent.click(link);
|
fireEvent.click(link);
|
||||||
|
|
||||||
expect(getByText("Select...")).toBeInTheDocument();
|
const menu = await screen.findByText("Select new context...");
|
||||||
selectEvent.openMenu(getByText("Select..."));
|
|
||||||
|
|
||||||
expect(getByText("test")).toBeInTheDocument();
|
expect(menu).toBeInTheDocument();
|
||||||
expect(getByText("test2")).toBeInTheDocument();
|
selectEvent.openMenu(menu);
|
||||||
|
|
||||||
|
expect(await screen.findByText("test")).toBeInTheDocument();
|
||||||
|
expect(await screen.findByText("test2")).toBeInTheDocument();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("shows warning for internal kubeconfig cluster", () => {
|
it("shows warning for internal kubeconfig cluster", async () => {
|
||||||
const cluster = createCluster({
|
const cluster = createCluster({
|
||||||
id: "some-cluster",
|
id: "some-cluster",
|
||||||
contextName: "test",
|
contextName: "test",
|
||||||
@ -231,10 +233,9 @@ describe("<DeleteClusterDialog />", () => {
|
|||||||
const spy = jest.spyOn(cluster, "isInLocalKubeconfig").mockImplementation(() => true);
|
const spy = jest.spyOn(cluster, "isInLocalKubeconfig").mockImplementation(() => true);
|
||||||
|
|
||||||
openDeleteClusterDialog({ cluster, config });
|
openDeleteClusterDialog({ cluster, config });
|
||||||
|
render(<DeleteClusterDialog />);
|
||||||
|
|
||||||
const { getByTestId } = render(<DeleteClusterDialog />);
|
expect(await screen.findByTestId("internal-kubeconfig-warning")).toBeInstanceOf(HTMLElement);
|
||||||
|
|
||||||
expect(getByTestId("internal-kubeconfig-warning")).toBeInstanceOf(HTMLElement);
|
|
||||||
|
|
||||||
spy.mockRestore();
|
spy.mockRestore();
|
||||||
});
|
});
|
||||||
@ -256,7 +257,7 @@ describe("<DeleteClusterDialog />", () => {
|
|||||||
mockFs.restore();
|
mockFs.restore();
|
||||||
});
|
});
|
||||||
|
|
||||||
it("shows warning if no other contexts left", () => {
|
it("shows warning if no other contexts left", async () => {
|
||||||
const cluster = createCluster({
|
const cluster = createCluster({
|
||||||
id: "other-cluster",
|
id: "other-cluster",
|
||||||
contextName: "other-context",
|
contextName: "other-context",
|
||||||
@ -267,10 +268,9 @@ describe("<DeleteClusterDialog />", () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
openDeleteClusterDialog({ cluster, config });
|
openDeleteClusterDialog({ cluster, config });
|
||||||
|
render(<DeleteClusterDialog />);
|
||||||
|
|
||||||
const { getByTestId } = render(<DeleteClusterDialog />);
|
expect(await screen.findByTestId("no-more-contexts-warning")).toBeInstanceOf(HTMLElement);
|
||||||
|
|
||||||
expect(getByTestId("no-more-contexts-warning")).toBeInstanceOf(HTMLElement);
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|||||||
@ -5,7 +5,7 @@
|
|||||||
import styles from "./view.module.scss";
|
import styles from "./view.module.scss";
|
||||||
|
|
||||||
import type { IObservableValue } from "mobx";
|
import type { IObservableValue } from "mobx";
|
||||||
import { action, observable } from "mobx";
|
import { action, observable } from "mobx";
|
||||||
import { observer } from "mobx-react";
|
import { observer } from "mobx-react";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
|
|
||||||
@ -31,7 +31,7 @@ export interface Dependencies {
|
|||||||
@observer
|
@observer
|
||||||
class NonInjectedDeleteClusterDialog extends React.Component<Dependencies> {
|
class NonInjectedDeleteClusterDialog extends React.Component<Dependencies> {
|
||||||
private readonly showContextSwitch = observable.box(false);
|
private readonly showContextSwitch = observable.box(false);
|
||||||
private readonly newCurrentContext = observable.box("");
|
private readonly newCurrentContext = observable.box<string | undefined>();
|
||||||
|
|
||||||
@action
|
@action
|
||||||
onOpen(state: DeleteClusterDialogState) {
|
onOpen(state: DeleteClusterDialogState) {
|
||||||
@ -99,24 +99,27 @@ class NonInjectedDeleteClusterDialog extends React.Component<Dependencies> {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const contextName = this.newCurrentContext.get();
|
||||||
|
const selectOptions = config
|
||||||
|
.contexts
|
||||||
|
.filter(context => context.name !== cluster.contextName);
|
||||||
|
const selectedOption = selectOptions.find(ctx => ctx.name === contextName);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="mt-4">
|
<div className="mt-4">
|
||||||
<Select
|
<Select
|
||||||
id="delete-cluster-input"
|
id="delete-cluster-input"
|
||||||
options={(
|
options={selectOptions}
|
||||||
config
|
getOptionLabel={opt => opt.name}
|
||||||
.contexts
|
value={selectedOption}
|
||||||
.filter(context => context.name !== cluster.contextName)
|
onChange={opt => {
|
||||||
.map(ctx => ctx.name)
|
if (opt) {
|
||||||
)}
|
this.newCurrentContext.set(opt.name);
|
||||||
value={this.newCurrentContext.get()}
|
|
||||||
onChange={contextName => {
|
|
||||||
if (contextName) {
|
|
||||||
this.newCurrentContext.set(contextName);
|
|
||||||
}
|
}
|
||||||
}}
|
}}
|
||||||
themeName="light"
|
themeName="light"
|
||||||
className="ml-[1px] mr-[1px]"
|
className="ml-[1px] mr-[1px]"
|
||||||
|
placeholder="Select new context..."
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@ -25,14 +25,28 @@ export interface SelectOption<T> {
|
|||||||
label?: React.ReactElement | string;
|
label?: React.ReactElement | string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface SelectProps<Option, IsMulti extends boolean, Group extends GroupBase<Option> = GroupBase<Option>> extends ReactSelectProps<Option, IsMulti, Group> {
|
export interface SelectProps<
|
||||||
|
/**
|
||||||
|
* This needs to extend `object` because even though `ReactSelectProps` allows for any `T`, the
|
||||||
|
* maintainers of `react-select` says that they don't support it.
|
||||||
|
*
|
||||||
|
* Ref: https://github.com/JedWatson/react-select/issues/5032
|
||||||
|
*/
|
||||||
|
Option extends object,
|
||||||
|
IsMulti extends boolean,
|
||||||
|
Group extends GroupBase<Option> = GroupBase<Option>,
|
||||||
|
> extends ReactSelectProps<Option, IsMulti, Group> {
|
||||||
id?: string; // Optional only because of Extension API. Required to make Select deterministic in unit tests
|
id?: string; // Optional only because of Extension API. Required to make Select deterministic in unit tests
|
||||||
themeName?: "dark" | "light" | "outlined" | "lens";
|
themeName?: "dark" | "light" | "outlined" | "lens";
|
||||||
menuClass?: string;
|
menuClass?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@observer
|
@observer
|
||||||
export class Select<Option, IsMulti extends boolean = false, Group extends GroupBase<Option> = GroupBase<Option>> extends React.Component<SelectProps<Option, IsMulti, Group>> {
|
export class Select<
|
||||||
|
Option extends object,
|
||||||
|
IsMulti extends boolean = false,
|
||||||
|
Group extends GroupBase<Option> = GroupBase<Option>,
|
||||||
|
> extends React.Component<SelectProps<Option, IsMulti, Group>> {
|
||||||
static defaultProps = {
|
static defaultProps = {
|
||||||
menuPortalTarget: document.body,
|
menuPortalTarget: document.body,
|
||||||
menuPlacement: "auto",
|
menuPlacement: "auto",
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user