Resolve kube object status texts again on re-render to make it look like it's reactive (#5875)

* Make tests for kube object status icon more realistic

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

* Start resolving kube object status texts on each re-render to mimic reactivity

Note: This is done due the current implementation exposed in Extension API expects it to work so. However, this is bad.

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

* Switch to using existing implementation for isDefined

Signed-off-by: Janne Savolainen <janne.savolainen@live.fi>
This commit is contained in:
Janne Savolainen authored and GitHub committed 2022-07-27 09:21:38 +03:00
1 parent f61330611e
commit a12b94405a
8 files changed
+2903 -379

No files matched your search

@@ -1,116 +0,0 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`kube-object-status-icon given info and warning statuses are present, when rendered, renders with statuses 1`] = `
<body>
<div>
<i
class="Icon KubeObjectStatusIcon warning material focusable"
id="tooltip_target_5"
>
<span
class="icon"
data-icon-name="warning"
>
warning
</span>
<div />
</i>
</div>
</body>
`;
exports[`kube-object-status-icon given level "critical" status, when rendered, renders with status 1`] = `
<body>
<div>
<i
class="Icon KubeObjectStatusIcon error material focusable"
id="tooltip_target_1"
>
<span
class="icon"
data-icon-name="error"
>
error
</span>
<div />
</i>
</div>
</body>
`;
exports[`kube-object-status-icon given level "info" status, when rendered, renders with status 1`] = `
<body>
<div>
<i
class="Icon KubeObjectStatusIcon info material focusable"
id="tooltip_target_2"
>
<span
class="icon"
data-icon-name="info"
>
info
</span>
<div />
</i>
</div>
</body>
`;
exports[`kube-object-status-icon given level "warning" status, when rendered, renders with status 1`] = `
<body>
<div>
<i
class="Icon KubeObjectStatusIcon warning material focusable"
id="tooltip_target_3"
>
<span
class="icon"
data-icon-name="warning"
>
warning
</span>
<div />
</i>
</div>
</body>
`;
exports[`kube-object-status-icon given no statuses, when rendered, renders as empty 1`] = `<div />`;
exports[`kube-object-status-icon given registration for wrong api version, when rendered, renders as empty 1`] = `
<body>
<div />
</body>
`;
exports[`kube-object-status-icon given registration for wrong kind, when rendered, renders as empty 1`] = `
<body>
<div />
</body>
`;
exports[`kube-object-status-icon given registration without status for exact kube object, when rendered, renders as empty 1`] = `
<body>
<div />
</body>
`;
exports[`kube-object-status-icon given status for all levels is present, when rendered, renders with statuses 1`] = `
<body>
<div>
<i
class="Icon KubeObjectStatusIcon error material focusable"
id="tooltip_target_4"
>
<span
class="icon"
data-icon-name="error"
>
error
</span>
<div />
</i>
</div>
</body>
`;
@@ -1,251 +0,0 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import { getDiForUnitTesting } from "../../getDiForUnitTesting";
import type { DiRender } from "../test-utils/renderFor";
import { renderFor } from "../test-utils/renderFor";
import type { KubeObjectStatus } from "../../../common/k8s-api/kube-object-status";
import { KubeObjectStatusLevel } from "../../../common/k8s-api/kube-object-status";
import { KubeObject } from "../../../common/k8s-api/kube-object";
import { KubeObjectStatusIcon } from "./kube-object-status-icon";
import React from "react";
import { useFakeTime } from "../../../common/test-utils/use-fake-time";
import { getInjectable } from "@ogre-tools/injectable";
import type { DiContainer } from "@ogre-tools/injectable";
import { kubeObjectStatusTextInjectionToken } from "./kube-object-status-text-injection-token";
import { computed } from "mobx";
describe("kube-object-status-icon", () => {
let render: DiRender;
let di: DiContainer;
beforeEach(() => {
useFakeTime("2015-10-21T07:28:00Z");
di = getDiForUnitTesting({ doGeneralOverrides: true });
render = renderFor(di);
});
it("given no statuses, when rendered, renders as empty", () => {
const kubeObject = getKubeObjectStub("irrelevant", "irrelevant");
const { container } = render(<KubeObjectStatusIcon object={kubeObject} />);
expect(container).toMatchSnapshot();
});
it('given level "critical" status, when rendered, renders with status', () => {
const kubeObject = getKubeObjectStub("some-kind", "some-api-version");
const statusTextInjectable = getStatusTextInjectable(
KubeObjectStatusLevel.CRITICAL,
"critical",
"some-kind",
["some-api-version"],
);
di.register(statusTextInjectable);
const { baseElement } = render(
<KubeObjectStatusIcon object={kubeObject} />,
);
expect(baseElement).toMatchSnapshot();
});
it('given level "info" status, when rendered, renders with status', () => {
const kubeObject = getKubeObjectStub("some-kind", "some-api-version");
const statusTextInjectable = getStatusTextInjectable(
KubeObjectStatusLevel.INFO,
"info",
"some-kind",
["some-api-version"],
);
di.register(statusTextInjectable);
const { baseElement } = render(
<KubeObjectStatusIcon object={kubeObject} />,
);
expect(baseElement).toMatchSnapshot();
});
it('given level "warning" status, when rendered, renders with status', () => {
const kubeObject = getKubeObjectStub("some-kind", "some-api-version");
const statusTextInjectable = getStatusTextInjectable(
KubeObjectStatusLevel.WARNING,
"warning",
"some-kind",
["some-api-version"],
);
di.register(statusTextInjectable);
const { baseElement } = render(
<KubeObjectStatusIcon object={kubeObject} />,
);
expect(baseElement).toMatchSnapshot();
});
it("given status for all levels is present, when rendered, renders with statuses", () => {
const kubeObject = getKubeObjectStub("some-kind", "some-api-version");
const criticalStatusTextInjectable = getStatusTextInjectable(
KubeObjectStatusLevel.CRITICAL,
"critical",
"some-kind",
["some-api-version"],
);
const warningStatusTextInjectable = getStatusTextInjectable(
KubeObjectStatusLevel.WARNING,
"warning",
"some-kind",
["some-api-version"],
);
const infoStatusTextInjectable = getStatusTextInjectable(
KubeObjectStatusLevel.INFO,
"info",
"some-kind",
["some-api-version"],
);
di.register(
criticalStatusTextInjectable,
warningStatusTextInjectable,
infoStatusTextInjectable,
);
const { baseElement } = render(
<KubeObjectStatusIcon object={kubeObject} />,
);
expect(baseElement).toMatchSnapshot();
});
it("given info and warning statuses are present, when rendered, renders with statuses", () => {
const kubeObject = getKubeObjectStub("some-kind", "some-api-version");
const warningStatusTextInjectable = getStatusTextInjectable(
KubeObjectStatusLevel.WARNING,
"warning",
"some-kind",
["some-api-version"],
);
const infoStatusTextInjectable = getStatusTextInjectable(
KubeObjectStatusLevel.INFO,
"info",
"some-kind",
["some-api-version"],
);
di.register(warningStatusTextInjectable, infoStatusTextInjectable);
const { baseElement } = render(
<KubeObjectStatusIcon object={kubeObject} />,
);
expect(baseElement).toMatchSnapshot();
});
it("given registration for wrong api version, when rendered, renders as empty", () => {
const kubeObject = getKubeObjectStub("some-kind", "some-api-version");
const statusTextInjectable = getStatusTextInjectable(
KubeObjectStatusLevel.CRITICAL,
"irrelevant",
"some-kind",
["some-other-api-version"],
);
di.register(statusTextInjectable);
const { baseElement } = render(
<KubeObjectStatusIcon object={kubeObject} />,
);
expect(baseElement).toMatchSnapshot();
});
it("given registration for wrong kind, when rendered, renders as empty", () => {
const kubeObject = getKubeObjectStub("some-kind", "some-api-version");
const statusTextInjectable = getStatusTextInjectable(
KubeObjectStatusLevel.CRITICAL,
"irrelevant",
"some-other-kind",
["some-api-version"],
);
di.register(statusTextInjectable);
const { baseElement } = render(
<KubeObjectStatusIcon object={kubeObject} />,
);
expect(baseElement).toMatchSnapshot();
});
it("given registration without status for exact kube object, when rendered, renders as empty", () => {
const kubeObject = getKubeObjectStub("some-kind", "some-api-version");
const statusTextInjectable = getInjectable({
id: "some-id",
instantiate: () => ({
apiVersions: ["some-api-version"],
kind: "some-kind",
resolve: () => { return undefined as unknown as KubeObjectStatus; },
enabled: computed(() => true),
}),
injectionToken: kubeObjectStatusTextInjectionToken,
});
di.register(statusTextInjectable);
const { baseElement } = render(
<KubeObjectStatusIcon object={kubeObject} />,
);
expect(baseElement).toMatchSnapshot();
});
});
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 getStatusTextInjectable = (level: KubeObjectStatusLevel, title: string, kind: string, apiVersions: string[]) => getInjectable({
id: title,
instantiate: () => ({
apiVersions,
kind,
resolve: (kubeObject: KubeObject) => ({
level,
text: `Some ${title} status for ${kubeObject.getName()}`,
timestamp: "2015-10-19T07:28:00Z",
}),
enabled: computed(() => true),
}),
injectionToken: kubeObjectStatusTextInjectionToken,
});
@@ -7,7 +7,7 @@ import "./kube-object-status-icon.scss";
import React from "react";
import { Icon } from "../icon";
import { cssNames, formatDuration, getOrInsert } from "../../utils";
import { cssNames, formatDuration, getOrInsert, isDefined } from "../../utils";
import { withInjectables } from "@ogre-tools/injectable-react";
import kubeObjectStatusTextsForObjectInjectable from "./kube-object-status-texts-for-object.injectable";
import type { KubeObject } from "../../../common/k8s-api/kube-object";
@@ -15,6 +15,7 @@ import type { KubeObjectStatus } from "../../../common/k8s-api/kube-object-statu
import { KubeObjectStatusLevel } from "../../../common/k8s-api/kube-object-status";
import type { IComputedValue } from "mobx";
import { observer } from "mobx-react";
import type { KubeObjectStatusText } from "./kube-object-status-text-injection-token";
function statusClassName(level: KubeObjectStatusLevel): string {
switch (level) {
@@ -78,7 +79,7 @@ export interface KubeObjectStatusIconProps {
}
interface Dependencies {
statuses: IComputedValue<KubeObjectStatus[]>;
statuses: IComputedValue<KubeObjectStatusText[]>;
}
@observer
@@ -107,7 +108,11 @@ class NonInjectedKubeObjectStatusIcon extends React.Component<KubeObjectStatusIc
}
render() {
const statuses = this.props.statuses.get();
const statusTexts = this.props.statuses.get();
const statuses = statusTexts
.map((statusText) => statusText.resolve(this.props.object))
.filter(isDefined);
if (statuses.length === 0) {
return null;
@@ -119,6 +124,7 @@ class NonInjectedKubeObjectStatusIcon extends React.Component<KubeObjectStatusIc
<Icon
material={maxLevel}
className={cssNames("KubeObjectStatusIcon", maxLevel)}
data-testid={`kube-object-status-icon-for-${this.props.object.getId()}`}
tooltip={{
children: (
<div className="KubeObjectStatusTooltip">
@@ -10,7 +10,7 @@ import type { IComputedValue } from "mobx";
export interface KubeObjectStatusText {
kind: string;
apiVersions: string[];
resolve: (object: KubeObject) => KubeObjectStatus;
resolve: (object: KubeObject) => KubeObjectStatus | null;
enabled: IComputedValue<boolean>;
}
@@ -6,7 +6,6 @@ import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
import kubeObjectStatusTextsInjectable from "./kube-object-status-texts.injectable";
import type { KubeObject } from "../../../common/k8s-api/kube-object";
import { conforms, eq, includes } from "lodash/fp";
import type { KubeObjectStatusRegistration } from "./kube-object-status-registration";
import { computed } from "mobx";
const kubeObjectStatusTextsForObjectInjectable = getInjectable({
@@ -18,9 +17,7 @@ const kubeObjectStatusTextsForObjectInjectable = getInjectable({
return computed(() =>
allStatusTexts
.get()
.filter(toKubeObjectRelated(kubeObject))
.map(toStatus(kubeObject))
.filter(Boolean),
.filter(toKubeObjectRelated(kubeObject)),
);
},
@@ -35,8 +32,4 @@ const toKubeObjectRelated = (kubeObject: KubeObject) =>
apiVersions: includes(kubeObject.apiVersion),
});
const toStatus =
(kubeObject: KubeObject) => (item: KubeObjectStatusRegistration) =>
item.resolve(kubeObject);
export default kubeObjectStatusTextsForObjectInjectable;