metis-desk/modules/companies/src/web/access/access.test.tsx

272 lines
9.4 KiB
TypeScript

import assert from "node:assert/strict";
import { test } from "node:test";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { createInstance } from "i18next";
import { renderToStaticMarkup } from "react-dom/server";
import { I18nextProvider } from "react-i18next";
import type { AccessResponseDTO } from "../../common";
import { accessKeys } from "./access-api";
import { accessFields } from "./access-fields";
import { AccessForm } from "./access-form";
import { AccessWorkspacePage } from "./access-workspace";
import { accessEnglish, accessSpanish } from "./i18n";
import { quickCreatePlan } from "./quick-create-plan";
test("los catálogos presentan alta mediante acción y no un formulario junto al listado", async () => {
for (const [language, label] of [
["es", "Nuevo sistema"],
["en", "New system"],
] as const) {
const i18n = createInstance();
await i18n.init({
lng: language,
resources: { es: { access: accessSpanish }, en: { access: accessEnglish } },
});
const client = new QueryClient();
client.setQueryData(accessKeys.scope("global"), { items: [], reviews: [], coverage: [] });
const markup = renderToStaticMarkup(
<I18nextProvider i18n={i18n}>
<QueryClientProvider client={client}>
<AccessWorkspacePage csrfToken="test" scope="global" />
</QueryClientProvider>
</I18nextProvider>
);
assert.ok(markup.includes(label));
assert.equal(markup.includes("<form"), false);
client.clear();
}
});
test("cuentas ofrecen caducidad opcional y campos sin contraseña", async () => {
const i18n = createInstance();
await i18n.init({ lng: "es", resources: { es: { access: accessSpanish } } });
const client = new QueryClient();
const markup = renderToStaticMarkup(
<I18nextProvider i18n={i18n}>
<QueryClientProvider client={client}>
<AccessForm
csrfToken="test"
data={{ items: [], reviews: [], coverage: [] }}
kind="account"
onSaved={() => undefined}
people={[]}
scope="e0420eb9-2aab-4368-96a0-2ce83dd23eb4"
/>
</QueryClientProvider>
</I18nextProvider>
);
assert.ok(markup.includes("Fecha de caducidad"));
assert.ok(markup.includes('aria-label="Añadir sistema"'));
assert.equal(markup.includes('aria-label="Añadir entorno"'), false);
assert.ok(markup.includes("Sistema, entorno y uso quedan fijos"));
assert.equal(markup.includes('type="password"'), false);
const field = markup.match(/<input[^>]*name="expiresOn"[^>]*>/)?.[0];
assert.ok(field);
assert.equal(field.includes("required"), false);
client.clear();
});
test("la ayuda explica todos los elementos en ambos idiomas y distingue el ámbito", async () => {
const { EntityHelp } = await import("./entity-help");
const { accessSpanish: helpSpanish, accessEnglish: helpEnglish } = await import("./i18n");
for (const [language, content] of [
["es", helpSpanish],
["en", helpEnglish],
] as const) {
const i18n = createInstance();
await i18n.init({ lng: language, resources: { [language]: { access: content } } });
for (const kind of [
"system",
"resource_type",
"permission",
"template",
"environment",
"account",
"account_person",
"group",
"membership",
"resource",
"grant",
"need",
"coverage",
"company",
"person",
"department",
"site",
"assignment",
] as const) {
const markup = renderToStaticMarkup(
<I18nextProvider i18n={i18n}>
<EntityHelp kind={kind} scope="global" />
</I18nextProvider>
);
assert.ok(markup.includes("<details"));
assert.ok(
markup.includes(
content.helpContent[kind].examples.replaceAll("&", "&amp;").replaceAll("'", "&#x27;")
)
);
assert.equal(markup.includes("helpContent."), false);
}
const renderScope = (scope: string) =>
renderToStaticMarkup(
<I18nextProvider i18n={i18n}>
<EntityHelp kind="system" scope={scope} />
</I18nextProvider>
);
assert.ok(renderScope("global").includes(content.helpGlobalScope));
assert.ok(renderScope("company").includes(content.helpCompanyScope));
assert.equal(renderScope("company").includes(content.helpGlobalScope), false);
}
});
test("los ejemplos del sistema orientan sin rellenar datos del alta", async () => {
const i18n = createInstance();
await i18n.init({ lng: "es", resources: { es: { access: accessSpanish } } });
const client = new QueryClient();
const markup = renderToStaticMarkup(
<I18nextProvider i18n={i18n}>
<QueryClientProvider client={client}>
<AccessForm
csrfToken="test"
data={{ items: [], reviews: [], coverage: [] }}
kind="system"
onSaved={() => undefined}
people={[]}
scope="global"
/>
</QueryClientProvider>
</I18nextProvider>
);
assert.ok(markup.includes("Microsoft 365"));
assert.ok(markup.includes("Ámbito global"));
assert.ok(markup.indexOf('name="name"') < markup.indexOf("<aside"));
assert.ok(markup.indexOf("<aside") < markup.indexOf('type="submit"'));
const name = markup.match(/<input[^>]*name="name"[^>]*>/)?.[0];
assert.ok(name);
assert.equal(/value="[^"]+"/.test(name), false);
assert.equal(markup.includes('value="Microsoft 365"'), false);
client.clear();
});
test("las altas rápidas respetan el contexto, ámbito y relaciones históricas", () => {
const data: AccessResponseDTO = {
items: [
{
id: "system",
companyId: null,
history: [],
values: { kind: "system", name: "Directorio", active: true },
},
{
id: "type",
companyId: null,
history: [],
values: { kind: "resource_type", name: "Carpeta", active: true },
},
{
id: "resource",
companyId: "company",
history: [],
values: {
kind: "resource",
name: "Documentos",
resourceTypeId: "type",
active: true,
systemId: null,
environmentId: null,
reference: null,
notes: null,
},
},
{
id: "account",
companyId: "company",
history: [],
values: {
kind: "account",
systemId: "system",
environmentId: "env",
login: "ana",
expiresOn: null,
notes: null,
usage: "personal",
active: true,
},
},
],
reviews: [],
coverage: [],
};
const field = (kind: keyof typeof accessFields, key: string) => {
const result = accessFields[kind].find((candidate) => candidate.key === key);
assert.ok(result);
return result;
};
const plan = (kind: keyof typeof accessFields, key: string, values = {}, scope = "company") =>
quickCreatePlan(field(kind, key), scope, kind, data, values);
assert.equal(plan("account", "usage"), undefined);
assert.equal(plan("account", "environmentId"), undefined);
assert.deepEqual(plan("account", "environmentId", { systemId: "system" }), {
type: "simple",
target: { kind: "environment", systemId: "system", systemName: "Directorio" },
});
assert.equal(plan("grant", "permissionId"), undefined);
assert.deepEqual(plan("grant", "permissionId", { resourceId: "resource" }), {
type: "access",
kind: "permission",
scope: "company",
defaults: { active: true, resourceTypeId: "type" },
locked: ["active", "resourceTypeId"],
});
assert.equal(plan("membership", "groupId"), undefined);
assert.deepEqual(plan("membership", "groupId", { accountId: "account" }), {
type: "access",
kind: "group",
scope: "company",
defaults: { active: true, systemId: "system", environmentId: "env" },
locked: ["active", "systemId", "environmentId"],
});
assert.deepEqual(plan("account_person", "personId"), { type: "person" });
assert.equal(plan("account_person", "personId", {}, "global"), undefined);
assert.deepEqual(plan("group", "templateId"), {
type: "access",
kind: "template",
scope: "global",
defaults: { active: true },
locked: ["active"],
});
for (const entry of accessFields.coverage) {
assert.equal(quickCreatePlan(entry, "company", "coverage", data, {}), undefined);
}
});
test("los formularios ofrecen altas relacionadas y el segundo modal evita altas anidadas", async () => {
const i18n = createInstance();
await i18n.init({ lng: "es", resources: { es: { access: accessSpanish } } });
const client = new QueryClient();
const render = (kind: keyof typeof accessFields, allowQuickCreate = true) =>
renderToStaticMarkup(
<I18nextProvider i18n={i18n}>
<QueryClientProvider client={client}>
<AccessForm
allowQuickCreate={allowQuickCreate}
csrfToken="test"
data={{ items: [], reviews: [], coverage: [] }}
kind={kind}
onSaved={() => undefined}
people={[]}
scope="company"
/>
</QueryClientProvider>
</I18nextProvider>
);
for (const kind of ["permission", "account_person", "grant", "need", "group"] as const) {
assert.ok(render(kind).includes('data-slot="button-group"'), kind);
assert.equal(render(kind, false).includes('data-slot="button-group"'), false, kind);
}
assert.equal(render("coverage").includes('data-slot="button-group"'), false);
client.clear();
});