mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Rename old directory for behaviours as "features" to better communicate new intent with new directory structure to organize code and tests around features instead of technicalities (#6033)
Co-authored-by: Mikko Aspiala <mikko.aspiala@gmail.com> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> Signed-off-by: Janne Savolainen <janne.savolainen@live.fi> Co-authored-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
1 parent
36077a9fea
commit
299922c8a7
107 files changed
No files matched your search
File diff suppressed because it is too large.
Load diff
+3664
File diff suppressed because it is too large.
Load diff
+4304
File diff suppressed because it is too large.
Load diff
File diff suppressed because it is too large.
Load diff
+1442
File diff suppressed because it is too large.
Load diff
+1581
File diff suppressed because it is too large.
Load diff
+106
@@ -0,0 +1,106 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import type { ApplicationBuilder } 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 { getExtensionFakeFor } from "../../../renderer/components/test-utils/get-extension-fake";
|
||||
import type { KubernetesCluster } from "../../../common/catalog-entities";
|
||||
import React from "react";
|
||||
import extensionShouldBeEnabledForClusterFrameInjectable from "../../../renderer/extension-loader/extension-should-be-enabled-for-cluster-frame.injectable";
|
||||
|
||||
describe("disable-cluster-pages-when-cluster-is-not-relevant", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
let rendered: RenderResult;
|
||||
let rendererTestExtension: TestExtensionRenderer;
|
||||
let isEnabledForClusterMock: AsyncFnMock<(cluster: KubernetesCluster) => Promise<boolean>>;
|
||||
|
||||
beforeEach(async () => {
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
builder.setEnvironmentToClusterFrame();
|
||||
|
||||
builder.dis.rendererDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable);
|
||||
|
||||
const getExtensionFake = getExtensionFakeFor(builder);
|
||||
|
||||
isEnabledForClusterMock = asyncFn();
|
||||
|
||||
const testExtension = getExtensionFake({
|
||||
id: "test-extension-id",
|
||||
name: "test-extension",
|
||||
|
||||
rendererOptions: {
|
||||
isEnabledForCluster: isEnabledForClusterMock,
|
||||
|
||||
clusterPages: [{
|
||||
components: {
|
||||
Page: () => <div data-testid="some-test-page">Some page</div>,
|
||||
},
|
||||
}],
|
||||
},
|
||||
});
|
||||
|
||||
rendererTestExtension = testExtension.renderer;
|
||||
|
||||
rendered = await builder.render();
|
||||
|
||||
builder.extensions.enable(testExtension);
|
||||
});
|
||||
|
||||
describe("given not yet known if extension should be enabled for the cluster, when navigating", () => {
|
||||
beforeEach(() => {
|
||||
rendererTestExtension.navigate();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show the page", () => {
|
||||
const actual = rendered.queryByTestId("some-test-page");
|
||||
|
||||
expect(actual).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("given extension shouldn't be enabled for the cluster, when navigating", () => {
|
||||
beforeEach(async () => {
|
||||
await isEnabledForClusterMock.resolve(false);
|
||||
|
||||
rendererTestExtension.navigate();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show the page", () => {
|
||||
const actual = rendered.queryByTestId("some-test-page");
|
||||
|
||||
expect(actual).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("given extension should be enabled for the cluster, when navigating", () => {
|
||||
beforeEach(async () => {
|
||||
await isEnabledForClusterMock.resolve(true);
|
||||
|
||||
rendererTestExtension.navigate();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows the page", () => {
|
||||
const actual = rendered.getByTestId("some-test-page");
|
||||
|
||||
expect(actual).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import type { ApplicationBuilder } 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 React from "react";
|
||||
import extensionShouldBeEnabledForClusterFrameInjectable from "../../../renderer/extension-loader/extension-should-be-enabled-for-cluster-frame.injectable";
|
||||
|
||||
describe("disable sidebar items when cluster is not relevant", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
let rendered: RenderResult;
|
||||
let isEnabledForClusterMock: AsyncFnMock<(cluster: KubernetesCluster) => Promise<boolean>>;
|
||||
|
||||
beforeEach(async () => {
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
builder.setEnvironmentToClusterFrame();
|
||||
|
||||
builder.dis.rendererDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable);
|
||||
|
||||
const getExtensionFake = getExtensionFakeFor(builder);
|
||||
|
||||
isEnabledForClusterMock = asyncFn();
|
||||
|
||||
const testExtension = getExtensionFake({
|
||||
id: "test-extension-id",
|
||||
name: "test-extension",
|
||||
|
||||
rendererOptions: {
|
||||
isEnabledForCluster: isEnabledForClusterMock,
|
||||
|
||||
clusterPages: [{
|
||||
components: {
|
||||
Page: () => <div data-testid="some-test-page">Some page</div>,
|
||||
},
|
||||
}],
|
||||
|
||||
clusterPageMenus: [
|
||||
{
|
||||
id: "some-sidebar-item",
|
||||
title: "Some sidebar item",
|
||||
|
||||
components: {
|
||||
Icon: () => <div>Some icon</div>,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
rendered = await builder.render();
|
||||
|
||||
builder.extensions.enable(testExtension);
|
||||
});
|
||||
|
||||
describe("given not yet known if extension should be enabled for the cluster", () => {
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show the sidebar item", () => {
|
||||
const actual = rendered.queryByTestId(
|
||||
"sidebar-item-some-extension-name-some-sidebar-item",
|
||||
);
|
||||
|
||||
expect(actual).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("given extension shouldn't be enabled for the cluster", () => {
|
||||
beforeEach(async () => {
|
||||
await isEnabledForClusterMock.resolve(false);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show the sidebar item", () => {
|
||||
const actual = rendered.queryByTestId(
|
||||
"sidebar-item-some-extension-name-some-sidebar-item",
|
||||
);
|
||||
|
||||
expect(actual).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("given extension should be enabled for the cluster", () => {
|
||||
beforeEach(async () => {
|
||||
await isEnabledForClusterMock.resolve(true);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows the sidebar item", () => {
|
||||
const actual = rendered.getByTestId(
|
||||
"sidebar-item-test-extension-some-sidebar-item",
|
||||
);
|
||||
|
||||
expect(actual).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import type { IObservableValue } from "mobx";
|
||||
import { observable, runInAction, computed } from "mobx";
|
||||
import React from "react";
|
||||
import type { TestExtensionRenderer } from "../../../renderer/components/test-utils/get-extension-fake";
|
||||
import type { ApplicationBuilder } 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", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
let rendered: RenderResult;
|
||||
let someObservable: IObservableValue<boolean>;
|
||||
let rendererTestExtension: TestExtensionRenderer;
|
||||
|
||||
beforeEach(async () => {
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
builder.setEnvironmentToClusterFrame();
|
||||
|
||||
const getExtensionFake = getExtensionFakeFor(builder);
|
||||
|
||||
someObservable = observable.box(false);
|
||||
|
||||
const testExtension = getExtensionFake({
|
||||
id: "test-extension-id",
|
||||
name: "test-extension",
|
||||
|
||||
rendererOptions: {
|
||||
clusterPages: [{
|
||||
components: {
|
||||
Page: () => <div data-testid="some-test-page">Some page</div>,
|
||||
},
|
||||
|
||||
enabled: computed(() => someObservable.get()),
|
||||
}],
|
||||
},
|
||||
});
|
||||
|
||||
rendered = await builder.render();
|
||||
|
||||
builder.extensions.enable(testExtension);
|
||||
|
||||
rendererTestExtension = testExtension.renderer;
|
||||
});
|
||||
|
||||
it("when navigating to the page, does not show the page", () => {
|
||||
rendererTestExtension.navigate();
|
||||
|
||||
const actual = rendered.queryByTestId("some-test-page");
|
||||
|
||||
expect(actual).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("given page becomes enabled, when navigating to the page, shows the page", () => {
|
||||
runInAction(() => {
|
||||
someObservable.set(true);
|
||||
});
|
||||
|
||||
rendererTestExtension.navigate();
|
||||
|
||||
const actual = rendered.queryByTestId("some-test-page");
|
||||
|
||||
expect(actual).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
+1451
File diff suppressed because it is too large.
Load diff
+172
@@ -0,0 +1,172 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import type { ApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
|
||||
import type { KubernetesCluster } from "../../../../common/catalog-entities";
|
||||
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 { frontEndRouteInjectionToken } from "../../../../common/front-end-routing/front-end-route-injection-token";
|
||||
import { computed } from "mobx";
|
||||
import React from "react";
|
||||
import { navigateToRouteInjectionToken } from "../../../../common/front-end-routing/navigate-to-route-injection-token";
|
||||
import { routeSpecificComponentInjectionToken } from "../../../../renderer/routes/route-specific-component-injection-token";
|
||||
import { KubeObject } from "../../../../common/k8s-api/kube-object";
|
||||
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 { KubeObjectDetails } from "../../../../renderer/components/kube-object-details";
|
||||
import type { ApiManager } from "../../../../common/k8s-api/api-manager";
|
||||
|
||||
describe("disable kube object detail items when cluster is not relevant", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
let rendered: RenderResult;
|
||||
let isEnabledForClusterMock: AsyncFnMock<
|
||||
(cluster: KubernetesCluster) => Promise<boolean>
|
||||
>;
|
||||
|
||||
beforeEach(async () => {
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
builder.beforeApplicationStart(({ rendererDi }) => {
|
||||
rendererDi.override(
|
||||
apiManagerInjectable,
|
||||
() =>
|
||||
({
|
||||
getStore: () => ({
|
||||
getByPath: () =>
|
||||
getKubeObjectStub("some-kind", "some-api-version"),
|
||||
}),
|
||||
} as unknown as ApiManager),
|
||||
);
|
||||
});
|
||||
|
||||
const rendererDi = builder.dis.rendererDi;
|
||||
|
||||
rendererDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable);
|
||||
|
||||
rendererDi.register(testRouteInjectable, testRouteComponentInjectable);
|
||||
|
||||
builder.setEnvironmentToClusterFrame();
|
||||
|
||||
const getExtensionFake = getExtensionFakeFor(builder);
|
||||
|
||||
isEnabledForClusterMock = asyncFn();
|
||||
|
||||
const testExtension = getExtensionFake({
|
||||
id: "test-extension-id",
|
||||
name: "test-extension",
|
||||
|
||||
rendererOptions: {
|
||||
isEnabledForCluster: isEnabledForClusterMock,
|
||||
|
||||
kubeObjectDetailItems: [
|
||||
{
|
||||
kind: "some-kind",
|
||||
apiVersions: ["some-api-version"],
|
||||
components: {
|
||||
Details: () => (
|
||||
<div data-testid="some-kube-object-detail-item">
|
||||
Some detail
|
||||
</div>
|
||||
),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
rendered = await builder.render();
|
||||
|
||||
const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken);
|
||||
const testRoute = rendererDi.inject(testRouteInjectable);
|
||||
|
||||
navigateToRoute(testRoute);
|
||||
|
||||
builder.extensions.enable(testExtension);
|
||||
});
|
||||
|
||||
describe("given not yet known if extension should be enabled for the cluster", () => {
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show the kube object detail item", () => {
|
||||
const actual = rendered.queryByTestId("some-kube-object-detail-item");
|
||||
|
||||
expect(actual).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("given extension shouldn't be enabled for the cluster", () => {
|
||||
beforeEach(async () => {
|
||||
await isEnabledForClusterMock.resolve(false);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show the kube object detail item", () => {
|
||||
const actual = rendered.queryByTestId("some-kube-object-detail-item");
|
||||
|
||||
expect(actual).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("given extension should be enabled for the cluster", () => {
|
||||
beforeEach(async () => {
|
||||
await isEnabledForClusterMock.resolve(true);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows the kube object detail item", () => {
|
||||
const actual = rendered.getByTestId("some-kube-object-detail-item");
|
||||
|
||||
expect(actual).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const testRouteInjectable = getInjectable({
|
||||
id: "test-route",
|
||||
|
||||
instantiate: () => ({
|
||||
path: "/test-route",
|
||||
clusterFrame: true,
|
||||
isEnabled: computed(() => true),
|
||||
}),
|
||||
|
||||
injectionToken: frontEndRouteInjectionToken,
|
||||
});
|
||||
|
||||
const testRouteComponentInjectable = getInjectable({
|
||||
id: "test-route-component",
|
||||
|
||||
instantiate: (di) => ({
|
||||
route: di.inject(testRouteInjectable),
|
||||
|
||||
Component: () => <KubeObjectDetails />,
|
||||
}),
|
||||
|
||||
injectionToken: routeSpecificComponentInjectionToken,
|
||||
});
|
||||
|
||||
const getKubeObjectStub = (kind: string, apiVersion: string) =>
|
||||
KubeObject.create({
|
||||
apiVersion,
|
||||
kind,
|
||||
metadata: {
|
||||
uid: "some-uid",
|
||||
name: "some-name",
|
||||
resourceVersion: "some-resource-version",
|
||||
namespace: "some-namespace",
|
||||
selfLink: "",
|
||||
},
|
||||
});
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import type { ApplicationBuilder } 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 { frontEndRouteInjectionToken } from "../../../../common/front-end-routing/front-end-route-injection-token";
|
||||
import type { IObservableValue } from "mobx";
|
||||
import { runInAction, computed, observable } from "mobx";
|
||||
import React from "react";
|
||||
import { navigateToRouteInjectionToken } from "../../../../common/front-end-routing/navigate-to-route-injection-token";
|
||||
import { routeSpecificComponentInjectionToken } from "../../../../renderer/routes/route-specific-component-injection-token";
|
||||
import { KubeObject } from "../../../../common/k8s-api/kube-object";
|
||||
import apiManagerInjectable from "../../../../common/k8s-api/api-manager/manager.injectable";
|
||||
import { KubeObjectDetails } from "../../../../renderer/components/kube-object-details";
|
||||
import type { ApiManager } from "../../../../common/k8s-api/api-manager";
|
||||
|
||||
describe("reactively hide kube object detail item", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
let rendered: RenderResult;
|
||||
let someObservable: IObservableValue<boolean>;
|
||||
|
||||
beforeEach(async () => {
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
builder.beforeApplicationStart(({ rendererDi }) => {
|
||||
rendererDi.override(
|
||||
apiManagerInjectable,
|
||||
() =>
|
||||
({
|
||||
getStore: () => ({
|
||||
getByPath: () =>
|
||||
getKubeObjectStub("some-kind", "some-api-version"),
|
||||
}),
|
||||
} as unknown as ApiManager),
|
||||
);
|
||||
});
|
||||
|
||||
const rendererDi = builder.dis.rendererDi;
|
||||
|
||||
rendererDi.register(testRouteInjectable, testRouteComponentInjectable);
|
||||
|
||||
builder.setEnvironmentToClusterFrame();
|
||||
|
||||
const getExtensionFake = getExtensionFakeFor(builder);
|
||||
|
||||
someObservable = observable.box(false);
|
||||
|
||||
const testExtension = getExtensionFake({
|
||||
id: "test-extension-id",
|
||||
name: "test-extension",
|
||||
|
||||
rendererOptions: {
|
||||
kubeObjectDetailItems: [
|
||||
{
|
||||
kind: "some-kind",
|
||||
apiVersions: ["some-api-version"],
|
||||
|
||||
components: {
|
||||
Details: () => (
|
||||
<div data-testid="some-kube-object-detail-item">
|
||||
Some detail
|
||||
</div>
|
||||
),
|
||||
},
|
||||
|
||||
visible: computed(() => someObservable.get()),
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
rendered = await builder.render();
|
||||
|
||||
const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken);
|
||||
const testRoute = rendererDi.inject(testRouteInjectable);
|
||||
|
||||
navigateToRoute(testRoute);
|
||||
|
||||
builder.extensions.enable(testExtension);
|
||||
});
|
||||
|
||||
it("does not show the kube object detail item", () => {
|
||||
const actual = rendered.queryByTestId("some-kube-object-detail-item");
|
||||
|
||||
expect(actual).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("given item should be shown, shows the kube object detail item", () => {
|
||||
runInAction(() => {
|
||||
someObservable.set(true);
|
||||
});
|
||||
|
||||
const actual = rendered.queryByTestId("some-kube-object-detail-item");
|
||||
|
||||
expect(actual).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
const testRouteInjectable = getInjectable({
|
||||
id: "test-route",
|
||||
|
||||
instantiate: () => ({
|
||||
path: "/test-route",
|
||||
clusterFrame: true,
|
||||
isEnabled: computed(() => true),
|
||||
}),
|
||||
|
||||
injectionToken: frontEndRouteInjectionToken,
|
||||
});
|
||||
|
||||
const testRouteComponentInjectable = getInjectable({
|
||||
id: "test-route-component",
|
||||
|
||||
instantiate: (di) => ({
|
||||
route: di.inject(testRouteInjectable),
|
||||
|
||||
Component: () => <KubeObjectDetails />,
|
||||
}),
|
||||
|
||||
injectionToken: routeSpecificComponentInjectionToken,
|
||||
});
|
||||
|
||||
const getKubeObjectStub = (kind: string, apiVersion: string) =>
|
||||
KubeObject.create({
|
||||
apiVersion,
|
||||
kind,
|
||||
metadata: {
|
||||
uid: "some-uid",
|
||||
name: "some-name",
|
||||
resourceVersion: "some-resource-version",
|
||||
namespace: "some-namespace",
|
||||
selfLink: "",
|
||||
},
|
||||
});
|
||||
+1207
File diff suppressed because it is too large.
Load diff
+160
@@ -0,0 +1,160 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import type { ApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
|
||||
import type { KubernetesCluster } from "../../../../common/catalog-entities";
|
||||
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 { frontEndRouteInjectionToken } from "../../../../common/front-end-routing/front-end-route-injection-token";
|
||||
import { computed } from "mobx";
|
||||
import React from "react";
|
||||
import { navigateToRouteInjectionToken } from "../../../../common/front-end-routing/navigate-to-route-injection-token";
|
||||
import { routeSpecificComponentInjectionToken } from "../../../../renderer/routes/route-specific-component-injection-token";
|
||||
import { KubeObject } from "../../../../common/k8s-api/kube-object";
|
||||
import extensionShouldBeEnabledForClusterFrameInjectable from "../../../../renderer/extension-loader/extension-should-be-enabled-for-cluster-frame.injectable";
|
||||
import { KubeObjectMenu } from "../../../../renderer/components/kube-object-menu";
|
||||
|
||||
describe("disable kube object menu items when cluster is not relevant", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
let rendered: RenderResult;
|
||||
let isEnabledForClusterMock: AsyncFnMock<
|
||||
(cluster: KubernetesCluster) => Promise<boolean>
|
||||
>;
|
||||
|
||||
beforeEach(async () => {
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
const rendererDi = builder.dis.rendererDi;
|
||||
|
||||
rendererDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable);
|
||||
|
||||
rendererDi.register(testRouteInjectable, testRouteComponentInjectable);
|
||||
|
||||
builder.setEnvironmentToClusterFrame();
|
||||
|
||||
const getExtensionFake = getExtensionFakeFor(builder);
|
||||
|
||||
isEnabledForClusterMock = asyncFn();
|
||||
|
||||
const testExtension = getExtensionFake({
|
||||
id: "test-extension-id",
|
||||
name: "test-extension",
|
||||
|
||||
rendererOptions: {
|
||||
isEnabledForCluster: isEnabledForClusterMock,
|
||||
|
||||
kubeObjectMenuItems: [
|
||||
{
|
||||
kind: "some-kind",
|
||||
apiVersions: ["some-api-version"],
|
||||
components: {
|
||||
MenuItem: () => (
|
||||
<div data-testid="some-test-id">Some menu item</div>
|
||||
),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
rendered = await builder.render();
|
||||
|
||||
const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken);
|
||||
const testRoute = rendererDi.inject(testRouteInjectable);
|
||||
|
||||
navigateToRoute(testRoute);
|
||||
|
||||
builder.extensions.enable(testExtension);
|
||||
});
|
||||
|
||||
describe("given not yet known if extension should be enabled for the cluster", () => {
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show the kube object menu item", () => {
|
||||
const actual = rendered.queryByTestId("some-test-id");
|
||||
|
||||
expect(actual).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("given extension shouldn't be enabled for the cluster", () => {
|
||||
beforeEach(async () => {
|
||||
await isEnabledForClusterMock.resolve(false);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show the kube object menu item", () => {
|
||||
const actual = rendered.queryByTestId("some-test-id");
|
||||
|
||||
expect(actual).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("given extension should be enabled for the cluster", () => {
|
||||
beforeEach(async () => {
|
||||
await isEnabledForClusterMock.resolve(true);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows the kube object menu item", () => {
|
||||
const actual = rendered.getByTestId("some-test-id");
|
||||
|
||||
expect(actual).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const testRouteInjectable = getInjectable({
|
||||
id: "test-route",
|
||||
|
||||
instantiate: () => ({
|
||||
path: "/test-route",
|
||||
clusterFrame: true,
|
||||
isEnabled: computed(() => true),
|
||||
}),
|
||||
|
||||
injectionToken: frontEndRouteInjectionToken,
|
||||
});
|
||||
|
||||
const testRouteComponentInjectable = getInjectable({
|
||||
id: "test-route-component",
|
||||
|
||||
instantiate: (di) => ({
|
||||
route: di.inject(testRouteInjectable),
|
||||
|
||||
Component: () => (
|
||||
<KubeObjectMenu
|
||||
toolbar={true}
|
||||
object={getKubeObjectStub("some-kind", "some-api-version")}
|
||||
/>
|
||||
),
|
||||
}),
|
||||
|
||||
injectionToken: routeSpecificComponentInjectionToken,
|
||||
});
|
||||
|
||||
const getKubeObjectStub = (kind: string, apiVersion: string) =>
|
||||
KubeObject.create({
|
||||
apiVersion,
|
||||
kind,
|
||||
metadata: {
|
||||
uid: "some-uid",
|
||||
name: "some-name",
|
||||
resourceVersion: "some-resource-version",
|
||||
namespace: "some-namespace",
|
||||
selfLink: "",
|
||||
},
|
||||
});
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import type { ApplicationBuilder } 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 { frontEndRouteInjectionToken } from "../../../../common/front-end-routing/front-end-route-injection-token";
|
||||
import type { IObservableValue } from "mobx";
|
||||
import { observable, runInAction, computed } from "mobx";
|
||||
import React from "react";
|
||||
import { navigateToRouteInjectionToken } from "../../../../common/front-end-routing/navigate-to-route-injection-token";
|
||||
import { routeSpecificComponentInjectionToken } from "../../../../renderer/routes/route-specific-component-injection-token";
|
||||
import { KubeObject } from "../../../../common/k8s-api/kube-object";
|
||||
import { KubeObjectMenu } from "../../../../renderer/components/kube-object-menu";
|
||||
|
||||
describe("reactively hide kube object menu item", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
let rendered: RenderResult;
|
||||
let someObservable: IObservableValue<boolean>;
|
||||
|
||||
beforeEach(async () => {
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
const rendererDi = builder.dis.rendererDi;
|
||||
|
||||
rendererDi.register(testRouteInjectable, testRouteComponentInjectable);
|
||||
|
||||
builder.setEnvironmentToClusterFrame();
|
||||
|
||||
const getExtensionFake = getExtensionFakeFor(builder);
|
||||
|
||||
someObservable = observable.box(false);
|
||||
|
||||
const testExtension = getExtensionFake({
|
||||
id: "test-extension-id",
|
||||
name: "test-extension",
|
||||
|
||||
rendererOptions: {
|
||||
kubeObjectMenuItems: [
|
||||
{
|
||||
kind: "some-kind",
|
||||
apiVersions: ["some-api-version"],
|
||||
components: {
|
||||
MenuItem: () => (
|
||||
<div data-testid="some-kube-object-menu-item">Some menu item</div>
|
||||
),
|
||||
},
|
||||
|
||||
visible: computed(() => someObservable.get()),
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
rendered = await builder.render();
|
||||
|
||||
const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken);
|
||||
const testRoute = rendererDi.inject(testRouteInjectable);
|
||||
|
||||
navigateToRoute(testRoute);
|
||||
|
||||
builder.extensions.enable(testExtension);
|
||||
});
|
||||
|
||||
it("does not show the kube object menu item", () => {
|
||||
const actual = rendered.queryByTestId("some-kube-object-menu-item");
|
||||
|
||||
expect(actual).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("given item should be shown, shows the kube object menu item", () => {
|
||||
runInAction(() => {
|
||||
someObservable.set(true);
|
||||
});
|
||||
|
||||
const actual = rendered.queryByTestId("some-kube-object-menu-item");
|
||||
|
||||
expect(actual).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
const testRouteInjectable = getInjectable({
|
||||
id: "test-route",
|
||||
|
||||
instantiate: () => ({
|
||||
path: "/test-route",
|
||||
clusterFrame: true,
|
||||
isEnabled: computed(() => true),
|
||||
}),
|
||||
|
||||
injectionToken: frontEndRouteInjectionToken,
|
||||
});
|
||||
|
||||
const testRouteComponentInjectable = getInjectable({
|
||||
id: "test-route-component",
|
||||
|
||||
instantiate: (di) => ({
|
||||
route: di.inject(testRouteInjectable),
|
||||
|
||||
Component: () => (
|
||||
<KubeObjectMenu
|
||||
toolbar={true}
|
||||
object={getKubeObjectStub("some-kind", "some-api-version")}
|
||||
/>
|
||||
),
|
||||
}),
|
||||
|
||||
injectionToken: routeSpecificComponentInjectionToken,
|
||||
});
|
||||
|
||||
const getKubeObjectStub = (kind: string, apiVersion: string) =>
|
||||
KubeObject.create({
|
||||
apiVersion,
|
||||
kind,
|
||||
metadata: {
|
||||
uid: "some-uid",
|
||||
name: "some-name",
|
||||
resourceVersion: "some-resource-version",
|
||||
namespace: "some-namespace",
|
||||
selfLink: "",
|
||||
},
|
||||
});
|
||||
|
||||
+2491
File diff suppressed because it is too large.
Load diff
+1226
File diff suppressed because it is too large.
Load diff
+160
@@ -0,0 +1,160 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import type { ApplicationBuilder } from "../../../../renderer/components/test-utils/get-application-builder";
|
||||
import type { KubernetesCluster } from "../../../../common/catalog-entities";
|
||||
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 { frontEndRouteInjectionToken } from "../../../../common/front-end-routing/front-end-route-injection-token";
|
||||
import { computed } from "mobx";
|
||||
import React from "react";
|
||||
import { navigateToRouteInjectionToken } from "../../../../common/front-end-routing/navigate-to-route-injection-token";
|
||||
import { routeSpecificComponentInjectionToken } from "../../../../renderer/routes/route-specific-component-injection-token";
|
||||
import { KubeObjectStatusIcon } from "../../../../renderer/components/kube-object-status-icon/kube-object-status-icon";
|
||||
import { KubeObject } from "../../../../common/k8s-api/kube-object";
|
||||
import { KubeObjectStatusLevel } from "../../../../common/k8s-api/kube-object-status";
|
||||
import extensionShouldBeEnabledForClusterFrameInjectable from "../../../../renderer/extension-loader/extension-should-be-enabled-for-cluster-frame.injectable";
|
||||
|
||||
describe("disable kube object statuses when cluster is not relevant", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
let rendered: RenderResult;
|
||||
let isEnabledForClusterMock: AsyncFnMock<
|
||||
(cluster: KubernetesCluster) => Promise<boolean>
|
||||
>;
|
||||
|
||||
beforeEach(async () => {
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
const rendererDi = builder.dis.rendererDi;
|
||||
|
||||
rendererDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable);
|
||||
|
||||
rendererDi.register(testRouteInjectable, testRouteComponentInjectable);
|
||||
|
||||
builder.setEnvironmentToClusterFrame();
|
||||
|
||||
const getExtensionFake = getExtensionFakeFor(builder);
|
||||
|
||||
isEnabledForClusterMock = asyncFn();
|
||||
|
||||
const testExtension = getExtensionFake({
|
||||
id: "test-extension-id",
|
||||
name: "test-extension",
|
||||
|
||||
rendererOptions: {
|
||||
isEnabledForCluster: isEnabledForClusterMock,
|
||||
|
||||
kubeObjectStatusTexts: [
|
||||
{
|
||||
kind: "some-kind",
|
||||
apiVersions: ["some-api-version"],
|
||||
|
||||
resolve: () => ({
|
||||
level: KubeObjectStatusLevel.CRITICAL,
|
||||
text: "some-kube-object-status-text",
|
||||
}),
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
rendered = await builder.render();
|
||||
|
||||
const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken);
|
||||
const testRoute = rendererDi.inject(testRouteInjectable);
|
||||
|
||||
navigateToRoute(testRoute);
|
||||
|
||||
builder.extensions.enable(testExtension);
|
||||
});
|
||||
|
||||
describe("given not yet known if extension should be enabled for the cluster", () => {
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show the status", () => {
|
||||
const actual = rendered.baseElement.querySelectorAll(".KubeObjectStatusIcon");
|
||||
|
||||
expect(actual).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("given extension shouldn't be enabled for the cluster", () => {
|
||||
beforeEach(async () => {
|
||||
await isEnabledForClusterMock.resolve(false);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show the status", () => {
|
||||
const actual = rendered.baseElement.querySelectorAll(".KubeObjectStatusIcon");
|
||||
|
||||
expect(actual).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
|
||||
describe("given extension should be enabled for the cluster", () => {
|
||||
beforeEach(async () => {
|
||||
await isEnabledForClusterMock.resolve(true);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows the status", () => {
|
||||
const actual = rendered.baseElement.querySelectorAll(".KubeObjectStatusIcon");
|
||||
|
||||
expect(actual).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const testRouteInjectable = getInjectable({
|
||||
id: "test-route",
|
||||
|
||||
instantiate: () => ({
|
||||
path: "/test-route",
|
||||
clusterFrame: true,
|
||||
isEnabled: computed(() => true),
|
||||
}),
|
||||
|
||||
injectionToken: frontEndRouteInjectionToken,
|
||||
});
|
||||
|
||||
const testRouteComponentInjectable = getInjectable({
|
||||
id: "test-route-component",
|
||||
|
||||
instantiate: (di) => ({
|
||||
route: di.inject(testRouteInjectable),
|
||||
|
||||
Component: () => (
|
||||
<KubeObjectStatusIcon
|
||||
object={getKubeObjectStub("some-kind", "some-api-version")}
|
||||
/>
|
||||
),
|
||||
}),
|
||||
|
||||
injectionToken: routeSpecificComponentInjectionToken,
|
||||
});
|
||||
|
||||
const getKubeObjectStub = (kind: string, apiVersion: string) =>
|
||||
KubeObject.create({
|
||||
apiVersion,
|
||||
kind,
|
||||
metadata: {
|
||||
uid: "some-uid",
|
||||
name: "some-name",
|
||||
resourceVersion: "some-resource-version",
|
||||
namespace: "some-namespace",
|
||||
selfLink: "/foo",
|
||||
},
|
||||
});
|
||||
+132
@@ -0,0 +1,132 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import type { ApplicationBuilder } 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 { frontEndRouteInjectionToken } from "../../../../common/front-end-routing/front-end-route-injection-token";
|
||||
import type { IObservableValue } from "mobx";
|
||||
import { observable, runInAction, computed } from "mobx";
|
||||
import React from "react";
|
||||
import { navigateToRouteInjectionToken } from "../../../../common/front-end-routing/navigate-to-route-injection-token";
|
||||
import { routeSpecificComponentInjectionToken } from "../../../../renderer/routes/route-specific-component-injection-token";
|
||||
import extensionShouldBeEnabledForClusterFrameInjectable from "../../../../renderer/extension-loader/extension-should-be-enabled-for-cluster-frame.injectable";
|
||||
import { KubeObject } from "../../../../common/k8s-api/kube-object";
|
||||
import { KubeObjectStatusLevel } from "../../../../common/k8s-api/kube-object-status";
|
||||
import { KubeObjectStatusIcon } from "../../../../renderer/components/kube-object-status-icon";
|
||||
|
||||
describe("reactively hide kube object status", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
let rendered: RenderResult;
|
||||
let someObservable: IObservableValue<boolean>;
|
||||
|
||||
beforeEach(async () => {
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
const rendererDi = builder.dis.rendererDi;
|
||||
|
||||
rendererDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable);
|
||||
|
||||
rendererDi.register(testRouteInjectable, testRouteComponentInjectable);
|
||||
|
||||
builder.setEnvironmentToClusterFrame();
|
||||
|
||||
const getExtensionFake = getExtensionFakeFor(builder);
|
||||
|
||||
someObservable = observable.box(false);
|
||||
|
||||
const testExtension = getExtensionFake({
|
||||
id: "test-extension-id",
|
||||
name: "test-extension",
|
||||
|
||||
rendererOptions: {
|
||||
kubeObjectStatusTexts: [
|
||||
{
|
||||
kind: "some-kind",
|
||||
apiVersions: ["some-api-version"],
|
||||
|
||||
resolve: () => ({
|
||||
level: KubeObjectStatusLevel.CRITICAL,
|
||||
text: "some-kube-object-status-text",
|
||||
}),
|
||||
|
||||
visible: computed(() => someObservable.get()),
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
rendered = await builder.render();
|
||||
|
||||
const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken);
|
||||
const testRoute = rendererDi.inject(testRouteInjectable);
|
||||
|
||||
navigateToRoute(testRoute);
|
||||
|
||||
builder.extensions.enable(testExtension);
|
||||
});
|
||||
|
||||
it("does not show the kube object status", () => {
|
||||
const actual = rendered.baseElement.querySelectorAll(
|
||||
".KubeObjectStatusIcon",
|
||||
);
|
||||
|
||||
expect(actual).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("given item should be shown, shows the kube object status", () => {
|
||||
runInAction(() => {
|
||||
someObservable.set(true);
|
||||
});
|
||||
|
||||
const actual = rendered.baseElement.querySelectorAll(
|
||||
".KubeObjectStatusIcon",
|
||||
);
|
||||
|
||||
expect(actual).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
||||
const testRouteInjectable = getInjectable({
|
||||
id: "test-route",
|
||||
|
||||
instantiate: () => ({
|
||||
path: "/test-route",
|
||||
clusterFrame: true,
|
||||
isEnabled: computed(() => true),
|
||||
}),
|
||||
|
||||
injectionToken: frontEndRouteInjectionToken,
|
||||
});
|
||||
|
||||
const testRouteComponentInjectable = getInjectable({
|
||||
id: "test-route-component",
|
||||
|
||||
instantiate: (di) => ({
|
||||
route: di.inject(testRouteInjectable),
|
||||
|
||||
Component: () => (
|
||||
<KubeObjectStatusIcon
|
||||
object={getKubeObjectStub("some-kind", "some-api-version")}
|
||||
/>
|
||||
),
|
||||
}),
|
||||
|
||||
injectionToken: routeSpecificComponentInjectionToken,
|
||||
});
|
||||
|
||||
const getKubeObjectStub = (kind: string, apiVersion: string) =>
|
||||
KubeObject.create({
|
||||
apiVersion,
|
||||
kind,
|
||||
metadata: {
|
||||
uid: "some-uid",
|
||||
name: "some-name",
|
||||
resourceVersion: "some-resource-version",
|
||||
namespace: "some-namespace",
|
||||
selfLink: "",
|
||||
},
|
||||
});
|
||||
@@ -0,0 +1,351 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { KubeObjectStatusLevel } from "../../../common/k8s-api/kube-object-status";
|
||||
import { KubeObject } from "../../../common/k8s-api/kube-object";
|
||||
import React from "react";
|
||||
import { useFakeTime } from "../../../common/test-utils/use-fake-time";
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import type { IAtom } from "mobx";
|
||||
import { createAtom, computed } from "mobx";
|
||||
import { frontEndRouteInjectionToken } from "../../../common/front-end-routing/front-end-route-injection-token";
|
||||
import { routeSpecificComponentInjectionToken } from "../../../renderer/routes/route-specific-component-injection-token";
|
||||
import type { ApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
|
||||
import { navigateToRouteInjectionToken } from "../../../common/front-end-routing/navigate-to-route-injection-token";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import { act } from "@testing-library/react";
|
||||
import { observer } from "mobx-react";
|
||||
import { kubeObjectStatusTextInjectionToken } from "../../../renderer/components/kube-object-status-icon/kube-object-status-text-injection-token";
|
||||
import { KubeObjectStatusIcon } from "../../../renderer/components/kube-object-status-icon";
|
||||
|
||||
describe("show status for a kube object", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
let infoStatusIsShown: boolean;
|
||||
let warningStatusIsShown: boolean;
|
||||
let criticalStatusIsShown: boolean;
|
||||
|
||||
beforeEach(() => {
|
||||
useFakeTime("2015-10-21T07:28:00Z");
|
||||
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
const rendererDi = builder.dis.rendererDi;
|
||||
|
||||
infoStatusIsShown = false;
|
||||
|
||||
const infoStatusInjectable = getInjectable({
|
||||
id: "some-info-status",
|
||||
injectionToken: kubeObjectStatusTextInjectionToken,
|
||||
|
||||
instantiate: () => ({
|
||||
apiVersions: ["some-api-version"],
|
||||
kind: "some-kind",
|
||||
enabled: computed(() => true),
|
||||
|
||||
resolve: (resource) => infoStatusIsShown ? ({
|
||||
level: KubeObjectStatusLevel.INFO,
|
||||
text: `Some info status for ${resource.getName()}`,
|
||||
timestamp: "2015-10-19T07:28:00Z",
|
||||
}) : null,
|
||||
}),
|
||||
});
|
||||
|
||||
warningStatusIsShown = false;
|
||||
|
||||
const warningStatusInjectable = getInjectable({
|
||||
id: "some-warning-status",
|
||||
injectionToken: kubeObjectStatusTextInjectionToken,
|
||||
|
||||
instantiate: () => ({
|
||||
apiVersions: ["some-api-version"],
|
||||
kind: "some-kind",
|
||||
enabled: computed(() => true),
|
||||
|
||||
resolve: (resource) => warningStatusIsShown ? ({
|
||||
level: KubeObjectStatusLevel.WARNING,
|
||||
text: `Some warning status for ${resource.getName()}`,
|
||||
timestamp: "2015-10-19T07:28:00Z",
|
||||
}) : null,
|
||||
}),
|
||||
});
|
||||
|
||||
criticalStatusIsShown = false;
|
||||
|
||||
const criticalStatusInjectable = getInjectable({
|
||||
id: "some-critical-status",
|
||||
injectionToken: kubeObjectStatusTextInjectionToken,
|
||||
|
||||
instantiate: () => ({
|
||||
apiVersions: ["some-api-version"],
|
||||
kind: "some-kind",
|
||||
enabled: computed(() => true),
|
||||
|
||||
resolve: (resource) => {
|
||||
return criticalStatusIsShown
|
||||
? {
|
||||
level: KubeObjectStatusLevel.CRITICAL,
|
||||
text: `Some critical status for ${resource.getName()}`,
|
||||
timestamp: "2015-10-19T07:28:00Z",
|
||||
}
|
||||
: null;
|
||||
},
|
||||
}),
|
||||
});
|
||||
|
||||
rendererDi.register(
|
||||
testRouteInjectable,
|
||||
testRouteComponentInjectable,
|
||||
infoStatusInjectable,
|
||||
warningStatusInjectable,
|
||||
criticalStatusInjectable,
|
||||
someAtomInjectable,
|
||||
);
|
||||
|
||||
builder.setEnvironmentToClusterFrame();
|
||||
});
|
||||
|
||||
describe("given application starts and in test page", () => {
|
||||
let rendererDi: DiContainer;
|
||||
let rendered: RenderResult;
|
||||
let rerenderParent: () => void;
|
||||
|
||||
beforeEach(async () => {
|
||||
rendered = await builder.render();
|
||||
|
||||
rendererDi = builder.dis.rendererDi;
|
||||
|
||||
const someAtom = rendererDi.inject(someAtomInjectable);
|
||||
|
||||
rerenderParent = rerenderParentFor(someAtom);
|
||||
|
||||
const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken);
|
||||
const testRoute = rendererDi.inject(testRouteInjectable);
|
||||
|
||||
navigateToRoute(testRoute);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show any statuses yet", () => {
|
||||
const status = rendered.queryByTestId(
|
||||
"kube-object-status-icon-for-some-uid",
|
||||
);
|
||||
|
||||
expect(status).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe("when status for irrelevant kube object kind emerges", () => {
|
||||
beforeEach(() => {
|
||||
rendererDi.register(statusForIrrelevantKubeObjectKindInjectable);
|
||||
|
||||
rerenderParent();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show any statuses", () => {
|
||||
const status = rendered.queryByTestId(
|
||||
"kube-object-status-icon-for-some-uid",
|
||||
);
|
||||
|
||||
expect(status).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when status for irrelevant kube object api version emerges", () => {
|
||||
beforeEach(() => {
|
||||
rendererDi.register(statusForIrrelevantKubeObjectApiVersionInjectable);
|
||||
|
||||
rerenderParent();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show any statuses", () => {
|
||||
const status = rendered.queryByTestId(
|
||||
"kube-object-status-icon-for-some-uid",
|
||||
);
|
||||
|
||||
expect(status).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when info status emerges", () => {
|
||||
beforeEach(() => {
|
||||
infoStatusIsShown = true;
|
||||
|
||||
rerenderParent();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows status", () => {
|
||||
const status = rendered.getByTestId(
|
||||
"kube-object-status-icon-for-some-uid",
|
||||
);
|
||||
|
||||
expect(status).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("show info status", () => {
|
||||
const tooltipContent = rendered.getByTestId(
|
||||
"tooltip-content-for-kube-object-status-icon-for-some-uid",
|
||||
);
|
||||
|
||||
expect(tooltipContent).toHaveTextContent(
|
||||
"Some info status for some-name",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when warning status emerges", () => {
|
||||
beforeEach(() => {
|
||||
warningStatusIsShown = true;
|
||||
|
||||
rerenderParent();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("show warning status", () => {
|
||||
const tooltipContent = rendered.getByTestId(
|
||||
"tooltip-content-for-kube-object-status-icon-for-some-uid",
|
||||
);
|
||||
|
||||
expect(tooltipContent).toHaveTextContent(
|
||||
"Some warning status for some-name",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when critical status emerges", () => {
|
||||
beforeEach(() => {
|
||||
criticalStatusIsShown = true;
|
||||
|
||||
rerenderParent();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("show critical status", () => {
|
||||
const tooltipContent = rendered.getByTestId(
|
||||
"tooltip-content-for-kube-object-status-icon-for-some-uid",
|
||||
);
|
||||
|
||||
expect(tooltipContent).toHaveTextContent(
|
||||
"Some critical status for some-name",
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const testRouteInjectable = getInjectable({
|
||||
id: "test-route",
|
||||
|
||||
instantiate: () => ({
|
||||
path: "/test-route",
|
||||
clusterFrame: true,
|
||||
isEnabled: computed(() => true),
|
||||
}),
|
||||
|
||||
injectionToken: frontEndRouteInjectionToken,
|
||||
});
|
||||
|
||||
const rerenderParentFor = (atom: IAtom) => () => {
|
||||
act(() => {
|
||||
atom.reportChanged();
|
||||
});
|
||||
};
|
||||
|
||||
const TestComponent = observer(({ someAtom }: { someAtom: IAtom }) => {
|
||||
void someAtom.reportObserved();
|
||||
|
||||
return (
|
||||
<KubeObjectStatusIcon
|
||||
object={getKubeObjectStub("some-kind", "some-api-version")}
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
const testRouteComponentInjectable = getInjectable({
|
||||
id: "test-route-component",
|
||||
|
||||
instantiate: (di) => {
|
||||
const someAtom = di.inject(someAtomInjectable);
|
||||
|
||||
return {
|
||||
route: di.inject(testRouteInjectable),
|
||||
Component: () => <TestComponent someAtom={someAtom} />,
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: routeSpecificComponentInjectionToken,
|
||||
});
|
||||
|
||||
const someAtomInjectable = getInjectable({
|
||||
id: "some-atom",
|
||||
instantiate: () => createAtom("some-atom"),
|
||||
});
|
||||
|
||||
const getKubeObjectStub = (kind: string, apiVersion: string) =>
|
||||
KubeObject.create({
|
||||
apiVersion,
|
||||
kind,
|
||||
metadata: {
|
||||
uid: "some-uid",
|
||||
name: "some-name",
|
||||
resourceVersion: "some-resource-version",
|
||||
namespace: "some-namespace",
|
||||
selfLink: "/foo",
|
||||
},
|
||||
});
|
||||
|
||||
const statusForIrrelevantKubeObjectKindInjectable = getInjectable({
|
||||
id: "status-for-irrelevant-kube-object-kind",
|
||||
injectionToken: kubeObjectStatusTextInjectionToken,
|
||||
|
||||
instantiate: () => ({
|
||||
apiVersions: ["some-api-version"],
|
||||
kind: "some-other-kind",
|
||||
enabled: computed(() => true),
|
||||
|
||||
resolve: () => ({
|
||||
level: KubeObjectStatusLevel.INFO,
|
||||
text: "irrelevant",
|
||||
timestamp: "2015-10-19T07:28:00Z",
|
||||
}),
|
||||
}),
|
||||
});
|
||||
|
||||
const statusForIrrelevantKubeObjectApiVersionInjectable = getInjectable({
|
||||
id: "status-for-irrelevant-kube-object-api-version",
|
||||
injectionToken: kubeObjectStatusTextInjectionToken,
|
||||
|
||||
instantiate: () => ({
|
||||
apiVersions: ["some-other-api-version"],
|
||||
kind: "some-kind",
|
||||
enabled: computed(() => true),
|
||||
|
||||
resolve: () => ({
|
||||
level: KubeObjectStatusLevel.INFO,
|
||||
text: "irrelevant",
|
||||
timestamp: "2015-10-19T07:28:00Z",
|
||||
}),
|
||||
}),
|
||||
});
|
||||
+11006
File diff suppressed because it is too large.
Load diff
+1180
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,966 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { DiContainer } from "@ogre-tools/injectable";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import { fireEvent } from "@testing-library/react";
|
||||
import type { ApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
|
||||
import navigateToNamespacesInjectable from "../../../common/front-end-routing/routes/cluster/namespaces/navigate-to-namespaces.injectable";
|
||||
import createEditResourceTabInjectable from "../../../renderer/components/dock/edit-resource/edit-resource-tab.injectable";
|
||||
import getRandomIdForEditResourceTabInjectable from "../../../renderer/components/dock/edit-resource/get-random-id-for-edit-resource-tab.injectable";
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { CallForResource } from "../../../renderer/components/dock/edit-resource/edit-resource-model/call-for-resource/call-for-resource.injectable";
|
||||
import callForResourceInjectable from "../../../renderer/components/dock/edit-resource/edit-resource-model/call-for-resource/call-for-resource.injectable";
|
||||
import type { CallForPatchResource } from "../../../renderer/components/dock/edit-resource/edit-resource-model/call-for-patch-resource/call-for-patch-resource.injectable";
|
||||
import callForPatchResourceInjectable from "../../../renderer/components/dock/edit-resource/edit-resource-model/call-for-patch-resource/call-for-patch-resource.injectable";
|
||||
import dockStoreInjectable from "../../../renderer/components/dock/dock/store.injectable";
|
||||
import { Namespace } from "../../../common/k8s-api/endpoints";
|
||||
import showSuccessNotificationInjectable from "../../../renderer/components/notifications/show-success-notification.injectable";
|
||||
import showErrorNotificationInjectable from "../../../renderer/components/notifications/show-error-notification.injectable";
|
||||
import readJsonFileInjectable from "../../../common/fs/read-json-file.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 { controlWhenStoragesAreReady } from "../../../renderer/utils/create-storage/storages-are-ready";
|
||||
|
||||
describe("cluster/namespaces - edit namespace from new tab", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
let callForNamespaceMock: AsyncFnMock<CallForResource>;
|
||||
let callForPatchNamespaceMock: AsyncFnMock<CallForPatchResource>;
|
||||
let showSuccessNotificationMock: jest.Mock;
|
||||
let showErrorNotificationMock: jest.Mock;
|
||||
let storagesAreReady: () => Promise<void>;
|
||||
|
||||
beforeEach(() => {
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
builder.setEnvironmentToClusterFrame();
|
||||
|
||||
callForNamespaceMock = asyncFn();
|
||||
callForPatchNamespaceMock = asyncFn();
|
||||
|
||||
showSuccessNotificationMock = jest.fn();
|
||||
showErrorNotificationMock = jest.fn();
|
||||
|
||||
builder.beforeApplicationStart(({ rendererDi }) => {
|
||||
rendererDi.override(
|
||||
directoryForLensLocalStorageInjectable,
|
||||
() => "/some-directory-for-lens-local-storage",
|
||||
);
|
||||
|
||||
rendererDi.override(hostedClusterIdInjectable, () => "some-cluster-id");
|
||||
|
||||
storagesAreReady = controlWhenStoragesAreReady(rendererDi);
|
||||
|
||||
rendererDi.override(
|
||||
showSuccessNotificationInjectable,
|
||||
() => showSuccessNotificationMock,
|
||||
);
|
||||
|
||||
rendererDi.override(
|
||||
showErrorNotificationInjectable,
|
||||
() => showErrorNotificationMock,
|
||||
);
|
||||
|
||||
rendererDi.override(getRandomIdForEditResourceTabInjectable, () =>
|
||||
jest
|
||||
.fn(() => "some-irrelevant-random-id")
|
||||
.mockReturnValueOnce("some-first-tab-id")
|
||||
.mockReturnValueOnce("some-second-tab-id"),
|
||||
);
|
||||
|
||||
rendererDi.override(callForResourceInjectable, () => async (selfLink: string) => {
|
||||
if (
|
||||
[
|
||||
"/apis/some-api-version/namespaces/some-uid",
|
||||
"/apis/some-api-version/namespaces/some-other-uid",
|
||||
].includes(selfLink)
|
||||
) {
|
||||
return await callForNamespaceMock(selfLink);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
});
|
||||
|
||||
rendererDi.override(callForPatchResourceInjectable, () => async (namespace, ...args) => {
|
||||
if (
|
||||
[
|
||||
"/apis/some-api-version/namespaces/some-uid",
|
||||
"/apis/some-api-version/namespaces/some-other-uid",
|
||||
].includes(namespace.selfLink)
|
||||
) {
|
||||
return await callForPatchNamespaceMock(namespace, ...args);
|
||||
}
|
||||
|
||||
return undefined;
|
||||
});
|
||||
});
|
||||
|
||||
builder.allowKubeResource("namespaces");
|
||||
});
|
||||
|
||||
describe("when navigating to namespaces", () => {
|
||||
let rendered: RenderResult;
|
||||
let rendererDi: DiContainer;
|
||||
|
||||
beforeEach(async () => {
|
||||
rendered = await builder.render();
|
||||
|
||||
await storagesAreReady();
|
||||
|
||||
rendererDi = builder.dis.rendererDi;
|
||||
|
||||
const navigateToNamespaces = rendererDi.inject(
|
||||
navigateToNamespacesInjectable,
|
||||
);
|
||||
|
||||
navigateToNamespaces();
|
||||
|
||||
const dockStore = rendererDi.inject(dockStoreInjectable);
|
||||
|
||||
// TODO: Make TerminalWindow unit testable to allow realistic behaviour
|
||||
dockStore.closeTab("terminal");
|
||||
});
|
||||
|
||||
// TODO: Implement skipped tests when loading of resources can be tested
|
||||
xit("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
xit("calls for namespaces", () => {
|
||||
|
||||
});
|
||||
|
||||
xit("shows spinner", () => {
|
||||
|
||||
});
|
||||
|
||||
describe("when namespaces resolve", () => {
|
||||
beforeEach(() => {
|
||||
|
||||
});
|
||||
|
||||
xit("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
xit("does not show spinner anymore", () => {
|
||||
|
||||
});
|
||||
|
||||
describe("when clicking the context menu for a namespace", () => {
|
||||
beforeEach(() => {
|
||||
|
||||
});
|
||||
|
||||
xit("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
xit("does not show edit resource tab yet", () => {
|
||||
|
||||
});
|
||||
|
||||
describe("when clicking to edit namespace", () => {
|
||||
beforeEach(() => {
|
||||
// TODO: Make implementation match the description (tests above)
|
||||
const namespaceStub = new Namespace(someNamespaceDataStub);
|
||||
|
||||
const createEditResourceTab = rendererDi.inject(createEditResourceTabInjectable);
|
||||
|
||||
createEditResourceTab(namespaceStub);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows dock tab for editing namespace", () => {
|
||||
expect(
|
||||
rendered.getByTestId("dock-tab-for-some-first-tab-id"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows spinner in the dock tab", () => {
|
||||
expect(
|
||||
rendered.getByTestId("edit-resource-tab-spinner"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("calls for namespace", () => {
|
||||
expect(callForNamespaceMock).toHaveBeenCalledWith(
|
||||
"/apis/some-api-version/namespaces/some-uid",
|
||||
);
|
||||
});
|
||||
|
||||
describe("when call for namespace resolves with namespace", () => {
|
||||
let someNamespace: Namespace;
|
||||
|
||||
beforeEach(async () => {
|
||||
someNamespace = new Namespace({
|
||||
apiVersion: "some-api-version",
|
||||
kind: "Namespace",
|
||||
|
||||
metadata: {
|
||||
uid: "some-uid",
|
||||
name: "some-name",
|
||||
resourceVersion: "some-resource-version",
|
||||
selfLink: "/apis/some-api-version/namespaces/some-uid",
|
||||
somePropertyToBeRemoved: "some-value",
|
||||
somePropertyToBeChanged: "some-old-value",
|
||||
},
|
||||
});
|
||||
|
||||
await callForNamespaceMock.resolve({
|
||||
callWasSuccessful: true,
|
||||
response: someNamespace,
|
||||
});
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show spinner anymore", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("edit-resource-tab-spinner"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("has the configuration in editor", () => {
|
||||
const input = rendered.getByTestId(
|
||||
"monaco-editor-for-some-first-tab-id",
|
||||
) as HTMLTextAreaElement;
|
||||
|
||||
expect(input.value).toBe(`apiVersion: some-api-version
|
||||
kind: Namespace
|
||||
metadata:
|
||||
uid: some-uid
|
||||
name: some-name
|
||||
resourceVersion: some-resource-version
|
||||
selfLink: /apis/some-api-version/namespaces/some-uid
|
||||
somePropertyToBeRemoved: some-value
|
||||
somePropertyToBeChanged: some-old-value
|
||||
`);
|
||||
});
|
||||
|
||||
describe("given no changes in the configuration, when selecting to save", () => {
|
||||
beforeEach(() => {
|
||||
const saveButton = rendered.getByTestId(
|
||||
"save-edit-resource-from-tab-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
fireEvent.click(saveButton);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("calls for save with empty values", () => {
|
||||
expect(callForPatchNamespaceMock).toHaveBeenCalledWith(
|
||||
someNamespace,
|
||||
[],
|
||||
);
|
||||
});
|
||||
|
||||
it("shows spinner", () => {
|
||||
expect(
|
||||
rendered.getByTestId("saving-edit-resource-from-tab-for-some-first-tab-id"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("save button is disabled", () => {
|
||||
const saveButton = rendered.getByTestId(
|
||||
"save-edit-resource-from-tab-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
expect(saveButton).toHaveAttribute("disabled");
|
||||
});
|
||||
|
||||
it("save and close button is disabled", () => {
|
||||
const saveButton = rendered.getByTestId(
|
||||
"save-and-close-edit-resource-from-tab-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
expect(saveButton).toHaveAttribute("disabled");
|
||||
});
|
||||
|
||||
describe("when saving resolves with success", () => {
|
||||
beforeEach(async () => {
|
||||
await callForPatchNamespaceMock.resolve({
|
||||
callWasSuccessful: true,
|
||||
response: { name: "some-name", kind: "Namespace" },
|
||||
});
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show spinner anymore", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("saving-edit-resource-from-tab-for-some-first-tab-id"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("save button is enabled", () => {
|
||||
const saveButton = rendered.getByTestId(
|
||||
"save-edit-resource-from-tab-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
expect(saveButton).not.toHaveAttribute("disabled");
|
||||
});
|
||||
|
||||
it("save and close button is enabled", () => {
|
||||
const saveButton = rendered.getByTestId(
|
||||
"save-and-close-edit-resource-from-tab-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
expect(saveButton).not.toHaveAttribute("disabled");
|
||||
});
|
||||
|
||||
it("shows success notification", () => {
|
||||
expect(showSuccessNotificationMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not show error notification", () => {
|
||||
expect(showErrorNotificationMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not close the dock tab", () => {
|
||||
expect(
|
||||
rendered.getByTestId("dock-tab-for-some-first-tab-id"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when saving resolves with failure", () => {
|
||||
beforeEach(async () => {
|
||||
await callForPatchNamespaceMock.resolve({
|
||||
callWasSuccessful: false,
|
||||
error: "some-error",
|
||||
});
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show spinner anymore", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("edit-resource-tab-spinner"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("save button is enabled", () => {
|
||||
const saveButton = rendered.getByTestId(
|
||||
"save-edit-resource-from-tab-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
expect(saveButton).not.toHaveAttribute("disabled");
|
||||
});
|
||||
|
||||
it("save and close button is enabled", () => {
|
||||
const saveButton = rendered.getByTestId(
|
||||
"save-and-close-edit-resource-from-tab-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
expect(saveButton).not.toHaveAttribute("disabled");
|
||||
});
|
||||
|
||||
it("does not show success notification", () => {
|
||||
expect(showSuccessNotificationMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("shows error notification", () => {
|
||||
expect(showErrorNotificationMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not close the dock tab", () => {
|
||||
expect(
|
||||
rendered.getByTestId("dock-tab-for-some-first-tab-id"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when selecting to save and close", () => {
|
||||
beforeEach(() => {
|
||||
const saveButton = rendered.getByTestId(
|
||||
"save-and-close-edit-resource-from-tab-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
fireEvent.click(saveButton);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not close the tab yet", () => {
|
||||
expect(
|
||||
rendered.getByTestId("dock-tab-for-some-first-tab-id"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe("when saving resolves with success", () => {
|
||||
beforeEach(async () => {
|
||||
await callForPatchNamespaceMock.resolve({
|
||||
callWasSuccessful: true,
|
||||
response: { name: "some-name", kind: "Namespace" },
|
||||
});
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("closes the dock tab", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("dock-tab-for-some-first-tab-id"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when saving resolves with failure", () => {
|
||||
beforeEach(async () => {
|
||||
await callForPatchNamespaceMock.resolve({
|
||||
callWasSuccessful: false,
|
||||
error: "Some error",
|
||||
});
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
// TODO: Not doable at the moment because info panel controls closing of the tab
|
||||
xit("does not close the dock tab", () => {
|
||||
expect(
|
||||
rendered.getByTestId("dock-tab-for-some-first-tab-id"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when selecting to cancel", () => {
|
||||
beforeEach(() => {
|
||||
const cancelButton = rendered.getByTestId(
|
||||
"cancel-edit-resource-from-tab-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
fireEvent.click(cancelButton);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not have dock tab anymore", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("dock-tab-for-some-first-tab-id"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("given change in configuration", () => {
|
||||
beforeEach(() => {
|
||||
const input = rendered.getByTestId(
|
||||
"monaco-editor-for-some-first-tab-id",
|
||||
) as HTMLInputElement;
|
||||
|
||||
fireEvent.change(input, {
|
||||
target: {
|
||||
value: `apiVersion: some-api-version
|
||||
kind: Namespace
|
||||
metadata:
|
||||
uid: some-uid
|
||||
name: some-name
|
||||
resourceVersion: some-resource-version
|
||||
selfLink: /apis/some-api-version/namespaces/some-uid
|
||||
somePropertyToBeChanged: some-changed-value
|
||||
someAddedProperty: some-new-value
|
||||
`,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("has the changed configuration in editor", () => {
|
||||
const input = rendered.getByTestId(
|
||||
"monaco-editor-for-some-first-tab-id",
|
||||
) as HTMLTextAreaElement;
|
||||
|
||||
expect(input.value).toBe(`apiVersion: some-api-version
|
||||
kind: Namespace
|
||||
metadata:
|
||||
uid: some-uid
|
||||
name: some-name
|
||||
resourceVersion: some-resource-version
|
||||
selfLink: /apis/some-api-version/namespaces/some-uid
|
||||
somePropertyToBeChanged: some-changed-value
|
||||
someAddedProperty: some-new-value
|
||||
`);
|
||||
});
|
||||
|
||||
it("stores the changed configuration", async () => {
|
||||
const readJsonFile = rendererDi.inject(
|
||||
readJsonFileInjectable,
|
||||
);
|
||||
|
||||
const actual = (await readJsonFile(
|
||||
"/some-directory-for-lens-local-storage/some-cluster-id.json",
|
||||
)) as any;
|
||||
|
||||
expect(
|
||||
actual.edit_resource_store["some-first-tab-id"],
|
||||
).toEqual({
|
||||
resource: "/apis/some-api-version/namespaces/some-uid",
|
||||
firstDraft: `apiVersion: some-api-version
|
||||
kind: Namespace
|
||||
metadata:
|
||||
uid: some-uid
|
||||
name: some-name
|
||||
resourceVersion: some-resource-version
|
||||
selfLink: /apis/some-api-version/namespaces/some-uid
|
||||
somePropertyToBeRemoved: some-value
|
||||
somePropertyToBeChanged: some-old-value
|
||||
`,
|
||||
draft: `apiVersion: some-api-version
|
||||
kind: Namespace
|
||||
metadata:
|
||||
uid: some-uid
|
||||
name: some-name
|
||||
resourceVersion: some-resource-version
|
||||
selfLink: /apis/some-api-version/namespaces/some-uid
|
||||
somePropertyToBeChanged: some-changed-value
|
||||
someAddedProperty: some-new-value
|
||||
`,
|
||||
});
|
||||
});
|
||||
|
||||
describe("when selecting to save", () => {
|
||||
beforeEach(() => {
|
||||
const saveButton = rendered.getByTestId(
|
||||
"save-edit-resource-from-tab-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
fireEvent.click(saveButton);
|
||||
});
|
||||
|
||||
it("calls for save with changed configuration", () => {
|
||||
expect(callForPatchNamespaceMock).toHaveBeenCalledWith(
|
||||
someNamespace,
|
||||
[
|
||||
{
|
||||
op: "remove",
|
||||
path: "/metadata/somePropertyToBeRemoved",
|
||||
},
|
||||
{
|
||||
op: "add",
|
||||
path: "/metadata/someAddedProperty",
|
||||
value: "some-new-value",
|
||||
},
|
||||
{
|
||||
op: "replace",
|
||||
path: "/metadata/somePropertyToBeChanged",
|
||||
value: "some-changed-value",
|
||||
},
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
it("given save resolves and another change in configuration, when saving, calls for save with changed configuration", async () => {
|
||||
await callForPatchNamespaceMock.resolve({
|
||||
callWasSuccessful: true,
|
||||
|
||||
response: {
|
||||
name: "some-name",
|
||||
kind: "Namespace",
|
||||
},
|
||||
});
|
||||
|
||||
const input = rendered.getByTestId(
|
||||
"monaco-editor-for-some-first-tab-id",
|
||||
) as HTMLInputElement;
|
||||
|
||||
fireEvent.change(input, {
|
||||
target: {
|
||||
value: `apiVersion: some-api-version
|
||||
kind: Namespace
|
||||
metadata:
|
||||
uid: some-uid
|
||||
name: some-name
|
||||
resourceVersion: some-resource-version
|
||||
selfLink: /apis/some-api-version/namespaces/some-uid
|
||||
somePropertyToBeChanged: some-changed-value
|
||||
someAddedProperty: some-new-value
|
||||
someOtherAddedProperty: some-other-new-value
|
||||
`,
|
||||
},
|
||||
});
|
||||
|
||||
|
||||
callForPatchNamespaceMock.mockClear();
|
||||
|
||||
const saveButton = rendered.getByTestId(
|
||||
"save-edit-resource-from-tab-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
fireEvent.click(saveButton);
|
||||
|
||||
expect(callForPatchNamespaceMock).toHaveBeenCalledWith(
|
||||
someNamespace,
|
||||
[
|
||||
{
|
||||
op: "add",
|
||||
path: "/metadata/someOtherAddedProperty",
|
||||
value: "some-other-new-value",
|
||||
},
|
||||
],
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("given invalid change in configuration", () => {
|
||||
beforeEach(() => {
|
||||
const input = rendered.getByTestId(
|
||||
"monaco-editor-for-some-first-tab-id",
|
||||
) as HTMLInputElement;
|
||||
|
||||
fireEvent.change(input, {
|
||||
target: {
|
||||
value: "@some-invalid-configuration@",
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("has the changed configuration in editor", () => {
|
||||
const input = rendered.getByTestId(
|
||||
"monaco-editor-for-some-first-tab-id",
|
||||
) as HTMLTextAreaElement;
|
||||
|
||||
expect(input.value).toBe(`@some-invalid-configuration@`);
|
||||
});
|
||||
|
||||
it("save button is disabled", () => {
|
||||
const saveButton = rendered.getByTestId(
|
||||
"save-edit-resource-from-tab-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
expect(saveButton).toHaveAttribute("disabled");
|
||||
});
|
||||
|
||||
it("save and close button is disabled", () => {
|
||||
const saveButton = rendered.getByTestId(
|
||||
"save-and-close-edit-resource-from-tab-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
expect(saveButton).toHaveAttribute("disabled");
|
||||
});
|
||||
|
||||
describe("when valid change in configuration", () => {
|
||||
|
||||
beforeEach(() => {
|
||||
const input = rendered.getByTestId(
|
||||
"monaco-editor-for-some-first-tab-id",
|
||||
) as HTMLInputElement;
|
||||
|
||||
|
||||
fireEvent.change(input, {
|
||||
target: {
|
||||
value: `apiVersion: some-api-version
|
||||
kind: Namespace
|
||||
metadata:
|
||||
uid: some-uid
|
||||
name: some-name
|
||||
resourceVersion: some-resource-version
|
||||
selfLink: /apis/some-api-version/namespaces/some-uid
|
||||
`,
|
||||
},
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it("save button is enabled", () => {
|
||||
const saveButton = rendered.getByTestId(
|
||||
"save-edit-resource-from-tab-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
expect(saveButton).not.toHaveAttribute("disabled");
|
||||
});
|
||||
|
||||
it("save and close button is enabled", () => {
|
||||
const saveButton = rendered.getByTestId(
|
||||
"save-and-close-edit-resource-from-tab-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
expect(saveButton).not.toHaveAttribute("disabled");
|
||||
});
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
describe("given clicking the context menu for second namespace, when clicking to edit namespace", () => {
|
||||
beforeEach(() => {
|
||||
callForNamespaceMock.mockClear();
|
||||
|
||||
// TODO: Make implementation match the description
|
||||
const namespaceStub = new Namespace(someOtherNamespaceDataStub);
|
||||
|
||||
const createEditResourceTab = rendererDi.inject(createEditResourceTabInjectable);
|
||||
|
||||
createEditResourceTab(namespaceStub);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows dock tab for editing second namespace", () => {
|
||||
expect(
|
||||
rendered.getByTestId("dock-tab-content-for-some-second-tab-id"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("still has dock tab for first namespace", () => {
|
||||
expect(
|
||||
rendered.getByTestId("dock-tab-for-some-first-tab-id"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows spinner in the dock tab", () => {
|
||||
expect(
|
||||
rendered.getByTestId("edit-resource-tab-spinner"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("calls for second namespace", () => {
|
||||
expect(callForNamespaceMock).toHaveBeenCalledWith(
|
||||
"/apis/some-api-version/namespaces/some-other-uid",
|
||||
);
|
||||
});
|
||||
|
||||
describe("when second namespace resolves", () => {
|
||||
let someOtherNamespace: Namespace;
|
||||
|
||||
beforeEach(async () => {
|
||||
someOtherNamespace = new Namespace({
|
||||
apiVersion: "some-api-version",
|
||||
kind: "Namespace",
|
||||
|
||||
metadata: {
|
||||
uid: "some-other-uid",
|
||||
name: "some-other-name",
|
||||
resourceVersion: "some-resource-version",
|
||||
selfLink:
|
||||
"/apis/some-api-version/namespaces/some-other-uid",
|
||||
},
|
||||
});
|
||||
|
||||
await callForNamespaceMock.resolve({
|
||||
callWasSuccessful: true,
|
||||
response: someOtherNamespace,
|
||||
});
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("has the configuration in editor", () => {
|
||||
const input = rendered.getByTestId(
|
||||
"monaco-editor-for-some-second-tab-id",
|
||||
) as HTMLTextAreaElement;
|
||||
|
||||
expect(input.value).toBe(`apiVersion: some-api-version
|
||||
kind: Namespace
|
||||
metadata:
|
||||
uid: some-other-uid
|
||||
name: some-other-name
|
||||
resourceVersion: some-resource-version
|
||||
selfLink: /apis/some-api-version/namespaces/some-other-uid
|
||||
`);
|
||||
});
|
||||
|
||||
it("when selecting to save, calls for save of second namespace", () => {
|
||||
callForPatchNamespaceMock.mockClear();
|
||||
|
||||
const saveButton = rendered.getByTestId(
|
||||
"save-edit-resource-from-tab-for-some-second-tab-id",
|
||||
);
|
||||
|
||||
fireEvent.click(saveButton);
|
||||
|
||||
expect(callForPatchNamespaceMock).toHaveBeenCalledWith(
|
||||
someOtherNamespace,
|
||||
[],
|
||||
);
|
||||
});
|
||||
|
||||
describe("when clicking dock tab for the first namespace", () => {
|
||||
beforeEach(() => {
|
||||
callForNamespaceMock.mockClear();
|
||||
|
||||
const tab = rendered.getByTestId("dock-tab-for-some-first-tab-id");
|
||||
|
||||
fireEvent.click(tab);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows dock tab for editing first namespace", () => {
|
||||
expect(
|
||||
rendered.getByTestId("dock-tab-content-for-some-first-tab-id"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("still has dock tab for second namespace", () => {
|
||||
expect(
|
||||
rendered.getByTestId("dock-tab-for-some-second-tab-id"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("does not show spinner in the dock tab", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("edit-resource-tab-spinner"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("does not call for namespace", () => {
|
||||
expect(callForNamespaceMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("has configuration in the editor", () => {
|
||||
const input = rendered.getByTestId(
|
||||
"monaco-editor-for-some-first-tab-id",
|
||||
) as HTMLTextAreaElement;
|
||||
|
||||
expect(input.value).toBe(`apiVersion: some-api-version
|
||||
kind: Namespace
|
||||
metadata:
|
||||
uid: some-uid
|
||||
name: some-name
|
||||
resourceVersion: some-resource-version
|
||||
selfLink: /apis/some-api-version/namespaces/some-uid
|
||||
somePropertyToBeRemoved: some-value
|
||||
somePropertyToBeChanged: some-old-value
|
||||
`);
|
||||
});
|
||||
|
||||
it("when selecting to save, calls for save of first namespace", () => {
|
||||
callForPatchNamespaceMock.mockClear();
|
||||
|
||||
const saveButton = rendered.getByTestId(
|
||||
"save-edit-resource-from-tab-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
fireEvent.click(saveButton);
|
||||
|
||||
expect(callForPatchNamespaceMock).toHaveBeenCalledWith(
|
||||
someNamespace,
|
||||
[],
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when call for namespace resolves without namespace", () => {
|
||||
beforeEach(async () => {
|
||||
await callForNamespaceMock.resolve({
|
||||
callWasSuccessful: true,
|
||||
response: undefined,
|
||||
});
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("still shows the dock tab for editing namespace", () => {
|
||||
expect(
|
||||
rendered.getByTestId("dock-tab-for-some-first-tab-id"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows error message", () => {
|
||||
expect(
|
||||
rendered.getByTestId("dock-tab-content-for-some-first-tab-id"),
|
||||
).toHaveTextContent("Resource not found");
|
||||
});
|
||||
|
||||
it("does not show error notification", () => {
|
||||
expect(showErrorNotificationMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when call for namespace resolves with failure", () => {
|
||||
beforeEach(async () => {
|
||||
await callForNamespaceMock.resolve({
|
||||
callWasSuccessful: false,
|
||||
error: "some-error",
|
||||
});
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("still shows the dock tab for editing namespace", () => {
|
||||
expect(
|
||||
rendered.getByTestId("dock-tab-for-some-first-tab-id"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows error message", () => {
|
||||
expect(
|
||||
rendered.getByTestId("dock-tab-content-for-some-first-tab-id"),
|
||||
).toHaveTextContent("Resource not found");
|
||||
});
|
||||
|
||||
it("shows error notification", () => {
|
||||
expect(showErrorNotificationMock).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const someNamespaceDataStub = {
|
||||
apiVersion: "some-api-version",
|
||||
kind: "Namespace",
|
||||
metadata: {
|
||||
uid: "some-uid",
|
||||
name: "some-name",
|
||||
resourceVersion: "some-resource-version",
|
||||
selfLink: "/apis/some-api-version/namespaces/some-uid",
|
||||
},
|
||||
};
|
||||
|
||||
const someOtherNamespaceDataStub = {
|
||||
apiVersion: "some-api-version",
|
||||
kind: "Namespace",
|
||||
metadata: {
|
||||
uid: "some-other-uid",
|
||||
name: "some-other-name",
|
||||
resourceVersion: "some-resource-version",
|
||||
selfLink: "/apis/some-api-version/namespaces/some-other-uid",
|
||||
},
|
||||
};
|
||||
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import { act } from "@testing-library/react";
|
||||
import type { ApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { CallForResource } from "../../../renderer/components/dock/edit-resource/edit-resource-model/call-for-resource/call-for-resource.injectable";
|
||||
import callForResourceInjectable from "../../../renderer/components/dock/edit-resource/edit-resource-model/call-for-resource/call-for-resource.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 { controlWhenStoragesAreReady } from "../../../renderer/utils/create-storage/storages-are-ready";
|
||||
import writeJsonFileInjectable from "../../../common/fs/write-json-file.injectable";
|
||||
import { TabKind } from "../../../renderer/components/dock/dock/store";
|
||||
import { Namespace } from "../../../common/k8s-api/endpoints";
|
||||
|
||||
describe("cluster/namespaces - edit namespaces from previously opened tab", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
let callForNamespaceMock: AsyncFnMock<CallForResource>;
|
||||
let storagesAreReady: () => Promise<void>;
|
||||
|
||||
beforeEach(() => {
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
builder.setEnvironmentToClusterFrame();
|
||||
|
||||
callForNamespaceMock = asyncFn();
|
||||
|
||||
builder.beforeApplicationStart(({ rendererDi }) => {
|
||||
rendererDi.override(
|
||||
directoryForLensLocalStorageInjectable,
|
||||
() => "/some-directory-for-lens-local-storage",
|
||||
);
|
||||
|
||||
rendererDi.override(hostedClusterIdInjectable, () => "some-cluster-id");
|
||||
|
||||
storagesAreReady = controlWhenStoragesAreReady(rendererDi);
|
||||
|
||||
rendererDi.override(callForResourceInjectable, () => callForNamespaceMock);
|
||||
});
|
||||
|
||||
builder.allowKubeResource("namespaces");
|
||||
});
|
||||
|
||||
describe("given tab was previously opened, when application is started", () => {
|
||||
let rendered: RenderResult;
|
||||
|
||||
beforeEach(async () => {
|
||||
const writeJsonFile = builder.dis.rendererDi.inject(writeJsonFileInjectable);
|
||||
|
||||
await writeJsonFile(
|
||||
"/some-directory-for-lens-local-storage/some-cluster-id.json",
|
||||
{
|
||||
dock: {
|
||||
height: 300,
|
||||
tabs: [
|
||||
{
|
||||
id: "some-first-tab-id",
|
||||
kind: TabKind.EDIT_RESOURCE,
|
||||
title: "Namespace: some-namespace",
|
||||
pinned: false,
|
||||
},
|
||||
],
|
||||
|
||||
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();
|
||||
|
||||
await storagesAreReady();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows dock tab for editing namespace", () => {
|
||||
expect(
|
||||
rendered.getByTestId("dock-tab-for-some-first-tab-id"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows spinner in the dock tab", () => {
|
||||
expect(
|
||||
rendered.getByTestId("edit-resource-tab-spinner"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("calls for namespace", () => {
|
||||
expect(callForNamespaceMock).toHaveBeenCalledWith(
|
||||
"/apis/some-api-version/namespaces/some-uid",
|
||||
);
|
||||
});
|
||||
|
||||
describe("when call for namespace resolves with namespace", () => {
|
||||
let someNamespace: Namespace;
|
||||
|
||||
beforeEach(async () => {
|
||||
someNamespace = new Namespace({
|
||||
apiVersion: "some-api-version",
|
||||
kind: "Namespace",
|
||||
|
||||
metadata: {
|
||||
uid: "some-uid",
|
||||
name: "some-name",
|
||||
resourceVersion: "some-resource-version",
|
||||
selfLink: "/apis/some-api-version/namespaces/some-uid",
|
||||
somePropertyToBeRemoved: "some-value",
|
||||
somePropertyToBeChanged: "some-old-value",
|
||||
},
|
||||
});
|
||||
|
||||
// TODO: Figure out why act is needed here. In CI it works without it.
|
||||
await act(async () => {
|
||||
await callForNamespaceMock.resolve({
|
||||
callWasSuccessful: true,
|
||||
response: someNamespace,
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("has the saved configuration in editor", () => {
|
||||
const input = rendered.getByTestId(
|
||||
"monaco-editor-for-some-first-tab-id",
|
||||
) as HTMLTextAreaElement;
|
||||
|
||||
expect(input.value).toBe("some-saved-configuration");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,127 @@
|
||||
/**
|
||||
* 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 type { RenderResult } from "@testing-library/react";
|
||||
import { fireEvent } from "@testing-library/react";
|
||||
import type { SidebarItemRegistration } from "../../renderer/components/layout/sidebar-items.injectable";
|
||||
import { sidebarItemsInjectionToken } from "../../renderer/components/layout/sidebar-items.injectable";
|
||||
import { computed } from "mobx";
|
||||
import { noop } from "lodash/fp";
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
|
||||
describe("cluster - order of sidebar items", () => {
|
||||
let rendered: RenderResult;
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
|
||||
beforeEach(() => {
|
||||
applicationBuilder = getApplicationBuilder().setEnvironmentToClusterFrame();
|
||||
|
||||
applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
|
||||
rendererDi.register(testSidebarItemsInjectable);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when rendered", () => {
|
||||
beforeEach(async () => {
|
||||
rendered = await applicationBuilder.render();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("has parent items in order", () => {
|
||||
const actual = rendered
|
||||
.queryAllByTestId(/^sidebar-item-(some-parent-id|some-other-parent-id|some-another-parent-id)/)
|
||||
.map(elem => elem.dataset.testid);
|
||||
|
||||
expect(actual).toEqual([
|
||||
"sidebar-item-some-parent-id",
|
||||
"sidebar-item-some-another-parent-id",
|
||||
"sidebar-item-some-other-parent-id",
|
||||
]);
|
||||
});
|
||||
|
||||
describe("when parent is expanded", () => {
|
||||
beforeEach(() => {
|
||||
const parentLink = rendered.getByTestId(
|
||||
"sidebar-item-link-for-some-parent-id",
|
||||
);
|
||||
|
||||
fireEvent.click(parentLink);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("has child items in order", () => {
|
||||
const actual = rendered
|
||||
.queryAllByTestId(/^sidebar-item-*/)
|
||||
.filter((element) => element.dataset.parentIdTest === "some-parent-id")
|
||||
.map(elem => elem.dataset.testid);
|
||||
|
||||
expect(actual).toEqual([
|
||||
"sidebar-item-some-child-id",
|
||||
"sidebar-item-some-another-child-id",
|
||||
"sidebar-item-some-other-child-id",
|
||||
]);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const testSidebarItemsInjectable = getInjectable({
|
||||
id: "some-sidebar-item-injectable",
|
||||
|
||||
instantiate: () =>
|
||||
computed((): SidebarItemRegistration[] => [
|
||||
{
|
||||
id: "some-parent-id",
|
||||
parentId: null,
|
||||
title: "Some parent",
|
||||
onClick: noop,
|
||||
orderNumber: 42,
|
||||
},
|
||||
{
|
||||
id: "some-other-parent-id",
|
||||
parentId: null,
|
||||
title: "Some other parent",
|
||||
onClick: noop,
|
||||
orderNumber: 126,
|
||||
},
|
||||
{
|
||||
id: "some-another-parent-id",
|
||||
parentId: null,
|
||||
title: "Some another parent",
|
||||
onClick: noop,
|
||||
orderNumber: 84,
|
||||
},
|
||||
{
|
||||
id: "some-child-id",
|
||||
parentId: "some-parent-id",
|
||||
title: "Some child",
|
||||
onClick: noop,
|
||||
orderNumber: 168,
|
||||
},
|
||||
{
|
||||
id: "some-other-child-id",
|
||||
parentId: "some-parent-id",
|
||||
title: "Some other child",
|
||||
onClick: noop,
|
||||
orderNumber: 252,
|
||||
},
|
||||
{
|
||||
id: "some-another-child-id",
|
||||
parentId: "some-parent-id",
|
||||
title: "Some another child",
|
||||
onClick: noop,
|
||||
orderNumber: 210,
|
||||
},
|
||||
]),
|
||||
|
||||
injectionToken: sidebarItemsInjectionToken,
|
||||
});
|
||||
@@ -0,0 +1,358 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* 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 React from "react";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import { fireEvent } from "@testing-library/react";
|
||||
import directoryForLensLocalStorageInjectable from "../../common/directory-for-lens-local-storage/directory-for-lens-local-storage.injectable";
|
||||
import { routeSpecificComponentInjectionToken } from "../../renderer/routes/route-specific-component-injection-token";
|
||||
import type { SidebarItemRegistration } from "../../renderer/components/layout/sidebar-items.injectable";
|
||||
import { sidebarItemsInjectionToken } from "../../renderer/components/layout/sidebar-items.injectable";
|
||||
import { computed } from "mobx";
|
||||
import { noop } from "lodash/fp";
|
||||
import routeIsActiveInjectable from "../../renderer/routes/route-is-active.injectable";
|
||||
import { frontEndRouteInjectionToken } from "../../common/front-end-routing/front-end-route-injection-token";
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import writeJsonFileInjectable from "../../common/fs/write-json-file.injectable";
|
||||
import pathExistsInjectable from "../../common/fs/path-exists.injectable";
|
||||
import readJsonFileInjectable from "../../common/fs/read-json-file.injectable";
|
||||
import { navigateToRouteInjectionToken } from "../../common/front-end-routing/navigate-to-route-injection-token";
|
||||
import sidebarStorageInjectable from "../../renderer/components/layout/sidebar-storage/sidebar-storage.injectable";
|
||||
import hostedClusterIdInjectable from "../../renderer/cluster-frame-context/hosted-cluster-id.injectable";
|
||||
import { advanceFakeTime, useFakeTime } from "../../common/test-utils/use-fake-time";
|
||||
import storageSaveDelayInjectable from "../../renderer/utils/create-storage/storage-save-delay.injectable";
|
||||
|
||||
describe("cluster - sidebar and tab navigation for core", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
let rendererDi: DiContainer;
|
||||
let rendered: RenderResult;
|
||||
|
||||
beforeEach(() => {
|
||||
useFakeTime("2015-10-21T07:28:00Z");
|
||||
|
||||
applicationBuilder = getApplicationBuilder();
|
||||
rendererDi = applicationBuilder.dis.rendererDi;
|
||||
|
||||
applicationBuilder.setEnvironmentToClusterFrame();
|
||||
|
||||
applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
|
||||
rendererDi.override(hostedClusterIdInjectable, () => "some-hosted-cluster-id");
|
||||
|
||||
rendererDi.override(storageSaveDelayInjectable, () => 250);
|
||||
|
||||
rendererDi.override(
|
||||
directoryForLensLocalStorageInjectable,
|
||||
() => "/some-directory-for-lens-local-storage",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("given core registrations", () => {
|
||||
beforeEach(() => {
|
||||
applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
|
||||
rendererDi.register(testRouteInjectable);
|
||||
rendererDi.register(testRouteComponentInjectable);
|
||||
rendererDi.register(testSidebarItemsInjectable);
|
||||
});
|
||||
});
|
||||
|
||||
describe("given no state for expanded sidebar items exists, and navigated to child sidebar item, when rendered", () => {
|
||||
beforeEach(async () => {
|
||||
applicationBuilder.beforeRender(({ rendererDi }) => {
|
||||
const route = rendererDi.inject(testRouteInjectable);
|
||||
|
||||
const navigateToRoute = rendererDi.inject(navigateToRouteInjectionToken);
|
||||
|
||||
navigateToRoute(route);
|
||||
});
|
||||
|
||||
rendered = await applicationBuilder.render();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("parent is highlighted", () => {
|
||||
const parent = rendered.queryByTestId("sidebar-item-some-parent-id");
|
||||
|
||||
expect(parent?.dataset.isActiveTest).toBe("true");
|
||||
});
|
||||
|
||||
it("parent sidebar item is not expanded", () => {
|
||||
const child = rendered.queryByTestId("sidebar-item-some-child-id");
|
||||
|
||||
expect(child).toBeNull();
|
||||
});
|
||||
|
||||
it("child page is shown", () => {
|
||||
expect(rendered.getByTestId("some-child-page")).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("given state for expanded sidebar items already exists, when rendered", () => {
|
||||
beforeEach(async () => {
|
||||
applicationBuilder.beforeRender(async ({ rendererDi }) => {
|
||||
const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable);
|
||||
|
||||
await writeJsonFileFake(
|
||||
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
|
||||
{
|
||||
sidebar: {
|
||||
expanded: { "some-parent-id": true },
|
||||
width: 200,
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
applicationBuilder.beforeRender(async ({ rendererDi }) => {
|
||||
const sidebarStorage = rendererDi.inject(sidebarStorageInjectable);
|
||||
|
||||
await sidebarStorage.whenReady;
|
||||
});
|
||||
|
||||
rendered = await applicationBuilder.render();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("parent sidebar item is not highlighted", () => {
|
||||
const parent = rendered.queryByTestId("sidebar-item-some-parent-id");
|
||||
|
||||
expect(parent?.dataset.isActiveTest).toBe("false");
|
||||
});
|
||||
|
||||
it("parent sidebar item is expanded", () => {
|
||||
const child = rendered.queryByTestId("sidebar-item-some-child-id");
|
||||
|
||||
expect(child).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("given state for expanded unknown sidebar items already exists, when rendered", () => {
|
||||
beforeEach(async () => {
|
||||
applicationBuilder.beforeRender(async ({ rendererDi }) => {
|
||||
const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable);
|
||||
|
||||
await writeJsonFileFake(
|
||||
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
|
||||
{
|
||||
sidebar: {
|
||||
expanded: { "some-unknown-parent-id": true },
|
||||
width: 200,
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
rendered = await applicationBuilder.render();
|
||||
});
|
||||
|
||||
it("renders without errors", () => {
|
||||
expect(rendered.container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("parent sidebar item is not expanded", () => {
|
||||
const child = rendered.queryByTestId("sidebar-item-some-child-id");
|
||||
|
||||
expect(child).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("given empty state for expanded sidebar items already exists, when rendered", () => {
|
||||
beforeEach(async () => {
|
||||
applicationBuilder.beforeRender(async ({ rendererDi }) => {
|
||||
const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable);
|
||||
|
||||
await writeJsonFileFake(
|
||||
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
|
||||
{
|
||||
someThingButSidebar: {},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
rendered = await applicationBuilder.render();
|
||||
});
|
||||
|
||||
it("renders without errors", () => {
|
||||
expect(rendered.container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("parent sidebar item is not expanded", () => {
|
||||
const child = rendered.queryByTestId("sidebar-item-some-child-id");
|
||||
|
||||
expect(child).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("given no initially persisted state for sidebar items, when rendered", () => {
|
||||
beforeEach(async () => {
|
||||
rendered = await applicationBuilder.render();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("parent sidebar item is not highlighted", () => {
|
||||
const parent = rendered.queryByTestId("sidebar-item-some-parent-id");
|
||||
|
||||
expect(parent?.dataset.isActiveTest).toBe("false");
|
||||
});
|
||||
|
||||
it("parent sidebar item is not expanded", () => {
|
||||
const child = rendered.queryByTestId("sidebar-item-some-child-id");
|
||||
|
||||
expect(child).toBeNull();
|
||||
});
|
||||
|
||||
describe("when a parent sidebar item is expanded", () => {
|
||||
beforeEach(() => {
|
||||
const parentLink = rendered.getByTestId(
|
||||
"sidebar-item-link-for-some-parent-id",
|
||||
);
|
||||
|
||||
fireEvent.click(parentLink);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("parent sidebar item is not highlighted", () => {
|
||||
const parent = rendered.queryByTestId("sidebar-item-some-parent-id");
|
||||
|
||||
expect(parent?.dataset.isActiveTest).toBe("false");
|
||||
});
|
||||
|
||||
it("parent sidebar item is expanded", () => {
|
||||
const child = rendered.queryByTestId("sidebar-item-some-child-id");
|
||||
|
||||
expect(child).not.toBeNull();
|
||||
});
|
||||
|
||||
describe("when a child of the parent is selected", () => {
|
||||
beforeEach(() => {
|
||||
const childLink = rendered.getByTestId(
|
||||
"sidebar-item-link-for-some-child-id",
|
||||
);
|
||||
|
||||
fireEvent.click(childLink);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("parent is highlighted", () => {
|
||||
const parent = rendered.queryByTestId("sidebar-item-some-parent-id");
|
||||
|
||||
expect(parent?.dataset.isActiveTest).toBe("true");
|
||||
});
|
||||
|
||||
it("child is highlighted", () => {
|
||||
const child = rendered.queryByTestId("sidebar-item-some-child-id");
|
||||
|
||||
expect(child?.dataset.isActiveTest).toBe("true");
|
||||
});
|
||||
|
||||
it("child page is shown", () => {
|
||||
expect(rendered.getByTestId("some-child-page")).not.toBeNull();
|
||||
});
|
||||
|
||||
it("when not enough time passes, does not store state for expanded sidebar items to file system yet", async () => {
|
||||
advanceFakeTime(250 - 1);
|
||||
|
||||
const pathExistsFake = rendererDi.inject(pathExistsInjectable);
|
||||
|
||||
const actual = await pathExistsFake(
|
||||
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
|
||||
);
|
||||
|
||||
expect(actual).toBe(false);
|
||||
});
|
||||
|
||||
it("when enough time passes, stores state for expanded sidebar items to file system", async () => {
|
||||
advanceFakeTime(250);
|
||||
|
||||
const readJsonFileFake = rendererDi.inject(readJsonFileInjectable);
|
||||
|
||||
const actual = await readJsonFileFake(
|
||||
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
|
||||
);
|
||||
|
||||
expect(actual).toEqual({
|
||||
sidebar: {
|
||||
expanded: { "some-parent-id": true },
|
||||
width: 200,
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const testSidebarItemsInjectable = getInjectable({
|
||||
id: "some-sidebar-items-injectable",
|
||||
|
||||
instantiate: (di) => {
|
||||
const route = di.inject(testRouteInjectable);
|
||||
const navigateToRoute = di.inject(navigateToRouteInjectionToken);
|
||||
const routeIsActive = di.inject(routeIsActiveInjectable, route);
|
||||
|
||||
return computed((): SidebarItemRegistration[] => [
|
||||
{
|
||||
id: "some-parent-id",
|
||||
parentId: null,
|
||||
title: "Some parent",
|
||||
onClick: noop,
|
||||
getIcon: () => <div data-testid="some-icon-for-parent" />,
|
||||
orderNumber: 42,
|
||||
},
|
||||
|
||||
{
|
||||
id: "some-child-id",
|
||||
parentId: "some-parent-id",
|
||||
title: "Some child",
|
||||
onClick: () => navigateToRoute(route),
|
||||
isActive: routeIsActive,
|
||||
orderNumber: 42,
|
||||
},
|
||||
]);
|
||||
},
|
||||
|
||||
injectionToken: sidebarItemsInjectionToken,
|
||||
});
|
||||
|
||||
const testRouteInjectable = getInjectable({
|
||||
id: "some-route-injectable-id",
|
||||
|
||||
instantiate: () => ({
|
||||
path: "/some-child-page",
|
||||
clusterFrame: true,
|
||||
isEnabled: computed(() => true),
|
||||
}),
|
||||
|
||||
injectionToken: frontEndRouteInjectionToken,
|
||||
});
|
||||
|
||||
const testRouteComponentInjectable = getInjectable({
|
||||
id: "some-child-page-route-component-injectable",
|
||||
|
||||
instantiate: (di) => ({
|
||||
route: di.inject(testRouteInjectable),
|
||||
Component: () => <div data-testid="some-child-page" />,
|
||||
}),
|
||||
|
||||
injectionToken: routeSpecificComponentInjectionToken,
|
||||
});
|
||||
@@ -0,0 +1,455 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import React from "react";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import { fireEvent } from "@testing-library/react";
|
||||
import directoryForLensLocalStorageInjectable from "../../common/directory-for-lens-local-storage/directory-for-lens-local-storage.injectable";
|
||||
import routesInjectable from "../../renderer/routes/routes.injectable";
|
||||
import { matches } from "lodash/fp";
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import writeJsonFileInjectable from "../../common/fs/write-json-file.injectable";
|
||||
import pathExistsInjectable from "../../common/fs/path-exists.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 assert from "assert";
|
||||
import hostedClusterIdInjectable from "../../renderer/cluster-frame-context/hosted-cluster-id.injectable";
|
||||
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 { runInAction, computed, observable } from "mobx";
|
||||
import storageSaveDelayInjectable from "../../renderer/utils/create-storage/storage-save-delay.injectable";
|
||||
|
||||
describe("cluster - sidebar and tab navigation for extensions", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
let rendererDi: DiContainer;
|
||||
let rendered: RenderResult;
|
||||
|
||||
beforeEach(() => {
|
||||
useFakeTime("2015-10-21T07:28:00Z");
|
||||
|
||||
applicationBuilder = getApplicationBuilder();
|
||||
rendererDi = applicationBuilder.dis.rendererDi;
|
||||
|
||||
applicationBuilder.setEnvironmentToClusterFrame();
|
||||
|
||||
applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
|
||||
rendererDi.override(hostedClusterIdInjectable, () => "some-hosted-cluster-id");
|
||||
|
||||
rendererDi.override(storageSaveDelayInjectable, () => 250);
|
||||
|
||||
rendererDi.override(
|
||||
directoryForLensLocalStorageInjectable,
|
||||
() => "/some-directory-for-lens-local-storage",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("given extension with cluster pages and cluster page menus", () => {
|
||||
let someObservable: IObservableValue<boolean>;
|
||||
|
||||
beforeEach(() => {
|
||||
someObservable = observable.box(false);
|
||||
|
||||
const getExtensionFake = getExtensionFakeFor(applicationBuilder);
|
||||
|
||||
const testExtension = getExtensionFake({
|
||||
id: "some-extension-id",
|
||||
name: "some-extension-name",
|
||||
|
||||
rendererOptions: {
|
||||
clusterPages: [
|
||||
{
|
||||
components: {
|
||||
Page: () => {
|
||||
throw new Error("should never come here");
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "some-child-page-id",
|
||||
|
||||
components: {
|
||||
Page: () => <div data-testid="some-child-page">Some child page</div>,
|
||||
},
|
||||
},
|
||||
{
|
||||
id: "some-other-child-page-id",
|
||||
|
||||
components: {
|
||||
Page: () => (
|
||||
<div data-testid="some-other-child-page">Some other child page</div>
|
||||
),
|
||||
},
|
||||
},
|
||||
],
|
||||
|
||||
clusterPageMenus: [
|
||||
{
|
||||
id: "some-parent-id",
|
||||
title: "Parent",
|
||||
|
||||
components: {
|
||||
Icon: () => <div>Some icon</div>,
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
id: "some-child-id",
|
||||
target: { pageId: "some-child-page-id" },
|
||||
parentId: "some-parent-id",
|
||||
title: "Child 1",
|
||||
|
||||
components: {
|
||||
Icon: null as never,
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
id: "some-other-child-id",
|
||||
target: { pageId: "some-other-child-page-id" },
|
||||
parentId: "some-parent-id",
|
||||
title: "Child 2",
|
||||
|
||||
components: {
|
||||
Icon: null as never,
|
||||
},
|
||||
},
|
||||
|
||||
{
|
||||
id: "some-menu-with-controlled-visibility",
|
||||
title: "Some menu with controlled visibility",
|
||||
visible: computed(() => someObservable.get()),
|
||||
|
||||
components: {
|
||||
Icon: () => <div>Some icon</div>,
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
applicationBuilder.extensions.enable(testExtension);
|
||||
});
|
||||
|
||||
describe("given no state for expanded sidebar items exists, and navigated to child sidebar item, when rendered", () => {
|
||||
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();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("parent is highlighted", () => {
|
||||
const parent = rendered.getByTestId("sidebar-item-some-extension-name-some-parent-id");
|
||||
|
||||
expect(parent?.dataset.isActiveTest).toBe("true");
|
||||
});
|
||||
|
||||
it("parent sidebar item is not expanded", () => {
|
||||
const child = rendered.queryByTestId("sidebar-item-some-extension-name-some-child-id");
|
||||
|
||||
expect(child).toBeNull();
|
||||
});
|
||||
|
||||
it("child page is shown", () => {
|
||||
expect(rendered.getByTestId("some-child-page")).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("given state for expanded sidebar items already exists, when rendered", () => {
|
||||
beforeEach(async () => {
|
||||
applicationBuilder.beforeRender(async ({ rendererDi }) => {
|
||||
const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable);
|
||||
|
||||
await writeJsonFileFake(
|
||||
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
|
||||
{
|
||||
sidebar: {
|
||||
expanded: { "some-extension-name-some-parent-id": true },
|
||||
width: 200,
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
rendered = await applicationBuilder.render();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("parent sidebar item is not highlighted", () => {
|
||||
const parent = rendered.getByTestId("sidebar-item-some-extension-name-some-parent-id");
|
||||
|
||||
expect(parent?.dataset.isActiveTest).toBe("false");
|
||||
});
|
||||
|
||||
it("parent sidebar item is expanded", () => {
|
||||
const child = rendered.queryByTestId("sidebar-item-some-extension-name-some-child-id");
|
||||
|
||||
expect(child).not.toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("given state for expanded unknown sidebar items already exists, when rendered", () => {
|
||||
beforeEach(async () => {
|
||||
applicationBuilder.beforeRender(async ({ rendererDi }) => {
|
||||
const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable);
|
||||
|
||||
await writeJsonFileFake(
|
||||
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
|
||||
{
|
||||
sidebar: {
|
||||
expanded: { "some-extension-name-some-unknown-parent-id": true },
|
||||
width: 200,
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
rendered = await applicationBuilder.render();
|
||||
});
|
||||
|
||||
it("renders without errors", () => {
|
||||
expect(rendered.container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("parent sidebar item is not expanded", () => {
|
||||
const child = rendered.queryByTestId("sidebar-item-some-extension-name-some-child-id");
|
||||
|
||||
expect(child).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("given empty state for expanded sidebar items already exists, when rendered", () => {
|
||||
beforeEach(async () => {
|
||||
applicationBuilder.beforeRender(async ({ rendererDi }) => {
|
||||
const writeJsonFileFake = rendererDi.inject(writeJsonFileInjectable);
|
||||
|
||||
await writeJsonFileFake(
|
||||
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
|
||||
{
|
||||
someThingButSidebar: {},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
rendered = await applicationBuilder.render();
|
||||
});
|
||||
|
||||
it("renders without errors", () => {
|
||||
expect(rendered.container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("parent sidebar item is not expanded", () => {
|
||||
const child = rendered.queryByTestId("sidebar-item-some-extension-name-some-child-id");
|
||||
|
||||
expect(child).toBeNull();
|
||||
});
|
||||
});
|
||||
|
||||
describe("given no initially persisted state for sidebar items, when rendered", () => {
|
||||
beforeEach(async () => {
|
||||
rendered = await applicationBuilder.render();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("parent sidebar item is not highlighted", () => {
|
||||
const parent = rendered.getByTestId("sidebar-item-some-extension-name-some-parent-id");
|
||||
|
||||
expect(parent?.dataset.isActiveTest).toBe("false");
|
||||
});
|
||||
|
||||
it("parent sidebar item is not expanded", () => {
|
||||
const child = rendered.queryByTestId("sidebar-item-some-extension-name-some-child-id");
|
||||
|
||||
expect(child).toBeNull();
|
||||
});
|
||||
|
||||
it("does not show the sidebar item that should be hidden", () => {
|
||||
const child = rendered.queryByTestId(
|
||||
"sidebar-item-some-extension-name-some-menu-with-controlled-visibility",
|
||||
);
|
||||
|
||||
expect(child).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("when sidebar item becomes visible, shows the sidebar item", () => {
|
||||
runInAction(() => {
|
||||
someObservable.set(true);
|
||||
});
|
||||
|
||||
const child = rendered.queryByTestId(
|
||||
"sidebar-item-some-extension-name-some-menu-with-controlled-visibility",
|
||||
);
|
||||
|
||||
expect(child).toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe("when a parent sidebar item is expanded", () => {
|
||||
beforeEach(() => {
|
||||
const parentLink = rendered.getByTestId(
|
||||
"sidebar-item-link-for-some-extension-name-some-parent-id",
|
||||
);
|
||||
|
||||
fireEvent.click(parentLink);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("parent sidebar item is not highlighted", () => {
|
||||
const parent = rendered.getByTestId("sidebar-item-some-extension-name-some-parent-id");
|
||||
|
||||
expect(parent?.dataset.isActiveTest).toBe("false");
|
||||
});
|
||||
|
||||
it("parent sidebar item is expanded", () => {
|
||||
const child = rendered.queryByTestId("sidebar-item-some-extension-name-some-child-id");
|
||||
|
||||
expect(child).not.toBeNull();
|
||||
});
|
||||
|
||||
describe("when a child of the parent is selected", () => {
|
||||
beforeEach(() => {
|
||||
const childLink = rendered.getByTestId(
|
||||
"sidebar-item-link-for-some-extension-name-some-child-id",
|
||||
);
|
||||
|
||||
fireEvent.click(childLink);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("parent is highlighted", () => {
|
||||
const parent = rendered.getByTestId("sidebar-item-some-extension-name-some-parent-id");
|
||||
|
||||
expect(parent?.dataset.isActiveTest).toBe("true");
|
||||
});
|
||||
|
||||
it("child is highlighted", () => {
|
||||
const child = rendered.getByTestId("sidebar-item-some-extension-name-some-child-id");
|
||||
|
||||
expect(child?.dataset.isActiveTest).toBe("true");
|
||||
});
|
||||
|
||||
it("child page is shown", () => {
|
||||
expect(rendered.getByTestId("some-child-page")).not.toBeNull();
|
||||
});
|
||||
|
||||
it("renders tabs", () => {
|
||||
expect(rendered.getByTestId("tab-layout")).not.toBeNull();
|
||||
});
|
||||
|
||||
it("tab for child page is active", () => {
|
||||
const tabLink = rendered.getByTestId(
|
||||
"tab-link-for-some-extension-name-some-child-id",
|
||||
);
|
||||
|
||||
expect(tabLink.dataset.isActiveTest).toBe("true");
|
||||
});
|
||||
|
||||
it("tab for sibling page is not active", () => {
|
||||
const tabLink = rendered.getByTestId(
|
||||
"tab-link-for-some-extension-name-some-other-child-id",
|
||||
);
|
||||
|
||||
expect(tabLink.dataset.isActiveTest).toBe("false");
|
||||
});
|
||||
|
||||
it("when not enough time passes, does not store state for expanded sidebar items to file system yet", async () => {
|
||||
advanceFakeTime(250 - 1);
|
||||
|
||||
const pathExistsFake = rendererDi.inject(pathExistsInjectable);
|
||||
|
||||
const actual = await pathExistsFake(
|
||||
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
|
||||
);
|
||||
|
||||
expect(actual).toBe(false);
|
||||
});
|
||||
|
||||
it("when enough time passes, stores state for expanded sidebar items to file system", async () => {
|
||||
advanceFakeTime(250);
|
||||
|
||||
const readJsonFileFake = rendererDi.inject(readJsonFileInjectable);
|
||||
|
||||
const actual = await readJsonFileFake(
|
||||
"/some-directory-for-lens-local-storage/some-hosted-cluster-id.json",
|
||||
);
|
||||
|
||||
expect(actual).toEqual({
|
||||
sidebar: {
|
||||
expanded: { "some-extension-name-some-parent-id": true },
|
||||
width: 200,
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
describe("when selecting sibling tab", () => {
|
||||
beforeEach(() => {
|
||||
const childTabLink = rendered.getByTestId(
|
||||
"tab-link-for-some-extension-name-some-other-child-id",
|
||||
);
|
||||
|
||||
fireEvent.click(childTabLink);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("sibling child page is shown", () => {
|
||||
expect(
|
||||
rendered.getByTestId("some-other-child-page"),
|
||||
).not.toBeNull();
|
||||
});
|
||||
|
||||
it("tab for sibling page is active", () => {
|
||||
const tabLink = rendered.getByTestId(
|
||||
"tab-link-for-some-extension-name-some-other-child-id",
|
||||
);
|
||||
|
||||
expect(tabLink.dataset.isActiveTest).toBe("true");
|
||||
});
|
||||
|
||||
it("tab for previous page is not active", () => {
|
||||
const tabLink = rendered.getByTestId(
|
||||
"tab-link-for-some-extension-name-some-child-id",
|
||||
);
|
||||
|
||||
expect(tabLink.dataset.isActiveTest).toBe("false");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,120 @@
|
||||
/**
|
||||
* 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 type { RenderResult } from "@testing-library/react";
|
||||
import type { SidebarItemRegistration } from "../../renderer/components/layout/sidebar-items.injectable";
|
||||
import { sidebarItemsInjectionToken } from "../../renderer/components/layout/sidebar-items.injectable";
|
||||
import { computed } from "mobx";
|
||||
import { routeSpecificComponentInjectionToken } from "../../renderer/routes/route-specific-component-injection-token";
|
||||
import React from "react";
|
||||
import isAllowedResourceInjectable from "../../common/utils/is-allowed-resource.injectable";
|
||||
import { frontEndRouteInjectionToken } from "../../common/front-end-routing/front-end-route-injection-token";
|
||||
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
|
||||
import { navigateToRouteInjectionToken } from "../../common/front-end-routing/navigate-to-route-injection-token";
|
||||
|
||||
describe("cluster - visibility of sidebar items", () => {
|
||||
let applicationBuilder: ApplicationBuilder;
|
||||
let rendered: RenderResult;
|
||||
|
||||
beforeEach(() => {
|
||||
applicationBuilder = getApplicationBuilder();
|
||||
|
||||
applicationBuilder.setEnvironmentToClusterFrame();
|
||||
|
||||
applicationBuilder.beforeApplicationStart(({ rendererDi }) => {
|
||||
rendererDi.register(testRouteInjectable);
|
||||
rendererDi.register(testRouteComponentInjectable);
|
||||
rendererDi.register(testSidebarItemsInjectable);
|
||||
});
|
||||
});
|
||||
|
||||
describe("given kube resource for route is not allowed", () => {
|
||||
beforeEach(async () => {
|
||||
rendered = await applicationBuilder.render();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("related sidebar item does not exist", () => {
|
||||
const item = rendered.queryByTestId("sidebar-item-some-item-id");
|
||||
|
||||
expect(item).toBeNull();
|
||||
});
|
||||
|
||||
describe("when kube resource becomes allowed", () => {
|
||||
beforeEach(() => {
|
||||
applicationBuilder.allowKubeResource("namespaces");
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.container).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("related sidebar item exists", () => {
|
||||
const item = rendered.queryByTestId("sidebar-item-some-item-id");
|
||||
|
||||
expect(item).not.toBeNull();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const testRouteInjectable = getInjectable({
|
||||
id: "some-route-injectable-id",
|
||||
|
||||
instantiate: (di) => {
|
||||
const someKubeResourceName = "namespaces";
|
||||
|
||||
const kubeResourceIsAllowed = di.inject(
|
||||
isAllowedResourceInjectable,
|
||||
someKubeResourceName,
|
||||
);
|
||||
|
||||
return {
|
||||
path: "/some-child-page",
|
||||
isEnabled: kubeResourceIsAllowed,
|
||||
clusterFrame: true,
|
||||
};
|
||||
},
|
||||
|
||||
injectionToken: frontEndRouteInjectionToken,
|
||||
});
|
||||
|
||||
const testRouteComponentInjectable = getInjectable({
|
||||
id: "some-child-page-route-component-injectable",
|
||||
|
||||
instantiate: (di) => ({
|
||||
route: di.inject(testRouteInjectable),
|
||||
Component: () => <div data-testid="some-child-page" />,
|
||||
}),
|
||||
|
||||
injectionToken: routeSpecificComponentInjectionToken,
|
||||
});
|
||||
|
||||
const testSidebarItemsInjectable = getInjectable({
|
||||
id: "some-sidebar-item-injectable",
|
||||
|
||||
instantiate: (di) => {
|
||||
const testRoute = di.inject(testRouteInjectable);
|
||||
const navigateToRoute = di.inject(navigateToRouteInjectionToken);
|
||||
|
||||
return computed((): SidebarItemRegistration[] => [
|
||||
{
|
||||
id: "some-item-id",
|
||||
parentId: null,
|
||||
title: "Some item",
|
||||
onClick: () => navigateToRoute(testRoute),
|
||||
isVisible: testRoute.isEnabled,
|
||||
orderNumber: 42,
|
||||
},
|
||||
]);
|
||||
},
|
||||
|
||||
injectionToken: sidebarItemsInjectionToken,
|
||||
});
|
||||
|
||||
+1566
File diff suppressed because it is too large.
Load diff
+114
@@ -0,0 +1,114 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import type { ApplicationBuilder } from "../../../../../renderer/components/test-utils/get-application-builder";
|
||||
import type { KubernetesCluster } from "../../../../../common/catalog-entities";
|
||||
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 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 React from "react";
|
||||
|
||||
describe("disable workloads overview details when cluster is not relevant", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
let rendered: RenderResult;
|
||||
let isEnabledForClusterMock: AsyncFnMock<
|
||||
(cluster: KubernetesCluster) => Promise<boolean>
|
||||
>;
|
||||
|
||||
beforeEach(async () => {
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
builder.beforeApplicationStart(({ mainDi }) => {
|
||||
mainDi.override(apiManagerInjectable, () => ({}));
|
||||
});
|
||||
|
||||
const rendererDi = builder.dis.rendererDi;
|
||||
|
||||
rendererDi.unoverride(extensionShouldBeEnabledForClusterFrameInjectable);
|
||||
|
||||
builder.setEnvironmentToClusterFrame();
|
||||
|
||||
const getExtensionFake = getExtensionFakeFor(builder);
|
||||
|
||||
isEnabledForClusterMock = asyncFn();
|
||||
|
||||
const testExtension = getExtensionFake({
|
||||
id: "test-extension-id",
|
||||
name: "test-extension",
|
||||
|
||||
rendererOptions: {
|
||||
isEnabledForCluster: isEnabledForClusterMock,
|
||||
|
||||
kubeWorkloadsOverviewItems: [
|
||||
{
|
||||
components: {
|
||||
Details: () => (
|
||||
<div data-testid="some-detail-component">Some detail component</div>
|
||||
),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
rendered = await builder.render();
|
||||
|
||||
const navigateToWorkloadsOverview = rendererDi.inject(
|
||||
navigateToWorkloadsOverviewInjectable,
|
||||
);
|
||||
|
||||
navigateToWorkloadsOverview();
|
||||
|
||||
builder.extensions.enable(testExtension);
|
||||
});
|
||||
|
||||
describe("given not yet known if extension should be enabled for the cluster", () => {
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show the detail", () => {
|
||||
const actual = rendered.queryByTestId("some-detail-component");
|
||||
|
||||
expect(actual).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("given extension shouldn't be enabled for the cluster", () => {
|
||||
beforeEach(async () => {
|
||||
await isEnabledForClusterMock.resolve(false);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show the detail", () => {
|
||||
const actual = rendered.queryByTestId("some-detail-component");
|
||||
|
||||
expect(actual).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("given extension should be enabled for the cluster", () => {
|
||||
beforeEach(async () => {
|
||||
await isEnabledForClusterMock.resolve(true);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows the detail", () => {
|
||||
const actual = rendered.getByTestId("some-detail-component");
|
||||
|
||||
expect(actual).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
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 getRandomIdInjectable from "../../../../../common/utils/get-random-id.injectable";
|
||||
import { workloadOverviewDetailInjectionToken } from "../../../../../renderer/components/+workloads-overview/workload-overview-details/workload-overview-detail-injection-token";
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { computed } from "mobx";
|
||||
|
||||
describe("order of workload overview details", () => {
|
||||
let rendered: RenderResult;
|
||||
|
||||
beforeEach(async () => {
|
||||
const builder = getApplicationBuilder();
|
||||
|
||||
builder.beforeApplicationStart(({ rendererDi }) => {
|
||||
rendererDi.unoverride(getRandomIdInjectable);
|
||||
rendererDi.permitSideEffects(getRandomIdInjectable);
|
||||
});
|
||||
|
||||
builder.setEnvironmentToClusterFrame();
|
||||
|
||||
rendered = await builder.render();
|
||||
|
||||
const testExtension = getExtensionFakeFor(builder)({
|
||||
id: "some-extension-id",
|
||||
name: "some-extension",
|
||||
|
||||
rendererOptions: {
|
||||
kubeWorkloadsOverviewItems: [
|
||||
{
|
||||
components: {
|
||||
Details: () => (
|
||||
<div
|
||||
data-testid="workload-overview-detail"
|
||||
id="some-extension-item-without-priority"
|
||||
/>
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
priority: 70,
|
||||
components: {
|
||||
Details: () => (
|
||||
<div
|
||||
data-testid="workload-overview-detail"
|
||||
id="some-extension-item-with-high-priority"
|
||||
/>
|
||||
),
|
||||
},
|
||||
},
|
||||
{
|
||||
priority: 10,
|
||||
components: {
|
||||
Details: () => (
|
||||
<div
|
||||
data-testid="workload-overview-detail"
|
||||
id="some-extension-item-with-low-priority"
|
||||
/>
|
||||
),
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
builder.extensions.enable(testExtension);
|
||||
|
||||
|
||||
builder.dis.rendererDi.register(
|
||||
someCoreItemWithLowOrderNumberInjectable,
|
||||
someCoreItemWithHighOrderNumberInjectable,
|
||||
someCoreItemWithDefaultOrderNumberInjectable,
|
||||
);
|
||||
});
|
||||
|
||||
it("shows items in correct order", () => {
|
||||
const actual = rendered.queryAllByTestId("workload-overview-detail").map(x => x.id);
|
||||
|
||||
expect(actual).toEqual([
|
||||
"some-core-item-with-low-order-number",
|
||||
"some-extension-item-with-high-priority",
|
||||
"some-core-item-with-default-order-number",
|
||||
"some-extension-item-without-priority",
|
||||
"some-core-item-with-high-order-number",
|
||||
"some-extension-item-with-low-priority",
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
||||
const someCoreItemWithLowOrderNumberInjectable = getInjectable({
|
||||
id: "some-core-item-with-low-order-number",
|
||||
|
||||
instantiate: () => ({
|
||||
orderNumber: 30,
|
||||
enabled: computed(() => true),
|
||||
|
||||
Component: () => (
|
||||
<div
|
||||
data-testid="workload-overview-detail"
|
||||
id="some-core-item-with-low-order-number"
|
||||
/>
|
||||
),
|
||||
}),
|
||||
|
||||
injectionToken: workloadOverviewDetailInjectionToken,
|
||||
});
|
||||
|
||||
const someCoreItemWithDefaultOrderNumberInjectable = getInjectable({
|
||||
id: "some-core-item-with-default-order-number",
|
||||
|
||||
instantiate: () => ({
|
||||
orderNumber: 50,
|
||||
enabled: computed(() => true),
|
||||
|
||||
Component: () => (
|
||||
<div
|
||||
data-testid="workload-overview-detail"
|
||||
id="some-core-item-with-default-order-number"
|
||||
/>
|
||||
),
|
||||
}),
|
||||
|
||||
injectionToken: workloadOverviewDetailInjectionToken,
|
||||
});
|
||||
|
||||
const someCoreItemWithHighOrderNumberInjectable = getInjectable({
|
||||
id: "some-core-item-high-order-number",
|
||||
|
||||
instantiate: () => ({
|
||||
orderNumber: 60,
|
||||
enabled: computed(() => true),
|
||||
|
||||
Component: () => (
|
||||
<div
|
||||
data-testid="workload-overview-detail"
|
||||
id="some-core-item-with-high-order-number"
|
||||
/>
|
||||
),
|
||||
}),
|
||||
|
||||
injectionToken: workloadOverviewDetailInjectionToken,
|
||||
});
|
||||
+75
@@ -0,0 +1,75 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { RenderResult } from "@testing-library/react";
|
||||
import type { IObservableValue } from "mobx";
|
||||
import { computed, observable, runInAction } from "mobx";
|
||||
import React from "react";
|
||||
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 { 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", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
let rendered: RenderResult;
|
||||
let someObservable: IObservableValue<boolean>;
|
||||
|
||||
beforeEach(async () => {
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
const rendererDi = builder.dis.rendererDi;
|
||||
|
||||
builder.setEnvironmentToClusterFrame();
|
||||
|
||||
const getExtensionFake = getExtensionFakeFor(builder);
|
||||
|
||||
someObservable = observable.box(false);
|
||||
|
||||
const testExtension = getExtensionFake({
|
||||
id: "test-extension-id",
|
||||
name: "test-extension",
|
||||
|
||||
rendererOptions: {
|
||||
kubeWorkloadsOverviewItems: [
|
||||
{
|
||||
components: {
|
||||
Details: () => (
|
||||
<div data-testid="some-workload-overview-detail-item">Some detail component</div>
|
||||
),
|
||||
},
|
||||
|
||||
visible: computed(() => someObservable.get()),
|
||||
},
|
||||
],
|
||||
},
|
||||
});
|
||||
|
||||
rendered = await builder.render();
|
||||
|
||||
const navigateToWorkloadsOverview = rendererDi.inject(
|
||||
navigateToWorkloadsOverviewInjectable,
|
||||
);
|
||||
|
||||
navigateToWorkloadsOverview();
|
||||
|
||||
builder.extensions.enable(testExtension);
|
||||
});
|
||||
|
||||
it("does not show the workload overview detail item", () => {
|
||||
const actual = rendered.queryByTestId("some-workload-overview-detail-item");
|
||||
|
||||
expect(actual).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("given item should be shown, shows the workload overview detail item", () => {
|
||||
runInAction(() => {
|
||||
someObservable.set(true);
|
||||
});
|
||||
|
||||
const actual = rendered.queryByTestId("some-workload-overview-detail-item");
|
||||
|
||||
expect(actual).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user