1
0
mirror of https://github.com/lensapp/lens.git synced 2025-05-20 05:10:56 +00:00

Fixing namespace-select-filter tests

Signed-off-by: Sebastian Malton <sebastian@malton.name>
This commit is contained in:
Sebastian Malton 2022-11-29 10:45:55 -05:00
parent 4847cfc35f
commit 31f0b8ed3a
8 changed files with 629 additions and 611 deletions

View File

@ -18,65 +18,9 @@ import { flushPromises } from "../../test-utils/flush-promises";
import createKubeJsonApiInjectable from "../create-kube-json-api.injectable"; import createKubeJsonApiInjectable from "../create-kube-json-api.injectable";
import type { IKubeWatchEvent } from "../kube-watch-event"; import type { IKubeWatchEvent } from "../kube-watch-event";
import type { KubeJsonApiDataFor } from "../kube-object"; import type { KubeJsonApiDataFor } from "../kube-object";
import type { Response, Headers as NodeFetchHeaders } from "node-fetch";
import AbortController from "abort-controller"; import AbortController from "abort-controller";
import setupAutoRegistrationInjectable from "../../../renderer/before-frame-starts/runnables/setup-auto-registration.injectable"; import setupAutoRegistrationInjectable from "../../../renderer/before-frame-starts/runnables/setup-auto-registration.injectable";
import { createMockResponseFromStream, createMockResponseFromString } from "../../../test-utils/mock-responses";
const createMockResponseFromString = (url: string, data: string, statusCode = 200) => {
const res: jest.Mocked<Response> = {
buffer: jest.fn(async () => { throw new Error("buffer() is not supported"); }),
clone: jest.fn(() => res),
arrayBuffer: jest.fn(async () => { throw new Error("arrayBuffer() is not supported"); }),
blob: jest.fn(async () => { throw new Error("blob() is not supported"); }),
body: new PassThrough(),
bodyUsed: false,
headers: new Headers() as NodeFetchHeaders,
json: jest.fn(async () => JSON.parse(await res.text())),
ok: 200 <= statusCode && statusCode < 300,
redirected: 300 <= statusCode && statusCode < 400,
size: data.length,
status: statusCode,
statusText: "some-text",
text: jest.fn(async () => data),
type: "basic",
url,
formData: jest.fn(async () => { throw new Error("formData() is not supported"); }),
};
return res;
};
const createMockResponseFromStream = (url: string, stream: NodeJS.ReadableStream, statusCode = 200) => {
const res: jest.Mocked<Response> = {
buffer: jest.fn(async () => { throw new Error("buffer() is not supported"); }),
clone: jest.fn(() => res),
arrayBuffer: jest.fn(async () => { throw new Error("arrayBuffer() is not supported"); }),
blob: jest.fn(async () => { throw new Error("blob() is not supported"); }),
body: stream,
bodyUsed: false,
headers: new Headers() as NodeFetchHeaders,
json: jest.fn(async () => JSON.parse(await res.text())),
ok: 200 <= statusCode && statusCode < 300,
redirected: 300 <= statusCode && statusCode < 400,
size: 10,
status: statusCode,
statusText: "some-text",
text: jest.fn(() => {
const chunks: Buffer[] = [];
return new Promise((resolve, reject) => {
stream.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
stream.on("error", (err) => reject(err));
stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
});
}),
type: "basic",
url,
formData: jest.fn(async () => { throw new Error("formData() is not supported"); }),
};
return res;
};
describe("createKubeApiForRemoteCluster", () => { describe("createKubeApiForRemoteCluster", () => {
let createKubeApiForRemoteCluster: CreateKubeApiForRemoteCluster; let createKubeApiForRemoteCluster: CreateKubeApiForRemoteCluster;

View File

@ -104,7 +104,8 @@ export class JsonApi<Data = JsonApiData, Params extends JsonApiParams<Data> = Js
); );
const { query } = params ?? {}; const { query } = params ?? {};
if (query) { if (query && Object.keys(query).length > 0) {
console.log(query);
const queryString = stringify(query as unknown as QueryParams); const queryString = stringify(query as unknown as QueryParams);
reqUrl += (reqUrl.includes("?") ? "&" : "?") + queryString; reqUrl += (reqUrl.includes("?") ? "&" : "?") + queryString;
@ -171,7 +172,8 @@ export class JsonApi<Data = JsonApiData, Params extends JsonApiParams<Data> = Js
reqInit.body = JSON.stringify(data); reqInit.body = JSON.stringify(data);
} }
if (query) { if (query && Object.keys(query).length > 0) {
console.log(query);
const queryString = stringify(query as unknown as QueryParams); const queryString = stringify(query as unknown as QueryParams);
reqUrl += (reqUrl.includes("?") ? "&" : "?") + queryString; reqUrl += (reqUrl.includes("?") ? "&" : "?") + queryString;

View File

@ -208,11 +208,7 @@ export abstract class KubeObjectStore<
} }
} }
const items = await res ?? []; return await res ?? [];
console.trace("loadItems", this.api, [...items]);
return items;
} }
this.loadedNamespaces.set(namespaces); this.loadedNamespaces.set(namespaces);
@ -253,8 +249,6 @@ export abstract class KubeObjectStore<
try { try {
const items = await this.loadItems({ namespaces, reqInit, onLoadFailure }); const items = await this.loadItems({ namespaces, reqInit, onLoadFailure });
console.log("loadAll", this.api, [...items]);
this.mergeItems(items, { merge, namespaces }); this.mergeItems(items, { merge, namespaces });
this.isLoaded = true; this.isLoaded = true;
@ -287,8 +281,6 @@ export abstract class KubeObjectStore<
protected mergeItems(partialItems: K[], { merge = true, updateStore = true, sort = true, filter = true, namespaces }: MergeItemsOptions): K[] { protected mergeItems(partialItems: K[], { merge = true, updateStore = true, sort = true, filter = true, namespaces }: MergeItemsOptions): K[] {
let items = partialItems; let items = partialItems;
console.log("mergeItems", this.api, [...partialItems]);
// update existing items // update existing items
if (merge && this.api.isNamespaced) { if (merge && this.api.isNamespaced) {
const ns = new Set(namespaces); const ns = new Set(namespaces);

View File

@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP // Jest Snapshot v1, https://goo.gl/fbAQLP
exports[`<NamespaceSelectFilter /> renders 1`] = ` exports[`<NamespaceSelectFilter /> once the subscribe resolves renders 1`] = `
<body> <body>
<div> <div>
<div <div
@ -86,7 +86,7 @@ exports[`<NamespaceSelectFilter /> renders 1`] = `
</body> </body>
`; `;
exports[`<NamespaceSelectFilter /> when clicked renders 1`] = ` exports[`<NamespaceSelectFilter /> once the subscribe resolves when clicked renders 1`] = `
<body> <body>
<div> <div>
<div <div
@ -229,286 +229,6 @@ exports[`<NamespaceSelectFilter /> when clicked renders 1`] = `
class="Select__option Select__option--is-selected css-tr4s17-option" class="Select__option Select__option--is-selected css-tr4s17-option"
id="react-select-namespace-select-filter-option-2" id="react-select-namespace-select-filter-option-2"
tabindex="-1" tabindex="-1"
>
<div
class="flex gaps align-center"
>
<i
class="Icon material focusable small"
>
<span
class="icon"
data-icon-name="layers"
>
layers
</span>
</i>
<span>
test-2
</span>
<i
class="Icon box right material focusable small"
data-testid="namespace-select-filter-option-test-2-selected"
>
<span
class="icon"
data-icon-name="check"
>
check
</span>
</i>
</div>
</div>
<div
aria-disabled="false"
class="Select__option Select__option--is-selected css-tr4s17-option"
id="react-select-namespace-select-filter-option-3"
tabindex="-1"
>
<div
class="flex gaps align-center"
>
<i
class="Icon material focusable small"
>
<span
class="icon"
data-icon-name="layers"
>
layers
</span>
</i>
<span>
test-3
</span>
<i
class="Icon box right material focusable small"
data-testid="namespace-select-filter-option-test-3-selected"
>
<span
class="icon"
data-icon-name="check"
>
check
</span>
</i>
</div>
</div>
<div
aria-disabled="false"
class="Select__option Select__option--is-selected css-tr4s17-option"
id="react-select-namespace-select-filter-option-4"
tabindex="-1"
>
<div
class="flex gaps align-center"
>
<i
class="Icon material focusable small"
>
<span
class="icon"
data-icon-name="layers"
>
layers
</span>
</i>
<span>
test-4
</span>
<i
class="Icon box right material focusable small"
data-testid="namespace-select-filter-option-test-4-selected"
>
<span
class="icon"
data-icon-name="check"
>
check
</span>
</i>
</div>
</div>
<div
aria-disabled="false"
class="Select__option Select__option--is-selected css-tr4s17-option"
id="react-select-namespace-select-filter-option-5"
tabindex="-1"
>
<div
class="flex gaps align-center"
>
<i
class="Icon material focusable small"
>
<span
class="icon"
data-icon-name="layers"
>
layers
</span>
</i>
<span>
test-5
</span>
<i
class="Icon box right material focusable small"
data-testid="namespace-select-filter-option-test-5-selected"
>
<span
class="icon"
data-icon-name="check"
>
check
</span>
</i>
</div>
</div>
<div
aria-disabled="false"
class="Select__option Select__option--is-selected css-tr4s17-option"
id="react-select-namespace-select-filter-option-6"
tabindex="-1"
>
<div
class="flex gaps align-center"
>
<i
class="Icon material focusable small"
>
<span
class="icon"
data-icon-name="layers"
>
layers
</span>
</i>
<span>
test-6
</span>
<i
class="Icon box right material focusable small"
data-testid="namespace-select-filter-option-test-6-selected"
>
<span
class="icon"
data-icon-name="check"
>
check
</span>
</i>
</div>
</div>
<div
aria-disabled="false"
class="Select__option Select__option--is-selected css-tr4s17-option"
id="react-select-namespace-select-filter-option-7"
tabindex="-1"
>
<div
class="flex gaps align-center"
>
<i
class="Icon material focusable small"
>
<span
class="icon"
data-icon-name="layers"
>
layers
</span>
</i>
<span>
test-7
</span>
<i
class="Icon box right material focusable small"
data-testid="namespace-select-filter-option-test-7-selected"
>
<span
class="icon"
data-icon-name="check"
>
check
</span>
</i>
</div>
</div>
<div
aria-disabled="false"
class="Select__option Select__option--is-selected css-tr4s17-option"
id="react-select-namespace-select-filter-option-8"
tabindex="-1"
>
<div
class="flex gaps align-center"
>
<i
class="Icon material focusable small"
>
<span
class="icon"
data-icon-name="layers"
>
layers
</span>
</i>
<span>
test-8
</span>
<i
class="Icon box right material focusable small"
data-testid="namespace-select-filter-option-test-8-selected"
>
<span
class="icon"
data-icon-name="check"
>
check
</span>
</i>
</div>
</div>
<div
aria-disabled="false"
class="Select__option Select__option--is-selected css-tr4s17-option"
id="react-select-namespace-select-filter-option-9"
tabindex="-1"
>
<div
class="flex gaps align-center"
>
<i
class="Icon material focusable small"
>
<span
class="icon"
data-icon-name="layers"
>
layers
</span>
</i>
<span>
test-9
</span>
<i
class="Icon box right material focusable small"
data-testid="namespace-select-filter-option-test-9-selected"
>
<span
class="icon"
data-icon-name="check"
>
check
</span>
</i>
</div>
</div>
<div
aria-disabled="false"
class="Select__option Select__option--is-selected css-tr4s17-option"
id="react-select-namespace-select-filter-option-10"
tabindex="-1"
> >
<div <div
class="flex gaps align-center" class="flex gaps align-center"
@ -542,7 +262,7 @@ exports[`<NamespaceSelectFilter /> when clicked renders 1`] = `
<div <div
aria-disabled="false" aria-disabled="false"
class="Select__option Select__option--is-selected css-tr4s17-option" class="Select__option Select__option--is-selected css-tr4s17-option"
id="react-select-namespace-select-filter-option-11" id="react-select-namespace-select-filter-option-3"
tabindex="-1" tabindex="-1"
> >
<div <div
@ -577,7 +297,7 @@ exports[`<NamespaceSelectFilter /> when clicked renders 1`] = `
<div <div
aria-disabled="false" aria-disabled="false"
class="Select__option Select__option--is-selected css-tr4s17-option" class="Select__option Select__option--is-selected css-tr4s17-option"
id="react-select-namespace-select-filter-option-12" id="react-select-namespace-select-filter-option-4"
tabindex="-1" tabindex="-1"
> >
<div <div
@ -612,7 +332,7 @@ exports[`<NamespaceSelectFilter /> when clicked renders 1`] = `
<div <div
aria-disabled="false" aria-disabled="false"
class="Select__option Select__option--is-selected css-tr4s17-option" class="Select__option Select__option--is-selected css-tr4s17-option"
id="react-select-namespace-select-filter-option-13" id="react-select-namespace-select-filter-option-5"
tabindex="-1" tabindex="-1"
> >
<div <div
@ -644,13 +364,293 @@ exports[`<NamespaceSelectFilter /> when clicked renders 1`] = `
</i> </i>
</div> </div>
</div> </div>
<div
aria-disabled="false"
class="Select__option Select__option--is-selected css-tr4s17-option"
id="react-select-namespace-select-filter-option-6"
tabindex="-1"
>
<div
class="flex gaps align-center"
>
<i
class="Icon material focusable small"
>
<span
class="icon"
data-icon-name="layers"
>
layers
</span>
</i>
<span>
test-2
</span>
<i
class="Icon box right material focusable small"
data-testid="namespace-select-filter-option-test-2-selected"
>
<span
class="icon"
data-icon-name="check"
>
check
</span>
</i>
</div>
</div>
<div
aria-disabled="false"
class="Select__option Select__option--is-selected css-tr4s17-option"
id="react-select-namespace-select-filter-option-7"
tabindex="-1"
>
<div
class="flex gaps align-center"
>
<i
class="Icon material focusable small"
>
<span
class="icon"
data-icon-name="layers"
>
layers
</span>
</i>
<span>
test-3
</span>
<i
class="Icon box right material focusable small"
data-testid="namespace-select-filter-option-test-3-selected"
>
<span
class="icon"
data-icon-name="check"
>
check
</span>
</i>
</div>
</div>
<div
aria-disabled="false"
class="Select__option Select__option--is-selected css-tr4s17-option"
id="react-select-namespace-select-filter-option-8"
tabindex="-1"
>
<div
class="flex gaps align-center"
>
<i
class="Icon material focusable small"
>
<span
class="icon"
data-icon-name="layers"
>
layers
</span>
</i>
<span>
test-4
</span>
<i
class="Icon box right material focusable small"
data-testid="namespace-select-filter-option-test-4-selected"
>
<span
class="icon"
data-icon-name="check"
>
check
</span>
</i>
</div>
</div>
<div
aria-disabled="false"
class="Select__option Select__option--is-selected css-tr4s17-option"
id="react-select-namespace-select-filter-option-9"
tabindex="-1"
>
<div
class="flex gaps align-center"
>
<i
class="Icon material focusable small"
>
<span
class="icon"
data-icon-name="layers"
>
layers
</span>
</i>
<span>
test-5
</span>
<i
class="Icon box right material focusable small"
data-testid="namespace-select-filter-option-test-5-selected"
>
<span
class="icon"
data-icon-name="check"
>
check
</span>
</i>
</div>
</div>
<div
aria-disabled="false"
class="Select__option Select__option--is-selected css-tr4s17-option"
id="react-select-namespace-select-filter-option-10"
tabindex="-1"
>
<div
class="flex gaps align-center"
>
<i
class="Icon material focusable small"
>
<span
class="icon"
data-icon-name="layers"
>
layers
</span>
</i>
<span>
test-6
</span>
<i
class="Icon box right material focusable small"
data-testid="namespace-select-filter-option-test-6-selected"
>
<span
class="icon"
data-icon-name="check"
>
check
</span>
</i>
</div>
</div>
<div
aria-disabled="false"
class="Select__option Select__option--is-selected css-tr4s17-option"
id="react-select-namespace-select-filter-option-11"
tabindex="-1"
>
<div
class="flex gaps align-center"
>
<i
class="Icon material focusable small"
>
<span
class="icon"
data-icon-name="layers"
>
layers
</span>
</i>
<span>
test-7
</span>
<i
class="Icon box right material focusable small"
data-testid="namespace-select-filter-option-test-7-selected"
>
<span
class="icon"
data-icon-name="check"
>
check
</span>
</i>
</div>
</div>
<div
aria-disabled="false"
class="Select__option Select__option--is-selected css-tr4s17-option"
id="react-select-namespace-select-filter-option-12"
tabindex="-1"
>
<div
class="flex gaps align-center"
>
<i
class="Icon material focusable small"
>
<span
class="icon"
data-icon-name="layers"
>
layers
</span>
</i>
<span>
test-8
</span>
<i
class="Icon box right material focusable small"
data-testid="namespace-select-filter-option-test-8-selected"
>
<span
class="icon"
data-icon-name="check"
>
check
</span>
</i>
</div>
</div>
<div
aria-disabled="false"
class="Select__option Select__option--is-selected css-tr4s17-option"
id="react-select-namespace-select-filter-option-13"
tabindex="-1"
>
<div
class="flex gaps align-center"
>
<i
class="Icon material focusable small"
>
<span
class="icon"
data-icon-name="layers"
>
layers
</span>
</i>
<span>
test-9
</span>
<i
class="Icon box right material focusable small"
data-testid="namespace-select-filter-option-test-9-selected"
>
<span
class="icon"
data-icon-name="check"
>
check
</span>
</i>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>
</body> </body>
`; `;
exports[`<NamespaceSelectFilter /> when clicked when 'test-2' is clicked renders 1`] = ` exports[`<NamespaceSelectFilter /> once the subscribe resolves when clicked when 'test-2' is clicked renders 1`] = `
<body> <body>
<div> <div>
<div <div
@ -736,7 +736,7 @@ exports[`<NamespaceSelectFilter /> when clicked when 'test-2' is clicked renders
</body> </body>
`; `;
exports[`<NamespaceSelectFilter /> when clicked when 'test-2' is clicked when clicked again renders 1`] = ` exports[`<NamespaceSelectFilter /> once the subscribe resolves when clicked when 'test-2' is clicked when clicked again renders 1`] = `
<body> <body>
<div> <div>
<div <div
@ -918,7 +918,7 @@ exports[`<NamespaceSelectFilter /> when clicked when 'test-2' is clicked when cl
</span> </span>
</i> </i>
<span> <span>
test-3 test-10
</span> </span>
</div> </div>
</div> </div>
@ -942,7 +942,7 @@ exports[`<NamespaceSelectFilter /> when clicked when 'test-2' is clicked when cl
</span> </span>
</i> </i>
<span> <span>
test-4 test-11
</span> </span>
</div> </div>
</div> </div>
@ -966,7 +966,7 @@ exports[`<NamespaceSelectFilter /> when clicked when 'test-2' is clicked when cl
</span> </span>
</i> </i>
<span> <span>
test-5 test-12
</span> </span>
</div> </div>
</div> </div>
@ -990,7 +990,7 @@ exports[`<NamespaceSelectFilter /> when clicked when 'test-2' is clicked when cl
</span> </span>
</i> </i>
<span> <span>
test-6 test-13
</span> </span>
</div> </div>
</div> </div>
@ -1014,7 +1014,7 @@ exports[`<NamespaceSelectFilter /> when clicked when 'test-2' is clicked when cl
</span> </span>
</i> </i>
<span> <span>
test-7 test-3
</span> </span>
</div> </div>
</div> </div>
@ -1038,7 +1038,7 @@ exports[`<NamespaceSelectFilter /> when clicked when 'test-2' is clicked when cl
</span> </span>
</i> </i>
<span> <span>
test-8 test-4
</span> </span>
</div> </div>
</div> </div>
@ -1062,7 +1062,7 @@ exports[`<NamespaceSelectFilter /> when clicked when 'test-2' is clicked when cl
</span> </span>
</i> </i>
<span> <span>
test-9 test-5
</span> </span>
</div> </div>
</div> </div>
@ -1086,7 +1086,7 @@ exports[`<NamespaceSelectFilter /> when clicked when 'test-2' is clicked when cl
</span> </span>
</i> </i>
<span> <span>
test-10 test-6
</span> </span>
</div> </div>
</div> </div>
@ -1110,7 +1110,7 @@ exports[`<NamespaceSelectFilter /> when clicked when 'test-2' is clicked when cl
</span> </span>
</i> </i>
<span> <span>
test-11 test-7
</span> </span>
</div> </div>
</div> </div>
@ -1134,7 +1134,7 @@ exports[`<NamespaceSelectFilter /> when clicked when 'test-2' is clicked when cl
</span> </span>
</i> </i>
<span> <span>
test-12 test-8
</span> </span>
</div> </div>
</div> </div>
@ -1158,7 +1158,7 @@ exports[`<NamespaceSelectFilter /> when clicked when 'test-2' is clicked when cl
</span> </span>
</i> </i>
<span> <span>
test-13 test-9
</span> </span>
</div> </div>
</div> </div>
@ -1168,7 +1168,7 @@ exports[`<NamespaceSelectFilter /> when clicked when 'test-2' is clicked when cl
</body> </body>
`; `;
exports[`<NamespaceSelectFilter /> when clicked when 'test-2' is clicked when clicked again when 'test-1' is clicked renders 1`] = ` exports[`<NamespaceSelectFilter /> once the subscribe resolves when clicked when 'test-2' is clicked when clicked again when 'test-1' is clicked renders 1`] = `
<body> <body>
<div> <div>
<div <div
@ -1254,7 +1254,7 @@ exports[`<NamespaceSelectFilter /> when clicked when 'test-2' is clicked when cl
</body> </body>
`; `;
exports[`<NamespaceSelectFilter /> when clicked when 'test-2' is clicked when clicked again when 'test-1' is clicked when clicked again, then holding down multi select key when 'test-3' is clicked renders 1`] = ` exports[`<NamespaceSelectFilter /> once the subscribe resolves when clicked when 'test-2' is clicked when clicked again when 'test-1' is clicked when clicked again, then holding down multi select key when 'test-3' is clicked renders 1`] = `
<body> <body>
<div> <div>
<div <div
@ -1397,6 +1397,102 @@ exports[`<NamespaceSelectFilter /> when clicked when 'test-2' is clicked when cl
class="Select__option css-10wo9uf-option" class="Select__option css-10wo9uf-option"
id="react-select-namespace-select-filter-option-2" id="react-select-namespace-select-filter-option-2"
tabindex="-1" tabindex="-1"
>
<div
class="flex gaps align-center"
>
<i
class="Icon material focusable small"
>
<span
class="icon"
data-icon-name="layers"
>
layers
</span>
</i>
<span>
test-10
</span>
</div>
</div>
<div
aria-disabled="false"
class="Select__option css-10wo9uf-option"
id="react-select-namespace-select-filter-option-3"
tabindex="-1"
>
<div
class="flex gaps align-center"
>
<i
class="Icon material focusable small"
>
<span
class="icon"
data-icon-name="layers"
>
layers
</span>
</i>
<span>
test-11
</span>
</div>
</div>
<div
aria-disabled="false"
class="Select__option css-10wo9uf-option"
id="react-select-namespace-select-filter-option-4"
tabindex="-1"
>
<div
class="flex gaps align-center"
>
<i
class="Icon material focusable small"
>
<span
class="icon"
data-icon-name="layers"
>
layers
</span>
</i>
<span>
test-12
</span>
</div>
</div>
<div
aria-disabled="false"
class="Select__option css-10wo9uf-option"
id="react-select-namespace-select-filter-option-5"
tabindex="-1"
>
<div
class="flex gaps align-center"
>
<i
class="Icon material focusable small"
>
<span
class="icon"
data-icon-name="layers"
>
layers
</span>
</i>
<span>
test-13
</span>
</div>
</div>
<div
aria-disabled="false"
class="Select__option css-10wo9uf-option"
id="react-select-namespace-select-filter-option-6"
tabindex="-1"
> >
<div <div
class="flex gaps align-center" class="flex gaps align-center"
@ -1419,7 +1515,7 @@ exports[`<NamespaceSelectFilter /> when clicked when 'test-2' is clicked when cl
<div <div
aria-disabled="false" aria-disabled="false"
class="Select__option Select__option--is-selected css-tr4s17-option" class="Select__option Select__option--is-selected css-tr4s17-option"
id="react-select-namespace-select-filter-option-3" id="react-select-namespace-select-filter-option-7"
tabindex="-1" tabindex="-1"
> >
<div <div
@ -1454,7 +1550,7 @@ exports[`<NamespaceSelectFilter /> when clicked when 'test-2' is clicked when cl
<div <div
aria-disabled="false" aria-disabled="false"
class="Select__option css-10wo9uf-option" class="Select__option css-10wo9uf-option"
id="react-select-namespace-select-filter-option-4" id="react-select-namespace-select-filter-option-8"
tabindex="-1" tabindex="-1"
> >
<div <div
@ -1478,7 +1574,7 @@ exports[`<NamespaceSelectFilter /> when clicked when 'test-2' is clicked when cl
<div <div
aria-disabled="false" aria-disabled="false"
class="Select__option css-10wo9uf-option" class="Select__option css-10wo9uf-option"
id="react-select-namespace-select-filter-option-5" id="react-select-namespace-select-filter-option-9"
tabindex="-1" tabindex="-1"
> >
<div <div
@ -1502,7 +1598,7 @@ exports[`<NamespaceSelectFilter /> when clicked when 'test-2' is clicked when cl
<div <div
aria-disabled="false" aria-disabled="false"
class="Select__option css-10wo9uf-option" class="Select__option css-10wo9uf-option"
id="react-select-namespace-select-filter-option-6" id="react-select-namespace-select-filter-option-10"
tabindex="-1" tabindex="-1"
> >
<div <div
@ -1526,7 +1622,7 @@ exports[`<NamespaceSelectFilter /> when clicked when 'test-2' is clicked when cl
<div <div
aria-disabled="false" aria-disabled="false"
class="Select__option css-10wo9uf-option" class="Select__option css-10wo9uf-option"
id="react-select-namespace-select-filter-option-7" id="react-select-namespace-select-filter-option-11"
tabindex="-1" tabindex="-1"
> >
<div <div
@ -1550,7 +1646,7 @@ exports[`<NamespaceSelectFilter /> when clicked when 'test-2' is clicked when cl
<div <div
aria-disabled="false" aria-disabled="false"
class="Select__option css-10wo9uf-option" class="Select__option css-10wo9uf-option"
id="react-select-namespace-select-filter-option-8" id="react-select-namespace-select-filter-option-12"
tabindex="-1" tabindex="-1"
> >
<div <div
@ -1574,7 +1670,7 @@ exports[`<NamespaceSelectFilter /> when clicked when 'test-2' is clicked when cl
<div <div
aria-disabled="false" aria-disabled="false"
class="Select__option css-10wo9uf-option" class="Select__option css-10wo9uf-option"
id="react-select-namespace-select-filter-option-9" id="react-select-namespace-select-filter-option-13"
tabindex="-1" tabindex="-1"
> >
<div <div
@ -1595,102 +1691,6 @@ exports[`<NamespaceSelectFilter /> when clicked when 'test-2' is clicked when cl
</span> </span>
</div> </div>
</div> </div>
<div
aria-disabled="false"
class="Select__option css-10wo9uf-option"
id="react-select-namespace-select-filter-option-10"
tabindex="-1"
>
<div
class="flex gaps align-center"
>
<i
class="Icon material focusable small"
>
<span
class="icon"
data-icon-name="layers"
>
layers
</span>
</i>
<span>
test-10
</span>
</div>
</div>
<div
aria-disabled="false"
class="Select__option css-10wo9uf-option"
id="react-select-namespace-select-filter-option-11"
tabindex="-1"
>
<div
class="flex gaps align-center"
>
<i
class="Icon material focusable small"
>
<span
class="icon"
data-icon-name="layers"
>
layers
</span>
</i>
<span>
test-11
</span>
</div>
</div>
<div
aria-disabled="false"
class="Select__option css-10wo9uf-option"
id="react-select-namespace-select-filter-option-12"
tabindex="-1"
>
<div
class="flex gaps align-center"
>
<i
class="Icon material focusable small"
>
<span
class="icon"
data-icon-name="layers"
>
layers
</span>
</i>
<span>
test-12
</span>
</div>
</div>
<div
aria-disabled="false"
class="Select__option css-10wo9uf-option"
id="react-select-namespace-select-filter-option-13"
tabindex="-1"
>
<div
class="flex gaps align-center"
>
<i
class="Icon material focusable small"
>
<span
class="icon"
data-icon-name="layers"
>
layers
</span>
</i>
<span>
test-13
</span>
</div>
</div>
</div> </div>
</div> </div>
</div> </div>

View File

@ -3,14 +3,22 @@
* Licensed under MIT License. See LICENSE in root directory for more information. * 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 { DiContainer } from "@ogre-tools/injectable"; import type { DiContainer } from "@ogre-tools/injectable";
import type { RenderResult } from "@testing-library/react"; import type { RenderResult } from "@testing-library/react";
import { fireEvent } from "@testing-library/react"; import { fireEvent } from "@testing-library/react";
import React from "react"; import React from "react";
import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable"; import directoryForUserDataInjectable from "../../../common/app-paths/directory-for-user-data/directory-for-user-data.injectable";
import type { Fetch } from "../../../common/fetch/fetch.injectable";
import fetchInjectable from "../../../common/fetch/fetch.injectable";
import { Namespace } from "../../../common/k8s-api/endpoints"; import { Namespace } from "../../../common/k8s-api/endpoints";
import { createMockResponseFromString } from "../../../test-utils/mock-responses";
import { getDiForUnitTesting } from "../../getDiForUnitTesting"; import { getDiForUnitTesting } from "../../getDiForUnitTesting";
import subscribeStoresInjectable from "../../kube-watch-api/subscribe-stores.injectable";
import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable"; import storesAndApisCanBeCreatedInjectable from "../../stores-apis-can-be-created.injectable";
import type { Disposer } from "../../utils";
import { disposer } from "../../utils";
import { renderFor } from "../test-utils/renderFor"; import { renderFor } from "../test-utils/renderFor";
import { NamespaceSelectFilter } from "./namespace-select-filter"; import { NamespaceSelectFilter } from "./namespace-select-filter";
import type { NamespaceStore } from "./store"; import type { NamespaceStore } from "./store";
@ -32,17 +40,45 @@ function createNamespace(name: string): Namespace {
describe("<NamespaceSelectFilter />", () => { describe("<NamespaceSelectFilter />", () => {
let di: DiContainer; let di: DiContainer;
let namespaceStore: NamespaceStore; let namespaceStore: NamespaceStore;
let fetchMock: AsyncFnMock<Fetch>;
let result: RenderResult; let result: RenderResult;
let cleanup: Disposer;
beforeEach(() => { beforeEach(() => {
di = getDiForUnitTesting({ doGeneralOverrides: true }); di = getDiForUnitTesting({ doGeneralOverrides: true });
di.override(directoryForUserDataInjectable, () => "/some-directory"); di.override(directoryForUserDataInjectable, () => "/some-directory");
di.override(storesAndApisCanBeCreatedInjectable, () => true); di.override(storesAndApisCanBeCreatedInjectable, () => true);
di.unoverride(subscribeStoresInjectable);
namespaceStore = di.inject(namespaceStoreInjectable); namespaceStore = di.inject(namespaceStoreInjectable);
const subscribeStores = di.inject(subscribeStoresInjectable);
cleanup = disposer(subscribeStores([namespaceStore]));
fetchMock = asyncFn();
di.override(fetchInjectable, () => fetchMock);
const render = renderFor(di); const render = renderFor(di);
namespaceStore.items.replace([ result = render((
<NamespaceSelectFilter id="namespace-select-filter" />
));
});
afterEach(() => {
cleanup();
});
describe("once the subscribe resolves", () => {
beforeEach(async () => {
await fetchMock.resolveSpecific([
"http://127.0.0.1:12345/api-kube/api/v1/namespaces",
], createMockResponseFromString("http://127.0.0.1:12345/api-kube/api/v1/namespaces", JSON.stringify({
apiVersion: "v1",
kind: "NamespaceList",
metadata: {},
items: [
createNamespace("test-1"), createNamespace("test-1"),
createNamespace("test-2"), createNamespace("test-2"),
createNamespace("test-3"), createNamespace("test-3"),
@ -56,11 +92,8 @@ describe("<NamespaceSelectFilter />", () => {
createNamespace("test-11"), createNamespace("test-11"),
createNamespace("test-12"), createNamespace("test-12"),
createNamespace("test-13"), createNamespace("test-13"),
]); ],
})));
result = render((
<NamespaceSelectFilter id="namespace-select-filter" />
));
}); });
it("renders", () => { it("renders", () => {
@ -172,7 +205,7 @@ describe("<NamespaceSelectFilter />", () => {
it("'test-13' is not sorted to the top of the list", () => { it("'test-13' is not sorted to the top of the list", () => {
const topLevelElement = result.getByText("test-13").parentElement?.parentElement as HTMLElement; const topLevelElement = result.getByText("test-13").parentElement?.parentElement as HTMLElement;
expect(topLevelElement.nextSibling).toBe(null); expect(topLevelElement.previousSibling).not.toBe(null);
}); });
}); });
@ -250,3 +283,4 @@ describe("<NamespaceSelectFilter />", () => {
}); });
}); });
}); });
});

View File

@ -29,8 +29,19 @@ export class NamespaceStore extends KubeObjectStore<Namespace, NamespaceApi> {
private async init() { private async init() {
await this.dependencies.storage.whenReady; await this.dependencies.storage.whenReady;
this.selectNamespaces(this.initialNamespaces); const { allowedNamespaces } = this;
this.autoLoadAllowedNamespaces(); const selectedNamespaces = this.dependencies.storage.get(); // raw namespaces, undefined on first load
// return previously saved namespaces from local-storage (if any)
if (Array.isArray(selectedNamespaces)) {
this.selectNamespaces(selectedNamespaces.filter(namespace => allowedNamespaces.includes(namespace)));
} else if (allowedNamespaces.includes("default")) {
this.selectNamespaces(["default"]);
} else if (allowedNamespaces.length) {
this.selectNamespaces([allowedNamespaces[0]]);
} else {
this.selectNamespaces([]);
}
} }
public onContextChange(callback: (namespaces: string[]) => void, opts: { fireImmediately?: boolean } = {}): IReactionDisposer { public onContextChange(callback: (namespaces: string[]) => void, opts: { fireImmediately?: boolean } = {}): IReactionDisposer {
@ -40,32 +51,6 @@ export class NamespaceStore extends KubeObjectStore<Namespace, NamespaceApi> {
}); });
} }
private autoLoadAllowedNamespaces(): IReactionDisposer {
return reaction(() => this.allowedNamespaces, namespaces => this.loadAll({ namespaces }), {
fireImmediately: true,
equals: comparer.shallow,
});
}
private get initialNamespaces(): string[] {
const { allowedNamespaces } = this;
const selectedNamespaces = this.dependencies.storage.get(); // raw namespaces, undefined on first load
// return previously saved namespaces from local-storage (if any)
if (Array.isArray(selectedNamespaces)) {
return selectedNamespaces.filter(namespace => allowedNamespaces.includes(namespace));
}
// otherwise select "default" or first allowed namespace
if (allowedNamespaces.includes("default")) {
return ["default"];
} else if (allowedNamespaces.length) {
return [allowedNamespaces[0]];
}
return [];
}
/** /**
* @private * @private
* The current value (list of namespaces names) in the storage layer * The current value (list of namespaces names) in the storage layer

View File

@ -7,7 +7,6 @@ import kubeWatchApiInjectable from "./kube-watch-api.injectable";
const subscribeStoresInjectable = getInjectable({ const subscribeStoresInjectable = getInjectable({
id: "subscribe-stores", id: "subscribe-stores",
causesSideEffects: true,
instantiate: (di) => di.inject(kubeWatchApiInjectable).subscribeStores, instantiate: (di) => di.inject(kubeWatchApiInjectable).subscribeStores,
}); });

View File

@ -0,0 +1,62 @@
/**
* Copyright (c) OpenLens Authors. All rights reserved.
* Licensed under MIT License. See LICENSE in root directory for more information.
*/
import type { Response, Headers as NodeFetchHeaders } from "node-fetch";
import { PassThrough } from "stream";
export const createMockResponseFromString = (url: string, data: string, statusCode = 200) => {
const res: jest.Mocked<Response> = {
buffer: jest.fn(async () => { throw new Error("buffer() is not supported"); }),
clone: jest.fn(() => res),
arrayBuffer: jest.fn(async () => { throw new Error("arrayBuffer() is not supported"); }),
blob: jest.fn(async () => { throw new Error("blob() is not supported"); }),
body: new PassThrough(),
bodyUsed: false,
headers: new Headers() as NodeFetchHeaders,
json: jest.fn(async () => JSON.parse(await res.text())),
ok: 200 <= statusCode && statusCode < 300,
redirected: 300 <= statusCode && statusCode < 400,
size: data.length,
status: statusCode,
statusText: "some-text",
text: jest.fn(async () => data),
type: "basic",
url,
formData: jest.fn(async () => { throw new Error("formData() is not supported"); }),
};
return res;
};
export const createMockResponseFromStream = (url: string, stream: NodeJS.ReadableStream, statusCode = 200) => {
const res: jest.Mocked<Response> = {
buffer: jest.fn(async () => { throw new Error("buffer() is not supported"); }),
clone: jest.fn(() => res),
arrayBuffer: jest.fn(async () => { throw new Error("arrayBuffer() is not supported"); }),
blob: jest.fn(async () => { throw new Error("blob() is not supported"); }),
body: stream,
bodyUsed: false,
headers: new Headers() as NodeFetchHeaders,
json: jest.fn(async () => JSON.parse(await res.text())),
ok: 200 <= statusCode && statusCode < 300,
redirected: 300 <= statusCode && statusCode < 400,
size: 10,
status: statusCode,
statusText: "some-text",
text: jest.fn(() => {
const chunks: Buffer[] = [];
return new Promise((resolve, reject) => {
stream.on("data", (chunk) => chunks.push(Buffer.from(chunk)));
stream.on("error", (err) => reject(err));
stream.on("end", () => resolve(Buffer.concat(chunks).toString("utf8")));
});
}),
type: "basic",
url,
formData: jest.fn(async () => { throw new Error("formData() is not supported"); }),
};
return res;
};