1
0
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:
Sebastian Malton 2022-04-11 13:31:13 -04:00
parent 977c83502d
commit 203580ad92
6 changed files with 70 additions and 51 deletions

View File

@ -58,14 +58,14 @@ export class Cluster implements ClusterModel, ClusterState {
public get contextHandler() {
// 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;
}
protected get proxyKubeconfigManager() {
// 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;
}

View File

@ -17,7 +17,7 @@ const createContextHandlerInjectable = getInjectable({
instantiate: (di) => {
const createKubeAuthProxy = di.inject(createKubeAuthProxyInjectable);
return (cluster: Cluster): ClusterContextHandler => {
return (cluster: Cluster): ClusterContextHandler | undefined => {
const clusterUrl = new URLParse(cluster.apiUrl);
return new ContextHandler(

View File

@ -13,16 +13,18 @@ export interface KubeConfigManagerInstantiationParameter {
cluster: Cluster;
}
export type CreateKubeconfigManager = (cluster: Cluster) => KubeconfigManager | undefined;
const createKubeconfigManagerInjectable = getInjectable({
id: "create-kubeconfig-manager",
instantiate: (di) => {
instantiate: (di): CreateKubeconfigManager => {
const dependencies: KubeconfigManagerDependencies = {
directoryForTemp: di.inject(directoryForTempInjectable),
logger: di.inject(loggerInjectable),
};
return (cluster: Cluster) => new KubeconfigManager(dependencies, cluster);
return (cluster) => new KubeconfigManager(dependencies, cluster);
},
});

View File

@ -4,7 +4,7 @@
*/
import "@testing-library/jest-dom/extend-expect";
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 React from "react";
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 type { DiRender } from "../../test-utils/renderFor";
import { renderFor } from "../../test-utils/renderFor";
import hotbarStoreInjectable from "../../../../common/hotbars/store.injectable";
import type { OpenDeleteClusterDialog } 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", () => ({
app: {
@ -98,12 +99,11 @@ describe("<DeleteClusterDialog />", () => {
const { mainDi, rendererDi, runSetups } = getDisForUnitTesting({ doGeneralOverrides: true });
render = renderFor(rendererDi);
mainDi.override(createContextHandlerInjectable, () => () => undefined as never);
mainDi.override(createContextHandlerInjectable, () => () => undefined);
mainDi.override(createKubeconfigManagerInjectable, () => () => undefined);
mockFs();
rendererDi.override(hotbarStoreInjectable, () => ({}));
rendererDi.override(createStoresAndApisInjectable, () => true);
await runSetups();
@ -137,7 +137,7 @@ describe("<DeleteClusterDialog />", () => {
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({
id: "test",
contextName: "test",
@ -148,14 +148,14 @@ describe("<DeleteClusterDialog />", () => {
});
openDeleteClusterDialog({ cluster, config });
const { getByText } = render(<DeleteClusterDialog />);
render(<DeleteClusterDialog />);
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({
id: "other-cluster",
contextName: "other-context",
@ -166,10 +166,9 @@ describe("<DeleteClusterDialog />", () => {
});
openDeleteClusterDialog({ cluster, config });
render(<DeleteClusterDialog />);
const { getByTestId } = render(<DeleteClusterDialog />);
expect(getByTestId("current-context-warning")).toBeInstanceOf(HTMLElement);
expect(await screen.findByTestId("current-context-warning")).toBeInstanceOf(HTMLElement);
});
it("shows context switcher when deleting current cluster", async () => {
@ -183,14 +182,15 @@ describe("<DeleteClusterDialog />", () => {
});
openDeleteClusterDialog({ cluster, config });
render(<DeleteClusterDialog />);
const { getByText } = render(<DeleteClusterDialog />);
const menu = await screen.findByText("Select new context...");
expect(getByText("Select...")).toBeInTheDocument();
selectEvent.openMenu(getByText("Select..."));
expect(menu).toBeInTheDocument();
selectEvent.openMenu(menu);
expect(getByText("test")).toBeInTheDocument();
expect(getByText("test2")).toBeInTheDocument();
expect(await screen.findByText("test")).toBeInTheDocument();
expect(await screen.findByText("test2")).toBeInTheDocument();
});
it("shows context switcher after checkbox click", async () => {
@ -204,21 +204,23 @@ describe("<DeleteClusterDialog />", () => {
});
openDeleteClusterDialog({ cluster, config });
render(<DeleteClusterDialog />);
const { getByText, getByTestId } = render(<DeleteClusterDialog />);
const link = getByTestId("context-switch");
const link = await screen.findByTestId("context-switch");
expect(link).toBeInstanceOf(HTMLElement);
fireEvent.click(link);
expect(getByText("Select...")).toBeInTheDocument();
selectEvent.openMenu(getByText("Select..."));
const menu = await screen.findByText("Select new context...");
expect(getByText("test")).toBeInTheDocument();
expect(getByText("test2")).toBeInTheDocument();
expect(menu).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({
id: "some-cluster",
contextName: "test",
@ -231,10 +233,9 @@ describe("<DeleteClusterDialog />", () => {
const spy = jest.spyOn(cluster, "isInLocalKubeconfig").mockImplementation(() => true);
openDeleteClusterDialog({ cluster, config });
render(<DeleteClusterDialog />);
const { getByTestId } = render(<DeleteClusterDialog />);
expect(getByTestId("internal-kubeconfig-warning")).toBeInstanceOf(HTMLElement);
expect(await screen.findByTestId("internal-kubeconfig-warning")).toBeInstanceOf(HTMLElement);
spy.mockRestore();
});
@ -256,7 +257,7 @@ describe("<DeleteClusterDialog />", () => {
mockFs.restore();
});
it("shows warning if no other contexts left", () => {
it("shows warning if no other contexts left", async () => {
const cluster = createCluster({
id: "other-cluster",
contextName: "other-context",
@ -267,10 +268,9 @@ describe("<DeleteClusterDialog />", () => {
});
openDeleteClusterDialog({ cluster, config });
render(<DeleteClusterDialog />);
const { getByTestId } = render(<DeleteClusterDialog />);
expect(getByTestId("no-more-contexts-warning")).toBeInstanceOf(HTMLElement);
expect(await screen.findByTestId("no-more-contexts-warning")).toBeInstanceOf(HTMLElement);
});
});
});

View File

@ -5,7 +5,7 @@
import styles from "./view.module.scss";
import type { IObservableValue } from "mobx";
import { action, observable } from "mobx";
import { action, observable } from "mobx";
import { observer } from "mobx-react";
import React from "react";
@ -31,7 +31,7 @@ export interface Dependencies {
@observer
class NonInjectedDeleteClusterDialog extends React.Component<Dependencies> {
private readonly showContextSwitch = observable.box(false);
private readonly newCurrentContext = observable.box("");
private readonly newCurrentContext = observable.box<string | undefined>();
@action
onOpen(state: DeleteClusterDialogState) {
@ -99,24 +99,27 @@ class NonInjectedDeleteClusterDialog extends React.Component<Dependencies> {
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 (
<div className="mt-4">
<Select
id="delete-cluster-input"
options={(
config
.contexts
.filter(context => context.name !== cluster.contextName)
.map(ctx => ctx.name)
)}
value={this.newCurrentContext.get()}
onChange={contextName => {
if (contextName) {
this.newCurrentContext.set(contextName);
options={selectOptions}
getOptionLabel={opt => opt.name}
value={selectedOption}
onChange={opt => {
if (opt) {
this.newCurrentContext.set(opt.name);
}
}}
themeName="light"
className="ml-[1px] mr-[1px]"
placeholder="Select new context..."
/>
</div>
);

View File

@ -25,14 +25,28 @@ export interface SelectOption<T> {
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
themeName?: "dark" | "light" | "outlined" | "lens";
menuClass?: string;
}
@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 = {
menuPortalTarget: document.body,
menuPlacement: "auto",