mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Add happy path behavioural tests for upgrade chart tab
Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
parent
f14e603592
commit
fce3c95733
@ -11,7 +11,7 @@ import { isDefined } from "../../../utils";
|
||||
|
||||
const requestVersionsEndpoint = urlBuilderFor("/v2/charts/:repo/:name/versions");
|
||||
|
||||
export type RequestHelmChartVersions = (repo: string, name: string) => Promise<HelmChart[]>;
|
||||
export type RequestHelmChartVersions = (repo: string, chartName: string) => Promise<HelmChart[]>;
|
||||
|
||||
const requestHelmChartVersionsInjectable = getInjectable({
|
||||
id: "request-helm-chart-versions",
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,264 @@
|
||||
/**
|
||||
* 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 { NavigateToHelmReleases } from "../../../common/front-end-routing/routes/cluster/helm/releases/navigate-to-helm-releases.injectable";
|
||||
import navigateToHelmReleasesInjectable from "../../../common/front-end-routing/routes/cluster/helm/releases/navigate-to-helm-releases.injectable";
|
||||
import { HelmChart } from "../../../common/k8s-api/endpoints/helm-charts.api";
|
||||
import type { RequestHelmCharts } from "../../../common/k8s-api/endpoints/helm-charts.api/request-charts.injectable";
|
||||
import requestHelmChartsInjectable from "../../../common/k8s-api/endpoints/helm-charts.api/request-charts.injectable";
|
||||
import type { RequestHelmChartVersions } from "../../../common/k8s-api/endpoints/helm-charts.api/request-versions.injectable";
|
||||
import requestHelmChartVersionsInjectable from "../../../common/k8s-api/endpoints/helm-charts.api/request-versions.injectable";
|
||||
import type { RequestHelmReleaseConfiguration } from "../../../common/k8s-api/endpoints/helm-releases.api/request-configuration.injectable";
|
||||
import requestHelmReleaseConfigurationInjectable from "../../../common/k8s-api/endpoints/helm-releases.api/request-configuration.injectable";
|
||||
import type { RequestHelmReleases } from "../../../common/k8s-api/endpoints/helm-releases.api/request-releases.injectable";
|
||||
import requestHelmReleasesInjectable from "../../../common/k8s-api/endpoints/helm-releases.api/request-releases.injectable";
|
||||
import dockStoreInjectable from "../../../renderer/components/dock/dock/store.injectable";
|
||||
import type { ApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
|
||||
import { getApplicationBuilder } from "../../../renderer/components/test-utils/get-application-builder";
|
||||
|
||||
describe("New Upgrade Helm Chart Dock Tab", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
let renderResult: RenderResult;
|
||||
let requestHelmReleaseConfigurationMock: AsyncFnMock<RequestHelmReleaseConfiguration>;
|
||||
let requestHelmReleasesMock: AsyncFnMock<RequestHelmReleases>;
|
||||
let requestHelmChartsMock: AsyncFnMock<RequestHelmCharts>;
|
||||
let requestHelmChartVersionsMock: AsyncFnMock<RequestHelmChartVersions>;
|
||||
let navigateToHelmReleases: NavigateToHelmReleases;
|
||||
|
||||
beforeEach(async () => {
|
||||
builder = getApplicationBuilder();
|
||||
builder.setEnvironmentToClusterFrame();
|
||||
|
||||
builder.beforeWindowStart((windowDi) => {
|
||||
requestHelmReleaseConfigurationMock = asyncFn();
|
||||
windowDi.override(requestHelmReleaseConfigurationInjectable, () => requestHelmReleaseConfigurationMock);
|
||||
|
||||
requestHelmReleasesMock = asyncFn();
|
||||
windowDi.override(requestHelmReleasesInjectable, () => requestHelmReleasesMock);
|
||||
|
||||
requestHelmChartsMock = asyncFn();
|
||||
windowDi.override(requestHelmChartsInjectable, () => requestHelmChartsMock);
|
||||
|
||||
requestHelmChartVersionsMock = asyncFn();
|
||||
windowDi.override(requestHelmChartVersionsInjectable, () => requestHelmChartVersionsMock);
|
||||
|
||||
navigateToHelmReleases = windowDi.inject(navigateToHelmReleasesInjectable);
|
||||
});
|
||||
|
||||
builder.namespaces.add("my-first-namespace");
|
||||
builder.namespaces.add("my-second-namespace");
|
||||
|
||||
renderResult = await builder.render();
|
||||
|
||||
const dockStore = builder.applicationWindow.only.di.inject(dockStoreInjectable);
|
||||
|
||||
// TODO: Make TerminalWindow unit testable to allow realistic behaviour
|
||||
dockStore.closeTab("terminal");
|
||||
});
|
||||
|
||||
describe("given a namespace is selected", () => {
|
||||
beforeEach(() => {
|
||||
builder.namespaces.select("my-second-namespace");
|
||||
});
|
||||
|
||||
describe("when navigating to the helm releases view", () => {
|
||||
beforeEach(() => {
|
||||
navigateToHelmReleases();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(renderResult.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("requests helm releases for the selected namespace", () => {
|
||||
expect(requestHelmReleasesMock).toBeCalledWith("my-second-namespace");
|
||||
});
|
||||
|
||||
describe("when helm releases resolves", () => {
|
||||
beforeEach(async () => {
|
||||
await requestHelmReleasesMock.resolve([
|
||||
{
|
||||
appVersion: "some-app-version",
|
||||
name: "some-name",
|
||||
namespace: "my-second-namespace",
|
||||
chart: "some-chart-1.0.0",
|
||||
status: "some-status",
|
||||
updated: "some-updated",
|
||||
revision: "some-revision",
|
||||
},
|
||||
]);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(renderResult.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("when clicking the menu for a helm release", () => {
|
||||
beforeEach(() => {
|
||||
const helmReleaseMenu = renderResult.getByTestId("menu-actions-icon-for-release-menu-for-my-second-namespace/some-name");
|
||||
|
||||
helmReleaseMenu.click();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(renderResult.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("when clicking the upgrade chart menu item", () => {
|
||||
beforeEach(() => {
|
||||
const upgradeHelmChartMenuItem = renderResult.getByTestId("upgrade-chart-menu-item-for-my-second-namespace/some-name");
|
||||
|
||||
upgradeHelmChartMenuItem.click();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(renderResult.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("requests all helm charts", () => {
|
||||
expect(requestHelmChartsMock).toBeCalled();
|
||||
});
|
||||
|
||||
describe("when request for all helm charts resolves", () => {
|
||||
beforeEach(async () => {
|
||||
await requestHelmChartsMock.resolve([
|
||||
HelmChart.create({
|
||||
apiVersion: "1.2.3",
|
||||
version: "1.0.0",
|
||||
created: "at-some-time",
|
||||
name: "some-chart",
|
||||
repo: "some-repo",
|
||||
}),
|
||||
HelmChart.create({
|
||||
apiVersion: "1.2.3",
|
||||
version: "1.0.0",
|
||||
created: "at-some-third-time",
|
||||
name: "some-chart",
|
||||
repo: "some-third-repo",
|
||||
}),
|
||||
HelmChart.create({
|
||||
apiVersion: "1.2.3",
|
||||
version: "0.9.0",
|
||||
created: "at-some-other-time",
|
||||
name: "some-other-chart",
|
||||
repo: "some-repo",
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
it("requests versions of the helm charts", () => {
|
||||
expect(requestHelmChartVersionsMock).toBeCalledWith(
|
||||
"some-repo",
|
||||
"some-chart",
|
||||
);
|
||||
expect(requestHelmChartVersionsMock).toBeCalledWith(
|
||||
"some-third-repo",
|
||||
"some-chart",
|
||||
);
|
||||
});
|
||||
|
||||
it("shows the dock tab of the upgrade chart tab", () => {
|
||||
expect(renderResult.queryByTestId("dock-tab-content-for-some-irrelevant-random-id")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("does not yet show the dock contents of the upgrade chart tab", () => {
|
||||
expect(renderResult.queryByTestId("upgrade-chart-dock-tab-contents-for-my-second-namespace/some-name")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe("when the requests of versions of the helm charts resolves", () => {
|
||||
beforeEach(async () => {
|
||||
await requestHelmChartVersionsMock.resolveSpecific(
|
||||
["some-repo", "some-chart"],
|
||||
[
|
||||
HelmChart.create({
|
||||
apiVersion: "1.2.3",
|
||||
version: "1.0.0",
|
||||
created: "at-some-time",
|
||||
name: "some-chart",
|
||||
repo: "some-repo",
|
||||
}),
|
||||
HelmChart.create({
|
||||
apiVersion: "1.2.3",
|
||||
version: "1.0.1",
|
||||
created: "at-some-time",
|
||||
name: "some-chart",
|
||||
repo: "some-repo",
|
||||
}),
|
||||
],
|
||||
);
|
||||
|
||||
await requestHelmChartVersionsMock.resolveSpecific(
|
||||
["some-third-repo", "some-chart"],
|
||||
[
|
||||
HelmChart.create({
|
||||
apiVersion: "1.2.3",
|
||||
version: "0.9.0",
|
||||
created: "at-some-other-time",
|
||||
name: "some-other-chart",
|
||||
repo: "some-repo",
|
||||
}),
|
||||
HelmChart.create({
|
||||
apiVersion: "1.2.3",
|
||||
version: "0.9.1",
|
||||
created: "at-some-other-time",
|
||||
name: "some-other-chart",
|
||||
repo: "some-repo",
|
||||
}),
|
||||
],
|
||||
);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(renderResult.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows the dock contents of the upgrade chart tab", () => {
|
||||
expect(renderResult.queryByTestId("upgrade-chart-dock-tab-contents-for-my-second-namespace/some-name")).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("requests the configuration for the specific helm release", () => {
|
||||
expect(requestHelmReleaseConfigurationMock).toBeCalledWith(
|
||||
"some-name",
|
||||
"my-second-namespace",
|
||||
true,
|
||||
);
|
||||
});
|
||||
|
||||
describe("when the configuration request resolves", () => {
|
||||
beforeEach(async () => {
|
||||
await requestHelmReleaseConfigurationMock.resolve("some confiration for the helm release");
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(renderResult.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("when closing the upgrade chart tab", () => {
|
||||
beforeEach(() => {
|
||||
const closeDockTab = renderResult.getByTestId("dock-tab-close-for-some-irrelevant-random-id");
|
||||
|
||||
closeDockTab.click();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(renderResult.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does so", () => {
|
||||
expect(renderResult.queryByTestId("dock-tab-content-for-some-irrelevant-random-id")).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@ -61,7 +61,10 @@ class NonInjectedHelmReleaseMenu extends React.Component<HelmReleaseMenuProps &
|
||||
<span className="title">Rollback</span>
|
||||
</MenuItem>
|
||||
)}
|
||||
<MenuItem onClick={this.upgrade}>
|
||||
<MenuItem
|
||||
onClick={this.upgrade}
|
||||
data-testid={`upgrade-chart-menu-item-for-${release.getId()}`}
|
||||
>
|
||||
<Icon
|
||||
material="refresh"
|
||||
interactive={toolbar}
|
||||
@ -79,6 +82,10 @@ class NonInjectedHelmReleaseMenu extends React.Component<HelmReleaseMenuProps &
|
||||
return (
|
||||
<MenuActions
|
||||
id={`menu-actions-for-release-menu-for-${release.getId()}`}
|
||||
triggerIcon={{
|
||||
material: "more_vert",
|
||||
"data-testid": `menu-actions-icon-for-release-menu-for-${release.getId()}`,
|
||||
}}
|
||||
{...menuProps}
|
||||
className={cssNames("HelmReleaseMenu", className)}
|
||||
removeAction={this.remove}
|
||||
|
||||
@ -4,7 +4,6 @@
|
||||
*/
|
||||
import { getInjectable } from "@ogre-tools/injectable";
|
||||
import { asyncComputed } from "@ogre-tools/injectable-react";
|
||||
import namespaceStoreInjectable from "../+namespaces/store.injectable";
|
||||
import clusterFrameContextInjectable from "../../cluster-frame-context/cluster-frame-context.injectable";
|
||||
import releaseSecretsInjectable from "./release-secrets.injectable";
|
||||
import requestHelmReleasesInjectable from "../../../common/k8s-api/endpoints/helm-releases.api/request-releases.injectable";
|
||||
@ -15,28 +14,17 @@ const releasesInjectable = getInjectable({
|
||||
|
||||
instantiate: (di) => {
|
||||
const clusterContext = di.inject(clusterFrameContextInjectable);
|
||||
const namespaceStore = di.inject(namespaceStoreInjectable);
|
||||
const releaseSecrets = di.inject(releaseSecretsInjectable);
|
||||
const requestHelmReleases = di.inject(requestHelmReleasesInjectable);
|
||||
const toHelmRelease = di.inject(toHelmReleaseInjectable);
|
||||
|
||||
return asyncComputed(async () => {
|
||||
const contextNamespaces = namespaceStore.contextNamespaces || [];
|
||||
|
||||
void releaseSecrets.get();
|
||||
|
||||
const isLoadingAll =
|
||||
clusterContext.allNamespaces?.length > 1 &&
|
||||
clusterContext.cluster?.accessibleNamespaces.length === 0 &&
|
||||
clusterContext.allNamespaces.every((namespace) =>
|
||||
contextNamespaces.includes(namespace),
|
||||
);
|
||||
|
||||
const releaseArrays = await (isLoadingAll ? requestHelmReleases() : Promise.all(
|
||||
contextNamespaces.map((namespace) =>
|
||||
requestHelmReleases(namespace),
|
||||
),
|
||||
));
|
||||
const releaseArrays = await (clusterContext.hasSelectedAll
|
||||
? requestHelmReleases()
|
||||
: Promise.all(clusterContext.contextNamespaces.map(namespace => requestHelmReleases(namespace)))
|
||||
);
|
||||
|
||||
return releaseArrays.flat().map(toHelmRelease);
|
||||
}, []);
|
||||
|
||||
@ -103,6 +103,7 @@ class NonInjectedDockTab extends React.Component<DockTabProps & Dependencies> {
|
||||
material="close"
|
||||
tooltip={`Close ${this.props.isMac ? "⌘+W" : "Ctrl+W"}`}
|
||||
onClick={close}
|
||||
data-testid={`dock-tab-close-for-${id}`}
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@ -0,0 +1,21 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { getInjectable, lifecycleEnum } from "@ogre-tools/injectable";
|
||||
import { waitUntilDefined } from "../../../utils";
|
||||
import upgradeChartTabStoreInjectable from "./store.injectable";
|
||||
|
||||
const upgradeChartTabDataInjectable = getInjectable({
|
||||
id: "upgrade-chart-tab-data",
|
||||
instantiate: (di, tabId) => {
|
||||
const upgradeChartTabStore = di.inject(upgradeChartTabStoreInjectable);
|
||||
|
||||
return waitUntilDefined(() => upgradeChartTabStore.getData(tabId));
|
||||
},
|
||||
lifecycle: lifecycleEnum.keyedSingleton({
|
||||
getInstanceKey: (di, tabId: string) => tabId,
|
||||
}),
|
||||
});
|
||||
|
||||
export default upgradeChartTabDataInjectable;
|
||||
@ -16,7 +16,7 @@ import requestHelmReleaseConfigurationInjectable from "../../../../common/k8s-ap
|
||||
import { waitUntilDefined } from "../../../utils";
|
||||
import type { SelectOption } from "../../select";
|
||||
import type { DockTab } from "../dock/store";
|
||||
import upgradeChartTabStoreInjectable from "./store.injectable";
|
||||
import upgradeChartTabDataInjectable from "./tab-data.injectable";
|
||||
|
||||
export interface UpgradeChartModel {
|
||||
readonly release: HelmRelease;
|
||||
@ -41,13 +41,19 @@ export interface UpgradeChartSubmitResult {
|
||||
const upgradeChartModelInjectable = getInjectable({
|
||||
id: "upgrade-chart-model",
|
||||
instantiate: async (di, tab): Promise<UpgradeChartModel> => {
|
||||
const upgradeChartTabStore = di.inject(upgradeChartTabStoreInjectable);
|
||||
const releases = di.inject(releasesInjectable);
|
||||
const requestHelmReleaseConfiguration = di.inject(requestHelmReleaseConfigurationInjectable);
|
||||
const updateRelease = di.inject(updateReleaseInjectable);
|
||||
const tabData = await di.inject(upgradeChartTabDataInjectable, tab.id);
|
||||
|
||||
const tabData = await waitUntilDefined(() => upgradeChartTabStore.getData(tab.id));
|
||||
const release = await waitUntilDefined(() => releases.value.get().find(release => release.getName() === tabData.releaseName));
|
||||
const release = await waitUntilDefined(() => (
|
||||
releases.value
|
||||
.get()
|
||||
.find(release => (
|
||||
release.getName() === tabData.releaseName
|
||||
&& release.getNs() === tabData.releaseNamespace
|
||||
))
|
||||
));
|
||||
const versions = di.inject(helmChartVersionsInjectable, release);
|
||||
const storedConfiguration = asyncComputed(() => requestHelmReleaseConfiguration(
|
||||
release.getName(),
|
||||
|
||||
@ -6,7 +6,6 @@
|
||||
import "./upgrade-chart.scss";
|
||||
|
||||
import React from "react";
|
||||
import { makeObservable, observable } from "mobx";
|
||||
import { observer } from "mobx-react";
|
||||
import { cssNames } from "../../../utils";
|
||||
import type { DockTab } from "../dock/store";
|
||||
@ -32,13 +31,6 @@ interface Dependencies {
|
||||
|
||||
@observer
|
||||
export class NonInjectedUpgradeChart extends React.Component<UpgradeChartProps & Dependencies> {
|
||||
@observable error?: string;
|
||||
|
||||
constructor(props: UpgradeChartProps & Dependencies) {
|
||||
super(props);
|
||||
makeObservable(this);
|
||||
}
|
||||
|
||||
upgrade = async () => {
|
||||
const { model } = this.props;
|
||||
const { completedSuccessfully } = await model.submit();
|
||||
@ -63,7 +55,10 @@ export class NonInjectedUpgradeChart extends React.Component<UpgradeChartProps &
|
||||
const { release } = model;
|
||||
|
||||
return (
|
||||
<div className={cssNames("UpgradeChart flex column", className)}>
|
||||
<div
|
||||
className={cssNames("UpgradeChart flex column", className)}
|
||||
data-testid={`upgrade-chart-dock-tab-contents-for-${release.getId()}`}
|
||||
>
|
||||
<InfoPanel
|
||||
tabId={tabId}
|
||||
error={model.configration.error.get()}
|
||||
|
||||
@ -6,7 +6,7 @@ import type { LensRendererExtension } from "../../../extensions/lens-renderer-ex
|
||||
import rendererExtensionsInjectable from "../../../extensions/renderer-extensions.injectable";
|
||||
import currentlyInClusterFrameInjectable from "../../routes/currently-in-cluster-frame.injectable";
|
||||
import type { IComputedValue, ObservableMap } from "mobx";
|
||||
import { computed, observable, runInAction } from "mobx";
|
||||
import { action, computed, observable, runInAction } from "mobx";
|
||||
import React from "react";
|
||||
import { Router } from "react-router";
|
||||
import allowedResourcesInjectable from "../../cluster-frame-context/allowed-resources.injectable";
|
||||
@ -120,7 +120,10 @@ export interface ApplicationBuilder {
|
||||
click: (id: string) => void;
|
||||
};
|
||||
};
|
||||
|
||||
namespaces: {
|
||||
add: (namespace: string) => void;
|
||||
select: (namespace: string) => void;
|
||||
};
|
||||
helmCharts: {
|
||||
navigate: NavigateToHelmCharts;
|
||||
};
|
||||
@ -244,6 +247,9 @@ export const getApplicationBuilder = () => {
|
||||
|
||||
let applicationHasStarted = false;
|
||||
|
||||
const namespaces = observable.array<string>();
|
||||
const selectedNamespaces = observable.array<string>();
|
||||
|
||||
const builder: ApplicationBuilder = {
|
||||
mainDi,
|
||||
applicationWindow: {
|
||||
@ -304,7 +310,10 @@ export const getApplicationBuilder = () => {
|
||||
return builder.applicationWindow.get(id);
|
||||
},
|
||||
},
|
||||
|
||||
namespaces: {
|
||||
add: action((namespace) => namespaces.push(namespace)),
|
||||
select: action((namespace) => selectedNamespaces.push(namespace)),
|
||||
},
|
||||
applicationMenu: {
|
||||
click: (path: string) => {
|
||||
const applicationMenuItems = mainDi.inject(
|
||||
@ -470,7 +479,8 @@ export const getApplicationBuilder = () => {
|
||||
// TODO: Figure out a way to remove this stub.
|
||||
const namespaceStoreStub = {
|
||||
isLoaded: true,
|
||||
contextNamespaces: [],
|
||||
contextNamespaces: selectedNamespaces,
|
||||
allowedNamespaces: namespaces,
|
||||
contextItems: [],
|
||||
api: {
|
||||
kind: "Namespace",
|
||||
|
||||
Loading…
Reference in New Issue
Block a user