Skip to content

Commit

Permalink
chore: Add some behavioural tests for custom columns for custom resou…
Browse files Browse the repository at this point in the history
…rces

Signed-off-by: Sebastian Malton <sebastian@malton.name>
  • Loading branch information
Nokel81 committed May 12, 2023
1 parent 2d46ff4 commit 7a65887
Show file tree
Hide file tree
Showing 9 changed files with 815 additions and 87 deletions.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,123 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/

import type { KubeObjectMetadata, KubeObjectScope } from "@k8slens/kube-object";
import { KubeObject, CustomResourceDefinition } from "@k8slens/kube-object";
import type { RenderResult } from "@testing-library/react";
import navigateToCustomResourcesInjectable from "../../common/front-end-routing/routes/cluster/custom-resources/custom-resources/navigate-to-custom-resources.injectable";
import apiManagerInjectable from "../../common/k8s-api/api-manager/manager.injectable";
import type { CustomResourceStore } from "../../common/k8s-api/api-manager/resource.store";
import type { CustomResourceDefinitionStore } from "../../renderer/components/custom-resources/definition.store";
import customResourceDefinitionStoreInjectable from "../../renderer/components/custom-resources/definition.store.injectable";
import type { ApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";
import { getApplicationBuilder } from "../../renderer/components/test-utils/get-application-builder";

describe("Viewing Custom Resources with extra columns", () => {
let builder: ApplicationBuilder;
let result: RenderResult;
let customResourceDefinitionStore: CustomResourceDefinitionStore;
let customResourceStore: CustomResourceStore<KubeObject<KubeObjectMetadata<KubeObjectScope.Cluster>, void, { someColumn: Record<string, unknown> }>>;
let customResource: CustomResourceDefinition;

beforeEach(async () => {
builder = getApplicationBuilder();
builder.setEnvironmentToClusterFrame();

builder.afterWindowStart(({ windowDi }) => {
const apiManager = windowDi.inject(apiManagerInjectable);

customResourceDefinitionStore = windowDi.inject(customResourceDefinitionStoreInjectable);
customResource = new CustomResourceDefinition({
apiVersion: "apiextensions.k8s.io/v1",
kind: "CustomResourceDefinition",
metadata: {
name: "some-crd",
selfLink: "/apis/apiextensions.k8s.io/v1/customresourcedefinitions/some-crd",
uid: "some-uid",
resourceVersion: "1",
},
spec: {
group: "some-group",
scope: "Cluster",
names: {
kind: "SomeResource",
plural: "some-resources",
singular: "some-resource",
},
versions: [
{
storage: true,
name: "v1",
served: true,
additionalPrinterColumns: [
{
name: "Some Column",
type: "string",
description: "Some description",
jsonPath: ".spec.someColumn",
},
],
},
],
},
});

customResourceDefinitionStore.items.replace([
customResource,
]);

customResourceStore = apiManager.getStore(customResource.getResourceApiBase()) as typeof customResourceStore;

customResourceStore.items.replace([
new KubeObject({
apiVersion: "/some-group/v1",
kind: "SomeResource",
metadata: {
name: "some-resource",
selfLink: "/apis/some-group/v1/namespaces/default/some-resources/some-resource",
uid: "some-uid-2",
resourceVersion: "1",
},
spec: {
someColumn: {
"foo": "bar",
},
},
}),
]);
});

result = await builder.render();

builder.allowKubeResource({
group: "/apis/apiextensions.k8s.io/v1",
apiName: "customresourcedefinitions",
});

const windowDi = builder.applicationWindow.only.di;
const navigateToCustomResources = windowDi.inject(navigateToCustomResourcesInjectable);

navigateToCustomResources({
group: "some-group",
name: "some-resources",
});
});

it("renders", () => {
expect(result.container).toMatchSnapshot();
});

it("shows the table for the custom resource SomeResource", () => {
expect(result.getByText("SomeResource")).toBeInTheDocument();
});

it("shows the 'some-column' column", () => {
expect(result.getByTestId("custom-resource-column-title-some-column")).toBeInTheDocument();
});

it("shows some value for in the cells of 'some-column' column", () => {
expect(result.getByTestId("custom-resource-column-cell-some-column-for-some-resource")).toHaveTextContent(JSON.stringify({ foo: "bar" }));
});
});
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@
* Licensed under MIT License. See LICENSE in root directory for more information.
*/

import type { TableCellProps } from "@k8slens/list-layout";
import type { StrictReactNode } from "@k8slens/utilities";
import type { CatalogEntity } from "../../../common/catalog";
import type { TableCellProps } from "../table";

/**
* These are the supported props for the title cell
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import type { CustomResourceDefinitionStore } from "./definition.store";
import apiManagerInjectable from "../../../common/k8s-api/api-manager/manager.injectable";
import customResourceDefinitionStoreInjectable from "./definition.store.injectable";
import { NamespaceSelectBadge } from "../namespaces/namespace-select-badge";
import type { TableCellProps } from "@k8slens/list-layout";

enum columnId {
name = "name",
Expand Down Expand Up @@ -95,9 +96,10 @@ class NonInjectedCustomResources extends React.Component<Dependencies> {
: undefined,
...extraColumns.map(({ name }) => ({
title: name,
className: name.toLowerCase(),
className: name.toLowerCase().replace(/\s+/g, "-"),
sortBy: name,
id: name,
"data-testid": `custom-resource-column-title-${name.toLowerCase().replace(/\s+/g, "-")}`,
})),
{ title: "Age", className: "age", sortBy: columnId.age, id: columnId.age },
]}
Expand All @@ -106,11 +108,10 @@ class NonInjectedCustomResources extends React.Component<Dependencies> {
isNamespaced && (
<NamespaceSelectBadge namespace={customResource.getNs() as string} />
),
...(
extraColumns
.map((column) => safeJSONPathValue(customResource, column.jsonPath))
.map(formatJSONValue)
),
...extraColumns.map((column): TableCellProps => ({
"data-testid": `custom-resource-column-cell-${column.name.toLowerCase().replace(/\s+/g, "-")}-for-${customResource.getScopedName()}`,
title: formatJSONValue(safeJSONPathValue(customResource, column.jsonPath)),
})),
<KubeObjectAge key="age" object={customResource} />,
]}
failedToLoadMessage={(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,15 +10,15 @@ import type { IComputedValue } from "mobx";
import { computed, makeObservable } from "mobx";
import { Observer, observer } from "mobx-react";
import type { ConfirmDialogParams } from "../confirm-dialog";
import type { TableCellProps, TableProps, TableRowProps, TableSortCallbacks } from "../table";
import type { TableProps, TableRowProps, TableSortCallbacks } from "../table";
import { Table, TableCell, TableHead, TableRow } from "../table";
import type { IClassName, StrictReactNode } from "@k8slens/utilities";
import { cssNames, isDefined, isReactNode, noop, prevDefault, stopPropagation } from "@k8slens/utilities";
import type { AddRemoveButtonsProps } from "../add-remove-buttons";
import { AddRemoveButtons } from "../add-remove-buttons";
import { NoItems } from "../no-items";
import { Spinner } from "../spinner";
import type { ItemObject } from "@k8slens/list-layout";
import type { ItemObject, TableCellProps } from "@k8slens/list-layout";
import type { Filter, PageFiltersStore } from "./page-filters/store";
import type { LensTheme } from "../../themes/lens-theme";
import { MenuActions } from "../menu/menu-actions";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,11 @@ import React from "react";
import type { IComputedValue } from "mobx";
import { computed, makeObservable, untracked } from "mobx";
import type { ConfirmDialogParams } from "../confirm-dialog";
import type { TableCellProps, TableProps, TableRowProps, TableSortCallbacks } from "../table";
import type { TableProps, TableRowProps, TableSortCallbacks } from "../table";
import type { IClassName, StrictReactNode, SingleOrMany } from "@k8slens/utilities";
import { cssNames, noop } from "@k8slens/utilities";
import type { AddRemoveButtonsProps } from "../add-remove-buttons";
import type { ItemObject } from "@k8slens/list-layout";
import type { ItemObject, TableCellProps } from "@k8slens/list-layout";
import type { SearchInputUrlProps } from "../input";
import type { PageFiltersStore } from "./page-filters/store";
import { FilterType } from "./page-filters/store";
Expand Down
66 changes: 1 addition & 65 deletions packages/core/src/renderer/components/table/table-cell.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,80 +4,16 @@
*/

import "./table-cell.scss";
import type { TableSortBy, TableSortParams } from "./table";

import React from "react";
import type { StrictReactNode } from "@k8slens/utilities";
import { cssNames } from "@k8slens/utilities";
import { Icon } from "../icon";
import { Checkbox } from "../checkbox";
import autoBindReact from "auto-bind/react";
import type { TableCellProps } from "@k8slens/list-layout";

export type TableCellElem = React.ReactElement<TableCellProps>;

export interface TableCellProps extends React.DOMAttributes<HTMLDivElement> {
/**
* used for configuration visibility of columns
*/
id?: string;

/**
* Any css class names for this table cell. Only used if `title` is a "simple" react node
*/
className?: string;

/**
* The actual value of the cell
*/
title?: StrictReactNode;

/**
* content inside could be scrolled
*/
scrollable?: boolean;

/**
* render cell with a checkbox
*/
checkbox?: boolean;

/**
* mark checkbox as checked or not
*/
isChecked?: boolean;

/**
* column name, must be same as key in sortable object `<Table sortable={}></Table>`
*/
sortBy?: TableSortBy;

/**
* id of the column which follow same visibility rules
*/
showWithColumn?: string;

/**
* @internal
*/
_sorting?: Partial<TableSortParams>;

/**
* @internal
*/
_sort?(sortBy: TableSortBy): void;

/**
* @internal
* indicator, might come from parent <TableHead>, don't use this prop outside (!)
*/
_nowrap?: boolean;

/**
* For passing in the testid
*/
"data-testid"?: string;
}

export class TableCell extends React.Component<TableCellProps> {
constructor(props: TableCellProps) {
super(props);
Expand Down
20 changes: 10 additions & 10 deletions packages/kube-object/src/specifics/custom-resource-definition.ts
Original file line number Diff line number Diff line change
Expand Up @@ -141,13 +141,6 @@ export class CustomResourceDefinition extends KubeObject<
}

getPreferredVersion(): CustomResourceDefinitionVersion {
return this.getPreferedVersion();
}

/**
* @deprecated Switch to using {@link getPreferredVersion} instead (which fixes the is a typo)
*/
getPreferedVersion(): CustomResourceDefinitionVersion {
const { apiVersion } = this;

switch (apiVersion) {
Expand Down Expand Up @@ -179,8 +172,15 @@ export class CustomResourceDefinition extends KubeObject<
);
}

/**
* @deprecated Switch to using {@link getPreferredVersion} instead (which fixes the is a typo)
*/
getPreferedVersion(): CustomResourceDefinitionVersion {
return this.getPreferredVersion();
}

getVersion() {
return this.getPreferedVersion().name;
return this.getPreferredVersion().name;
}

isNamespaced() {
Expand All @@ -200,13 +200,13 @@ export class CustomResourceDefinition extends KubeObject<
}

getPrinterColumns(ignorePriority = true): AdditionalPrinterColumnsV1[] {
const columns = this.getPreferedVersion().additionalPrinterColumns ?? [];
const columns = this.getPreferredVersion().additionalPrinterColumns ?? [];

return columns.filter((column) => column.name.toLowerCase() !== "age" && (ignorePriority || !column.priority));
}

getValidation() {
return JSON.stringify(this.getPreferedVersion().schema, null, 2);
return JSON.stringify(this.getPreferredVersion().schema, null, 2);
}

getConditions() {
Expand Down
7 changes: 6 additions & 1 deletion packages/list-layout/src/list-layout-column.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ export interface TableCellProps extends React.DOMAttributes<HTMLDivElement> {
isChecked?: boolean;

/**
* column name, must be same as key in sortable object <Table sortable={}/>
* column name, must be same as key in sortable object `<Table sortable={}></Table>`
*/
sortBy?: TableSortBy;

Expand All @@ -78,4 +78,9 @@ export interface TableCellProps extends React.DOMAttributes<HTMLDivElement> {
* indicator, might come from parent <TableHead>, don't use this prop outside (!)
*/
_nowrap?: boolean;

/**
* For passing in the testid
*/
"data-testid"?: string;
}

0 comments on commit 7a65887

Please sign in to comment.