mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Restructure to monorepo (#6907)
* wip: restructure to monorepo Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * refactor create-release-pr to a package Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * build fixes Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * github workflow fixes Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix typo Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * add webpack-env types to core Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix github workflows Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * refactor/fix integration tests Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * lint fix Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * yarn run dev Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * eslint settings for vscode Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * move templates to right package Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * open-lens build fixes Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * integration test fix Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix nx task dependencies Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * use bash shell for unit tests in test workflow Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix test:unit for windows Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix win-ca webpack error in open-lens Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix win-ca webpack error in open-lens Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * fix build:app on windows Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * remove ELECTRON_BUILDER_EXTRA_ARGS Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * sync src/ from master Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> * remove Makefile from core Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com> Signed-off-by: Jari Kolehmainen <jari.kolehmainen@gmail.com>
This commit is contained in:
1 parent
0066ca4ea2
commit
2657df2293
3321 files changed
+28699
-11447
No files matched your search
+10010
File diff suppressed because it is too large.
Load diff
+7578
File diff suppressed because it is too large.
Load diff
+6788
File diff suppressed because it is too large.
Load diff
+2863
File diff suppressed because it is too large.
Load diff
+393
@@ -0,0 +1,393 @@
|
||||
/**
|
||||
* 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 { 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 type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { ExecFile } from "../../common/fs/exec-file.injectable";
|
||||
import execFileInjectable from "../../common/fs/exec-file.injectable";
|
||||
import helmBinaryPathInjectable from "../../main/helm/helm-binary-path.injectable";
|
||||
import getActiveHelmRepositoriesInjectable from "../../main/helm/repositories/get-active-helm-repositories/get-active-helm-repositories.injectable";
|
||||
import type { HelmRepo } from "../../common/helm/helm-repo";
|
||||
import requestPublicHelmRepositoriesInjectable from "./child-features/preferences/renderer/adding-of-public-helm-repository/public-helm-repositories/request-public-helm-repositories.injectable";
|
||||
import isPathInjectable from "../../renderer/components/input/validators/is-path.injectable";
|
||||
import showSuccessNotificationInjectable from "../../renderer/components/notifications/show-success-notification.injectable";
|
||||
import showErrorNotificationInjectable from "../../renderer/components/notifications/show-error-notification.injectable";
|
||||
import type { AsyncResult } from "../../common/utils/async-result";
|
||||
import { testUsingFakeTime } from "../../common/test-utils/use-fake-time";
|
||||
|
||||
describe("add custom helm repository in preferences", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
let showSuccessNotificationMock: jest.Mock;
|
||||
let showErrorNotificationMock: jest.Mock;
|
||||
let rendered: RenderResult;
|
||||
let execFileMock: AsyncFnMock<ExecFile>;
|
||||
let getActiveHelmRepositoriesMock: AsyncFnMock<() => Promise<AsyncResult<HelmRepo[]>>>;
|
||||
|
||||
beforeEach(async () => {
|
||||
jest.useFakeTimers();
|
||||
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
testUsingFakeTime("2021-01-01 12:00:00");
|
||||
|
||||
execFileMock = asyncFn();
|
||||
getActiveHelmRepositoriesMock = asyncFn();
|
||||
showSuccessNotificationMock = jest.fn();
|
||||
showErrorNotificationMock = jest.fn();
|
||||
|
||||
builder.beforeApplicationStart((mainDi) => {
|
||||
mainDi.override(getActiveHelmRepositoriesInjectable, () => getActiveHelmRepositoriesMock);
|
||||
mainDi.override(execFileInjectable, () => execFileMock);
|
||||
mainDi.override(helmBinaryPathInjectable, () => "some-helm-binary-path");
|
||||
});
|
||||
|
||||
builder.beforeWindowStart((windowDi) => {
|
||||
windowDi.override(requestPublicHelmRepositoriesInjectable, () => async () => []);
|
||||
windowDi.override(showSuccessNotificationInjectable, () => showSuccessNotificationMock);
|
||||
windowDi.override(showErrorNotificationInjectable, () => showErrorNotificationMock);
|
||||
|
||||
// TODO: Figure out how to make async validators unit testable
|
||||
windowDi.override(isPathInjectable, () => ({ debounce: 0, validate: async () => {} }));
|
||||
});
|
||||
|
||||
rendered = await builder.render();
|
||||
});
|
||||
|
||||
describe("when navigating to preferences containing helm repositories", () => {
|
||||
beforeEach(async () => {
|
||||
builder.preferences.navigate();
|
||||
builder.preferences.navigation.click("kubernetes");
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("when active repositories resolve", () => {
|
||||
beforeEach(async () => {
|
||||
await Promise.all([
|
||||
getActiveHelmRepositoriesMock.resolve({
|
||||
callWasSuccessful: true,
|
||||
response: [{
|
||||
name: "Some active repository",
|
||||
url: "some-url",
|
||||
cacheFilePath: "/some-cache-file-for-active",
|
||||
}],
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("when selecting to add custom repository", () => {
|
||||
beforeEach(() => {
|
||||
const button = rendered.getByTestId("add-custom-helm-repo-button");
|
||||
|
||||
fireEvent.click(button);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows dialog", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("add-custom-helm-repository-dialog"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
// TODO: Figure out how to close dialog by clicking outside of it
|
||||
xdescribe("when closing the dialog by clicking outside", () => {
|
||||
beforeEach(() => {});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show dialog anymore", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("add-custom-helm-repository-dialog"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when closing the dialog by clicking cancel", () => {
|
||||
beforeEach(() => {
|
||||
const button = rendered.getByTestId("custom-helm-repository-cancel-button");
|
||||
|
||||
fireEvent.click(button);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show dialog anymore", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("add-custom-helm-repository-dialog"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when inputted minimal options for the repository", () => {
|
||||
beforeEach(() => {
|
||||
getActiveHelmRepositoriesMock.mockClear();
|
||||
|
||||
const nameInput = rendered.getByTestId("custom-helm-repository-name-input");
|
||||
|
||||
fireEvent.change(nameInput, { target: { value: "some-custom-repository" }});
|
||||
|
||||
const urlInput = rendered.getByTestId("custom-helm-repository-url-input");
|
||||
|
||||
fireEvent.change(urlInput, { target: { value: "http://some.url" }});
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("when submitted and some time passes", () => {
|
||||
beforeEach(() => {
|
||||
const submitButton = rendered.getByTestId("custom-helm-repository-submit-button");
|
||||
|
||||
fireEvent.click(submitButton);
|
||||
|
||||
// TODO: Remove when debounce is removed from WizardStep.submit
|
||||
jest.runOnlyPendingTimers();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("adds the repository", () => {
|
||||
expect(execFileMock).toHaveBeenCalledWith(
|
||||
"some-helm-binary-path",
|
||||
["repo", "add", "some-custom-repository", "http://some.url"],
|
||||
{
|
||||
maxBuffer: 34359738368,
|
||||
env: {},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("does not reload active repositories yet", () => {
|
||||
expect(getActiveHelmRepositoriesMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not show notification yet", () => {
|
||||
expect(showSuccessNotificationMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("when activation rejects", () => {
|
||||
beforeEach(async () => {
|
||||
await execFileMock.resolve({
|
||||
callWasSuccessful: false,
|
||||
error: Object.assign(new Error("Some error"), {
|
||||
stderr: "",
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows error notification", () => {
|
||||
expect(showErrorNotificationMock).toHaveBeenCalledWith(
|
||||
"Some error",
|
||||
);
|
||||
});
|
||||
|
||||
it("does not show success notification", () => {
|
||||
expect(showSuccessNotificationMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not show dialog anymore", () => {
|
||||
expect(rendered.queryByTestId("add-custom-helm-repository-dialog")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("does not reload active repositories", () => {
|
||||
expect(getActiveHelmRepositoriesMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when activation resolves with success", () => {
|
||||
beforeEach(async () => {
|
||||
await execFileMock.resolveSpecific(
|
||||
[
|
||||
"some-helm-binary-path",
|
||||
["repo", "add", "some-custom-repository", "http://some.url"],
|
||||
],
|
||||
{
|
||||
callWasSuccessful: true,
|
||||
response: "",
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show dialog anymore", () => {
|
||||
expect(rendered.queryByTestId("add-custom-helm-repository-dialog")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("reloads active repositories", () => {
|
||||
expect(getActiveHelmRepositoriesMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("shows success notification", () => {
|
||||
expect(showSuccessNotificationMock).toHaveBeenCalledWith(
|
||||
"Helm repository some-custom-repository has been added.",
|
||||
);
|
||||
});
|
||||
|
||||
describe("when adding custom repository again", () => {
|
||||
beforeEach(() => {
|
||||
const button = rendered.getByTestId("add-custom-helm-repo-button");
|
||||
|
||||
fireEvent.click(button);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("repository name is empty", () => {
|
||||
const input = rendered.getByTestId("custom-helm-repository-name-input") as HTMLInputElement;
|
||||
|
||||
expect(input.value).toBe("");
|
||||
});
|
||||
|
||||
it("repository url is empty", () => {
|
||||
const input = rendered.getByTestId("custom-helm-repository-url-input") as HTMLInputElement;
|
||||
|
||||
expect(input.value).toBe("");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when showing the maximal options", () => {
|
||||
beforeEach(() => {
|
||||
const button = rendered.getByTestId("toggle-maximal-options-for-custom-helm-repository-button");
|
||||
|
||||
fireEvent.click(button);
|
||||
});
|
||||
|
||||
it("shows maximal options", () => {
|
||||
const maximalOptions = rendered.getByTestId("maximal-options-for-custom-helm-repository-dialog");
|
||||
|
||||
expect(maximalOptions).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("given closing the dialog, when reopening the dialog, still shows maximal options", () => {
|
||||
const cancelButton = rendered.getByTestId("custom-helm-repository-cancel-button");
|
||||
|
||||
fireEvent.click(cancelButton);
|
||||
|
||||
const openButton = rendered.getByTestId("add-custom-helm-repo-button");
|
||||
|
||||
fireEvent.click(openButton);
|
||||
|
||||
const maximalOptions = rendered.getByTestId("maximal-options-for-custom-helm-repository-dialog");
|
||||
|
||||
expect(maximalOptions).toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe("when hiding maximal options", () => {
|
||||
beforeEach(() => {
|
||||
const button = rendered.getByTestId("toggle-maximal-options-for-custom-helm-repository-button");
|
||||
|
||||
fireEvent.click(button);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show maximal options anymore", () => {
|
||||
const maximalOptions = rendered.queryByTestId("maximal-options-for-custom-helm-repository-dialog");
|
||||
|
||||
expect(maximalOptions).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when inputted maximal options", () => {
|
||||
beforeEach(async () => {
|
||||
[
|
||||
{ selector: "username-input", value: "some-username" },
|
||||
{ selector: "password-input", value: "some-password" },
|
||||
{ selector: "ca-cert-file-input", value: "some-ca-cert-file" },
|
||||
{ selector: "cert-file-input", value: "some-cert-file" },
|
||||
{ selector: "key-file-input", value: "some-key-file" },
|
||||
].forEach(({ selector, value }) => {
|
||||
const input = rendered.getByTestId(`custom-helm-repository-${selector}`);
|
||||
|
||||
fireEvent.change(input, { target: { value }});
|
||||
});
|
||||
|
||||
const checkbox = rendered.getByTestId(`custom-helm-repository-verify-tls-input`);
|
||||
|
||||
fireEvent.click(checkbox);
|
||||
|
||||
jest.runOnlyPendingTimers();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("when submitted and some time passes, adds the repository with maximal options", () => {
|
||||
const submitButton = rendered.getByTestId("custom-helm-repository-submit-button");
|
||||
|
||||
fireEvent.click(submitButton);
|
||||
|
||||
// TODO: Remove when debounce is removed from WizardStep.submit
|
||||
jest.runOnlyPendingTimers();
|
||||
|
||||
expect(execFileMock).toHaveBeenCalledWith(
|
||||
"some-helm-binary-path",
|
||||
[
|
||||
"repo",
|
||||
"add",
|
||||
"some-custom-repository",
|
||||
"http://some.url",
|
||||
"--insecure-skip-tls-verify",
|
||||
"--username",
|
||||
"some-username",
|
||||
"--password",
|
||||
"some-password",
|
||||
"--ca-file",
|
||||
"some-ca-cert-file",
|
||||
"--key-file",
|
||||
"some-key-file",
|
||||
"--cert-file",
|
||||
"some-cert-file",
|
||||
],
|
||||
{
|
||||
maxBuffer: 34359738368,
|
||||
env: {},
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
+297
@@ -0,0 +1,297 @@
|
||||
/**
|
||||
* 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 type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { ExecFile } from "../../common/fs/exec-file.injectable";
|
||||
import execFileInjectable from "../../common/fs/exec-file.injectable";
|
||||
import helmBinaryPathInjectable from "../../main/helm/helm-binary-path.injectable";
|
||||
import getActiveHelmRepositoriesInjectable from "../../main/helm/repositories/get-active-helm-repositories/get-active-helm-repositories.injectable";
|
||||
import type { HelmRepo } from "../../common/helm/helm-repo";
|
||||
import requestPublicHelmRepositoriesInjectable from "./child-features/preferences/renderer/adding-of-public-helm-repository/public-helm-repositories/request-public-helm-repositories.injectable";
|
||||
import showSuccessNotificationInjectable from "../../renderer/components/notifications/show-success-notification.injectable";
|
||||
import showErrorNotificationInjectable from "../../renderer/components/notifications/show-error-notification.injectable";
|
||||
import type { AsyncResult } from "../../common/utils/async-result";
|
||||
|
||||
describe("add helm repository from list in preferences", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
let showSuccessNotificationMock: jest.Mock;
|
||||
let showErrorNotificationMock: jest.Mock;
|
||||
let rendered: RenderResult;
|
||||
let execFileMock: AsyncFnMock<ExecFile>;
|
||||
let getActiveHelmRepositoriesMock: AsyncFnMock<() => Promise<AsyncResult<HelmRepo[]>>>;
|
||||
let callForPublicHelmRepositoriesMock: AsyncFnMock<() => Promise<HelmRepo[]>>;
|
||||
|
||||
beforeEach(async () => {
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
execFileMock = asyncFn();
|
||||
getActiveHelmRepositoriesMock = asyncFn();
|
||||
callForPublicHelmRepositoriesMock = asyncFn();
|
||||
showSuccessNotificationMock = jest.fn();
|
||||
showErrorNotificationMock = jest.fn();
|
||||
|
||||
builder.beforeApplicationStart((mainDi) => {
|
||||
mainDi.override(getActiveHelmRepositoriesInjectable, () => getActiveHelmRepositoriesMock);
|
||||
mainDi.override(execFileInjectable, () => execFileMock);
|
||||
mainDi.override(helmBinaryPathInjectable, () => "some-helm-binary-path");
|
||||
});
|
||||
|
||||
builder.beforeWindowStart((windowDi) => {
|
||||
windowDi.override(showSuccessNotificationInjectable, () => showSuccessNotificationMock);
|
||||
windowDi.override(showErrorNotificationInjectable, () => showErrorNotificationMock);
|
||||
windowDi.override(requestPublicHelmRepositoriesInjectable, () => callForPublicHelmRepositoriesMock);
|
||||
});
|
||||
|
||||
rendered = await builder.render();
|
||||
});
|
||||
|
||||
describe("when navigating to preferences containing helm repositories", () => {
|
||||
beforeEach(() => {
|
||||
builder.preferences.navigate();
|
||||
builder.preferences.navigation.click("kubernetes");
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("calls for public repositories", () => {
|
||||
expect(callForPublicHelmRepositoriesMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("calls for active repositories", () => {
|
||||
expect(getActiveHelmRepositoriesMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("when both active and public repositories resolve", () => {
|
||||
beforeEach(async () => {
|
||||
await Promise.all([
|
||||
callForPublicHelmRepositoriesMock.resolve([
|
||||
{
|
||||
name: "Some already active repository",
|
||||
url: "some-url",
|
||||
cacheFilePath: "/some-cache-file-for-active",
|
||||
},
|
||||
{
|
||||
name: "Some to be added repository",
|
||||
url: "some-other-url",
|
||||
cacheFilePath: "/some-cache-file-for-non-active",
|
||||
},
|
||||
]),
|
||||
|
||||
getActiveHelmRepositoriesMock.resolve({
|
||||
callWasSuccessful: true,
|
||||
response: [{
|
||||
name: "Some already active repository",
|
||||
url: "some-url",
|
||||
cacheFilePath: "/some-cache-file-for-active",
|
||||
}],
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("when select for adding public repositories is clicked", () => {
|
||||
beforeEach(() => {
|
||||
builder.select.openMenu(
|
||||
"selection-of-active-public-helm-repository",
|
||||
);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("when deactive public repository is selected", () => {
|
||||
beforeEach(async () => {
|
||||
getActiveHelmRepositoriesMock.mockClear();
|
||||
|
||||
builder.select.selectOption(
|
||||
"selection-of-active-public-helm-repository",
|
||||
"Some to be added repository",
|
||||
);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("adds the repository", () => {
|
||||
expect(execFileMock).toHaveBeenCalledWith(
|
||||
"some-helm-binary-path",
|
||||
["repo", "add", "Some to be added repository", "some-other-url"],
|
||||
{
|
||||
maxBuffer: 34359738368,
|
||||
env: {},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("does not reload active repositories yet", () => {
|
||||
expect(getActiveHelmRepositoriesMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("when adding rejects", () => {
|
||||
beforeEach(async () => {
|
||||
await execFileMock.resolve({
|
||||
callWasSuccessful: false,
|
||||
error: Object.assign(new Error("Some error"), {
|
||||
stderr: "",
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows error notification", () => {
|
||||
expect(showErrorNotificationMock).toHaveBeenCalledWith(
|
||||
"Some error",
|
||||
);
|
||||
});
|
||||
|
||||
it("does not show success notification", () => {
|
||||
expect(showSuccessNotificationMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not show dialog anymore", () => {
|
||||
expect(rendered.queryByTestId("add-custom-helm-repository-dialog")).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("does not reload active repositories", () => {
|
||||
expect(getActiveHelmRepositoriesMock).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when adding resolves", () => {
|
||||
beforeEach(async () => {
|
||||
await execFileMock.resolveSpecific(
|
||||
[
|
||||
"some-helm-binary-path",
|
||||
["repo", "add", "Some to be added repository", "some-other-url"],
|
||||
],
|
||||
{
|
||||
callWasSuccessful: true,
|
||||
response: "",
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("reloads active repositories", () => {
|
||||
expect(getActiveHelmRepositoriesMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("shows success notification", () => {
|
||||
expect(showSuccessNotificationMock).toHaveBeenCalledWith(
|
||||
"Helm repository Some to be added repository has been added.",
|
||||
);
|
||||
});
|
||||
|
||||
describe("when active repositories resolve again", () => {
|
||||
beforeEach(async () => {
|
||||
await getActiveHelmRepositoriesMock.resolve({
|
||||
callWasSuccessful: true,
|
||||
response: [
|
||||
{
|
||||
name: "Some already active repository",
|
||||
url: "some-url",
|
||||
cacheFilePath: "/some-cache-file-for-active",
|
||||
},
|
||||
{
|
||||
name: "Some to be added repository",
|
||||
url: "some-other-url",
|
||||
cacheFilePath: "/some-cache-file-for-non-active",
|
||||
},
|
||||
],
|
||||
});
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("when select for selecting active repositories is clicked", () => {
|
||||
beforeEach(() => {
|
||||
builder.select.openMenu(
|
||||
"selection-of-active-public-helm-repository",
|
||||
);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("when active repository is selected", () => {
|
||||
beforeEach(() => {
|
||||
execFileMock.mockClear();
|
||||
getActiveHelmRepositoriesMock.mockClear();
|
||||
|
||||
builder.select.selectOption(
|
||||
"selection-of-active-public-helm-repository",
|
||||
"Some already active repository",
|
||||
);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("removes the repository", () => {
|
||||
expect(execFileMock).toHaveBeenCalledWith(
|
||||
"some-helm-binary-path",
|
||||
["repo", "remove", "Some already active repository"],
|
||||
{
|
||||
maxBuffer: 34359738368,
|
||||
env: {},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("does not reload active repositories yet", () => {
|
||||
expect(getActiveHelmRepositoriesMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("when removing resolves", () => {
|
||||
beforeEach(async () => {
|
||||
await execFileMock.resolveSpecific(
|
||||
[
|
||||
"some-helm-binary-path",
|
||||
["repo", "remove", "Some already active repository"],
|
||||
],
|
||||
{
|
||||
callWasSuccessful: true,
|
||||
response: "",
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("reloads active repositories", () => {
|
||||
expect(getActiveHelmRepositoriesMock).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/**
|
||||
* 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 { asyncComputed } from "@ogre-tools/injectable-react";
|
||||
import { getActiveHelmRepositoriesChannel } from "../../../../../common/helm/get-active-helm-repositories-channel";
|
||||
import { requestFromChannelInjectionToken } from "../../../../../common/utils/channel/request-from-channel-injection-token";
|
||||
import showErrorNotificationInjectable from "../../../../../renderer/components/notifications/show-error-notification.injectable";
|
||||
import helmRepositoriesErrorStateInjectable from "./helm-repositories-error-state.injectable";
|
||||
import { runInAction } from "mobx";
|
||||
|
||||
const activeHelmRepositoriesInjectable = getInjectable({
|
||||
id: "active-helm-repositories",
|
||||
|
||||
instantiate: (di) => {
|
||||
const requestFromChannel = di.inject(requestFromChannelInjectionToken);
|
||||
const showErrorNotification = di.inject(showErrorNotificationInjectable);
|
||||
const helmRepositoriesErrorState = di.inject(
|
||||
helmRepositoriesErrorStateInjectable,
|
||||
);
|
||||
|
||||
return asyncComputed({
|
||||
getValueFromObservedPromise: async () => {
|
||||
const result = await requestFromChannel(
|
||||
getActiveHelmRepositoriesChannel,
|
||||
);
|
||||
|
||||
if (result.callWasSuccessful) {
|
||||
return result.response;
|
||||
} else {
|
||||
showErrorNotification(result.error);
|
||||
|
||||
runInAction(() =>
|
||||
helmRepositoriesErrorState.set({
|
||||
controlsAreShown: false,
|
||||
errorMessage: result.error,
|
||||
}),
|
||||
);
|
||||
|
||||
return [];
|
||||
}
|
||||
},
|
||||
|
||||
valueWhenPending: [],
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default activeHelmRepositoriesInjectable;
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
.AddHelmRepoDialog {
|
||||
--flex-gap: #{$margin * 1.5};
|
||||
|
||||
.accordion {
|
||||
font-weight: bold;
|
||||
align-self: flex-start;
|
||||
padding: 0;
|
||||
&:focus:not(:active) {
|
||||
box-shadow: none;
|
||||
}
|
||||
}
|
||||
.Icon {
|
||||
--color-active: black;
|
||||
}
|
||||
|
||||
.fields-title {
|
||||
display: grid;
|
||||
grid-template-columns: min-content auto;
|
||||
align-items: center;
|
||||
gap: $margin * 0.5;
|
||||
}
|
||||
}
|
||||
+154
@@ -0,0 +1,154 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import "./add-helm-repo-dialog.scss";
|
||||
|
||||
import React from "react";
|
||||
import { Wizard, WizardStep } from "../../../../../../renderer/components/wizard";
|
||||
import { Input } from "../../../../../../renderer/components/input";
|
||||
import { isUrl, systemName } from "../../../../../../renderer/components/input/input_validators";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import customHelmRepoInjectable from "./custom-helm-repo.injectable";
|
||||
import type { HelmRepo } from "../../../../../../common/helm/helm-repo";
|
||||
import { observer } from "mobx-react";
|
||||
import type { IObservableValue } from "mobx";
|
||||
import { action } from "mobx";
|
||||
import submitCustomHelmRepositoryInjectable from "./submit-custom-helm-repository.injectable";
|
||||
import hideDialogForAddingCustomHelmRepositoryInjectable from "./dialog-visibility/hide-dialog-for-adding-custom-helm-repository.injectable";
|
||||
import { Button } from "../../../../../../renderer/components/button";
|
||||
import { Icon } from "../../../../../../renderer/components/icon";
|
||||
import maximalCustomHelmRepoOptionsAreShownInjectable from "./maximal-custom-helm-repo-options-are-shown.injectable";
|
||||
import { SubTitle } from "../../../../../../renderer/components/layout/sub-title";
|
||||
import { Checkbox } from "../../../../../../renderer/components/checkbox";
|
||||
import { HelmFileInput } from "./helm-file-input/helm-file-input";
|
||||
import { toJS } from "../../../../../../common/utils";
|
||||
|
||||
interface Dependencies {
|
||||
helmRepo: HelmRepo;
|
||||
hideDialog: () => void;
|
||||
submitCustomRepository: (repository: HelmRepo) => Promise<void>;
|
||||
maximalOptionsAreShown: IObservableValue<boolean>;
|
||||
}
|
||||
|
||||
const NonInjectedActivationOfCustomHelmRepositoryDialogContent = observer(({
|
||||
helmRepo,
|
||||
submitCustomRepository,
|
||||
maximalOptionsAreShown,
|
||||
hideDialog,
|
||||
} : Dependencies) => (
|
||||
<Wizard header={<h5>Add custom Helm Repo</h5>} done={hideDialog}>
|
||||
<WizardStep
|
||||
contentClass="flow column"
|
||||
nextLabel="Add"
|
||||
next={() => submitCustomRepository(toJS(helmRepo))}
|
||||
testIdForNext="custom-helm-repository-submit-button"
|
||||
testIdForPrev="custom-helm-repository-cancel-button"
|
||||
>
|
||||
<div className="flex column gaps" data-testid="add-custom-helm-repository-dialog">
|
||||
<Input
|
||||
autoFocus
|
||||
required
|
||||
placeholder="Helm repo name"
|
||||
trim
|
||||
validators={systemName}
|
||||
value={helmRepo.name}
|
||||
onChange={action(v => helmRepo.name = v)}
|
||||
data-testid="custom-helm-repository-name-input"
|
||||
/>
|
||||
<Input
|
||||
required
|
||||
placeholder="URL"
|
||||
validators={isUrl}
|
||||
value={helmRepo.url}
|
||||
onChange={action(v => helmRepo.url = v)}
|
||||
data-testid="custom-helm-repository-url-input"
|
||||
/>
|
||||
<Button
|
||||
plain
|
||||
className="accordion"
|
||||
data-testid="toggle-maximal-options-for-custom-helm-repository-button"
|
||||
onClick={action(() => maximalOptionsAreShown.set(!maximalOptionsAreShown.get()))}
|
||||
>
|
||||
More
|
||||
<Icon
|
||||
small
|
||||
tooltip="More"
|
||||
material={maximalOptionsAreShown.get() ? "remove" : "add"}
|
||||
/>
|
||||
</Button>
|
||||
|
||||
{maximalOptionsAreShown.get() && (
|
||||
<div data-testid="maximal-options-for-custom-helm-repository-dialog">
|
||||
<SubTitle title="Security settings" />
|
||||
|
||||
<Checkbox
|
||||
label="Skip TLS certificate checks for the repository"
|
||||
value={helmRepo.insecureSkipTlsVerify}
|
||||
onChange={action(v => {
|
||||
helmRepo.insecureSkipTlsVerify = v;
|
||||
})}
|
||||
data-testid="custom-helm-repository-verify-tls-input"
|
||||
/>
|
||||
|
||||
<HelmFileInput
|
||||
placeholder="Key file"
|
||||
value={helmRepo.keyFile || ""}
|
||||
setValue={action((value) => helmRepo.keyFile = value)}
|
||||
fileExtensions={keyExtensions}
|
||||
data-testid="custom-helm-repository-key-file-input"
|
||||
/>
|
||||
|
||||
<HelmFileInput
|
||||
placeholder="Ca file"
|
||||
value={helmRepo.caFile || ""}
|
||||
setValue={action((value) => helmRepo.caFile = value)}
|
||||
fileExtensions={certExtensions}
|
||||
data-testid="custom-helm-repository-ca-cert-file-input"
|
||||
/>
|
||||
|
||||
<HelmFileInput
|
||||
placeholder="Certificate file"
|
||||
value={helmRepo.certFile || ""}
|
||||
setValue={action((value) => helmRepo.certFile = value)}
|
||||
fileExtensions={certExtensions}
|
||||
data-testid="custom-helm-repository-cert-file-input"
|
||||
/>
|
||||
|
||||
<SubTitle title="Chart Repository Credentials" />
|
||||
|
||||
<Input
|
||||
placeholder="Username"
|
||||
value={helmRepo.username}
|
||||
onChange= {action(v => helmRepo.username = v)}
|
||||
data-testid="custom-helm-repository-username-input"
|
||||
/>
|
||||
<Input
|
||||
type="password"
|
||||
placeholder="Password"
|
||||
value={helmRepo.password}
|
||||
onChange={action(v => helmRepo.password = v)}
|
||||
data-testid="custom-helm-repository-password-input"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</WizardStep>
|
||||
</Wizard>
|
||||
));
|
||||
|
||||
|
||||
|
||||
export const AddingOfCustomHelmRepositoryDialogContent = withInjectables<Dependencies>(NonInjectedActivationOfCustomHelmRepositoryDialogContent, {
|
||||
getProps: (di) => ({
|
||||
helmRepo: di.inject(customHelmRepoInjectable),
|
||||
hideDialog: di.inject(hideDialogForAddingCustomHelmRepositoryInjectable),
|
||||
submitCustomRepository: di.inject(submitCustomHelmRepositoryInjectable),
|
||||
maximalOptionsAreShown: di.inject(maximalCustomHelmRepoOptionsAreShownInjectable),
|
||||
}),
|
||||
});
|
||||
|
||||
const keyExtensions = ["key", "keystore", "jks", "p12", "pfx", "pem"];
|
||||
const certExtensions = ["crt", "cer", "ca-bundle", "p7b", "p7c", "p7s", "p12", "pfx", "pem"];
|
||||
|
||||
+47
@@ -0,0 +1,47 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import "./add-helm-repo-dialog.scss";
|
||||
|
||||
import React from "react";
|
||||
import { Dialog } from "../../../../../../renderer/components/dialog";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import { AddingOfCustomHelmRepositoryDialogContent } from "./adding-of-custom-helm-repository-dialog-content";
|
||||
import addingOfCustomHelmRepositoryDialogIsVisibleInjectable from "./dialog-visibility/adding-of-custom-helm-repository-dialog-is-visible.injectable";
|
||||
import type { IObservableValue } from "mobx";
|
||||
import { observer } from "mobx-react";
|
||||
import hideDialogForAddingCustomHelmRepositoryInjectable from "./dialog-visibility/hide-dialog-for-adding-custom-helm-repository.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
contentIsVisible: IObservableValue<boolean>;
|
||||
hideDialog: () => void;
|
||||
}
|
||||
|
||||
const NonInjectedActivationOfCustomHelmRepositoryDialog = observer(({
|
||||
contentIsVisible,
|
||||
hideDialog,
|
||||
}: Dependencies) => (
|
||||
<div>
|
||||
<Dialog
|
||||
className="AddHelmRepoDialog"
|
||||
isOpen={contentIsVisible.get()}
|
||||
close={hideDialog}
|
||||
>
|
||||
{contentIsVisible.get() && <AddingOfCustomHelmRepositoryDialogContent />}
|
||||
</Dialog>
|
||||
</div>
|
||||
));
|
||||
|
||||
|
||||
export const AddingOfCustomHelmRepositoryDialog = withInjectables<Dependencies>(
|
||||
NonInjectedActivationOfCustomHelmRepositoryDialog,
|
||||
|
||||
{
|
||||
getProps: (di) => ({
|
||||
contentIsVisible: di.inject(addingOfCustomHelmRepositoryDialogIsVisibleInjectable),
|
||||
hideDialog: di.inject(hideDialogForAddingCustomHelmRepositoryInjectable),
|
||||
}),
|
||||
},
|
||||
);
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import React from "react";
|
||||
import { Button } from "../../../../../../renderer/components/button";
|
||||
import showDialogForAddingCustomHelmRepositoryInjectable from "./dialog-visibility/show-dialog-for-adding-custom-helm-repository.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
showDialog: () => void;
|
||||
}
|
||||
|
||||
const NonInjectedActivationOfCustomHelmRepositoryOpenButton = ({ showDialog }: Dependencies) => (
|
||||
<Button
|
||||
primary
|
||||
label="Add Custom Helm Repo"
|
||||
onClick={showDialog}
|
||||
data-testid="add-custom-helm-repo-button"
|
||||
/>
|
||||
);
|
||||
|
||||
export const AddingOfCustomHelmRepositoryOpenButton = withInjectables<Dependencies>(
|
||||
NonInjectedActivationOfCustomHelmRepositoryOpenButton,
|
||||
|
||||
{
|
||||
getProps: (di) => ({
|
||||
showDialog: di.inject(showDialogForAddingCustomHelmRepositoryInjectable),
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* 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 { observable } from "mobx";
|
||||
import type { HelmRepo } from "../../../../../../common/helm/helm-repo";
|
||||
|
||||
const customHelmRepoInjectable = getInjectable({
|
||||
id: "custom-helm-repo",
|
||||
|
||||
instantiate: () => observable.object<HelmRepo>({
|
||||
name: "",
|
||||
url: "",
|
||||
username: "",
|
||||
password: "",
|
||||
insecureSkipTlsVerify: false,
|
||||
caFile: "",
|
||||
keyFile: "",
|
||||
certFile: "",
|
||||
cacheFilePath: "",
|
||||
}),
|
||||
|
||||
lifecycle: lifecycleEnum.transient,
|
||||
});
|
||||
|
||||
export default customHelmRepoInjectable;
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* 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 { observable } from "mobx";
|
||||
|
||||
const addingOfCustomHelmRepositoryDialogIsVisibleInjectable = getInjectable({
|
||||
id: "adding-of-custom-helm-repository-dialog-is-visible",
|
||||
instantiate: () => observable.box(false),
|
||||
});
|
||||
|
||||
export default addingOfCustomHelmRepositoryDialogIsVisibleInjectable;
|
||||
+21
@@ -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 } from "@ogre-tools/injectable";
|
||||
import { action } from "mobx";
|
||||
import addingOfCustomHelmRepositoryDialogIsVisibleInjectable from "./adding-of-custom-helm-repository-dialog-is-visible.injectable";
|
||||
|
||||
const hideDialogForAddingCustomHelmRepositoryInjectable = getInjectable({
|
||||
id: "hide-dialog-for-adding-custom-helm-repository",
|
||||
|
||||
instantiate: (di) => {
|
||||
const state = di.inject(addingOfCustomHelmRepositoryDialogIsVisibleInjectable);
|
||||
|
||||
return action(() => {
|
||||
state.set(false);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default hideDialogForAddingCustomHelmRepositoryInjectable;
|
||||
+21
@@ -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 } from "@ogre-tools/injectable";
|
||||
import { action } from "mobx";
|
||||
import addingOfCustomHelmRepositoryDialogIsVisibleInjectable from "./adding-of-custom-helm-repository-dialog-is-visible.injectable";
|
||||
|
||||
const showDialogForAddingCustomHelmRepositoryInjectable = getInjectable({
|
||||
id: "show-dialog-for-adding-custom-helm-repository",
|
||||
|
||||
instantiate: (di) => {
|
||||
const state = di.inject(addingOfCustomHelmRepositoryDialogIsVisibleInjectable);
|
||||
|
||||
return action(() => {
|
||||
state.set(true);
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default showDialogForAddingCustomHelmRepositoryInjectable;
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/**
|
||||
* 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 { FileFilter } from "electron";
|
||||
import type { PathPickOpts } from "../../../../../../../renderer/components/path-picker";
|
||||
import openPathPickingDialogInjectable from "../../../../../../path-picking-dialog/renderer/pick-paths.injectable";
|
||||
|
||||
export interface RequestFilePathOptions extends Pick<PathPickOpts, "onCancel" | "onPick"> {
|
||||
filter: FileFilter;
|
||||
}
|
||||
|
||||
export type RequestFilePaths = (options: RequestFilePathOptions) => Promise<void>;
|
||||
|
||||
const requestFilePathsInjectable = getInjectable({
|
||||
id: "request-file-paths",
|
||||
|
||||
instantiate: (di): RequestFilePaths => {
|
||||
const openPathPickingDialog = di.inject(openPathPickingDialogInjectable);
|
||||
|
||||
return async ({ filter, ...opts }) => await openPathPickingDialog({
|
||||
properties: ["openFile", "showHiddenFiles"],
|
||||
message: "Select file",
|
||||
buttonLabel: "Use file",
|
||||
filters: [filter, { name: "Any", extensions: ["*"] }],
|
||||
...opts,
|
||||
});
|
||||
},
|
||||
});
|
||||
|
||||
export default requestFilePathsInjectable;
|
||||
+69
@@ -0,0 +1,69 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { InputValidator } from "../../../../../../../renderer/components/input";
|
||||
import { Input } from "../../../../../../../renderer/components/input";
|
||||
import { Icon } from "../../../../../../../renderer/components/icon";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import React from "react";
|
||||
import type { RequestFilePaths } from "./get-file-paths.injectable";
|
||||
import requestFilePathsInjectable from "./get-file-paths.injectable";
|
||||
import isPathInjectable from "../../../../../../../renderer/components/input/validators/is-path.injectable";
|
||||
|
||||
interface HelmFileInputProps {
|
||||
placeholder: string;
|
||||
fileExtensions: string[];
|
||||
value: string;
|
||||
setValue: (value: string) => void;
|
||||
"data-testid"?: string;
|
||||
}
|
||||
|
||||
interface Dependencies {
|
||||
requestFilePaths: RequestFilePaths;
|
||||
isPath: InputValidator<true>;
|
||||
}
|
||||
|
||||
const NonInjectedHelmFileInput = ({
|
||||
placeholder,
|
||||
value,
|
||||
setValue,
|
||||
fileExtensions,
|
||||
requestFilePaths,
|
||||
isPath,
|
||||
"data-testid": testId,
|
||||
}: Dependencies & HelmFileInputProps) => (
|
||||
<div className="flex gaps align-center">
|
||||
<Input
|
||||
placeholder={placeholder}
|
||||
validators={isPath}
|
||||
className="box grow"
|
||||
value={value}
|
||||
onChange={(v) => setValue(v)}
|
||||
data-testid={testId}
|
||||
/>
|
||||
<Icon
|
||||
material="folder"
|
||||
onClick={() => void requestFilePaths({
|
||||
filter: {
|
||||
name: placeholder,
|
||||
extensions: fileExtensions,
|
||||
},
|
||||
onPick: (filePaths) => {
|
||||
if (filePaths.length) {
|
||||
setValue(filePaths[0]);
|
||||
}
|
||||
},
|
||||
})}
|
||||
tooltip="Browse"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
|
||||
export const HelmFileInput = withInjectables<Dependencies, HelmFileInputProps>(NonInjectedHelmFileInput, {
|
||||
getProps: (di, props) => ({
|
||||
...props,
|
||||
requestFilePaths: di.inject(requestFilePathsInjectable),
|
||||
isPath: di.inject(isPathInjectable),
|
||||
}),
|
||||
});
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
/**
|
||||
* 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 { observable } from "mobx";
|
||||
|
||||
const maximalCustomHelmRepoOptionsAreShownInjectable = getInjectable({
|
||||
id: "maximal-custom-helm-repo-options-are-shown",
|
||||
instantiate: () => observable.box(false),
|
||||
});
|
||||
|
||||
export default maximalCustomHelmRepoOptionsAreShownInjectable;
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* 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 { HelmRepo } from "../../../../../../common/helm/helm-repo";
|
||||
import addHelmRepositoryInjectable from "../adding-of-public-helm-repository/select-helm-repository/add-helm-repository.injectable";
|
||||
import hideDialogForAddingCustomHelmRepositoryInjectable from "./dialog-visibility/hide-dialog-for-adding-custom-helm-repository.injectable";
|
||||
|
||||
const submitCustomHelmRepositoryInjectable = getInjectable({
|
||||
id: "submit-custom-helm-repository",
|
||||
|
||||
instantiate: (di) => {
|
||||
const addHelmRepository = di.inject(addHelmRepositoryInjectable);
|
||||
const hideDialog = di.inject(hideDialogForAddingCustomHelmRepositoryInjectable);
|
||||
|
||||
return async (repository: HelmRepo) => {
|
||||
await addHelmRepository(repository);
|
||||
|
||||
hideDialog();
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default submitCustomHelmRepositoryInjectable;
|
||||
+80
@@ -0,0 +1,80 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
import type { IAsyncComputed } from "@ogre-tools/injectable-react";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import React from "react";
|
||||
import publicHelmRepositoriesInjectable from "./public-helm-repositories/public-helm-repositories.injectable";
|
||||
import type { HelmRepo } from "../../../../../../common/helm/helm-repo";
|
||||
import type { SelectOption } from "../../../../../../renderer/components/select";
|
||||
import { Select } from "../../../../../../renderer/components/select";
|
||||
import { Icon } from "../../../../../../renderer/components/icon";
|
||||
import { observer } from "mobx-react";
|
||||
import type { SingleValue } from "react-select";
|
||||
import selectHelmRepositoryInjectable from "./select-helm-repository/select-helm-repository.injectable";
|
||||
import { matches } from "lodash/fp";
|
||||
import activeHelmRepositoriesInjectable from "../active-helm-repositories.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
publicRepositories: IAsyncComputed<HelmRepo[]>;
|
||||
activeRepositories: IAsyncComputed<HelmRepo[]>;
|
||||
selectRepository: (value: SingleValue<SelectOption<HelmRepo>>) => void;
|
||||
}
|
||||
|
||||
const NonInjectedAddingOfPublicHelmRepository = observer(({
|
||||
publicRepositories,
|
||||
activeRepositories,
|
||||
selectRepository,
|
||||
}: Dependencies) => {
|
||||
const dereferencesPublicRepositories = publicRepositories.value.get();
|
||||
const dereferencesActiveRepositories = activeRepositories.value.get();
|
||||
|
||||
const valuesAreLoading = publicRepositories.pending.get() || activeRepositories.pending.get();
|
||||
|
||||
const repositoryOptions = dereferencesPublicRepositories.map(repository => ({
|
||||
value: repository,
|
||||
label: repository.name,
|
||||
isSelected: !!dereferencesActiveRepositories.find(matches({ name: repository.name })),
|
||||
}));
|
||||
|
||||
return (
|
||||
<Select
|
||||
id="selection-of-active-public-helm-repository"
|
||||
placeholder="Repositories"
|
||||
isLoading={valuesAreLoading}
|
||||
isDisabled={valuesAreLoading}
|
||||
options={repositoryOptions}
|
||||
onChange={selectRepository}
|
||||
value={dereferencesPublicRepositories}
|
||||
formatOptionLabel={formatOptionLabel}
|
||||
controlShouldRenderValue={false}
|
||||
className="box grow"
|
||||
themeName="lens"
|
||||
/>
|
||||
);
|
||||
});
|
||||
|
||||
export const AddingOfPublicHelmRepository = withInjectables<Dependencies>(
|
||||
NonInjectedAddingOfPublicHelmRepository,
|
||||
|
||||
{
|
||||
getProps: (di) => ({
|
||||
publicRepositories: di.inject(publicHelmRepositoriesInjectable),
|
||||
activeRepositories: di.inject(activeHelmRepositoriesInjectable),
|
||||
selectRepository: di.inject(selectHelmRepositoryInjectable),
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
const formatOptionLabel = ({ value, isSelected }: SelectOption<HelmRepo>) => (
|
||||
<div className="flex gaps">
|
||||
<span>{value.name}</span>
|
||||
{isSelected && (
|
||||
<Icon
|
||||
small
|
||||
material="check"
|
||||
className="box right" />
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/**
|
||||
* 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 { asyncComputed } from "@ogre-tools/injectable-react";
|
||||
import requestPublicHelmRepositoriesInjectable from "./request-public-helm-repositories.injectable";
|
||||
|
||||
const publicHelmRepositoriesInjectable = getInjectable({
|
||||
id: "public-helm-repositories",
|
||||
|
||||
instantiate: (di) => asyncComputed({
|
||||
getValueFromObservedPromise: di.inject(requestPublicHelmRepositoriesInjectable),
|
||||
valueWhenPending: [],
|
||||
}),
|
||||
});
|
||||
|
||||
export default publicHelmRepositoriesInjectable;
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import { getGlobalOverrideForFunction } from "../../../../../../../common/test-utils/get-global-override-for-function";
|
||||
import requestPublicHelmRepositoriesInjectable from "./request-public-helm-repositories.injectable";
|
||||
|
||||
export default getGlobalOverrideForFunction(requestPublicHelmRepositoriesInjectable);
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/**
|
||||
* 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 { sortBy } from "lodash/fp";
|
||||
import proxyDownloadJsonInjectable from "../../../../../../../common/fetch/download-json/proxy.injectable";
|
||||
import { withTimeout } from "../../../../../../../common/fetch/timeout-controller";
|
||||
import type { HelmRepo } from "../../../../../../../common/helm/helm-repo";
|
||||
import loggerInjectable from "../../../../../../../common/logger.injectable";
|
||||
|
||||
const publicHelmReposUrl = "https://github.com/lensapp/artifact-hub-repositories/releases/download/latest/repositories.json";
|
||||
|
||||
const requestPublicHelmRepositoriesInjectable = getInjectable({
|
||||
id: "request-public-helm-repositories",
|
||||
|
||||
instantiate: (di) => {
|
||||
const downloadJson = di.inject(proxyDownloadJsonInjectable);
|
||||
const logger = di.inject(loggerInjectable);
|
||||
|
||||
return async (): Promise<HelmRepo[]> => {
|
||||
const controller = withTimeout(10_000);
|
||||
const result = await downloadJson(publicHelmReposUrl, {
|
||||
signal: controller.signal,
|
||||
});
|
||||
|
||||
if (!result.callWasSuccessful) {
|
||||
logger.warn(`Failed to download public helm repos: ${result.error}`);
|
||||
|
||||
return [];
|
||||
}
|
||||
|
||||
return sortBy(repo => repo.name, result.response as HelmRepo[]);
|
||||
};
|
||||
},
|
||||
|
||||
causesSideEffects: true,
|
||||
});
|
||||
|
||||
export default requestPublicHelmRepositoriesInjectable;
|
||||
+41
@@ -0,0 +1,41 @@
|
||||
/**
|
||||
* 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 { HelmRepo } from "../../../../../../../common/helm/helm-repo";
|
||||
import { requestFromChannelInjectionToken } from "../../../../../../../common/utils/channel/request-from-channel-injection-token";
|
||||
import activeHelmRepositoriesInjectable from "../../active-helm-repositories.injectable";
|
||||
import showErrorNotificationInjectable from "../../../../../../../renderer/components/notifications/show-error-notification.injectable";
|
||||
import showSuccessNotificationInjectable from "../../../../../../../renderer/components/notifications/show-success-notification.injectable";
|
||||
import { addHelmRepositoryChannel } from "../../../../../../../common/helm/add-helm-repository-channel";
|
||||
|
||||
const addHelmRepositoryInjectable = getInjectable({
|
||||
id: "add-public-helm-repository",
|
||||
|
||||
instantiate: (di) => {
|
||||
const requestFromChannel = di.inject(requestFromChannelInjectionToken);
|
||||
const activeHelmRepositories = di.inject(activeHelmRepositoriesInjectable);
|
||||
const showErrorNotification = di.inject(showErrorNotificationInjectable);
|
||||
const showSuccessNotification = di.inject(showSuccessNotificationInjectable);
|
||||
|
||||
return async (repository: HelmRepo) => {
|
||||
const result = await requestFromChannel(
|
||||
addHelmRepositoryChannel,
|
||||
repository,
|
||||
);
|
||||
|
||||
if (result.callWasSuccessful) {
|
||||
showSuccessNotification(
|
||||
`Helm repository ${repository.name} has been added.`,
|
||||
);
|
||||
|
||||
activeHelmRepositories.invalidate();
|
||||
} else {
|
||||
showErrorNotification(result.error);
|
||||
}
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default addHelmRepositoryInjectable;
|
||||
+33
@@ -0,0 +1,33 @@
|
||||
/**
|
||||
* 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 addHelmRepositoryInjectable from "./add-helm-repository.injectable";
|
||||
import type { SelectOption } from "../../../../../../../renderer/components/select";
|
||||
import type { HelmRepo } from "../../../../../../../common/helm/helm-repo";
|
||||
import type { SingleValue } from "react-select";
|
||||
import removeHelmRepositoryInjectable from "../../remove-helm-repository.injectable";
|
||||
|
||||
const selectHelmRepositoryInjectable = getInjectable({
|
||||
id: "select-helm-repository",
|
||||
|
||||
instantiate: (di) => {
|
||||
const addHelmRepository = di.inject(addHelmRepositoryInjectable);
|
||||
const removeHelmRepository = di.inject(removeHelmRepositoryInjectable);
|
||||
|
||||
return (selected: SingleValue<SelectOption<HelmRepo>>) => {
|
||||
if (!selected) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!selected.isSelected) {
|
||||
addHelmRepository(selected.value);
|
||||
} else {
|
||||
removeHelmRepository(selected.value);
|
||||
}
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default selectHelmRepositoryInjectable;
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* 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 { HelmCharts } from "./helm-charts";
|
||||
import { preferenceItemInjectionToken } from "../../../../preferences/renderer/preference-items/preference-item-injection-token";
|
||||
|
||||
const helmChartsPreferenceBlockInjectable = getInjectable({
|
||||
id: "helm-charts-preference-block",
|
||||
|
||||
instantiate: () => ({
|
||||
kind: "block" as const,
|
||||
id: "helm-charts",
|
||||
parentId: "kubernetes-page",
|
||||
orderNumber: 30,
|
||||
Component: HelmCharts,
|
||||
}),
|
||||
|
||||
injectionToken: preferenceItemInjectionToken,
|
||||
});
|
||||
|
||||
export default helmChartsPreferenceBlockInjectable;
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
.repos {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
margin-top: calc(var(--margin) * 2);
|
||||
}
|
||||
|
||||
.repos .repo + .repo {
|
||||
margin-top: calc(var(--margin) * 1.5);
|
||||
}
|
||||
|
||||
.contents {
|
||||
display: flex;
|
||||
gap: var(--padding);
|
||||
}
|
||||
|
||||
.repoName {
|
||||
font-weight: 500;
|
||||
}
|
||||
|
||||
.repoUrl {
|
||||
color: var(--textColorDimmed);
|
||||
}
|
||||
+65
@@ -0,0 +1,65 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import React from "react";
|
||||
|
||||
import { HelmRepositories } from "./helm-repositories";
|
||||
import { AddingOfPublicHelmRepository } from "./adding-of-public-helm-repository/adding-of-public-helm-repository";
|
||||
import { AddingOfCustomHelmRepositoryOpenButton } from "./adding-of-custom-helm-repository/adding-of-custom-helm-repository-open-button";
|
||||
import { AddingOfCustomHelmRepositoryDialog } from "./adding-of-custom-helm-repository/adding-of-custom-helm-repository-dialog";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import type { HelmRepositoriesErrorState } from "./helm-repositories-error-state.injectable";
|
||||
import helmRepositoriesErrorStateInjectable from "./helm-repositories-error-state.injectable";
|
||||
import type { IObservableValue } from "mobx";
|
||||
import { observer } from "mobx-react";
|
||||
import { Notice } from "../../../../../renderer/components/+extensions/notice";
|
||||
|
||||
interface Dependencies {
|
||||
helmRepositoriesErrorState: IObservableValue<HelmRepositoriesErrorState>;
|
||||
}
|
||||
|
||||
const NonInjectedHelmCharts = observer(
|
||||
({ helmRepositoriesErrorState }: Dependencies) => {
|
||||
const state = helmRepositoriesErrorState.get();
|
||||
|
||||
return (
|
||||
<section id="helm">
|
||||
<h2>Helm Charts</h2>
|
||||
|
||||
<div>
|
||||
{!state.controlsAreShown && (
|
||||
<Notice>
|
||||
<div className="flex-grow text-center">{state.errorMessage}</div>
|
||||
</Notice>
|
||||
)}
|
||||
|
||||
{state.controlsAreShown && (
|
||||
<div data-testid="helm-controls">
|
||||
<div className="flex gaps">
|
||||
<AddingOfPublicHelmRepository />
|
||||
|
||||
<AddingOfCustomHelmRepositoryOpenButton />
|
||||
</div>
|
||||
|
||||
<HelmRepositories />
|
||||
|
||||
<AddingOfCustomHelmRepositoryDialog />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</section>
|
||||
);
|
||||
},
|
||||
);
|
||||
|
||||
export const HelmCharts = withInjectables<Dependencies>(
|
||||
NonInjectedHelmCharts,
|
||||
|
||||
{
|
||||
getProps: (di) => ({
|
||||
helmRepositoriesErrorState: di.inject(helmRepositoriesErrorStateInjectable),
|
||||
}),
|
||||
},
|
||||
);
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
/**
|
||||
* 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 { observable } from "mobx";
|
||||
|
||||
export type HelmRepositoriesErrorState =
|
||||
| { controlsAreShown: true }
|
||||
| { controlsAreShown: false; errorMessage: string };
|
||||
|
||||
const helmRepositoriesErrorStateInjectable = getInjectable({
|
||||
id: "helm-repositories-error-state",
|
||||
|
||||
instantiate: () =>
|
||||
observable.box<HelmRepositoriesErrorState>({ controlsAreShown: true }),
|
||||
});
|
||||
|
||||
export default helmRepositoriesErrorStateInjectable;
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* Copyright (c) OpenLens Authors. All rights reserved.
|
||||
* Licensed under MIT License. See LICENSE in root directory for more information.
|
||||
*/
|
||||
|
||||
import styles from "./helm-charts.module.scss";
|
||||
|
||||
import React from "react";
|
||||
|
||||
import { observer } from "mobx-react";
|
||||
import activeHelmRepositoriesInjectable from "./active-helm-repositories.injectable";
|
||||
import type { IAsyncComputed } from "@ogre-tools/injectable-react";
|
||||
import { withInjectables } from "@ogre-tools/injectable-react";
|
||||
import { Spinner } from "../../../../../renderer/components/spinner";
|
||||
import type { HelmRepo } from "../../../../../common/helm/helm-repo";
|
||||
import { RemovableItem } from "../../../../preferences/renderer/removable-item/removable-item";
|
||||
import removeHelmRepositoryInjectable from "./remove-helm-repository.injectable";
|
||||
|
||||
interface Dependencies {
|
||||
activeHelmRepositories: IAsyncComputed<HelmRepo[]>;
|
||||
removeRepository: (repository: HelmRepo) => Promise<void>;
|
||||
}
|
||||
|
||||
const NonInjectedActiveHelmRepositories = observer(({ activeHelmRepositories, removeRepository }: Dependencies) => {
|
||||
if (activeHelmRepositories.pending.get()) {
|
||||
return (
|
||||
<div className={styles.repos}>
|
||||
<div className="pt-5 relative">
|
||||
<Spinner center data-testid="helm-repositories-are-loading" />
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
const repositories = activeHelmRepositories.value.get();
|
||||
|
||||
return (
|
||||
<div className={styles.repos}>
|
||||
{repositories.map((repository) => (
|
||||
<RemovableItem
|
||||
key={repository.name}
|
||||
onRemove={() => removeRepository(repository)}
|
||||
className={styles.repo}
|
||||
data-testid={`remove-helm-repository-${repository.name}`}
|
||||
>
|
||||
<div>
|
||||
<div data-testid={`helm-repository-${repository.name}`} className={styles.repoName}>
|
||||
{repository.name}
|
||||
</div>
|
||||
|
||||
<div className={styles.repoUrl}>{repository.url}</div>
|
||||
</div>
|
||||
</RemovableItem>
|
||||
))}
|
||||
</div>
|
||||
);
|
||||
|
||||
});
|
||||
|
||||
export const HelmRepositories = withInjectables<Dependencies>(
|
||||
NonInjectedActiveHelmRepositories,
|
||||
|
||||
{
|
||||
getProps: (di) => ({
|
||||
activeHelmRepositories: di.inject(activeHelmRepositoriesInjectable),
|
||||
removeRepository: di.inject(removeHelmRepositoryInjectable),
|
||||
}),
|
||||
},
|
||||
);
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/**
|
||||
* 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 { HelmRepo } from "../../../../../common/helm/helm-repo";
|
||||
import { requestFromChannelInjectionToken } from "../../../../../common/utils/channel/request-from-channel-injection-token";
|
||||
import activeHelmRepositoriesInjectable from "./active-helm-repositories.injectable";
|
||||
import { removeHelmRepositoryChannel } from "../../../../../common/helm/remove-helm-repository-channel";
|
||||
|
||||
const removePublicHelmRepositoryInjectable = getInjectable({
|
||||
id: "remove-public-helm-repository",
|
||||
|
||||
instantiate: (di) => {
|
||||
const requestFromChannel = di.inject(requestFromChannelInjectionToken);
|
||||
const activeHelmRepositories = di.inject(activeHelmRepositoriesInjectable);
|
||||
|
||||
return async (repository: HelmRepo) => {
|
||||
await requestFromChannel(removeHelmRepositoryChannel, repository);
|
||||
|
||||
activeHelmRepositories.invalidate();
|
||||
};
|
||||
},
|
||||
});
|
||||
|
||||
export default removePublicHelmRepositoryInjectable;
|
||||
+19952
File diff suppressed because it is too large.
Load diff
+1334
File diff suppressed because it is too large.
Load diff
+7566
File diff suppressed because it is too large.
Load diff
+991
@@ -0,0 +1,991 @@
|
||||
/**
|
||||
* 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 { 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 { HelmChart } from "../../../common/k8s-api/endpoints/helm-charts.api";
|
||||
import getRandomInstallChartTabIdInjectable from "../../../renderer/components/dock/install-chart/get-random-install-chart-tab-id.injectable";
|
||||
import type { RequestCreateHelmRelease } from "../../../common/k8s-api/endpoints/helm-releases.api/request-create.injectable";
|
||||
import requestCreateHelmReleaseInjectable from "../../../common/k8s-api/endpoints/helm-releases.api/request-create.injectable";
|
||||
import currentPathInjectable from "../../../renderer/routes/current-path.injectable";
|
||||
import writeJsonFileInjectable from "../../../common/fs/write-json-file.injectable";
|
||||
import directoryForLensLocalStorageInjectable from "../../../common/directory-for-lens-local-storage/directory-for-lens-local-storage.injectable";
|
||||
import dockStoreInjectable from "../../../renderer/components/dock/dock/store.injectable";
|
||||
import readJsonFileInjectable from "../../../common/fs/read-json-file.injectable";
|
||||
import type { DiContainer } from "@ogre-tools/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 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";
|
||||
|
||||
describe("installing helm chart from new tab", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
let requestDetailedHelmReleaseMock: AsyncFnMock<RequestDetailedHelmRelease>;
|
||||
let requestHelmChartsMock: AsyncFnMock<RequestHelmCharts>;
|
||||
let requestHelmChartVersionsMock: AsyncFnMock<RequestHelmChartVersions>;
|
||||
let requestHelmChartReadmeMock: AsyncFnMock<RequestHelmChartReadme>;
|
||||
let requestHelmChartValuesMock: AsyncFnMock<RequestHelmChartValues>;
|
||||
let requestCreateHelmReleaseMock: AsyncFnMock<RequestCreateHelmRelease>;
|
||||
|
||||
beforeEach(() => {
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
builder.setEnvironmentToClusterFrame();
|
||||
|
||||
requestDetailedHelmReleaseMock = asyncFn();
|
||||
requestHelmChartsMock = asyncFn();
|
||||
requestHelmChartVersionsMock = asyncFn();
|
||||
requestHelmChartReadmeMock = asyncFn();
|
||||
requestHelmChartValuesMock = asyncFn();
|
||||
requestCreateHelmReleaseMock = asyncFn();
|
||||
|
||||
builder.beforeWindowStart((windowDi) => {
|
||||
windowDi.override(directoryForLensLocalStorageInjectable, () => "/some-directory-for-lens-local-storage");
|
||||
windowDi.override(requestDetailedHelmReleaseInjectable, () => requestDetailedHelmReleaseMock);
|
||||
windowDi.override(requestHelmChartsInjectable, () => requestHelmChartsMock);
|
||||
windowDi.override(requestHelmChartVersionsInjectable, () => requestHelmChartVersionsMock);
|
||||
windowDi.override(requestHelmChartReadmeInjectable, () => requestHelmChartReadmeMock);
|
||||
windowDi.override(requestHelmChartValuesInjectable, () => requestHelmChartValuesMock);
|
||||
windowDi.override(requestCreateHelmReleaseInjectable, () => requestCreateHelmReleaseMock);
|
||||
|
||||
windowDi.override(getRandomInstallChartTabIdInjectable, () =>
|
||||
jest
|
||||
.fn(() => "some-irrelevant-tab-id")
|
||||
.mockReturnValueOnce("some-first-tab-id")
|
||||
.mockReturnValueOnce("some-second-tab-id"),
|
||||
);
|
||||
});
|
||||
|
||||
builder.namespaces.add("default");
|
||||
builder.namespaces.add("some-other-namespace");
|
||||
});
|
||||
|
||||
describe("given tab for installing chart was not previously opened and application is started", () => {
|
||||
let rendered: RenderResult;
|
||||
let windowDi: DiContainer;
|
||||
|
||||
beforeEach(async () => {
|
||||
rendered = await builder.render();
|
||||
|
||||
windowDi = builder.applicationWindow.only.di;
|
||||
|
||||
const writeJsonFile = windowDi.inject(writeJsonFileInjectable);
|
||||
|
||||
await writeJsonFile(
|
||||
"/some-directory-for-lens-local-storage/some-cluster-id.json",
|
||||
{
|
||||
dock: {
|
||||
height: 300,
|
||||
tabs: [],
|
||||
isOpen: false,
|
||||
},
|
||||
},
|
||||
);
|
||||
|
||||
const dockStore = windowDi.inject(dockStoreInjectable);
|
||||
|
||||
// TODO: Make TerminalWindow unit testable to allow realistic behaviour
|
||||
dockStore.closeTab("terminal");
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("when navigating to helm charts", () => {
|
||||
beforeEach(async () => {
|
||||
builder.helmCharts.navigate({
|
||||
chartName: "some-name",
|
||||
repo: "some-repository",
|
||||
});
|
||||
|
||||
await requestHelmChartsMock.resolve([
|
||||
HelmChart.create({
|
||||
apiVersion: "some-api-version",
|
||||
name: "some-name",
|
||||
version: "some-version",
|
||||
repo: "some-repository",
|
||||
created: "2015-10-21T07:28:00Z",
|
||||
description: "some-description",
|
||||
keywords: [],
|
||||
sources: [],
|
||||
urls: [],
|
||||
annotations: {},
|
||||
dependencies: [],
|
||||
maintainers: [],
|
||||
deprecated: false,
|
||||
}),
|
||||
|
||||
HelmChart.create({
|
||||
apiVersion: "some-api-version",
|
||||
name: "some-other-name",
|
||||
version: "some-version",
|
||||
repo: "some-repository",
|
||||
created: "2015-10-21T07:28:00Z",
|
||||
description: "some-description",
|
||||
keywords: [],
|
||||
sources: [],
|
||||
urls: [],
|
||||
annotations: {},
|
||||
dependencies: [],
|
||||
maintainers: [],
|
||||
deprecated: false,
|
||||
}),
|
||||
]);
|
||||
|
||||
await requestHelmChartVersionsMock.resolve([
|
||||
HelmChart.create({
|
||||
apiVersion: "some-api-version",
|
||||
name: "some-name",
|
||||
version: "some-version",
|
||||
repo: "some-repository",
|
||||
created: "2015-10-21T07:28:00Z",
|
||||
description: "some-description",
|
||||
keywords: [],
|
||||
sources: [],
|
||||
urls: [],
|
||||
annotations: {},
|
||||
dependencies: [],
|
||||
maintainers: [],
|
||||
deprecated: false,
|
||||
}),
|
||||
|
||||
HelmChart.create({
|
||||
apiVersion: "some-api-version",
|
||||
name: "some-name",
|
||||
version: "some-other-version",
|
||||
repo: "some-repository",
|
||||
created: "2015-10-21T07:28:00Z",
|
||||
description: "some-description",
|
||||
keywords: [],
|
||||
sources: [],
|
||||
urls: [],
|
||||
annotations: {},
|
||||
dependencies: [],
|
||||
maintainers: [],
|
||||
deprecated: false,
|
||||
}),
|
||||
]);
|
||||
|
||||
await requestHelmChartReadmeMock.resolve({
|
||||
callWasSuccessful: true,
|
||||
response: "some-readme",
|
||||
});
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("when selecting to install the chart", () => {
|
||||
beforeEach(() => {
|
||||
requestHelmChartVersionsMock.mockClear();
|
||||
|
||||
const installButton = rendered.getByTestId(
|
||||
"install-chart-for-some-repository-some-name",
|
||||
);
|
||||
|
||||
fireEvent.click(installButton);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows dock tab for installing the chart", () => {
|
||||
expect(
|
||||
rendered.getByTestId("dock-tab-content-for-some-first-tab-id"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("calls for default configuration of the chart", () => {
|
||||
expect(requestHelmChartValuesMock).toHaveBeenCalledWith(
|
||||
"some-repository",
|
||||
"some-name",
|
||||
"some-version",
|
||||
);
|
||||
});
|
||||
|
||||
it("calls for available versions", () => {
|
||||
expect(requestHelmChartVersionsMock).toHaveBeenCalledWith(
|
||||
"some-repository",
|
||||
"some-name",
|
||||
);
|
||||
});
|
||||
|
||||
it("shows spinner in dock tab", () => {
|
||||
expect(
|
||||
rendered.getByTestId("install-chart-tab-spinner"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("given versions resolve but default configuration has not resolved yet, still shows the spinner", async () => {
|
||||
await requestHelmChartVersionsMock.resolve([]);
|
||||
|
||||
expect(
|
||||
rendered.getByTestId("install-chart-tab-spinner"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe("when default configuration and versions resolve", () => {
|
||||
beforeEach(async () => {
|
||||
await requestHelmChartValuesMock.resolve({
|
||||
callWasSuccessful: true,
|
||||
response: "some-default-configuration",
|
||||
});
|
||||
|
||||
await requestHelmChartVersionsMock.resolve([
|
||||
HelmChart.create({
|
||||
apiVersion: "some-api-version",
|
||||
name: "some-name",
|
||||
version: "some-version",
|
||||
repo: "some-repository",
|
||||
created: "2015-10-21T07:28:00Z",
|
||||
description: "some-description",
|
||||
keywords: [],
|
||||
sources: [],
|
||||
urls: [],
|
||||
annotations: {},
|
||||
dependencies: [],
|
||||
maintainers: [],
|
||||
deprecated: false,
|
||||
}),
|
||||
|
||||
HelmChart.create({
|
||||
apiVersion: "some-api-version",
|
||||
name: "some-name",
|
||||
version: "some-other-version",
|
||||
repo: "some-repository",
|
||||
created: "2015-10-21T07:28:00Z",
|
||||
description: "some-description",
|
||||
keywords: [],
|
||||
sources: [],
|
||||
urls: [],
|
||||
annotations: {},
|
||||
dependencies: [],
|
||||
maintainers: [],
|
||||
deprecated: false,
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show spinner anymore", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("install-chart-tab-spinner"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe("when cancelled", () => {
|
||||
beforeEach(() => {
|
||||
const cancelButton = rendered.getByTestId(
|
||||
"cancel-install-chart-from-tab-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
fireEvent.click(cancelButton);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("closes the tab", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("dock-tab-for-some-first-tab-id"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("given no changes in configuration, when installing the chart", () => {
|
||||
let installButton: HTMLButtonElement;
|
||||
|
||||
beforeEach(() => {
|
||||
installButton = rendered.getByTestId(
|
||||
"install-chart-from-tab-for-some-first-tab-id",
|
||||
) as HTMLButtonElement;
|
||||
|
||||
fireEvent.click(installButton);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows spinner in dock tab", () => {
|
||||
expect(
|
||||
rendered.getByTestId(
|
||||
"installing-chart-from-tab-some-first-tab-id",
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("install button is disabled", () => {
|
||||
expect(installButton).toHaveAttribute("disabled");
|
||||
});
|
||||
|
||||
it("calls for installation with default configuration", () => {
|
||||
expect(requestCreateHelmReleaseMock).toHaveBeenCalledWith({
|
||||
chart: "some-name",
|
||||
name: undefined,
|
||||
namespace: "default",
|
||||
repo: "some-repository",
|
||||
values: "some-default-configuration",
|
||||
version: "some-version",
|
||||
});
|
||||
});
|
||||
|
||||
describe("when installation resolves", () => {
|
||||
beforeEach(async () => {
|
||||
await requestCreateHelmReleaseMock.resolve({
|
||||
log: "some-execution-output",
|
||||
|
||||
release: {
|
||||
resources: [],
|
||||
name: "some-release",
|
||||
namespace: "default",
|
||||
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",
|
||||
},
|
||||
},
|
||||
});
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show spinner anymore", () => {
|
||||
expect(
|
||||
rendered.queryByTestId(
|
||||
"installing-chart-from-tab-some-first-tab-id",
|
||||
),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe("when selected to see the installed release", () => {
|
||||
beforeEach(() => {
|
||||
const releaseButton = rendered.getByTestId(
|
||||
"show-release-some-release-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
fireEvent.click(releaseButton);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows the details of installed release", () => {
|
||||
const currentPath = windowDi
|
||||
.inject(currentPathInjectable)
|
||||
.get();
|
||||
|
||||
expect(currentPath).toBe(
|
||||
"/helm/releases/default/some-release",
|
||||
);
|
||||
});
|
||||
|
||||
it("closes the dock tab", () => {
|
||||
expect(
|
||||
rendered.queryByTestId(
|
||||
"dock-tab-for-some-first-tab-id",
|
||||
),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when selected to show execution output", () => {
|
||||
beforeEach(() => {
|
||||
const showNotesButton = rendered.getByTestId(
|
||||
"show-execution-output-for-some-release-in-some-first-tab-id",
|
||||
);
|
||||
|
||||
fireEvent.click(showNotesButton);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows the execution output", () => {
|
||||
expect(
|
||||
rendered.getByTestId(
|
||||
"logs-dialog-for-helm-chart-install",
|
||||
),
|
||||
).toHaveTextContent("some-execution-output");
|
||||
});
|
||||
|
||||
it("does not close the dock tab", () => {
|
||||
expect(
|
||||
rendered.getByTestId("dock-tab-for-some-first-tab-id"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("given opening details for second chart, when details resolve", () => {
|
||||
beforeEach(async () => {
|
||||
requestHelmChartReadmeMock.mockClear();
|
||||
requestHelmChartVersionsMock.mockClear();
|
||||
|
||||
const row = rendered.getByTestId(
|
||||
"helm-chart-row-for-some-repository-some-other-name",
|
||||
);
|
||||
|
||||
fireEvent.click(row);
|
||||
|
||||
await requestHelmChartVersionsMock.resolve([
|
||||
HelmChart.create({
|
||||
apiVersion: "some-api-version",
|
||||
name: "some-other-name",
|
||||
version: "some-version",
|
||||
repo: "some-repository",
|
||||
created: "2015-10-21T07:28:00Z",
|
||||
description: "some-description",
|
||||
keywords: [],
|
||||
sources: [],
|
||||
urls: [],
|
||||
annotations: {},
|
||||
dependencies: [],
|
||||
maintainers: [],
|
||||
deprecated: false,
|
||||
}),
|
||||
]);
|
||||
|
||||
await requestHelmChartReadmeMock.resolve({
|
||||
callWasSuccessful: true,
|
||||
response: "some-readme",
|
||||
});
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("when selecting to install second chart", () => {
|
||||
beforeEach(() => {
|
||||
requestHelmChartVersionsMock.mockClear();
|
||||
|
||||
const installButton = rendered.getByTestId(
|
||||
"install-chart-for-some-repository-some-other-name",
|
||||
);
|
||||
|
||||
fireEvent.click(installButton);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows dock tab for installing second chart", () => {
|
||||
expect(
|
||||
rendered.getByTestId(
|
||||
"dock-tab-content-for-some-second-tab-id",
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("still has the dock tab for installing first chart", () => {
|
||||
expect(
|
||||
rendered.getByTestId("dock-tab-for-some-first-tab-id"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("calls for default configuration of the second chart", () => {
|
||||
expect(requestHelmChartValuesMock).toHaveBeenCalledWith(
|
||||
"some-repository",
|
||||
"some-other-name",
|
||||
"some-version",
|
||||
);
|
||||
});
|
||||
|
||||
it("calls for available versions for the second chart", () => {
|
||||
expect(requestHelmChartVersionsMock).toHaveBeenCalledWith(
|
||||
"some-repository",
|
||||
"some-other-name",
|
||||
);
|
||||
});
|
||||
|
||||
it("shows spinner in dock tab", () => {
|
||||
expect(
|
||||
rendered.getByTestId("install-chart-tab-spinner"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe("when configuration and versions resolve", () => {
|
||||
beforeEach(async () => {
|
||||
await requestHelmChartValuesMock.resolve({
|
||||
callWasSuccessful: true,
|
||||
response: "some-other-default-configuration",
|
||||
});
|
||||
|
||||
await requestHelmChartVersionsMock.resolve([]);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show spinner anymore", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("install-chart-tab-spinner"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("when installing the second chart, calls for installation of second chart", () => {
|
||||
const installButton = rendered.getByTestId(
|
||||
"install-chart-from-tab-for-some-second-tab-id",
|
||||
);
|
||||
|
||||
fireEvent.click(installButton);
|
||||
|
||||
expect(
|
||||
requestCreateHelmReleaseMock,
|
||||
).toHaveBeenCalledWith({
|
||||
chart: "some-other-name",
|
||||
name: undefined,
|
||||
namespace: "default",
|
||||
repo: "some-repository",
|
||||
values: "some-other-default-configuration",
|
||||
version: "some-version",
|
||||
});
|
||||
});
|
||||
|
||||
describe("when selecting the dock tab for installing first chart", () => {
|
||||
beforeEach(() => {
|
||||
requestHelmChartValuesMock.mockClear();
|
||||
requestHelmChartVersionsMock.mockClear();
|
||||
|
||||
const tab = rendered.getByTestId(
|
||||
"dock-tab-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
fireEvent.click(tab);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not call for default configuration", () => {
|
||||
expect(
|
||||
requestHelmChartValuesMock,
|
||||
).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not call for available versions", () => {
|
||||
expect(
|
||||
requestHelmChartVersionsMock,
|
||||
).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("does not show spinner", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("install-chart-tab-spinner"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("when installing the first chart, calls for installation of first chart", () => {
|
||||
const installButton = rendered.getByTestId(
|
||||
"install-chart-from-tab-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
fireEvent.click(installButton);
|
||||
|
||||
expect(
|
||||
requestCreateHelmReleaseMock,
|
||||
).toHaveBeenCalledWith({
|
||||
chart: "some-name",
|
||||
name: undefined,
|
||||
namespace: "default",
|
||||
repo: "some-repository",
|
||||
values: "some-default-configuration",
|
||||
version: "some-version",
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("given changing version to be installed", () => {
|
||||
let menu: { selectOption: (labelText: string) => void };
|
||||
|
||||
beforeEach(() => {
|
||||
requestHelmChartVersionsMock.mockClear();
|
||||
requestHelmChartValuesMock.mockClear();
|
||||
|
||||
const menuId =
|
||||
"install-chart-version-select-for-some-first-tab-id";
|
||||
|
||||
menu = builder.select.openMenu(menuId);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("when version is selected", () => {
|
||||
let installButton: HTMLButtonElement;
|
||||
|
||||
beforeEach(() => {
|
||||
installButton = rendered.getByTestId(
|
||||
"install-chart-from-tab-for-some-first-tab-id",
|
||||
) as HTMLButtonElement;
|
||||
|
||||
menu.selectOption("some-other-version");
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("calls for default configuration for the version of chart", () => {
|
||||
expect(requestHelmChartValuesMock).toHaveBeenCalledWith(
|
||||
"some-repository",
|
||||
"some-name",
|
||||
"some-other-version",
|
||||
);
|
||||
});
|
||||
|
||||
it("shows spinner", () => {
|
||||
expect(
|
||||
rendered.getByTestId(
|
||||
"install-chart-configuration-spinner",
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("does not call for versions again", () => {
|
||||
expect(
|
||||
requestHelmChartVersionsMock,
|
||||
).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("install button is disabled", () => {
|
||||
expect(installButton).toHaveAttribute("disabled");
|
||||
});
|
||||
|
||||
it("stores the selected version", async () => {
|
||||
const readJsonFile = windowDi.inject(readJsonFileInjectable);
|
||||
|
||||
const actual = await readJsonFile(
|
||||
"/some-directory-for-lens-local-storage/some-cluster-id.json",
|
||||
) as any;
|
||||
|
||||
const version = actual.install_charts["some-first-tab-id"].version;
|
||||
|
||||
expect(version).toBe("some-other-version");
|
||||
});
|
||||
|
||||
describe("when default configuration resolves", () => {
|
||||
beforeEach(async () => {
|
||||
await requestHelmChartValuesMock.resolve({
|
||||
callWasSuccessful: true,
|
||||
response: "some-default-configuration-for-other-version",
|
||||
});
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show spinner", () => {
|
||||
expect(
|
||||
rendered.queryByTestId(
|
||||
"install-chart-configuration-spinner",
|
||||
),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("install button is enabled", () => {
|
||||
expect(installButton).not.toHaveAttribute("disabled");
|
||||
});
|
||||
|
||||
it("when installing the chart, calls for installation with changed version and default configuration", () => {
|
||||
fireEvent.click(installButton);
|
||||
|
||||
expect(
|
||||
requestCreateHelmReleaseMock,
|
||||
).toHaveBeenCalledWith({
|
||||
chart: "some-name",
|
||||
name: undefined,
|
||||
namespace: "default",
|
||||
repo: "some-repository",
|
||||
values:
|
||||
"some-default-configuration-for-other-version",
|
||||
version: "some-other-version",
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("given namespace selection is opened", () => {
|
||||
let menu: { selectOption: (labelText: string) => void };
|
||||
|
||||
beforeEach(() => {
|
||||
const menuId =
|
||||
"install-chart-namespace-select-for-some-first-tab-id";
|
||||
|
||||
menu = builder.select.openMenu(menuId);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("when namespace is selected", () => {
|
||||
beforeEach(() => {
|
||||
menu.selectOption("some-other-namespace");
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("stores the selected namespace", async () => {
|
||||
const readJsonFile = windowDi.inject(readJsonFileInjectable);
|
||||
|
||||
const actual = await readJsonFile(
|
||||
"/some-directory-for-lens-local-storage/some-cluster-id.json",
|
||||
) as any;
|
||||
|
||||
const namespace = actual.install_charts["some-first-tab-id"].namespace;
|
||||
|
||||
expect(namespace).toBe("some-other-namespace");
|
||||
});
|
||||
|
||||
it("when installing the chart, calls for installation with changed namespace", () => {
|
||||
const installButton = rendered.getByTestId(
|
||||
"install-chart-from-tab-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
fireEvent.click(installButton);
|
||||
|
||||
expect(requestCreateHelmReleaseMock).toHaveBeenCalledWith(
|
||||
{
|
||||
chart: "some-name",
|
||||
name: undefined,
|
||||
namespace: "some-other-namespace",
|
||||
repo: "some-repository",
|
||||
values: "some-default-configuration",
|
||||
version: "some-version",
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("given invalid change in configuration", () => {
|
||||
let installButton: HTMLButtonElement;
|
||||
let input: HTMLInputElement;
|
||||
|
||||
beforeEach(() => {
|
||||
installButton = rendered.getByTestId(
|
||||
"install-chart-from-tab-for-some-first-tab-id",
|
||||
) as HTMLButtonElement;
|
||||
|
||||
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("updates the editor with the changed value", () => {
|
||||
const input = rendered.getByTestId(
|
||||
"monaco-editor-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
expect(input).toHaveValue("@some-invalid-configuration@");
|
||||
});
|
||||
|
||||
it("install button is disabled", () => {
|
||||
expect(installButton).toHaveAttribute("disabled");
|
||||
});
|
||||
|
||||
it("when valid change in configuration, install button is enabled", () => {
|
||||
fireEvent.change(input, {
|
||||
target: { value: "some-valid-configuration" },
|
||||
});
|
||||
|
||||
expect(installButton).not.toHaveAttribute("disabled");
|
||||
});
|
||||
|
||||
it("given change in version, when default configuration resolves, install button is enabled", async () => {
|
||||
builder.select
|
||||
.openMenu(
|
||||
"install-chart-version-select-for-some-first-tab-id",
|
||||
)
|
||||
.selectOption("some-other-version");
|
||||
|
||||
await requestHelmChartValuesMock.resolve({
|
||||
callWasSuccessful: true,
|
||||
response: "some-default-configuration-for-other-version",
|
||||
});
|
||||
|
||||
expect(installButton).not.toHaveAttribute("disabled");
|
||||
});
|
||||
});
|
||||
|
||||
describe("given valid change in configuration", () => {
|
||||
beforeEach(() => {
|
||||
const input = rendered.getByTestId(
|
||||
"monaco-editor-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
fireEvent.change(input, {
|
||||
target: { value: "some-valid-configuration" },
|
||||
});
|
||||
});
|
||||
|
||||
it("updates the editor with the changed value", () => {
|
||||
const input = rendered.getByTestId(
|
||||
"monaco-editor-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
expect(input).toHaveValue("some-valid-configuration");
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("stores the changed configuration", async () => {
|
||||
const readJsonFile = windowDi.inject(readJsonFileInjectable);
|
||||
|
||||
const actual = await readJsonFile(
|
||||
"/some-directory-for-lens-local-storage/some-cluster-id.json",
|
||||
) as any;
|
||||
|
||||
const configuration = actual.install_charts["some-first-tab-id"].values;
|
||||
|
||||
expect(configuration).toBe("some-valid-configuration");
|
||||
});
|
||||
|
||||
it("does not show spinner", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("install-chart-tab-spinner"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("when installing the chart, calls for installation with changed configuration", () => {
|
||||
const installButton = rendered.getByTestId(
|
||||
"install-chart-from-tab-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
fireEvent.click(installButton);
|
||||
|
||||
expect(requestCreateHelmReleaseMock).toHaveBeenCalledWith({
|
||||
chart: "some-name",
|
||||
name: undefined,
|
||||
namespace: "default",
|
||||
repo: "some-repository",
|
||||
values: "some-valid-configuration",
|
||||
version: "some-version",
|
||||
});
|
||||
});
|
||||
|
||||
it("given version is changed, when default configuration resolves, defaults back to default configuration", async () => {
|
||||
builder.select
|
||||
.openMenu(
|
||||
"install-chart-version-select-for-some-first-tab-id",
|
||||
)
|
||||
.selectOption("some-other-version");
|
||||
|
||||
await requestHelmChartValuesMock.resolve({
|
||||
callWasSuccessful: true,
|
||||
response: "some-default-configuration-for-other-version",
|
||||
});
|
||||
|
||||
const input = rendered.getByTestId(
|
||||
"monaco-editor-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
expect(input).toHaveValue(
|
||||
"some-default-configuration-for-other-version",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("given custom name is inputted", () => {
|
||||
beforeEach(() => {
|
||||
const input = rendered.getByTestId(
|
||||
"install-chart-custom-name-input-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
fireEvent.change(input, {
|
||||
target: { value: "some-custom-name" },
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
it("stores the changed custom name", async () => {
|
||||
const readJsonFile = windowDi.inject(readJsonFileInjectable);
|
||||
|
||||
const actual = await readJsonFile(
|
||||
"/some-directory-for-lens-local-storage/some-cluster-id.json",
|
||||
) as any;
|
||||
|
||||
const customName = actual.install_charts["some-first-tab-id"].releaseName;
|
||||
|
||||
expect(customName).toBe("some-custom-name");
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("when installed, calls for installation with custom name", () => {
|
||||
const installButton = rendered.getByTestId(
|
||||
"install-chart-from-tab-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
fireEvent.click(installButton);
|
||||
|
||||
expect(requestCreateHelmReleaseMock).toHaveBeenCalledWith({
|
||||
chart: "some-name",
|
||||
name: "some-custom-name",
|
||||
namespace: "default",
|
||||
repo: "some-repository",
|
||||
values: "some-default-configuration",
|
||||
version: "some-version",
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
+209
@@ -0,0 +1,209 @@
|
||||
/**
|
||||
* 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 { HelmChart } from "../../../common/k8s-api/endpoints/helm-charts.api";
|
||||
import getRandomInstallChartTabIdInjectable from "../../../renderer/components/dock/install-chart/get-random-install-chart-tab-id.injectable";
|
||||
import writeJsonFileInjectable from "../../../common/fs/write-json-file.injectable";
|
||||
import directoryForLensLocalStorageInjectable from "../../../common/directory-for-lens-local-storage/directory-for-lens-local-storage.injectable";
|
||||
import { TabKind } from "../../../renderer/components/dock/dock/store";
|
||||
import requestCreateHelmReleaseInjectable from "../../../common/k8s-api/endpoints/helm-releases.api/request-create.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 { RequestHelmChartValues } from "../../../common/k8s-api/endpoints/helm-charts.api/request-values.injectable";
|
||||
import requestHelmChartValuesInjectable from "../../../common/k8s-api/endpoints/helm-charts.api/request-values.injectable";
|
||||
|
||||
describe("installing helm chart from previously opened tab", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
let requestHelmChartVersionsMock: AsyncFnMock<RequestHelmChartVersions>;
|
||||
let requestHelmChartValuesMock: AsyncFnMock<RequestHelmChartValues>;
|
||||
|
||||
beforeEach(() => {
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
builder.setEnvironmentToClusterFrame();
|
||||
|
||||
requestHelmChartVersionsMock = asyncFn();
|
||||
requestHelmChartValuesMock = asyncFn();
|
||||
|
||||
builder.namespaces.add("default");
|
||||
builder.namespaces.add("some-other-namespace");
|
||||
|
||||
builder.beforeWindowStart((windowDi) => {
|
||||
windowDi.override(directoryForLensLocalStorageInjectable, () => "/some-directory-for-lens-local-storage");
|
||||
windowDi.override(requestHelmChartVersionsInjectable, () => requestHelmChartVersionsMock);
|
||||
windowDi.override(requestHelmChartValuesInjectable, () => requestHelmChartValuesMock);
|
||||
windowDi.override(requestCreateHelmReleaseInjectable, () => jest.fn());
|
||||
|
||||
windowDi.override(getRandomInstallChartTabIdInjectable, () =>
|
||||
jest
|
||||
.fn(() => "some-irrelevant-tab-id")
|
||||
.mockReturnValueOnce("some-first-tab-id"),
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("given tab for installing chart was previously opened, when application is started", () => {
|
||||
let rendered: RenderResult;
|
||||
|
||||
beforeEach(async () => {
|
||||
builder.beforeWindowStart(async (windowDi) => {
|
||||
const writeJsonFile = windowDi.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.INSTALL_CHART,
|
||||
title: "Helm Install: some-repository/some-name",
|
||||
pinned: false,
|
||||
},
|
||||
],
|
||||
|
||||
isOpen: true,
|
||||
},
|
||||
|
||||
install_charts: {
|
||||
"some-first-tab-id": {
|
||||
name: "some-name",
|
||||
repo: "some-repository",
|
||||
version: "some-other-version",
|
||||
values: "some-stored-configuration",
|
||||
releaseName: "some-stored-custom-name",
|
||||
namespace: "some-other-namespace",
|
||||
},
|
||||
},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
rendered = await builder.render();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("still has the dock tab for installing chart", () => {
|
||||
expect(
|
||||
rendered.getByTestId("dock-tab-for-some-first-tab-id"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows dock tab for installing the chart", () => {
|
||||
expect(
|
||||
rendered.getByTestId("dock-tab-content-for-some-first-tab-id"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows spinner in dock tab", () => {
|
||||
expect(
|
||||
rendered.getByTestId("install-chart-tab-spinner"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("calls for default configuration of the chart", () => {
|
||||
expect(requestHelmChartValuesMock).toHaveBeenCalledWith(
|
||||
"some-repository",
|
||||
"some-name",
|
||||
"some-other-version",
|
||||
);
|
||||
});
|
||||
|
||||
it("calls for available versions", () => {
|
||||
expect(requestHelmChartVersionsMock).toHaveBeenCalledWith(
|
||||
"some-repository",
|
||||
"some-name",
|
||||
);
|
||||
});
|
||||
|
||||
describe("when configuration and version resolves", () => {
|
||||
beforeEach(async () => {
|
||||
await requestHelmChartValuesMock.resolve({
|
||||
callWasSuccessful: true,
|
||||
response: "some-default-configuration",
|
||||
});
|
||||
|
||||
await requestHelmChartVersionsMock.resolve([
|
||||
HelmChart.create({
|
||||
apiVersion: "some-api-version",
|
||||
name: "some-name",
|
||||
version: "some-version",
|
||||
repo: "some-repository",
|
||||
created: "2015-10-21T07:28:00Z",
|
||||
description: "some-description",
|
||||
keywords: [],
|
||||
sources: [],
|
||||
urls: [],
|
||||
annotations: {},
|
||||
dependencies: [],
|
||||
maintainers: [],
|
||||
deprecated: false,
|
||||
}),
|
||||
|
||||
HelmChart.create({
|
||||
apiVersion: "some-api-version",
|
||||
name: "some-name",
|
||||
version: "some-other-version",
|
||||
repo: "some-repository",
|
||||
created: "2015-10-21T07:28:00Z",
|
||||
description: "some-description",
|
||||
keywords: [],
|
||||
sources: [],
|
||||
urls: [],
|
||||
annotations: {},
|
||||
dependencies: [],
|
||||
maintainers: [],
|
||||
deprecated: false,
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("has the stored configuration", () => {
|
||||
const input = rendered.getByTestId(
|
||||
"monaco-editor-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
expect(input).toHaveValue("some-stored-configuration");
|
||||
});
|
||||
|
||||
it("has the stored custom name", () => {
|
||||
const input = rendered.getByTestId(
|
||||
"install-chart-custom-name-input-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
expect(input).toHaveValue("some-stored-custom-name");
|
||||
});
|
||||
|
||||
it("has the stored version", () => {
|
||||
const actual = builder.select.getValue(
|
||||
"install-chart-version-select-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
expect(actual).toBe("some-other-version");
|
||||
|
||||
});
|
||||
|
||||
it("has the stored namespace", () => {
|
||||
const actual = builder.select.getValue(
|
||||
"install-chart-namespace-select-for-some-first-tab-id",
|
||||
);
|
||||
|
||||
expect(actual).toBe("some-other-namespace");
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
+357
@@ -0,0 +1,357 @@
|
||||
/**
|
||||
* 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 { 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 { HelmChart } from "../../../common/k8s-api/endpoints/helm-charts.api";
|
||||
import getRandomInstallChartTabIdInjectable from "../../../renderer/components/dock/install-chart/get-random-install-chart-tab-id.injectable";
|
||||
import requestCreateHelmReleaseInjectable from "../../../common/k8s-api/endpoints/helm-releases.api/request-create.injectable";
|
||||
import { flushPromises } from "../../../common/test-utils/flush-promises";
|
||||
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 dockStoreInjectable from "../../../renderer/components/dock/dock/store.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 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";
|
||||
|
||||
describe("opening dock tab for installing helm chart", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
let requestHelmChartsMock: AsyncFnMock<RequestHelmCharts>;
|
||||
let requestHelmChartVersionsMock: AsyncFnMock<RequestHelmChartVersions>;
|
||||
let requestHelmChartReadmeMock: AsyncFnMock<RequestHelmChartReadme>;
|
||||
let requestHelmChartValuesMock: jest.Mock;
|
||||
|
||||
beforeEach(() => {
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
requestHelmChartsMock = asyncFn();
|
||||
requestHelmChartVersionsMock = asyncFn();
|
||||
requestHelmChartReadmeMock = asyncFn();
|
||||
requestHelmChartValuesMock = jest.fn();
|
||||
|
||||
builder.beforeWindowStart((windowDi) => {
|
||||
windowDi.override(directoryForLensLocalStorageInjectable, () => "/some-directory-for-lens-local-storage");
|
||||
windowDi.override(hostedClusterIdInjectable, () => "some-cluster-id");
|
||||
windowDi.override(requestHelmChartsInjectable, () => requestHelmChartsMock);
|
||||
windowDi.override(requestHelmChartVersionsInjectable, () => requestHelmChartVersionsMock);
|
||||
windowDi.override(requestHelmChartReadmeInjectable, () => requestHelmChartReadmeMock);
|
||||
windowDi.override(requestHelmChartValuesInjectable, () => requestHelmChartValuesMock);
|
||||
windowDi.override(requestCreateHelmReleaseInjectable, () => jest.fn());
|
||||
windowDi.override(getRandomInstallChartTabIdInjectable, () =>
|
||||
jest
|
||||
.fn(() => "some-irrelevant-tab-id")
|
||||
.mockReturnValueOnce("some-tab-id"),
|
||||
);
|
||||
});
|
||||
|
||||
builder.setEnvironmentToClusterFrame();
|
||||
});
|
||||
|
||||
describe("given application is started, when navigating to helm charts", () => {
|
||||
let rendered: RenderResult;
|
||||
|
||||
beforeEach(async () => {
|
||||
rendered = await builder.render();
|
||||
|
||||
builder.helmCharts.navigate();
|
||||
|
||||
const windowDi = builder.applicationWindow.only.di;
|
||||
|
||||
const dockStore = windowDi.inject(dockStoreInjectable);
|
||||
|
||||
// TODO: Make TerminalWindow unit testable to allow realistic behaviour
|
||||
dockStore.closeTab("terminal");
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("calls for charts", () => {
|
||||
expect(requestHelmChartsMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("when charts resolve", () => {
|
||||
beforeEach(async () => {
|
||||
await requestHelmChartsMock.resolve([
|
||||
HelmChart.create({
|
||||
apiVersion: "some-api-version",
|
||||
name: "some-name",
|
||||
version: "some-version",
|
||||
repo: "some-repository",
|
||||
created: "2015-10-21T07:28:00Z",
|
||||
description: "some-description",
|
||||
keywords: [],
|
||||
sources: [],
|
||||
urls: [],
|
||||
annotations: {},
|
||||
dependencies: [],
|
||||
maintainers: [{
|
||||
email: "some@foo.com",
|
||||
name: "Some Foo",
|
||||
}],
|
||||
deprecated: false,
|
||||
}),
|
||||
|
||||
HelmChart.create({
|
||||
apiVersion: "some-api-version",
|
||||
name: "some-other-name",
|
||||
version: "some-version",
|
||||
repo: "some-repository",
|
||||
created: "2015-10-21T07:28:00Z",
|
||||
description: "some-description",
|
||||
keywords: [],
|
||||
sources: [],
|
||||
urls: [],
|
||||
annotations: {},
|
||||
dependencies: [],
|
||||
maintainers: [{
|
||||
email: "other@bar.com",
|
||||
name: "Other Bar",
|
||||
}],
|
||||
deprecated: false,
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("when opening details of a chart", () => {
|
||||
beforeEach(() => {
|
||||
const row = rendered.getByTestId(
|
||||
"helm-chart-row-for-some-repository-some-name",
|
||||
);
|
||||
|
||||
fireEvent.click(row);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("calls for chart versions", () => {
|
||||
expect(requestHelmChartVersionsMock).toHaveBeenCalledWith(
|
||||
"some-repository",
|
||||
"some-name",
|
||||
);
|
||||
});
|
||||
|
||||
it("shows spinner", () => {
|
||||
expect(
|
||||
rendered.getByTestId("spinner-for-chart-details"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe("when chart versions resolve", () => {
|
||||
beforeEach(async () => {
|
||||
await requestHelmChartVersionsMock.resolve([
|
||||
HelmChart.create({
|
||||
apiVersion: "some-api-version",
|
||||
name: "some-name",
|
||||
version: "some-version",
|
||||
repo: "some-repository",
|
||||
created: "2015-10-21T07:28:00Z",
|
||||
description: "some-description",
|
||||
keywords: [],
|
||||
sources: [],
|
||||
urls: [],
|
||||
annotations: {},
|
||||
dependencies: [],
|
||||
maintainers: [{
|
||||
email: "some@foo.com",
|
||||
name: "Some Foo",
|
||||
}],
|
||||
deprecated: false,
|
||||
}),
|
||||
|
||||
HelmChart.create({
|
||||
apiVersion: "some-api-version",
|
||||
name: "some-name",
|
||||
version: "some-other-version",
|
||||
repo: "some-repository",
|
||||
created: "2015-10-21T07:28:00Z",
|
||||
description: "some-description",
|
||||
keywords: [],
|
||||
sources: [],
|
||||
urls: [],
|
||||
annotations: {},
|
||||
dependencies: [],
|
||||
maintainers: [{
|
||||
email: "other@bar.com",
|
||||
name: "Other Bar",
|
||||
}],
|
||||
deprecated: false,
|
||||
}),
|
||||
]);
|
||||
});
|
||||
|
||||
it("calls for chart readme for the version", () => {
|
||||
expect(requestHelmChartReadmeMock).toHaveBeenCalledWith(
|
||||
"some-repository",
|
||||
"some-name",
|
||||
"some-version",
|
||||
);
|
||||
});
|
||||
|
||||
it("has the latest version as selected", () => {
|
||||
const actual = builder.select.getValue(
|
||||
"helm-chart-version-selector-some-repository-some-name",
|
||||
);
|
||||
|
||||
expect(actual).toBe("some-version");
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not shows spinner for details", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("spinner-for-chart-details"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows spinner for readme", () => {
|
||||
expect(
|
||||
rendered.getByTestId("spinner-for-chart-readme"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe("when readme resolves", () => {
|
||||
beforeEach(async () => {
|
||||
await requestHelmChartReadmeMock.resolve({
|
||||
callWasSuccessful: true,
|
||||
response: "some-readme",
|
||||
});
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show spinner anymore", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("spinner-for-chart-readme"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
describe("when selecting different version", () => {
|
||||
beforeEach(() => {
|
||||
requestHelmChartReadmeMock.mockClear();
|
||||
|
||||
builder.select
|
||||
.openMenu(
|
||||
"helm-chart-version-selector-some-repository-some-name",
|
||||
)
|
||||
.selectOption("some-other-version");
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("selects the version", () => {
|
||||
const actual = builder.select.getValue(
|
||||
"helm-chart-version-selector-some-repository-some-name",
|
||||
);
|
||||
|
||||
expect(actual).toBe("some-other-version");
|
||||
});
|
||||
|
||||
it("calls for chart readme for the version", () => {
|
||||
expect(requestHelmChartReadmeMock).toHaveBeenCalledWith(
|
||||
"some-repository",
|
||||
"some-name",
|
||||
"some-other-version",
|
||||
);
|
||||
});
|
||||
|
||||
describe("when readme resolves", () => {
|
||||
beforeEach(async () => {
|
||||
await requestHelmChartReadmeMock.resolve({
|
||||
callWasSuccessful: true,
|
||||
response: "some-readme",
|
||||
});
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("when selecting to install chart, calls for the default configuration of the chart with specific version", async () => {
|
||||
const installButton = rendered.getByTestId(
|
||||
"install-chart-for-some-repository-some-name",
|
||||
);
|
||||
|
||||
fireEvent.click(installButton);
|
||||
|
||||
await flushPromises();
|
||||
|
||||
expect(requestHelmChartValuesMock).toHaveBeenCalledWith(
|
||||
"some-repository",
|
||||
"some-name",
|
||||
"some-other-version",
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("when readme rejects", () => {
|
||||
beforeEach(async () => {
|
||||
await requestHelmChartReadmeMock.resolve({
|
||||
callWasSuccessful: false,
|
||||
error: "some-error",
|
||||
});
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when selecting to install the chart", () => {
|
||||
beforeEach(() => {
|
||||
requestHelmChartVersionsMock.mockClear();
|
||||
|
||||
const installButton = rendered.getByTestId(
|
||||
"install-chart-for-some-repository-some-name",
|
||||
);
|
||||
|
||||
fireEvent.click(installButton);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("has the dock tab for installing chart", () => {
|
||||
expect(
|
||||
rendered.getByTestId("dock-tab-for-some-tab-id"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows dock tab for installing chart", () => {
|
||||
expect(
|
||||
rendered.getByTestId(
|
||||
"dock-tab-content-for-some-tab-id",
|
||||
),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
+512
@@ -0,0 +1,512 @@
|
||||
/**
|
||||
* 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 type { ReadYamlFile } from "../../common/fs/read-yaml-file.injectable";
|
||||
import readYamlFileInjectable from "../../common/fs/read-yaml-file.injectable";
|
||||
import type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { HelmRepositoriesFromYaml } from "../../main/helm/repositories/get-active-helm-repositories/get-active-helm-repositories.injectable";
|
||||
import execFileInjectable, { type ExecFile } from "../../common/fs/exec-file.injectable";
|
||||
import helmBinaryPathInjectable from "../../main/helm/helm-binary-path.injectable";
|
||||
import loggerInjectable from "../../common/logger.injectable";
|
||||
import type { Logger } from "../../common/logger";
|
||||
import requestPublicHelmRepositoriesInjectable from "./child-features/preferences/renderer/adding-of-public-helm-repository/public-helm-repositories/request-public-helm-repositories.injectable";
|
||||
import showErrorNotificationInjectable from "../../renderer/components/notifications/show-error-notification.injectable";
|
||||
import { noop } from "../../common/utils";
|
||||
|
||||
describe("listing active helm repositories in preferences", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
let rendered: RenderResult;
|
||||
let readYamlFileMock: AsyncFnMock<ReadYamlFile>;
|
||||
let execFileMock: AsyncFnMock<ExecFile>;
|
||||
let loggerStub: Logger;
|
||||
let showErrorNotificationMock: jest.Mock;
|
||||
|
||||
beforeEach(async () => {
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
readYamlFileMock = asyncFn();
|
||||
execFileMock = asyncFn();
|
||||
showErrorNotificationMock = jest.fn();
|
||||
|
||||
loggerStub = {
|
||||
error: jest.fn(),
|
||||
debug: noop,
|
||||
info: noop,
|
||||
silly: noop,
|
||||
warn: noop,
|
||||
};
|
||||
|
||||
builder.beforeApplicationStart((mainDi) => {
|
||||
mainDi.override(readYamlFileInjectable, () => readYamlFileMock);
|
||||
mainDi.override(execFileInjectable, () => execFileMock);
|
||||
mainDi.override(helmBinaryPathInjectable, () => "some-helm-binary-path");
|
||||
mainDi.override(loggerInjectable, () => loggerStub);
|
||||
});
|
||||
|
||||
builder.beforeWindowStart((windowDi) => {
|
||||
windowDi.override(showErrorNotificationInjectable, () => showErrorNotificationMock);
|
||||
windowDi.override(requestPublicHelmRepositoriesInjectable, () => async () => []);
|
||||
});
|
||||
|
||||
rendered = await builder.render();
|
||||
});
|
||||
|
||||
describe("when navigating to preferences containing helm repositories", () => {
|
||||
beforeEach(async () => {
|
||||
builder.preferences.navigate();
|
||||
builder.preferences.navigation.click("kubernetes");
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("shows loader for repositories", () => {
|
||||
expect(
|
||||
rendered.getByTestId("helm-repositories-are-loading"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("calls for helm configuration", () => {
|
||||
expect(execFileMock).toHaveBeenCalledWith(
|
||||
"some-helm-binary-path",
|
||||
["env"],
|
||||
{
|
||||
maxBuffer: 34359738368,
|
||||
env: {},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("does not call for updating of repositories yet", () => {
|
||||
expect(execFileMock).not.toHaveBeenCalledWith(
|
||||
"some-helm-binary-path",
|
||||
["repo", "update"],
|
||||
{
|
||||
maxBuffer: 34359738368,
|
||||
env: {},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe("when getting configuration rejects", () => {
|
||||
beforeEach(async () => {
|
||||
await execFileMock.resolve({
|
||||
callWasSuccessful: false,
|
||||
error: Object.assign(new Error("Some error"), {
|
||||
stderr: "some-error",
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
it("shows error notification", () => {
|
||||
expect(showErrorNotificationMock).toHaveBeenCalledWith(
|
||||
"Error getting Helm configuration: some-error",
|
||||
);
|
||||
});
|
||||
|
||||
it("removes all helm controls", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("helm-controls"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("does not show loader for repositories anymore", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("helm-repositories-are-loading"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when configuration resolves without path to repository config file", () => {
|
||||
beforeEach(async () => {
|
||||
execFileMock.mockClear();
|
||||
|
||||
await execFileMock.resolveSpecific(
|
||||
["some-helm-binary-path", ["env"]],
|
||||
{
|
||||
callWasSuccessful: true,
|
||||
response: "HELM_REPOSITORY_CACHE=some-helm-repository-cache-path",
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("logs error", () => {
|
||||
expect(loggerStub.error).toHaveBeenCalledWith(
|
||||
"Tried to get Helm repositories, but HELM_REPOSITORY_CONFIG was not present in `$ helm env`.",
|
||||
);
|
||||
});
|
||||
|
||||
it("shows error notification", () => {
|
||||
expect(showErrorNotificationMock).toHaveBeenCalledWith(
|
||||
"Error getting Helm configuration: Tried to get Helm repositories, but HELM_REPOSITORY_CONFIG was not present in `$ helm env`.",
|
||||
);
|
||||
});
|
||||
|
||||
it("removes all helm controls", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("helm-controls"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("does not show loader for repositories anymore", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("helm-repositories-are-loading"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when configuration resolves without path to repository cache directory", () => {
|
||||
beforeEach(async () => {
|
||||
execFileMock.mockClear();
|
||||
|
||||
await execFileMock.resolveSpecific(
|
||||
["some-helm-binary-path", ["env"]],
|
||||
{
|
||||
callWasSuccessful: true,
|
||||
response: "HELM_REPOSITORY_CONFIG=some-helm-repository-config-file.yaml",
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("logs error", () => {
|
||||
expect(loggerStub.error).toHaveBeenCalledWith(
|
||||
"Tried to get Helm repositories, but HELM_REPOSITORY_CACHE was not present in `$ helm env`.",
|
||||
);
|
||||
});
|
||||
|
||||
it("shows error notification", () => {
|
||||
expect(showErrorNotificationMock).toHaveBeenCalledWith(
|
||||
"Error getting Helm configuration: Tried to get Helm repositories, but HELM_REPOSITORY_CACHE was not present in `$ helm env`.",
|
||||
);
|
||||
});
|
||||
|
||||
it("removes all helm controls", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("helm-controls"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("does not show loader for repositories anymore", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("helm-repositories-are-loading"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when configuration resolves", () => {
|
||||
beforeEach(async () => {
|
||||
execFileMock.mockClear();
|
||||
|
||||
await execFileMock.resolveSpecific(
|
||||
["some-helm-binary-path", ["env"]],
|
||||
{
|
||||
callWasSuccessful: true,
|
||||
response: [
|
||||
"HELM_REPOSITORY_CONFIG=some-helm-repository-config-file.yaml",
|
||||
"HELM_REPOSITORY_CACHE=some-helm-repository-cache-path",
|
||||
].join("\n"),
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("calls for update of repositories", () => {
|
||||
expect(execFileMock).toHaveBeenCalledWith(
|
||||
"some-helm-binary-path",
|
||||
["repo", "update"],
|
||||
{
|
||||
maxBuffer: 34359738368,
|
||||
env: {},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("does not call for repositories yet", () => {
|
||||
expect(readYamlFileMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("when updating repositories reject with any other error", () => {
|
||||
beforeEach(async () => {
|
||||
await execFileMock.resolve({
|
||||
callWasSuccessful: false,
|
||||
error: Object.assign(new Error("Some error"), {
|
||||
stderr: "Some error",
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
it("shows error notification", () => {
|
||||
expect(showErrorNotificationMock).toHaveBeenCalledWith(
|
||||
"Error updating Helm repositories: Some error",
|
||||
);
|
||||
});
|
||||
|
||||
it("removes all helm controls", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("helm-controls"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("does not show loader for repositories anymore", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("helm-repositories-are-loading"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when updating repositories reject with error about no existing repositories", () => {
|
||||
beforeEach(async () => {
|
||||
execFileMock.mockClear();
|
||||
|
||||
await execFileMock.resolve({
|
||||
callWasSuccessful: false,
|
||||
error: Object.assign(new Error("no repositories found. You must add one before updating"), {
|
||||
stderr: "no repositories found. You must add one before updating",
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("still shows the loader for repositories", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("helm-repositories-are-loading"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it('adds "bitnami" as default repository', () => {
|
||||
expect(execFileMock).toHaveBeenCalledWith(
|
||||
"some-helm-binary-path",
|
||||
["repo", "add", "bitnami", "https://charts.bitnami.com/bitnami"],
|
||||
{
|
||||
maxBuffer: 34359738368,
|
||||
env: {},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
describe("when adding default repository reject", () => {
|
||||
beforeEach(async () => {
|
||||
await execFileMock.resolve({
|
||||
callWasSuccessful: false,
|
||||
error: Object.assign(new Error("Some error"), {
|
||||
stderr: "Some error",
|
||||
}),
|
||||
});
|
||||
});
|
||||
|
||||
it("shows error notification", () => {
|
||||
expect(showErrorNotificationMock).toHaveBeenCalledWith(
|
||||
"Error when adding default Helm repository: Some error",
|
||||
);
|
||||
});
|
||||
|
||||
it("removes all helm controls", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("helm-controls"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("does not show loader for repositories anymore", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("helm-repositories-are-loading"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
|
||||
describe("when adding of default repository resolves", () => {
|
||||
beforeEach(async () => {
|
||||
readYamlFileMock.mockClear();
|
||||
|
||||
await execFileMock.resolveSpecific(
|
||||
[
|
||||
"some-helm-binary-path",
|
||||
[
|
||||
"repo",
|
||||
"add",
|
||||
"bitnami",
|
||||
"https://charts.bitnami.com/bitnami",
|
||||
],
|
||||
],
|
||||
{
|
||||
callWasSuccessful: true,
|
||||
response: "",
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("still shows the loader for repositories", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("helm-repositories-are-loading"),
|
||||
).toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("calls for repositories again", () => {
|
||||
expect(readYamlFileMock).toHaveBeenCalledWith(
|
||||
"some-helm-repository-config-file.yaml",
|
||||
);
|
||||
});
|
||||
|
||||
describe("when another call for repositories resolve", () => {
|
||||
beforeEach(async () => {
|
||||
await readYamlFileMock.resolveSpecific(
|
||||
["some-helm-repository-config-file.yaml"],
|
||||
|
||||
{
|
||||
repositories: [
|
||||
{
|
||||
name: "bitnami",
|
||||
url: "https://charts.bitnami.com/bitnami",
|
||||
caFile: "irrelevant",
|
||||
certFile: "irrelevant",
|
||||
insecure_skip_tls_verify: false,
|
||||
keyFile: "irrelevant",
|
||||
pass_credentials_all: false,
|
||||
password: "irrelevant",
|
||||
username: "irrelevant",
|
||||
},
|
||||
],
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("does not show loader for repositories anymore", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("helm-repositories-are-loading"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows the added repository", () => {
|
||||
const actual = rendered.getByTestId("helm-repository-bitnami");
|
||||
|
||||
expect(actual).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe("when updating repositories resolve", () => {
|
||||
beforeEach(async () => {
|
||||
execFileMock.mockClear();
|
||||
|
||||
await execFileMock.resolveSpecific(
|
||||
["some-helm-binary-path", ["repo", "update"]],
|
||||
{
|
||||
callWasSuccessful: true,
|
||||
response: "",
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("loads repositories from file system", () => {
|
||||
expect(readYamlFileMock).toHaveBeenCalledWith(
|
||||
"some-helm-repository-config-file.yaml",
|
||||
);
|
||||
});
|
||||
|
||||
describe("when repositories resolves", () => {
|
||||
beforeEach(async () => {
|
||||
execFileMock.mockClear();
|
||||
|
||||
await readYamlFileMock.resolveSpecific(
|
||||
["some-helm-repository-config-file.yaml"],
|
||||
repositoryConfigStub,
|
||||
);
|
||||
});
|
||||
|
||||
it("does not add default repository", () => {
|
||||
expect(execFileMock).not.toHaveBeenCalledWith(
|
||||
"some-helm-binary-path",
|
||||
["repo", "add", "bitnami", "https://charts.bitnami.com/bitnami"],
|
||||
{
|
||||
maxBuffer: 34359738368,
|
||||
env: {},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("does not show loader for repositories anymore", () => {
|
||||
expect(
|
||||
rendered.queryByTestId("helm-repositories-are-loading"),
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
it("shows repositories in use", () => {
|
||||
const actual = rendered.getAllByTestId(
|
||||
/^helm-repository-(some-repository|some-other-repository)$/,
|
||||
);
|
||||
|
||||
expect(actual).toHaveLength(2);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
const repositoryConfigStub: HelmRepositoriesFromYaml = {
|
||||
repositories: [
|
||||
{
|
||||
name: "some-repository",
|
||||
url: "some-repository-url",
|
||||
caFile: "irrelevant",
|
||||
certFile: "irrelevant",
|
||||
insecure_skip_tls_verify: false,
|
||||
keyFile: "irrelevant",
|
||||
pass_credentials_all: false,
|
||||
password: "irrelevant",
|
||||
username: "irrelevant",
|
||||
},
|
||||
|
||||
{
|
||||
name: "some-other-repository",
|
||||
url: "some-other-repository-url",
|
||||
caFile: "irrelevant",
|
||||
certFile: "irrelevant",
|
||||
insecure_skip_tls_verify: false,
|
||||
keyFile: "irrelevant",
|
||||
pass_credentials_all: false,
|
||||
password: "irrelevant",
|
||||
username: "irrelevant",
|
||||
},
|
||||
],
|
||||
};
|
||||
+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 { 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 type { AsyncFnMock } from "@async-fn/jest";
|
||||
import asyncFn from "@async-fn/jest";
|
||||
import type { ExecFile } from "../../common/fs/exec-file.injectable";
|
||||
import execFileInjectable from "../../common/fs/exec-file.injectable";
|
||||
import helmBinaryPathInjectable from "../../main/helm/helm-binary-path.injectable";
|
||||
import getActiveHelmRepositoriesInjectable from "../../main/helm/repositories/get-active-helm-repositories/get-active-helm-repositories.injectable";
|
||||
import type { HelmRepo } from "../../common/helm/helm-repo";
|
||||
import requestPublicHelmRepositoriesInjectable from "./child-features/preferences/renderer/adding-of-public-helm-repository/public-helm-repositories/request-public-helm-repositories.injectable";
|
||||
import type { AsyncResult } from "../../common/utils/async-result";
|
||||
|
||||
describe("remove helm repository from list of active repositories in preferences", () => {
|
||||
let builder: ApplicationBuilder;
|
||||
let rendered: RenderResult;
|
||||
let getActiveHelmRepositoriesMock: AsyncFnMock<() => Promise<AsyncResult<HelmRepo[]>>>;
|
||||
let execFileMock: AsyncFnMock<ExecFile>;
|
||||
|
||||
beforeEach(async () => {
|
||||
builder = getApplicationBuilder();
|
||||
|
||||
execFileMock = asyncFn();
|
||||
getActiveHelmRepositoriesMock = asyncFn();
|
||||
|
||||
builder.beforeApplicationStart((mainDi) => {
|
||||
mainDi.override(getActiveHelmRepositoriesInjectable, () => getActiveHelmRepositoriesMock);
|
||||
mainDi.override(execFileInjectable, () => execFileMock);
|
||||
mainDi.override(helmBinaryPathInjectable, () => "some-helm-binary-path");
|
||||
});
|
||||
|
||||
builder.beforeWindowStart((windowDi) => {
|
||||
windowDi.override(requestPublicHelmRepositoriesInjectable, () => async () => []);
|
||||
});
|
||||
|
||||
rendered = await builder.render();
|
||||
});
|
||||
|
||||
describe("when navigating to preferences containing helm repositories", () => {
|
||||
beforeEach(async () => {
|
||||
builder.preferences.navigate();
|
||||
builder.preferences.navigation.click("kubernetes");
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("when active repositories resolve", () => {
|
||||
beforeEach(async () => {
|
||||
getActiveHelmRepositoriesMock.resolve({
|
||||
callWasSuccessful: true,
|
||||
response: [{
|
||||
name: "some-active-repository",
|
||||
url: "some-url",
|
||||
cacheFilePath: "/some-cache-file",
|
||||
}],
|
||||
});
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
describe("when removing repository", () => {
|
||||
beforeEach(() => {
|
||||
execFileMock.mockClear();
|
||||
getActiveHelmRepositoriesMock.mockClear();
|
||||
|
||||
const removeButton = rendered.getByTestId(
|
||||
"remove-helm-repository-some-active-repository",
|
||||
);
|
||||
|
||||
fireEvent.click(removeButton);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("removes the repository", () => {
|
||||
expect(execFileMock).toHaveBeenCalledWith(
|
||||
"some-helm-binary-path",
|
||||
["repo", "remove", "some-active-repository"],
|
||||
{
|
||||
maxBuffer: 34359738368,
|
||||
env: {},
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("does not reload active repositories yet", () => {
|
||||
expect(getActiveHelmRepositoriesMock).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
describe("when removing resolves", () => {
|
||||
beforeEach(async () => {
|
||||
await execFileMock.resolveSpecific(
|
||||
[
|
||||
"some-helm-binary-path",
|
||||
["repo", "remove", "some-active-repository"],
|
||||
],
|
||||
{
|
||||
callWasSuccessful: true,
|
||||
response: "",
|
||||
},
|
||||
);
|
||||
});
|
||||
|
||||
it("renders", () => {
|
||||
expect(rendered.baseElement).toMatchSnapshot();
|
||||
});
|
||||
|
||||
it("reloads active repositories", () => {
|
||||
expect(getActiveHelmRepositoriesMock).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
+5973
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,268 @@
|
||||
/**
|
||||
* 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 { advanceFakeTime, testUsingFakeTime } from "../../../common/test-utils/use-fake-time";
|
||||
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);
|
||||
});
|
||||
|
||||
testUsingFakeTime("2020-01-12 12:00:00");
|
||||
|
||||
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();
|
||||
advanceFakeTime(100);
|
||||
});
|
||||
|
||||
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();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
Reference in new issue
Block a user