/** * Copyright (c) OpenLens Authors. All rights reserved. * Licensed under MIT License. See LICENSE in root directory for more information. */ import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder"; import navigateToHelmReleasesInjectable from "../../common/front-end-routing/routes/cluster/helm/releases/navigate-to-helm-releases.injectable"; import type { RenderResult } from "@testing-library/react"; import { fireEvent } from "@testing-library/react"; import type { AsyncFnMock } from "@async-fn/jest"; import asyncFn from "@async-fn/jest"; 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 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 { RequestHelmReleaseUpdate } from "../../common/k8s-api/endpoints/helm-releases.api/request-update.injectable"; import requestHelmReleaseUpdateInjectable from "../../common/k8s-api/endpoints/helm-releases.api/request-update.injectable"; import type { RequestDetailedHelmRelease } from "../../renderer/components/+helm-releases/release-details/release-details-model/request-detailed-helm-release.injectable"; import requestDetailedHelmReleaseInjectable from "../../renderer/components/+helm-releases/release-details/release-details-model/request-detailed-helm-release.injectable"; import showSuccessNotificationInjectable from "../../renderer/components/notifications/show-success-notification.injectable"; import showCheckedErrorInjectable from "../../renderer/components/notifications/show-checked-error.injectable"; import getRandomUpgradeChartTabIdInjectable from "../../renderer/components/dock/upgrade-chart/get-random-upgrade-chart-tab-id.injectable"; import type { RequestHelmCharts } 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 type { RequestHelmChartReadme } from "../../common/k8s-api/endpoints/helm-charts.api/request-readme.injectable"; import type { RequestHelmChartValues } from "../../common/k8s-api/endpoints/helm-charts.api/request-values.injectable"; import requestHelmChartsInjectable from "../../common/k8s-api/endpoints/helm-charts.api/request-charts.injectable"; import requestHelmChartVersionsInjectable from "../../common/k8s-api/endpoints/helm-charts.api/request-versions.injectable"; import requestHelmChartReadmeInjectable from "../../common/k8s-api/endpoints/helm-charts.api/request-readme.injectable"; import requestHelmChartValuesInjectable from "../../common/k8s-api/endpoints/helm-charts.api/request-values.injectable"; import { HelmChart } from "../../common/k8s-api/endpoints/helm-charts.api"; describe("showing details for helm release", () => { let builder: ApplicationBuilder; let requestHelmReleasesMock: AsyncFnMock; let requestDetailedHelmReleaseMock: AsyncFnMock; let requestHelmReleaseConfigurationMock: AsyncFnMock; let requestHelmReleaseUpdateMock: AsyncFnMock; let requestHelmChartsMock: AsyncFnMock; let requestHelmChartVersionsMock: AsyncFnMock; let requestHelmChartReadmeMock: AsyncFnMock; let requestHelmChartValuesMock: AsyncFnMock; let showSuccessNotificationMock: jest.Mock; let showCheckedErrorNotificationMock: jest.Mock; beforeEach(() => { builder = getApplicationBuilder({ useFakeTime: { dateTime: "2015-10-21T07:28:00Z", }, }); builder.setEnvironmentToClusterFrame(); requestHelmReleasesMock = asyncFn(); requestDetailedHelmReleaseMock = asyncFn(); requestHelmReleaseConfigurationMock = asyncFn(); requestHelmReleaseUpdateMock = asyncFn(); requestHelmChartsMock = asyncFn(); requestHelmChartVersionsMock = asyncFn(); requestHelmChartReadmeMock = asyncFn(); requestHelmChartValuesMock = asyncFn(); showSuccessNotificationMock = jest.fn(); showCheckedErrorNotificationMock = jest.fn(); builder.beforeWindowStart((windowDi) => { windowDi.override(getRandomUpgradeChartTabIdInjectable, () => () => "some-tab-id"); windowDi.override(showSuccessNotificationInjectable, () => showSuccessNotificationMock); windowDi.override(showCheckedErrorInjectable, () => showCheckedErrorNotificationMock); windowDi.override(requestHelmReleasesInjectable, () => requestHelmReleasesMock); windowDi.override(requestDetailedHelmReleaseInjectable, () => requestDetailedHelmReleaseMock); windowDi.override(requestHelmReleaseConfigurationInjectable, () => requestHelmReleaseConfigurationMock); windowDi.override(requestHelmReleaseUpdateInjectable, () => requestHelmReleaseUpdateMock); windowDi.override(requestHelmChartsInjectable, () => requestHelmChartsMock); windowDi.override(requestHelmChartVersionsInjectable, () => requestHelmChartVersionsMock); windowDi.override(requestHelmChartReadmeInjectable, () => requestHelmChartReadmeMock); windowDi.override(requestHelmChartValuesInjectable, () => requestHelmChartValuesMock); }); builder.namespaces.add("some-namespace"); builder.namespaces.select("some-namespace"); builder.namespaces.add("some-namespace"); builder.namespaces.select("some-other-namespace"); }); describe("given application is started", () => { let rendered: RenderResult; beforeEach(async () => { rendered = await builder.render(); }); describe("when navigating to helm releases", () => { beforeEach(() => { const windowDi = builder.applicationWindow.only.di; const navigateToHelmReleases = windowDi.inject( navigateToHelmReleasesInjectable, ); navigateToHelmReleases(); }); it("renders", () => { expect(rendered.baseElement).toMatchSnapshot(); }); it("calls for releases for each selected namespace", () => { expect(requestHelmReleasesMock.mock.calls).toEqual([ ["some-namespace"], ["some-other-namespace"], ]); }); it("shows spinner", () => { expect( rendered.getByTestId("helm-releases-spinner"), ).toBeInTheDocument(); }); it("when releases resolve but there is none, renders", async () => { await requestHelmReleasesMock.resolve([]); await requestHelmReleasesMock.resolve([]); expect(rendered.baseElement).toMatchSnapshot(); }); describe("when releases resolve", () => { beforeEach(async () => { await requestHelmReleasesMock.resolveSpecific( ([namespace]) => namespace === "some-namespace", [ { appVersion: "some-app-version", name: "some-name", namespace: "some-namespace", chart: "some-chart-1.0.0", status: "some-status", updated: "some-updated", revision: "some-revision", }, ], ); await requestHelmReleasesMock.resolveSpecific( ([namespace]) => namespace === "some-other-namespace", [ { appVersion: "some-other-app-version", name: "some-other-name", namespace: "some-other-namespace", chart: "some-other-chart-2.0.0", status: "some-other-status", updated: "some-other-updated", revision: "some-other-revision", }, ], ); }); it("renders", () => { expect(rendered.baseElement).toMatchSnapshot(); }); it("does not show spinner anymore", () => { expect( rendered.queryByTestId("helm-releases-spinner"), ).not.toBeInTheDocument(); }); describe("when selecting release to see details", () => { beforeEach(() => { const row = rendered.getByTestId( "helm-release-row-for-some-namespace/some-name", ); fireEvent.click(row); }); it("renders", () => { expect(rendered.baseElement).toMatchSnapshot(); }); it("opens the details", () => { expect( rendered.getByTestId("helm-release-details-for-some-namespace/some-name"), ).toBeInTheDocument(); }); it("calls for release", () => { expect(requestDetailedHelmReleaseMock).toHaveBeenCalledWith( "some-name", "some-namespace", ); }); it("shows spinner", () => { expect( rendered.getByTestId("helm-release-detail-content-spinner"), ).toBeInTheDocument(); }); describe("when opening details for second release", () => { beforeEach(() => { requestDetailedHelmReleaseMock.mockClear(); const row = rendered.getByTestId( "helm-release-row-for-some-other-namespace/some-other-name", ); fireEvent.click(row); }); it("renders", () => { expect(rendered.baseElement).toMatchSnapshot(); }); it("calls for another release", () => { expect(requestDetailedHelmReleaseMock).toHaveBeenCalledWith( "some-other-name", "some-other-namespace", ); }); it("closes details for first release", () => { expect( rendered.queryByTestId("helm-release-details-for-some-namespace/some-name"), ).not.toBeInTheDocument(); }); it("opens details for second release", () => { expect( rendered.getByTestId("helm-release-details-for-some-other-namespace/some-other-name"), ).toBeInTheDocument(); }); }); describe("when details is closed", () => { beforeEach(() => { const closeButton = rendered.getByTestId( "close-helm-release-detail", ); fireEvent.click(closeButton); }); it("renders", () => { expect(rendered.baseElement).toMatchSnapshot(); }); it("closes the details", () => { expect( rendered.queryByTestId("helm-release-details-for-some-namespace/some-name"), ).not.toBeInTheDocument(); }); describe("when opening details for same release", () => { beforeEach(() => { requestDetailedHelmReleaseMock.mockClear(); const row = rendered.getByTestId( "helm-release-row-for-some-namespace/some-name", ); fireEvent.click(row); }); it("renders", () => { expect(rendered.baseElement).toMatchSnapshot(); }); it("does not reload", () => { expect(requestDetailedHelmReleaseMock).not.toHaveBeenCalled(); }); }); }); describe("when call for release resolves with error", () => { beforeEach(async () => { await requestDetailedHelmReleaseMock.resolve({ callWasSuccessful: false, error: "some-error", }); }); it("renders", async () => { expect(rendered.baseElement).toMatchSnapshot(); }); it("does not show spinner anymore", () => { expect( rendered.queryByTestId("helm-release-detail-content-spinner"), ).not.toBeInTheDocument(); }); it("shows error message about missing release", () => { expect( rendered.getByTestId("helm-release-detail-error"), ).toBeInTheDocument(); }); it("does not call for release configuration", () => { expect(requestHelmReleaseConfigurationMock).not.toHaveBeenCalled(); }); }); describe("when call for release resolve with release", () => { beforeEach(async () => { await requestDetailedHelmReleaseMock.resolve({ callWasSuccessful: true, response: { release: { appVersion: "some-app-version", chart: "some-chart-1.0.0", status: "some-status", updated: "some-updated", revision: "some-revision", name: "some-name", namespace: "some-namespace", }, details: { name: "some-name", namespace: "some-namespace", version: "some-version", config: "some-config", manifest: "some-manifest", info: { deleted: "some-deleted", description: "some-description", first_deployed: "some-first-deployed", last_deployed: "some-last-deployed", notes: "some-notes", status: "some-status", }, resources: [ { kind: "some-kind", apiVersion: "some-api-version", metadata: { uid: "some-uid", name: "some-resource", namespace: "some-namespace", creationTimestamp: "2015-10-22T07:28:00Z", }, }, ], }, }, }); }); it("renders", () => { expect(rendered.baseElement).toMatchSnapshot(); }); it("calls for release configuration", () => { expect(requestHelmReleaseConfigurationMock).toHaveBeenCalledWith( "some-name", "some-namespace", true, ); }); describe("when configuration resolves", () => { beforeEach(async () => { await requestHelmReleaseConfigurationMock.resolve( "some-configuration", ); }); it("renders", () => { expect(rendered.baseElement).toMatchSnapshot(); }); it("does not have tab for upgrading chart yet", () => { expect( rendered.queryByTestId("dock-tab-for-some-tab-id"), ).not.toBeInTheDocument(); }); describe("when selecting to upgrade chart", () => { beforeEach(() => { const upgradeButton = rendered.getByTestId( "helm-release-upgrade-button", ); fireEvent.click(upgradeButton); }); it("renders", () => { expect(rendered.baseElement).toMatchSnapshot(); }); it("opens tab for upgrading chart", () => { expect( rendered.getByTestId("dock-tab-for-some-tab-id"), ).toBeInTheDocument(); }); it("closes the details", () => { expect( rendered.queryByTestId("helm-release-details-for-some-namespace/some-name"), ).not.toBeInTheDocument(); }); }); describe("when changing the configuration", () => { beforeEach(() => { const configuration = rendered.getByTestId( "monaco-editor-for-helm-release-configuration", ); fireEvent.change(configuration, { target: { value: "some-new-configuration" }, }); }); it("renders", () => { expect(rendered.baseElement).toMatchSnapshot(); }); it("has the configuration", () => { const input = rendered.getByTestId( "monaco-editor-for-helm-release-configuration", ); expect(input).toHaveValue("some-new-configuration"); }); it("does not save changes yet", () => { expect(requestHelmReleaseUpdateMock).not.toHaveBeenCalled(); }); describe("when toggling to see only user defined values", () => { beforeEach(() => { requestHelmReleaseConfigurationMock.mockClear(); const toggle = rendered.getByTestId( "user-supplied-values-only-checkbox", ); fireEvent.click(toggle); }); it("calls for only user defined configuration", () => { expect(requestHelmReleaseConfigurationMock).toHaveBeenCalledWith( "some-name", "some-namespace", false, ); }); describe("when configuration resolves", () => { beforeEach(async () => { await requestHelmReleaseConfigurationMock.resolve( "some-other-configuration", ); }); it("renders", () => { expect(rendered.baseElement).toMatchSnapshot(); }); it("overrides the user inputted configuration with new configuration", () => { const input = rendered.getByTestId( "monaco-editor-for-helm-release-configuration", ); expect(input).toHaveValue("some-other-configuration"); }); it("when toggling again, calls for all configuration", () => { requestHelmReleaseConfigurationMock.mockClear(); const toggle = rendered.getByTestId( "user-supplied-values-only-checkbox", ); fireEvent.click(toggle); expect(requestHelmReleaseConfigurationMock).toHaveBeenCalledWith( "some-name", "some-namespace", true, ); }); }); }); describe("when saving", () => { beforeEach(() => { const saveButton = rendered.getByTestId( "helm-release-configuration-save-button", ); fireEvent.click(saveButton); }); it("renders", () => { expect(rendered.baseElement).toMatchSnapshot(); }); it("shows spinner", () => { const saveButton = rendered.getByTestId( "helm-release-configuration-save-button", ); expect(saveButton).toHaveClass("waiting"); }); describe("when requestHelmCharts 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", })]); }); describe("when requestHelmChartVersions resolves", () => { beforeEach(async () => { await requestHelmChartVersionsMock.resolve([HelmChart.create({ apiVersion: "1.2.3", version: "1.0.0", created: "at-some-time", name: "some-chart", repo: "some-repo", })]); }); it("calls for update", () => { expect(requestHelmReleaseUpdateMock).toHaveBeenCalledWith( "some-name", "some-namespace", { chart: "some-chart", repo: "some-repo", values: "some-new-configuration", version: "1.0.0", }, ); }); describe("when update resolves with success", () => { beforeEach(async () => { requestHelmReleasesMock.mockClear(); requestHelmReleaseConfigurationMock.mockClear(); await requestHelmReleaseUpdateMock.resolve({ callWasSuccessful: true, }); }); it("renders", () => { expect(rendered.baseElement).toMatchSnapshot(); }); it("does not show spinner anymore", () => { const saveButton = rendered.getByTestId( "helm-release-configuration-save-button", ); expect(saveButton).not.toHaveClass("waiting"); }); it("reloads the configuration", () => { expect(requestHelmReleaseConfigurationMock).toHaveBeenCalledWith( "some-name", "some-namespace", true, ); }); it("shows success notification", () => { expect(showSuccessNotificationMock).toHaveBeenCalled(); }); it("does not show error notification", () => { expect(showCheckedErrorNotificationMock).not.toHaveBeenCalled(); }); }); describe("when update resolves with failure", () => { beforeEach(async () => { requestHelmReleasesMock.mockClear(); requestHelmReleaseConfigurationMock.mockClear(); await requestHelmReleaseUpdateMock.resolve({ callWasSuccessful: false, error: "some-error", }); }); it("renders", () => { expect(rendered.baseElement).toMatchSnapshot(); }); it("does not show spinner anymore", () => { const saveButton = rendered.getByTestId( "helm-release-configuration-save-button", ); expect(saveButton).not.toHaveClass("waiting"); }); it("does not reload the configuration", () => { expect(requestHelmReleaseConfigurationMock).not.toHaveBeenCalled(); }); it("does not show success notification", () => { expect(showSuccessNotificationMock).not.toHaveBeenCalled(); }); it("shows error notification", () => { expect(showCheckedErrorNotificationMock).toHaveBeenCalled(); }); }); }); }); }); }); }); }); }); }); }); }); });