mirror of
https://github.com/lensapp/lens.git
synced 2025-05-20 05:10:56 +00:00
Refactor testing harness to use defaults
- Move tests into defaultly named test folders
- Use default test suffix of ".test" instead of "_test"
- Make cluster-store tests unit tests by adding more
nesting, so that order of tests doesn't matter
Signed-off-by: Sebastian Malton <smalton@mirantis.com>
This commit is contained in:
parent
14d3d88278
commit
dc0c5dc9ea
@ -60,7 +60,6 @@
|
|||||||
]
|
]
|
||||||
},
|
},
|
||||||
"jest": {
|
"jest": {
|
||||||
"testRegex": ".*_(spec|test)\\.[jt]sx?$",
|
|
||||||
"collectCoverage": false,
|
"collectCoverage": false,
|
||||||
"verbose": true,
|
"verbose": true,
|
||||||
"testEnvironment": "node",
|
"testEnvironment": "node",
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import fs from "fs";
|
import fs from "fs";
|
||||||
import mockFs from "mock-fs";
|
import mockFs from "mock-fs";
|
||||||
import yaml from "js-yaml";
|
import yaml from "js-yaml";
|
||||||
import { Cluster } from "../main/cluster";
|
import { Cluster } from "../../main/cluster";
|
||||||
import { ClusterStore } from "./cluster-store";
|
import { ClusterStore } from "../cluster-store";
|
||||||
import { workspaceStore } from "./workspace-store";
|
import { workspaceStore } from "../workspace-store";
|
||||||
|
|
||||||
const testDataIcon = fs.readFileSync("test-data/cluster-store-migration-icon.png")
|
const testDataIcon = fs.readFileSync("test-data/cluster-store-migration-icon.png")
|
||||||
|
|
||||||
@ -12,7 +12,7 @@ console.log("") // fix bug
|
|||||||
let clusterStore: ClusterStore;
|
let clusterStore: ClusterStore;
|
||||||
|
|
||||||
describe("empty config", () => {
|
describe("empty config", () => {
|
||||||
beforeAll(() => {
|
beforeEach(() => {
|
||||||
ClusterStore.resetInstance();
|
ClusterStore.resetInstance();
|
||||||
const mockOpts = {
|
const mockOpts = {
|
||||||
'tmp': {
|
'tmp': {
|
||||||
@ -24,109 +24,120 @@ describe("empty config", () => {
|
|||||||
return clusterStore.load();
|
return clusterStore.load();
|
||||||
})
|
})
|
||||||
|
|
||||||
afterAll(() => {
|
afterEach(() => {
|
||||||
mockFs.restore();
|
mockFs.restore();
|
||||||
})
|
})
|
||||||
|
|
||||||
it("adds new cluster to store", async () => {
|
describe("with foo cluster added", () => {
|
||||||
const cluster = new Cluster({
|
beforeEach(() => {
|
||||||
id: "foo",
|
clusterStore.addCluster(
|
||||||
contextName: "minikube",
|
new Cluster({
|
||||||
preferences: {
|
id: "foo",
|
||||||
terminalCWD: "/tmp",
|
contextName: "minikube",
|
||||||
icon: "data:;base64,iVBORw0KGgoAAAANSUhEUgAAA1wAAAKoCAYAAABjkf5",
|
preferences: {
|
||||||
clusterName: "minikube"
|
terminalCWD: "/tmp",
|
||||||
},
|
icon: "data:image/jpeg;base64, iVBORw0KGgoAAAANSUhEUgAAA1wAAAKoCAYAAABjkf5",
|
||||||
kubeConfigPath: ClusterStore.embedCustomKubeConfig("foo", "fancy foo config"),
|
clusterName: "minikube"
|
||||||
workspace: workspaceStore.currentWorkspaceId
|
},
|
||||||
|
kubeConfigPath: ClusterStore.embedCustomKubeConfig("foo", "fancy foo config"),
|
||||||
|
workspace: workspaceStore.currentWorkspaceId
|
||||||
|
})
|
||||||
|
);
|
||||||
|
})
|
||||||
|
|
||||||
|
it("adds new cluster to store", async () => {
|
||||||
|
const storedCluster = clusterStore.getById("foo");
|
||||||
|
expect(storedCluster.id).toBe("foo");
|
||||||
|
expect(storedCluster.preferences.terminalCWD).toBe("/tmp");
|
||||||
|
expect(storedCluster.preferences.icon).toBe("data:image/jpeg;base64, iVBORw0KGgoAAAANSUhEUgAAA1wAAAKoCAYAAABjkf5");
|
||||||
|
})
|
||||||
|
|
||||||
|
it("adds cluster to default workspace", () => {
|
||||||
|
const storedCluster = clusterStore.getById("foo");
|
||||||
|
expect(storedCluster.workspace).toBe("default");
|
||||||
|
})
|
||||||
|
|
||||||
|
it("removes cluster from store", async () => {
|
||||||
|
await clusterStore.removeById("foo");
|
||||||
|
expect(clusterStore.getById("foo")).toBeUndefined();
|
||||||
|
})
|
||||||
|
|
||||||
|
it("sets active cluster", () => {
|
||||||
|
clusterStore.setActive("foo");
|
||||||
|
expect(clusterStore.activeCluster.id).toBe("foo");
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
describe("with prod and dev clusters added", () => {
|
||||||
|
beforeEach(() => {
|
||||||
|
clusterStore.addCluster(
|
||||||
|
new Cluster({
|
||||||
|
id: "prod",
|
||||||
|
contextName: "prod",
|
||||||
|
preferences: {
|
||||||
|
clusterName: "prod"
|
||||||
|
},
|
||||||
|
kubeConfigPath: ClusterStore.embedCustomKubeConfig("prod", "fancy config"),
|
||||||
|
workspace: "workstation"
|
||||||
|
}),
|
||||||
|
new Cluster({
|
||||||
|
id: "dev",
|
||||||
|
contextName: "dev",
|
||||||
|
preferences: {
|
||||||
|
clusterName: "dev"
|
||||||
|
},
|
||||||
|
kubeConfigPath: ClusterStore.embedCustomKubeConfig("dev", "fancy config"),
|
||||||
|
workspace: "workstation"
|
||||||
|
})
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
it("check if store can contain multiple clusters", () => {
|
||||||
|
expect(clusterStore.hasClusters()).toBeTruthy();
|
||||||
|
expect(clusterStore.clusters.size).toBe(2);
|
||||||
});
|
});
|
||||||
clusterStore.addCluster(cluster);
|
|
||||||
const storedCluster = clusterStore.getById(cluster.id);
|
|
||||||
expect(storedCluster.id).toBe(cluster.id);
|
|
||||||
expect(storedCluster.preferences.terminalCWD).toBe(cluster.preferences.terminalCWD);
|
|
||||||
expect(storedCluster.preferences.icon).toBe(cluster.preferences.icon);
|
|
||||||
})
|
|
||||||
|
|
||||||
it("adds cluster to default workspace", () => {
|
it("gets clusters by workspaces", () => {
|
||||||
const storedCluster = clusterStore.getById("foo");
|
const wsClusters = clusterStore.getByWorkspaceId("workstation");
|
||||||
expect(storedCluster.workspace).toBe("default");
|
const defaultClusters = clusterStore.getByWorkspaceId("default");
|
||||||
})
|
expect(defaultClusters.length).toBe(0);
|
||||||
|
expect(wsClusters.length).toBe(2);
|
||||||
|
expect(wsClusters[0].id).toBe("prod");
|
||||||
|
expect(wsClusters[1].id).toBe("dev");
|
||||||
|
})
|
||||||
|
|
||||||
it("check if store can contain multiple clusters", () => {
|
it("check if cluster's kubeconfig file saved", () => {
|
||||||
const prodCluster = new Cluster({
|
const file = ClusterStore.embedCustomKubeConfig("boo", "kubeconfig");
|
||||||
id: "prod",
|
expect(fs.readFileSync(file, "utf8")).toBe("kubeconfig");
|
||||||
contextName: "prod",
|
})
|
||||||
preferences: {
|
|
||||||
clusterName: "prod"
|
|
||||||
},
|
|
||||||
kubeConfigPath: ClusterStore.embedCustomKubeConfig("prod", "fancy config"),
|
|
||||||
workspace: "workstation"
|
|
||||||
});
|
|
||||||
const devCluster = new Cluster({
|
|
||||||
id: "dev",
|
|
||||||
contextName: "dev",
|
|
||||||
preferences: {
|
|
||||||
clusterName: "dev"
|
|
||||||
},
|
|
||||||
kubeConfigPath: ClusterStore.embedCustomKubeConfig("dev", "fancy config"),
|
|
||||||
workspace: "workstation"
|
|
||||||
});
|
|
||||||
clusterStore.addCluster(prodCluster);
|
|
||||||
clusterStore.addCluster(devCluster);
|
|
||||||
expect(clusterStore.hasClusters()).toBeTruthy();
|
|
||||||
expect(clusterStore.clusters.size).toBe(3);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("gets clusters by workspaces", () => {
|
it("check if reorderring works for same from and to", () => {
|
||||||
const wsClusters = clusterStore.getByWorkspaceId("workstation");
|
clusterStore.swapIconOrders("workstation", 1, 1)
|
||||||
const defaultClusters = clusterStore.getByWorkspaceId("default");
|
|
||||||
expect(defaultClusters.length).toBe(1);
|
|
||||||
expect(wsClusters.length).toBe(2);
|
|
||||||
expect(wsClusters[0].id).toBe("prod");
|
|
||||||
expect(wsClusters[1].id).toBe("dev");
|
|
||||||
})
|
|
||||||
|
|
||||||
it("sets active cluster", () => {
|
const clusters = clusterStore.getByWorkspaceId("workstation");
|
||||||
clusterStore.setActive("foo");
|
expect(clusters[0].id).toBe("prod")
|
||||||
expect(clusterStore.activeCluster.id).toBe("foo");
|
expect(clusters[0].preferences.iconOrder).toBe(0)
|
||||||
})
|
expect(clusters[1].id).toBe("dev")
|
||||||
|
expect(clusters[1].preferences.iconOrder).toBe(1)
|
||||||
|
})
|
||||||
|
|
||||||
it("check if cluster's kubeconfig file saved", () => {
|
it("check if reorderring works for different from and to", () => {
|
||||||
const file = ClusterStore.embedCustomKubeConfig("boo", "kubeconfig");
|
clusterStore.swapIconOrders("workstation", 0, 1)
|
||||||
expect(fs.readFileSync(file, "utf8")).toBe("kubeconfig");
|
|
||||||
})
|
|
||||||
|
|
||||||
it("check if reorderring works for same from and to", () => {
|
const clusters = clusterStore.getByWorkspaceId("workstation");
|
||||||
clusterStore.swapIconOrders("workstation", 1, 1)
|
expect(clusters[0].id).toBe("dev")
|
||||||
|
expect(clusters[0].preferences.iconOrder).toBe(0)
|
||||||
|
expect(clusters[1].id).toBe("prod")
|
||||||
|
expect(clusters[1].preferences.iconOrder).toBe(1)
|
||||||
|
})
|
||||||
|
|
||||||
const clusters = clusterStore.getByWorkspaceId("workstation");
|
it("check if after icon reordering, changing workspaces still works", () => {
|
||||||
expect(clusters[0].id).toBe("prod")
|
clusterStore.swapIconOrders("workstation", 1, 1)
|
||||||
expect(clusters[0].preferences.iconOrder).toBe(0)
|
clusterStore.getById("prod").workspace = "default"
|
||||||
expect(clusters[1].id).toBe("dev")
|
|
||||||
expect(clusters[1].preferences.iconOrder).toBe(1)
|
|
||||||
});
|
|
||||||
|
|
||||||
it("check if reorderring works for different from and to", () => {
|
expect(clusterStore.getByWorkspaceId("workstation").length).toBe(1);
|
||||||
clusterStore.swapIconOrders("workstation", 0, 1)
|
expect(clusterStore.getByWorkspaceId("default").length).toBe(1);
|
||||||
|
})
|
||||||
const clusters = clusterStore.getByWorkspaceId("workstation");
|
|
||||||
expect(clusters[0].id).toBe("dev")
|
|
||||||
expect(clusters[0].preferences.iconOrder).toBe(0)
|
|
||||||
expect(clusters[1].id).toBe("prod")
|
|
||||||
expect(clusters[1].preferences.iconOrder).toBe(1)
|
|
||||||
});
|
|
||||||
|
|
||||||
it("check if after icon reordering, changing workspaces still works", () => {
|
|
||||||
clusterStore.swapIconOrders("workstation", 1, 1)
|
|
||||||
clusterStore.getById("prod").workspace = "default"
|
|
||||||
|
|
||||||
expect(clusterStore.getByWorkspaceId("workstation").length).toBe(1);
|
|
||||||
expect(clusterStore.getByWorkspaceId("default").length).toBe(2);
|
|
||||||
});
|
|
||||||
|
|
||||||
it("removes cluster from store", async () => {
|
|
||||||
await clusterStore.removeById("foo");
|
|
||||||
expect(clusterStore.getById("foo")).toBeUndefined();
|
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ jest.mock("electron", () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
import { UserStore } from "./user-store"
|
import { UserStore } from "../user-store"
|
||||||
import { SemVer } from "semver"
|
import { SemVer } from "semver"
|
||||||
import electron from "electron"
|
import electron from "electron"
|
||||||
|
|
||||||
@ -10,7 +10,7 @@ jest.mock("electron", () => {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
import { WorkspaceStore } from "./workspace-store"
|
import { WorkspaceStore } from "../workspace-store"
|
||||||
|
|
||||||
describe("workspace store tests", () => {
|
describe("workspace store tests", () => {
|
||||||
describe("for an empty config", () => {
|
describe("for an empty config", () => {
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import { splitArray } from "./splitArray";
|
import { splitArray } from "../splitArray";
|
||||||
|
|
||||||
describe("split array on element tests", () => {
|
describe("split array on element tests", () => {
|
||||||
test("empty array", () => {
|
test("empty array", () => {
|
||||||
@ -16,7 +16,7 @@ describe("split array on element tests", () => {
|
|||||||
test("one elements, in array", () => {
|
test("one elements, in array", () => {
|
||||||
expect(splitArray([1], 1)).toStrictEqual([[], [], true]);
|
expect(splitArray([1], 1)).toStrictEqual([[], [], true]);
|
||||||
});
|
});
|
||||||
|
|
||||||
test("ten elements, in front array", () => {
|
test("ten elements, in front array", () => {
|
||||||
expect(splitArray([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 0)).toStrictEqual([[], [1, 2, 3, 4, 5, 6, 7, 8, 9], true]);
|
expect(splitArray([0, 1, 2, 3, 4, 5, 6, 7, 8, 9], 0)).toStrictEqual([[], [1, 2, 3, 4, 5, 6, 7, 8, 9], true]);
|
||||||
});
|
});
|
||||||
@ -1,11 +1,11 @@
|
|||||||
import { IKubeApiParsed, parseKubeApi } from "./kube-api-parse";
|
import { IKubeApiParsed, parseKubeApi } from "../kube-api-parse";
|
||||||
|
|
||||||
interface KubeApi_Parse_Test {
|
interface KubeApiParseTestData {
|
||||||
url: string;
|
url: string;
|
||||||
expected: Required<IKubeApiParsed>;
|
expected: Required<IKubeApiParsed>;
|
||||||
}
|
}
|
||||||
|
|
||||||
const tests: KubeApi_Parse_Test[] = [
|
const tests: KubeApiParseTestData[] = [
|
||||||
{
|
{
|
||||||
url: "/apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions/prometheuses.monitoring.coreos.com",
|
url: "/apis/apiextensions.k8s.io/v1beta1/customresourcedefinitions/prometheuses.monitoring.coreos.com",
|
||||||
expected: {
|
expected: {
|
||||||
@ -125,11 +125,10 @@ const tests: KubeApi_Parse_Test[] = [
|
|||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
describe.only("parseApi unit tests", () => {
|
describe("parseApi unit tests", () => {
|
||||||
for (const i in tests) {
|
for (const { url, expected } of tests) {
|
||||||
const { url: tUrl, expected:tExpect} = tests[i];
|
test(`testing "${url}"`, () => {
|
||||||
test(`test #${parseInt(i)+1}`, () => {
|
expect(parseKubeApi(url)).toStrictEqual(expected);
|
||||||
expect(parseKubeApi(tUrl)).toStrictEqual(tExpect);
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
@ -4,7 +4,7 @@ import { Input } from "../../input";
|
|||||||
import { observable, autorun } from "mobx";
|
import { observable, autorun } from "mobx";
|
||||||
import { observer, disposeOnUnmount } from "mobx-react";
|
import { observer, disposeOnUnmount } from "mobx-react";
|
||||||
import { SubTitle } from "../../layout/sub-title";
|
import { SubTitle } from "../../layout/sub-title";
|
||||||
import { isRequired } from "../../input/input.validators";
|
import { isRequired } from "../../input/input_validators";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
cluster: Cluster;
|
cluster: Cluster;
|
||||||
@ -33,7 +33,7 @@ export class ClusterNameSetting extends React.Component<Props> {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SubTitle title="Cluster Name"/>
|
<SubTitle title="Cluster Name" />
|
||||||
<p>Define cluster name.</p>
|
<p>Define cluster name.</p>
|
||||||
<Input
|
<Input
|
||||||
theme="round-black"
|
theme="round-black"
|
||||||
|
|||||||
@ -3,7 +3,7 @@ import { observable, autorun } from "mobx";
|
|||||||
import { observer, disposeOnUnmount } from "mobx-react";
|
import { observer, disposeOnUnmount } from "mobx-react";
|
||||||
import { Cluster } from "../../../../main/cluster";
|
import { Cluster } from "../../../../main/cluster";
|
||||||
import { Input } from "../../input";
|
import { Input } from "../../input";
|
||||||
import { isUrl } from "../../input/input.validators";
|
import { isUrl } from "../../input/input_validators";
|
||||||
import { SubTitle } from "../../layout/sub-title";
|
import { SubTitle } from "../../layout/sub-title";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@ -33,7 +33,7 @@ export class ClusterProxySetting extends React.Component<Props> {
|
|||||||
render() {
|
render() {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SubTitle title="HTTP Proxy"/>
|
<SubTitle title="HTTP Proxy" />
|
||||||
<p>HTTP Proxy server. Used for communicating with Kubernetes API.</p>
|
<p>HTTP Proxy server. Used for communicating with Kubernetes API.</p>
|
||||||
<Input
|
<Input
|
||||||
theme="round-black"
|
theme="round-black"
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import { _i18n } from "../../i18n";
|
|||||||
import { Dialog, DialogProps } from "../dialog";
|
import { Dialog, DialogProps } from "../dialog";
|
||||||
import { Wizard, WizardStep } from "../wizard";
|
import { Wizard, WizardStep } from "../wizard";
|
||||||
import { Input } from "../input";
|
import { Input } from "../input";
|
||||||
import { systemName } from "../input/input.validators";
|
import { systemName } from "../input/input_validators";
|
||||||
import { IResourceQuotaValues, resourceQuotaApi } from "../../api/endpoints/resource-quota.api";
|
import { IResourceQuotaValues, resourceQuotaApi } from "../../api/endpoints/resource-quota.api";
|
||||||
import { Select } from "../select";
|
import { Select } from "../select";
|
||||||
import { Icon } from "../icon";
|
import { Icon } from "../icon";
|
||||||
@ -73,7 +73,7 @@ export class AddQuotaDialog extends React.Component<Props> {
|
|||||||
const isCount = quota.startsWith("count/");
|
const isCount = quota.startsWith("count/");
|
||||||
const icon = isCompute ? "memory" : isStorage ? "storage" : isCount ? "looks_one" : "";
|
const icon = isCompute ? "memory" : isStorage ? "storage" : isCount ? "looks_one" : "";
|
||||||
return {
|
return {
|
||||||
label: icon ? <span className="nobr"><Icon material={icon}/> {quota}</span> : quota,
|
label: icon ? <span className="nobr"><Icon material={icon} /> {quota}</span> : quota,
|
||||||
value: quota,
|
value: quota,
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
@ -151,7 +151,7 @@ export class AddQuotaDialog extends React.Component<Props> {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<SubTitle title={<Trans>Namespace</Trans>}/>
|
<SubTitle title={<Trans>Namespace</Trans>} />
|
||||||
<NamespaceSelect
|
<NamespaceSelect
|
||||||
value={this.namespace}
|
value={this.namespace}
|
||||||
placeholder={_i18n._(t`Namespace`)}
|
placeholder={_i18n._(t`Namespace`)}
|
||||||
@ -160,7 +160,7 @@ export class AddQuotaDialog extends React.Component<Props> {
|
|||||||
onChange={({ value }) => this.namespace = value}
|
onChange={({ value }) => this.namespace = value}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<SubTitle title={<Trans>Values</Trans>}/>
|
<SubTitle title={<Trans>Values</Trans>} />
|
||||||
<div className="flex gaps align-center">
|
<div className="flex gaps align-center">
|
||||||
<Select
|
<Select
|
||||||
className="quota-select"
|
className="quota-select"
|
||||||
@ -191,7 +191,7 @@ export class AddQuotaDialog extends React.Component<Props> {
|
|||||||
<div key={quota} className="quota flex gaps inline align-center">
|
<div key={quota} className="quota flex gaps inline align-center">
|
||||||
<div className="name">{quota}</div>
|
<div className="name">{quota}</div>
|
||||||
<div className="value">{value}</div>
|
<div className="value">{value}</div>
|
||||||
<Icon material="clear" onClick={() => this.quotas[quota] = ""}/>
|
<Icon material="clear" onClick={() => this.quotas[quota] = ""} />
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
})}
|
})}
|
||||||
|
|||||||
@ -8,7 +8,7 @@ import { _i18n } from "../../i18n";
|
|||||||
import { Dialog, DialogProps } from "../dialog";
|
import { Dialog, DialogProps } from "../dialog";
|
||||||
import { Wizard, WizardStep } from "../wizard";
|
import { Wizard, WizardStep } from "../wizard";
|
||||||
import { Input } from "../input";
|
import { Input } from "../input";
|
||||||
import { systemName } from "../input/input.validators";
|
import { systemName } from "../input/input_validators";
|
||||||
import { Secret, secretsApi, SecretType } from "../../api/endpoints";
|
import { Secret, secretsApi, SecretType } from "../../api/endpoints";
|
||||||
import { SubTitle } from "../layout/sub-title";
|
import { SubTitle } from "../layout/sub-title";
|
||||||
import { NamespaceSelect } from "../+namespaces/namespace-select";
|
import { NamespaceSelect } from "../+namespaces/namespace-select";
|
||||||
@ -184,7 +184,7 @@ export class AddSecretDialog extends React.Component<Props> {
|
|||||||
<Wizard header={header} done={this.close}>
|
<Wizard header={header} done={this.close}>
|
||||||
<WizardStep contentClass="flow column" nextLabel={<Trans>Create</Trans>} next={this.createSecret}>
|
<WizardStep contentClass="flow column" nextLabel={<Trans>Create</Trans>} next={this.createSecret}>
|
||||||
<div className="secret-name">
|
<div className="secret-name">
|
||||||
<SubTitle title={<Trans>Secret name</Trans>}/>
|
<SubTitle title={<Trans>Secret name</Trans>} />
|
||||||
<Input
|
<Input
|
||||||
autoFocus required
|
autoFocus required
|
||||||
placeholder={_i18n._(t`Name`)}
|
placeholder={_i18n._(t`Name`)}
|
||||||
@ -194,7 +194,7 @@ export class AddSecretDialog extends React.Component<Props> {
|
|||||||
</div>
|
</div>
|
||||||
<div className="flex auto gaps">
|
<div className="flex auto gaps">
|
||||||
<div className="secret-namespace">
|
<div className="secret-namespace">
|
||||||
<SubTitle title={<Trans>Namespace</Trans>}/>
|
<SubTitle title={<Trans>Namespace</Trans>} />
|
||||||
<NamespaceSelect
|
<NamespaceSelect
|
||||||
themeName="light"
|
themeName="light"
|
||||||
value={namespace}
|
value={namespace}
|
||||||
@ -202,7 +202,7 @@ export class AddSecretDialog extends React.Component<Props> {
|
|||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="secret-type">
|
<div className="secret-type">
|
||||||
<SubTitle title={<Trans>Secret type</Trans>}/>
|
<SubTitle title={<Trans>Secret type</Trans>} />
|
||||||
<Select
|
<Select
|
||||||
themeName="light"
|
themeName="light"
|
||||||
options={this.types}
|
options={this.types}
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import { Wizard, WizardStep } from "../wizard";
|
|||||||
import { namespaceStore } from "./namespace.store";
|
import { namespaceStore } from "./namespace.store";
|
||||||
import { Namespace } from "../../api/endpoints";
|
import { Namespace } from "../../api/endpoints";
|
||||||
import { Input } from "../input";
|
import { Input } from "../input";
|
||||||
import { systemName } from "../input/input.validators";
|
import { systemName } from "../input/input_validators";
|
||||||
import { Notifications } from "../notifications";
|
import { Notifications } from "../notifications";
|
||||||
|
|
||||||
interface Props extends DialogProps {
|
interface Props extends DialogProps {
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import { Wizard, WizardStep } from "../wizard";
|
|||||||
import { SubTitle } from "../layout/sub-title";
|
import { SubTitle } from "../layout/sub-title";
|
||||||
import { serviceAccountsStore } from "./service-accounts.store";
|
import { serviceAccountsStore } from "./service-accounts.store";
|
||||||
import { Input } from "../input";
|
import { Input } from "../input";
|
||||||
import { systemName } from "../input/input.validators";
|
import { systemName } from "../input/input_validators";
|
||||||
import { NamespaceSelect } from "../+namespaces/namespace-select";
|
import { NamespaceSelect } from "../+namespaces/namespace-select";
|
||||||
import { Notifications } from "../notifications";
|
import { Notifications } from "../notifications";
|
||||||
import { showDetails } from "../../navigation";
|
import { showDetails } from "../../navigation";
|
||||||
@ -62,14 +62,14 @@ export class CreateServiceAccountDialog extends React.Component<Props> {
|
|||||||
>
|
>
|
||||||
<Wizard header={header} done={this.close}>
|
<Wizard header={header} done={this.close}>
|
||||||
<WizardStep nextLabel={<Trans>Create</Trans>} next={this.createAccount}>
|
<WizardStep nextLabel={<Trans>Create</Trans>} next={this.createAccount}>
|
||||||
<SubTitle title={<Trans>Account Name</Trans>}/>
|
<SubTitle title={<Trans>Account Name</Trans>} />
|
||||||
<Input
|
<Input
|
||||||
autoFocus required
|
autoFocus required
|
||||||
placeholder={_i18n._(t`Enter a name`)}
|
placeholder={_i18n._(t`Enter a name`)}
|
||||||
validators={systemName}
|
validators={systemName}
|
||||||
value={name} onChange={v => this.name = v.toLowerCase()}
|
value={name} onChange={v => this.name = v.toLowerCase()}
|
||||||
/>
|
/>
|
||||||
<SubTitle title={<Trans>Namespace</Trans>}/>
|
<SubTitle title={<Trans>Namespace</Trans>} />
|
||||||
<NamespaceSelect
|
<NamespaceSelect
|
||||||
themeName="light"
|
themeName="light"
|
||||||
value={namespace}
|
value={namespace}
|
||||||
|
|||||||
@ -10,7 +10,7 @@ import { CronJob, cronJobApi, jobApi, Job } from "../../api/endpoints";
|
|||||||
import { Notifications } from "../notifications";
|
import { Notifications } from "../notifications";
|
||||||
import { cssNames } from "../../utils";
|
import { cssNames } from "../../utils";
|
||||||
import { Input } from "../input";
|
import { Input } from "../input";
|
||||||
import { systemName, maxLength } from "../input/input.validators";
|
import { systemName, maxLength } from "../input/input_validators";
|
||||||
|
|
||||||
interface Props extends Partial<DialogProps> {
|
interface Props extends Partial<DialogProps> {
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { isEmail, systemName } from "./input.validators";
|
import { isEmail, systemName } from "../input_validators";
|
||||||
|
|
||||||
describe("input validation tests", () => {
|
describe("input validation tests", () => {
|
||||||
describe("isEmail tests", () => {
|
describe("isEmail tests", () => {
|
||||||
@ -3,7 +3,7 @@ import "./input.scss";
|
|||||||
import React, { DOMAttributes, InputHTMLAttributes, TextareaHTMLAttributes } from "react";
|
import React, { DOMAttributes, InputHTMLAttributes, TextareaHTMLAttributes } from "react";
|
||||||
import { autobind, cssNames, debouncePromise } from "../../utils";
|
import { autobind, cssNames, debouncePromise } from "../../utils";
|
||||||
import { Icon } from "../icon";
|
import { Icon } from "../icon";
|
||||||
import { conditionalValidators, Validator } from "./input.validators";
|
import { conditionalValidators, Validator } from "./input_validators";
|
||||||
import isString from "lodash/isString"
|
import isString from "lodash/isString"
|
||||||
import isFunction from "lodash/isFunction"
|
import isFunction from "lodash/isFunction"
|
||||||
import isBoolean from "lodash/isBoolean"
|
import isBoolean from "lodash/isBoolean"
|
||||||
@ -288,9 +288,9 @@ export class Input extends React.Component<InputProps, State> {
|
|||||||
return (
|
return (
|
||||||
<div className={className}>
|
<div className={className}>
|
||||||
<label className="input-area flex gaps align-center">
|
<label className="input-area flex gaps align-center">
|
||||||
{isString(iconLeft) ? <Icon material={iconLeft}/> : iconLeft}
|
{isString(iconLeft) ? <Icon material={iconLeft} /> : iconLeft}
|
||||||
{multiLine ? <textarea {...inputProps as any}/> : <input {...inputProps as any}/>}
|
{multiLine ? <textarea {...inputProps as any} /> : <input {...inputProps as any} />}
|
||||||
{isString(iconRight) ? <Icon material={iconRight}/> : iconRight}
|
{isString(iconRight) ? <Icon material={iconRight} /> : iconRight}
|
||||||
</label>
|
</label>
|
||||||
<div className="input-info flex gaps">
|
<div className="input-info flex gaps">
|
||||||
{!valid && dirty && (
|
{!valid && dirty && (
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import { formatDuration } from "./formatDuration";
|
import { formatDuration } from "../formatDuration";
|
||||||
|
|
||||||
const second = 1000;
|
const second = 1000;
|
||||||
const minute = 60 * second;
|
const minute = 60 * second;
|
||||||
@ -9,34 +9,34 @@ const week = 7 * day;
|
|||||||
describe("human format durations", () => {
|
describe("human format durations", () => {
|
||||||
test("long formatted durations less than 24 hours long shouldn't have a 'd' component", () => {
|
test("long formatted durations less than 24 hours long shouldn't have a 'd' component", () => {
|
||||||
const res = formatDuration(19 * 60 * 60 * 1000, false);
|
const res = formatDuration(19 * 60 * 60 * 1000, false);
|
||||||
|
|
||||||
expect(res).not.toContain("d");
|
expect(res).not.toContain("d");
|
||||||
expect(res).toBe("19h");
|
expect(res).toBe("19h");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("long formatted durations more than a week have correct day count", () => {
|
test("long formatted durations more than a week have correct day count", () => {
|
||||||
const res = formatDuration(2 * week + 2 * day, false);
|
const res = formatDuration(2 * week + 2 * day, false);
|
||||||
|
|
||||||
expect(res).toBe("2w 2d");
|
expect(res).toBe("2w 2d");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("durations > 1/2 week shouldn't show 1w has passed", () => {
|
test("durations > 1/2 week shouldn't show 1w has passed", () => {
|
||||||
const res = formatDuration(5 * 24 * 60 * 60 * 1000, false);
|
const res = formatDuration(5 * 24 * 60 * 60 * 1000, false);
|
||||||
|
|
||||||
expect(res).not.toContain("w");
|
expect(res).not.toContain("w");
|
||||||
expect(res).toBe("5d");
|
expect(res).toBe("5d");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("durations shouldn't include zero magnitude parts", () => {
|
test("durations shouldn't include zero magnitude parts", () => {
|
||||||
const res = formatDuration(6 * day + 2 * minute, false);
|
const res = formatDuration(6 * day + 2 * minute, false);
|
||||||
|
|
||||||
expect(res).not.toContain("h");
|
expect(res).not.toContain("h");
|
||||||
expect(res).toBe("6d 2m");
|
expect(res).toBe("6d 2m");
|
||||||
});
|
});
|
||||||
|
|
||||||
test("seconds are ignored unless they are significant (< 1m)", () => {
|
test("seconds are ignored unless they are significant (< 1m)", () => {
|
||||||
const insignificant = formatDuration(1 * hour + 2 * minute + 31 * second, false);
|
const insignificant = formatDuration(1 * hour + 2 * minute + 31 * second, false);
|
||||||
|
|
||||||
expect(insignificant).not.toContain("s");
|
expect(insignificant).not.toContain("s");
|
||||||
expect(insignificant).toBe("1h 2m");
|
expect(insignificant).toBe("1h 2m");
|
||||||
|
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import { metricUnitsToNumber } from "./metricUnitsToNumber";
|
import { metricUnitsToNumber } from "../metricUnitsToNumber";
|
||||||
|
|
||||||
describe("metricUnitsToNumber tests", () => {
|
describe("metricUnitsToNumber tests", () => {
|
||||||
test("plain number", () => {
|
test("plain number", () => {
|
||||||
Loading…
Reference in New Issue
Block a user