metis-desk/packages/rdx-ui/src/entity-column-visibility.test.tsx
David ded45e1c42 feat: add AssetRelatedInformation component for displaying asset profiles and software installations
test: implement resource template propagation tests for resource revisions

feat: create prepareResourceTemplateUpdates function for handling resource template updates

feat: add resource revision specifications for managing resource revisions in the database

test: add tests for entity column visibility and local storage handling

feat: implement entity column visibility storage for managing column preferences

feat: create synchronizeTemplateStructure utility for managing template field and section synchronization
2026-10-19 11:45:09 +02:00

154 lines
4.8 KiB
TypeScript

import assert from "node:assert/strict";
import { test } from "node:test";
import { renderToStaticMarkup } from "react-dom/server";
import { EntityTable } from "./components/entity-list";
import {
readColumnVisibility,
writeColumnVisibility,
} from "./lib/entity-column-visibility-storage";
function withStorage(run: (values: Map<string, string>) => void) {
const original = Object.getOwnPropertyDescriptor(globalThis, "window");
const values = new Map<string, string>();
Object.defineProperty(globalThis, "window", {
configurable: true,
value: {
localStorage: {
getItem: (key: string) => values.get(key) ?? null,
setItem: (key: string, value: string) => values.set(key, value),
},
},
});
try {
run(values);
} finally {
if (original) {
Object.defineProperty(globalThis, "window", original);
} else {
Reflect.deleteProperty(globalThis, "window");
}
}
}
test("las columnas elegidas se restauran al volver a crear la tabla, incluidas las que llegan después", () => {
withStorage((storage) => {
writeColumnVisibility("assets", {
detail: true,
later: true,
optional: false,
name: false,
actions: false,
});
const render = (includeLater: boolean) =>
renderToStaticMarkup(
<EntityTable
columns={[
{ id: "name", label: "Nombre", hideable: false, render: () => "Equipo" },
{ id: "detail", label: "Detalle", defaultVisible: false, render: () => "Dato elegido" },
{ id: "optional", label: "Optativa", render: () => "Dato oculto" },
...(includeLater
? [
{
id: "later",
label: "Campo posterior",
defaultVisible: false,
render: () => "Columna asíncrona",
},
]
: []),
{
id: "actions",
label: "Acciones",
render: () => <button type="button">Editar</button>,
},
]}
columnVisibilityStorageKey="assets"
items={[{ id: "one" }]}
title="Activos"
/>
);
const initial = render(false);
const restored = render(true);
assert.ok(initial.includes("Dato elegido"));
assert.ok(restored.includes("Dato elegido"));
assert.ok(restored.includes("Columna asíncrona"));
assert.ok(restored.includes("Equipo"));
assert.ok(restored.includes("Editar"));
assert.equal(restored.includes("Dato oculto"), false);
assert.equal(readColumnVisibility("assets").later, true);
assert.equal(storage.has("entity-page-size"), false);
});
});
test("las preferencias quedan aisladas por lista y no se aplican cuando no se solicita persistencia", () => {
withStorage(() => {
writeColumnVisibility("assets", { detail: true });
writeColumnVisibility("picker", { detail: false });
assert.deepEqual(readColumnVisibility("assets"), { detail: true });
assert.deepEqual(readColumnVisibility("picker"), { detail: false });
assert.deepEqual(readColumnVisibility(undefined), {});
const html = renderToStaticMarkup(
<EntityTable
columns={[
{
id: "detail",
label: "Detalle",
defaultVisible: false,
render: () => "Preferencia ajena",
},
]}
items={[{ id: "one" }]}
title="Selector"
/>
);
assert.equal(html.includes("Preferencia ajena"), false);
});
});
test("datos locales inválidos no rompen el listado y solo se aceptan valores booleanos", () => {
withStorage((storage) => {
for (const serialized of ["{invalid", "[]", "null", '"text"', "42"]) {
storage.set("assets", serialized);
assert.deepEqual(readColumnVisibility("assets"), {});
}
storage.set("assets", '{"detail":true,"optional":false,"text":"true","object":{},"array":[]}');
assert.deepEqual(readColumnVisibility("assets"), { detail: true, optional: false });
});
});
test("almacenamiento bloqueado o sin cuota permite seguir utilizando la selección local", () => {
const original = Object.getOwnPropertyDescriptor(globalThis, "window");
Object.defineProperty(globalThis, "window", {
configurable: true,
value: {
localStorage: {
getItem: () => {
throw new Error("Storage blocked");
},
setItem: () => {
throw new Error("Quota exceeded");
},
},
},
});
try {
assert.deepEqual(readColumnVisibility("assets"), {});
assert.doesNotThrow(() => writeColumnVisibility("assets", { detail: true }));
} finally {
if (original) {
Object.defineProperty(globalThis, "window", original);
} else {
Reflect.deleteProperty(globalThis, "window");
}
}
});