Files
kita-planer/tests/notdienst-assignment-view.test.cjs

140 lines
4.9 KiB
JavaScript

/* eslint-disable @typescript-eslint/no-require-imports -- Render the actual client component through the TypeScript loader. */
const { test } = require("node:test");
const assert = require("node:assert/strict");
const fs = require("node:fs");
const path = require("node:path");
const vm = require("node:vm");
const ts = require("typescript");
const React = require("react");
const { renderToStaticMarkup } = require("react-dom/server");
function loader(overrides = {}) {
const cache = new Map();
function load(file) {
file = path.resolve(file);
if (cache.has(file)) return cache.get(file).exports;
const mod = { exports: {} };
cache.set(file, mod);
const code = ts.transpileModule(fs.readFileSync(file, "utf8"), {
compilerOptions: {
target: ts.ScriptTarget.ES2022,
module: ts.ModuleKind.CommonJS,
jsx: ts.JsxEmit.ReactJSX,
esModuleInterop: true,
},
fileName: file,
}).outputText;
const req = (spec) => {
if (Object.hasOwn(overrides, spec)) return overrides[spec];
if (spec === "server-only") return {};
if (spec === "@/lib/prisma")
throw new Error("No database in component render tests");
if (spec === "next/headers")
return { headers: async () => new Headers() };
if (spec === "next/cache") return { revalidatePath() {} };
if (spec === "next/navigation")
return {
redirect(url) {
throw new Error(`REDIRECT:${url}`);
},
notFound() {
throw new Error("NOT_FOUND");
},
};
if (spec.startsWith("@/") || spec.startsWith(".")) {
const target = spec.startsWith("@/")
? path.resolve("src", spec.slice(2))
: path.resolve(path.dirname(file), spec);
for (const suffix of [".ts", ".tsx", "/index.ts"])
if (fs.existsSync(target + suffix)) return load(target + suffix);
}
return require(spec);
};
vm.runInThisContext(`(function(require,module,exports){${code}\n})`, {
filename: file,
})(req, mod, mod.exports);
return mod.exports;
}
return load;
}
const load = loader({ "./actions": {} });
const { ManualAssignmentTable } = load(
"src/app/dashboard/notdienst/plan/plan-view.tsx",
);
const children = [
{ id: "a", name: "Alex", parentName: "Haushalt A", familyId: "family-a" },
{ id: "b", name: "Ben", parentName: "Haushalt B", familyId: "family-b" },
{ id: "a2", name: "Anna", parentName: "Haushalt A", familyId: "family-a" },
];
const day = {
date: "2030-11-04T00:00:00.000Z",
assignmentId: null,
childId: null,
};
const familyStatuses = [
{ id: "family-a", selectedDays: [{ iso: day.date }] },
{ id: "family-b", selectedDays: [{ iso: "2030-11-05T00:00:00.000Z" }] },
];
const render = (overrides = {}) =>
renderToStaticMarkup(
React.createElement(ManualAssignmentTable, {
days: [day],
allChildren: children,
familyStatuses,
isDraft: true,
isPending: false,
onAssignmentChange() {},
...overrides,
}),
);
test("Verfügbare Haushalte stehen zuerst; Geschwister zählen als eine verfügbare Familie", () => {
const html = render();
assert.ok(
html.indexOf("Verfügbar an diesem Tag") <
html.indexOf("Keine Verfügbarkeit für diesen Tag"),
);
assert.match(html, /1 Familie ist verfügbar/);
assert.match(html, /value="a2"/);
assert.match(html, /value="b"/);
assert.match(html, /aria-label="Familie für 04.11.2030"/);
});
test("Bestehende Einteilung ohne Rückmeldung bleibt auswählbar und wird kenntlich gemacht", () => {
const html = render({ days: [{ ...day, childId: "b" }] });
assert.match(html, /value="b" selected/);
assert.match(
html,
/Eingeteilte Familie hat für diesen Tag keine Verfügbarkeit angegeben/,
);
});
test("Eingeteilte verfügbare Familie und Haushaltseinteilungszahl werden angezeigt", () => {
const html = render({
days: [
{ ...day, childId: "a" },
{ ...day, date: "2030-11-05T00:00:00.000Z", childId: "a2" },
],
});
assert.match(html, /Eingeteilte Familie ist verfügbar/);
assert.match(html, /Haushalt A \(Alex\) — 2x/);
});
test("Fehlende Verfügbarkeiten erzeugen eine klare Angabe ohne Familien auszublenden", () => {
const html = render({ familyStatuses: [] });
assert.match(html, /0 Familien sind verfügbar/);
assert.match(html, /value="a"/);
assert.match(html, /value="b"/);
});
test("Aktiver Alarm sperrt die Auswahl weiterhin", () => {
const html = render({
days: [{ ...day, childId: "a", activeAlarmId: "alarm" }],
});
assert.match(html, /<select[^>]*disabled/);
});
test("Ungültige alte Einteilung bleibt entfernbar; neue Kinder sind dafür gesperrt", () => {
const html = render({
days: [{ ...day, childId: "inactive", isInvalid: true }],
});
assert.match(html, /value="empty"/);
assert.match(html, /value="inactive" disabled/);
assert.match(html, /value="a" disabled/);
assert.match(html, /Einteilung nicht mehr gültig/);
});