553 lines
22 KiB
TypeScript
553 lines
22 KiB
TypeScript
import { beforeEach, describe, expect, it } from "vitest";
|
||
import { VersionStatus } from "@/generated/prisma/enums";
|
||
import {
|
||
BausteinFehler,
|
||
bausteinAnlegen,
|
||
bausteinArchivieren,
|
||
bausteinBearbeiten,
|
||
bausteinEntwurfHolenOderErzeugen,
|
||
bausteinEntwurfSpeichern,
|
||
bausteinEntwurfVerwerfen,
|
||
bausteinVersionVeroeffentlichen,
|
||
} from "@/server/services/bausteine";
|
||
import {
|
||
bausteinHolen,
|
||
bausteinListe,
|
||
bausteinVerwendungen,
|
||
einsetzbareBausteine,
|
||
} from "@/server/queries/bausteine";
|
||
import {
|
||
VorlagenFehler,
|
||
entwurfHolenOderErzeugen,
|
||
entwurfSpeichern,
|
||
versionVeroeffentlichen,
|
||
vorlageAnlegen,
|
||
} from "@/server/services/vorlagen";
|
||
import { vorlageExportieren, vorlageImportieren } from "@/server/services/vorlagen-austausch";
|
||
import { datenbankLeeren, datenbankVerfuegbar, testPrisma } from "./helpers/db";
|
||
|
||
/**
|
||
* Wiederverwendbare Bausteine (#030).
|
||
*
|
||
* Die eine Zusage, die alles traegt: **eine Baustein-Aenderung fasst nichts
|
||
* Veroeffentlichtes an.** Ein Entwurf verweist, eine veroeffentlichte Version
|
||
* traegt Kopien — und ein Lauf sieht deshalb weiterhin konkrete Schritte.
|
||
*/
|
||
|
||
async function grundbestand() {
|
||
const admin = await testPrisma.benutzer.create({
|
||
data: { email: "admin@firma.example", name: "Admin", rolle: "ADMIN" },
|
||
});
|
||
return { adminId: admin.id };
|
||
}
|
||
|
||
/** Ein veroeffentlichter Baustein mit den uebergebenen Schritttiteln. */
|
||
async function bausteinMitSchritten(
|
||
name: string,
|
||
titel: string,
|
||
schritte: readonly string[],
|
||
adminId: string,
|
||
): Promise<{ bausteinId: string; versionId: string }> {
|
||
const { bausteinId, versionId } = await bausteinAnlegen({ name }, adminId);
|
||
await bausteinEntwurfSpeichern(versionId, {
|
||
titel,
|
||
schritte: schritte.map((schritt) => ({ titel: schritt })),
|
||
});
|
||
await bausteinVersionVeroeffentlichen(versionId, null, adminId);
|
||
return { bausteinId, versionId };
|
||
}
|
||
|
||
/** Eine Vorlage mit einem Baustein-Abschnitt und einem eigenen, veroeffentlicht. */
|
||
async function vorlageMitBaustein(
|
||
name: string,
|
||
bausteinVersionId: string,
|
||
adminId: string,
|
||
): Promise<{ vorlageId: string; versionId: string }> {
|
||
const { vorlage } = await vorlageAnlegen({ name }, adminId);
|
||
const entwurf = await entwurfHolenOderErzeugen(vorlage.id, adminId);
|
||
const versionId = entwurf.id;
|
||
await entwurfSpeichern(versionId, {
|
||
variablen: [],
|
||
abschnitte: [
|
||
{ titel: "Eigener Abschnitt", schritte: [{ titel: "Eigener Schritt" }] },
|
||
{ titel: "wird ersetzt", bausteinVersionId, schritte: [] },
|
||
],
|
||
});
|
||
await versionVeroeffentlichen(versionId, null, adminId);
|
||
return { vorlageId: vorlage.id, versionId };
|
||
}
|
||
|
||
async function schritteVon(versionId: string): Promise<readonly string[]> {
|
||
const abschnitte = await testPrisma.vorlagenAbschnitt.findMany({
|
||
where: { versionId },
|
||
orderBy: { position: "asc" },
|
||
include: { schritte: { orderBy: { position: "asc" } } },
|
||
});
|
||
return abschnitte.flatMap((abschnitt) => [
|
||
`# ${abschnitt.titel}`,
|
||
...abschnitt.schritte.map((schritt) => schritt.titel),
|
||
]);
|
||
}
|
||
|
||
describe.runIf(datenbankVerfuegbar)("Bausteine", () => {
|
||
beforeEach(async () => {
|
||
await datenbankLeeren();
|
||
});
|
||
|
||
describe("Pflegen", () => {
|
||
it("legt einen Baustein mit Entwurf in Version 1 an", async () => {
|
||
const { adminId } = await grundbestand();
|
||
const { bausteinId, versionId } = await bausteinAnlegen({ name: "Datensicherung prüfen" }, adminId);
|
||
|
||
const ansicht = await bausteinHolen(bausteinId);
|
||
expect(ansicht?.name).toBe("Datensicherung prüfen");
|
||
expect(ansicht?.versionen).toHaveLength(1);
|
||
expect(ansicht?.versionen[0]).toMatchObject({
|
||
id: versionId,
|
||
version: 1,
|
||
status: VersionStatus.ENTWURF,
|
||
// Der Titel beginnt als Name – in den meisten Fällen stimmt das.
|
||
titel: "Datensicherung prüfen",
|
||
});
|
||
});
|
||
|
||
it("hält Namen eindeutig, mit einem Satz statt eines Datenbankfehlers", async () => {
|
||
const { adminId } = await grundbestand();
|
||
await bausteinAnlegen({ name: "Datensicherung prüfen" }, adminId);
|
||
await expect(bausteinAnlegen({ name: "Datensicherung prüfen" }, adminId)).rejects.toThrow(
|
||
/gibt schon einen Baustein/,
|
||
);
|
||
});
|
||
|
||
it("lässt je Baustein höchstens einen Entwurf zu – auch an der Service-Schicht vorbei", async () => {
|
||
const { adminId } = await grundbestand();
|
||
const { bausteinId } = await bausteinAnlegen({ name: "Einmal" }, adminId);
|
||
await expect(
|
||
testPrisma.bausteinVersion.create({
|
||
data: { bausteinId, version: 2, status: VersionStatus.ENTWURF, titel: "zweiter" },
|
||
}),
|
||
).rejects.toThrow(/BausteinVersion_ein_entwurf/);
|
||
});
|
||
|
||
it("weist einen Baustein ohne Schritte beim Veröffentlichen ab", async () => {
|
||
const { adminId } = await grundbestand();
|
||
const { versionId } = await bausteinAnlegen({ name: "Leer" }, adminId);
|
||
await expect(bausteinVersionVeroeffentlichen(versionId, null, adminId)).rejects.toThrow(
|
||
/ohne Schritte/,
|
||
);
|
||
});
|
||
|
||
it("macht aus einer veröffentlichten Version einen Entwurf als tiefe Kopie", async () => {
|
||
const { adminId } = await grundbestand();
|
||
const { bausteinId } = await bausteinMitSchritten(
|
||
"Datensicherung prüfen",
|
||
"Datensicherung",
|
||
["Sicherung läuft", "Rücksicherung getestet"],
|
||
adminId,
|
||
);
|
||
|
||
const entwurfId = await bausteinEntwurfHolenOderErzeugen(bausteinId, adminId);
|
||
const ansicht = await bausteinHolen(bausteinId);
|
||
expect(ansicht?.versionen).toHaveLength(2);
|
||
const entwurf = ansicht?.versionen.find((version) => version.id === entwurfId);
|
||
expect(entwurf?.version).toBe(2);
|
||
expect(entwurf?.schritte.map((schritt) => schritt.titel)).toEqual([
|
||
"Sicherung läuft",
|
||
"Rücksicherung getestet",
|
||
]);
|
||
|
||
// Zweiter Aufruf gibt denselben Entwurf, nicht einen dritten.
|
||
expect(await bausteinEntwurfHolenOderErzeugen(bausteinId, adminId)).toBe(entwurfId);
|
||
});
|
||
|
||
it("lässt eine veröffentlichte Version nicht ändern – der Trigger hält das fest", async () => {
|
||
const { adminId } = await grundbestand();
|
||
const { versionId } = await bausteinMitSchritten("Fest", "Fest", ["Eins"], adminId);
|
||
|
||
await expect(
|
||
bausteinEntwurfSpeichern(versionId, { titel: "anders", schritte: [{ titel: "Zwei" }] }),
|
||
).rejects.toThrow(/unveränderlich/);
|
||
// Und auch an der Service-Schicht vorbei nicht.
|
||
await expect(
|
||
testPrisma.bausteinSchritt.create({ data: { versionId, titel: "Geschmuggelt" } }),
|
||
).rejects.toThrow(/unveraenderlich/);
|
||
});
|
||
|
||
it("lässt eine veröffentlichte Version nicht zum Entwurf zurückmachen", async () => {
|
||
const { adminId } = await grundbestand();
|
||
const { versionId } = await bausteinMitSchritten("Einbahn", "Einbahn", ["Eins"], adminId);
|
||
await expect(
|
||
testPrisma.bausteinVersion.update({
|
||
where: { id: versionId },
|
||
data: { status: VersionStatus.ENTWURF },
|
||
}),
|
||
).rejects.toThrow(/nicht wieder zum Entwurf/);
|
||
});
|
||
|
||
it("verwirft einen Entwurf nur, wenn es noch eine veröffentlichte Version gibt", async () => {
|
||
const { adminId } = await grundbestand();
|
||
const { bausteinId, versionId } = await bausteinAnlegen({ name: "Einzig" }, adminId);
|
||
await expect(bausteinEntwurfVerwerfen(versionId, adminId)).rejects.toThrow(/einzige Version/);
|
||
|
||
await bausteinEntwurfSpeichern(versionId, { titel: "Einzig", schritte: [{ titel: "Eins" }] });
|
||
await bausteinVersionVeroeffentlichen(versionId, null, adminId);
|
||
const zweiter = await bausteinEntwurfHolenOderErzeugen(bausteinId, adminId);
|
||
await bausteinEntwurfVerwerfen(zweiter, adminId);
|
||
expect((await bausteinHolen(bausteinId))?.versionen).toHaveLength(1);
|
||
});
|
||
|
||
it("benennt um und protokolliert", async () => {
|
||
const { adminId } = await grundbestand();
|
||
const { bausteinId } = await bausteinAnlegen({ name: "Alt" }, adminId);
|
||
await bausteinBearbeiten(bausteinId, { name: "Neu", beschreibung: "Erklärung" }, adminId);
|
||
|
||
expect((await bausteinHolen(bausteinId))?.name).toBe("Neu");
|
||
const eintraege = await testPrisma.protokoll.findMany({
|
||
where: { entitaet: "Baustein", entitaetId: bausteinId },
|
||
orderBy: { erstelltAm: "asc" },
|
||
select: { aktion: true },
|
||
});
|
||
expect(eintraege.map((eintrag) => eintrag.aktion)).toEqual([
|
||
"Baustein angelegt",
|
||
"Name und Beschreibung geändert",
|
||
]);
|
||
});
|
||
});
|
||
|
||
describe("Einsetzen und Auflösen", () => {
|
||
it("setzt die Schritte des Bausteins beim Veröffentlichen ein", async () => {
|
||
const { adminId } = await grundbestand();
|
||
const { versionId: bausteinVersionId } = await bausteinMitSchritten(
|
||
"Datensicherung prüfen",
|
||
"Datensicherung",
|
||
["Sicherung läuft", "Rücksicherung getestet"],
|
||
adminId,
|
||
);
|
||
const { versionId } = await vorlageMitBaustein("PC Neuinstallation", bausteinVersionId, adminId);
|
||
|
||
expect(await schritteVon(versionId)).toEqual([
|
||
"# Eigener Abschnitt",
|
||
"Eigener Schritt",
|
||
// Titel und Schritte kommen aus dem Baustein, nicht aus dem Entwurf.
|
||
"# Datensicherung",
|
||
"Sicherung läuft",
|
||
"Rücksicherung getestet",
|
||
]);
|
||
});
|
||
|
||
it("lässt den Verweis als Herkunft stehen", async () => {
|
||
const { adminId } = await grundbestand();
|
||
const { versionId: bausteinVersionId } = await bausteinMitSchritten(
|
||
"Herkunft",
|
||
"Herkunft",
|
||
["Eins"],
|
||
adminId,
|
||
);
|
||
const { versionId } = await vorlageMitBaustein("Mit Herkunft", bausteinVersionId, adminId);
|
||
|
||
const abschnitt = await testPrisma.vorlagenAbschnitt.findFirstOrThrow({
|
||
where: { versionId, bausteinVersionId: { not: null } },
|
||
include: { bausteinVersion: { include: { baustein: true } } },
|
||
});
|
||
expect(abschnitt.bausteinVersion?.baustein.name).toBe("Herkunft");
|
||
});
|
||
|
||
it("weist einen Verweis auf einen Entwurf ab", async () => {
|
||
// Einen Entwurf einzusetzen hieße, beim Veröffentlichen etwas zu kopieren,
|
||
// das sich danach noch ändert.
|
||
const { adminId } = await grundbestand();
|
||
const { versionId: entwurfId } = await bausteinAnlegen({ name: "Noch Entwurf" }, adminId);
|
||
const { vorlage } = await vorlageAnlegen({ name: "Will einen Entwurf" }, adminId);
|
||
const versionId = (await entwurfHolenOderErzeugen(vorlage.id, adminId)).id;
|
||
|
||
await expect(
|
||
entwurfSpeichern(versionId, {
|
||
variablen: [],
|
||
abschnitte: [{ titel: "x", bausteinVersionId: entwurfId, schritte: [] }],
|
||
}),
|
||
).rejects.toThrow(/veroeffentlichte Baustein-Version/);
|
||
});
|
||
|
||
it("weist das Veröffentlichen ab, wenn der Baustein archiviert wurde", async () => {
|
||
const { adminId } = await grundbestand();
|
||
const { bausteinId, versionId: bausteinVersionId } = await bausteinMitSchritten(
|
||
"Weggelegt",
|
||
"Weggelegt",
|
||
["Eins"],
|
||
adminId,
|
||
);
|
||
const { vorlage } = await vorlageAnlegen({ name: "Mit weggelegtem" }, adminId);
|
||
const versionId = (await entwurfHolenOderErzeugen(vorlage.id, adminId)).id;
|
||
await entwurfSpeichern(versionId, {
|
||
variablen: [],
|
||
abschnitte: [{ titel: "x", bausteinVersionId, schritte: [] }],
|
||
});
|
||
|
||
// Archivieren geht hier nicht: der Baustein steht in einem Entwurf.
|
||
await expect(bausteinArchivieren(bausteinId, true, adminId)).rejects.toThrow(/Entwurf/);
|
||
// An der Service-Schicht vorbei archiviert – dann greift die Prüfung beim
|
||
// Veröffentlichen.
|
||
await testPrisma.baustein.update({ where: { id: bausteinId }, data: { archiviert: true } });
|
||
await expect(versionVeroeffentlichen(versionId, null, adminId)).rejects.toThrow(/archiviert/);
|
||
});
|
||
|
||
it("hält im Protokoll fest, welcher Baustein in welcher Fassung eingesetzt wurde", async () => {
|
||
const { adminId } = await grundbestand();
|
||
const { versionId: bausteinVersionId } = await bausteinMitSchritten(
|
||
"Datensicherung prüfen",
|
||
"Datensicherung",
|
||
["Eins"],
|
||
adminId,
|
||
);
|
||
const { versionId } = await vorlageMitBaustein("Mit Protokoll", bausteinVersionId, adminId);
|
||
|
||
const eintrag = await testPrisma.protokoll.findFirstOrThrow({
|
||
where: { entitaet: "VorlagenVersion", entitaetId: versionId, aktion: "Version veröffentlicht" },
|
||
});
|
||
expect(eintrag.nachher).toMatchObject({
|
||
bausteine: [{ name: "Datensicherung prüfen", version: 1 }],
|
||
});
|
||
});
|
||
});
|
||
|
||
describe("Unveränderlichkeit über Baustein-Änderungen hinweg", () => {
|
||
it("ändert keine veröffentlichte Vorlagenversion, wenn der Baustein neu veröffentlicht wird", async () => {
|
||
const { adminId } = await grundbestand();
|
||
const { bausteinId, versionId: ersteBausteinVersion } = await bausteinMitSchritten(
|
||
"Datensicherung prüfen",
|
||
"Datensicherung",
|
||
["Sicherung läuft"],
|
||
adminId,
|
||
);
|
||
const { versionId } = await vorlageMitBaustein("PC Neuinstallation", ersteBausteinVersion, adminId);
|
||
const vorher = await schritteVon(versionId);
|
||
|
||
// Zweite Fassung des Bausteins, inhaltlich ganz anders.
|
||
const zweiterEntwurf = await bausteinEntwurfHolenOderErzeugen(bausteinId, adminId);
|
||
await bausteinEntwurfSpeichern(zweiterEntwurf, {
|
||
titel: "Datensicherung, neu gedacht",
|
||
schritte: [{ titel: "Ganz anders" }, { titel: "Und noch einer" }],
|
||
});
|
||
await bausteinVersionVeroeffentlichen(zweiterEntwurf, "Umgebaut", adminId);
|
||
|
||
expect(await schritteVon(versionId)).toEqual(vorher);
|
||
});
|
||
|
||
it("lässt einen laufenden Lauf unberührt", async () => {
|
||
const { adminId } = await grundbestand();
|
||
const kunde = await testPrisma.kunde.create({
|
||
data: { name: "Eigene Organisation", kuerzel: "EIGEN", istEigeneOrganisation: true },
|
||
});
|
||
const { bausteinId, versionId: ersteBausteinVersion } = await bausteinMitSchritten(
|
||
"Datensicherung prüfen",
|
||
"Datensicherung",
|
||
["Sicherung läuft"],
|
||
adminId,
|
||
);
|
||
const { versionId } = await vorlageMitBaustein("PC Neuinstallation", ersteBausteinVersion, adminId);
|
||
const lauf = await testPrisma.lauf.create({
|
||
data: { vorlagenVersionId: versionId, titel: "Ein Lauf", kundeId: kunde.id },
|
||
});
|
||
|
||
const zweiterEntwurf = await bausteinEntwurfHolenOderErzeugen(bausteinId, adminId);
|
||
await bausteinEntwurfSpeichern(zweiterEntwurf, {
|
||
titel: "Anders",
|
||
schritte: [{ titel: "Ganz anders" }],
|
||
});
|
||
await bausteinVersionVeroeffentlichen(zweiterEntwurf, null, adminId);
|
||
|
||
const nachher = await testPrisma.lauf.findUniqueOrThrow({
|
||
where: { id: lauf.id },
|
||
include: {
|
||
vorlagenVersion: {
|
||
include: { abschnitte: { include: { schritte: true }, orderBy: { position: "asc" } } },
|
||
},
|
||
},
|
||
});
|
||
const titel = nachher.vorlagenVersion.abschnitte.flatMap((abschnitt) =>
|
||
abschnitt.schritte.map((schritt) => schritt.titel),
|
||
);
|
||
expect(titel).toContain("Sicherung läuft");
|
||
expect(titel).not.toContain("Ganz anders");
|
||
});
|
||
|
||
it("nimmt die neue Fassung in die nächste veröffentlichte Vorlagenversion", async () => {
|
||
const { adminId } = await grundbestand();
|
||
const { bausteinId, versionId: ersteBausteinVersion } = await bausteinMitSchritten(
|
||
"Datensicherung prüfen",
|
||
"Datensicherung",
|
||
["Sicherung läuft"],
|
||
adminId,
|
||
);
|
||
const { vorlageId } = await vorlageMitBaustein("PC Neuinstallation", ersteBausteinVersion, adminId);
|
||
|
||
const zweiterEntwurf = await bausteinEntwurfHolenOderErzeugen(bausteinId, adminId);
|
||
await bausteinEntwurfSpeichern(zweiterEntwurf, {
|
||
titel: "Datensicherung",
|
||
schritte: [{ titel: "Sicherung läuft" }, { titel: "Rücksicherung getestet" }],
|
||
});
|
||
await bausteinVersionVeroeffentlichen(zweiterEntwurf, null, adminId);
|
||
const neueFassung = await testPrisma.bausteinVersion.findFirstOrThrow({
|
||
where: { bausteinId, status: VersionStatus.VEROEFFENTLICHT },
|
||
orderBy: { version: "desc" },
|
||
});
|
||
|
||
// Neue Vorlagenversion, die auf die neue Fassung zeigt.
|
||
const zweiteVorlagenVersion = (await entwurfHolenOderErzeugen(vorlageId, adminId)).id;
|
||
await entwurfSpeichern(zweiteVorlagenVersion, {
|
||
variablen: [],
|
||
abschnitte: [
|
||
{ titel: "Eigener Abschnitt", schritte: [{ titel: "Eigener Schritt" }] },
|
||
{ titel: "x", bausteinVersionId: neueFassung.id, schritte: [] },
|
||
],
|
||
});
|
||
await versionVeroeffentlichen(zweiteVorlagenVersion, null, adminId);
|
||
|
||
expect(await schritteVon(zweiteVorlagenVersion)).toEqual([
|
||
"# Eigener Abschnitt",
|
||
"Eigener Schritt",
|
||
"# Datensicherung",
|
||
"Sicherung läuft",
|
||
"Rücksicherung getestet",
|
||
]);
|
||
});
|
||
});
|
||
|
||
describe("Löschen und Verwendungen", () => {
|
||
it("lässt eine Baustein-Version nicht löschen, auf die eine Vorlage zeigt", async () => {
|
||
const { adminId } = await grundbestand();
|
||
const { versionId: bausteinVersionId } = await bausteinMitSchritten(
|
||
"Benutzt",
|
||
"Benutzt",
|
||
["Eins"],
|
||
adminId,
|
||
);
|
||
await vorlageMitBaustein("Benutzt ihn", bausteinVersionId, adminId);
|
||
|
||
await expect(testPrisma.bausteinVersion.delete({ where: { id: bausteinVersionId } })).rejects.toThrow();
|
||
});
|
||
|
||
it("nennt, wo ein Baustein steckt – mit Vorlage, Version und Fassung", async () => {
|
||
const { adminId } = await grundbestand();
|
||
const { bausteinId, versionId: bausteinVersionId } = await bausteinMitSchritten(
|
||
"Überall",
|
||
"Überall",
|
||
["Eins"],
|
||
adminId,
|
||
);
|
||
await vorlageMitBaustein("Vorlage A", bausteinVersionId, adminId);
|
||
await vorlageMitBaustein("Vorlage B", bausteinVersionId, adminId);
|
||
|
||
const verwendungen = await bausteinVerwendungen(bausteinId);
|
||
expect(verwendungen).toHaveLength(2);
|
||
expect(verwendungen.map((eintrag) => eintrag.vorlageName)).toEqual(["Vorlage A", "Vorlage B"]);
|
||
expect(verwendungen[0]).toMatchObject({
|
||
vorlagenVersion: 1,
|
||
status: VersionStatus.VEROEFFENTLICHT,
|
||
bausteinVersion: 1,
|
||
});
|
||
});
|
||
|
||
it("zählt in der Liste Verwendungen und Schritte", async () => {
|
||
const { adminId } = await grundbestand();
|
||
const { versionId: bausteinVersionId } = await bausteinMitSchritten(
|
||
"Gezählt",
|
||
"Gezählt",
|
||
["Eins", "Zwei"],
|
||
adminId,
|
||
);
|
||
await vorlageMitBaustein("Benutzt ihn", bausteinVersionId, adminId);
|
||
|
||
const liste = await bausteinListe();
|
||
expect(liste).toHaveLength(1);
|
||
expect(liste[0]).toMatchObject({
|
||
name: "Gezählt",
|
||
veroeffentlichteVersion: 1,
|
||
hatEntwurf: false,
|
||
anzahlSchritte: 2,
|
||
verwendungen: 1,
|
||
});
|
||
});
|
||
|
||
it("bietet zum Einsetzen nur veröffentlichte Fassungen nicht archivierter Bausteine", async () => {
|
||
const { adminId } = await grundbestand();
|
||
await bausteinMitSchritten("Brauchbar", "Brauchbar", ["Eins"], adminId);
|
||
await bausteinAnlegen({ name: "Nur Entwurf" }, adminId);
|
||
const { bausteinId } = await bausteinMitSchritten("Weggelegt", "Weggelegt", ["Eins"], adminId);
|
||
await bausteinArchivieren(bausteinId, true, adminId);
|
||
|
||
const einsetzbar = await einsetzbareBausteine();
|
||
expect(einsetzbar.map((eintrag) => eintrag.name)).toEqual(["Brauchbar"]);
|
||
expect(einsetzbar[0]).toMatchObject({ version: 1, anzahlSchritte: 1, titel: "Brauchbar" });
|
||
});
|
||
});
|
||
|
||
describe("Austausch", () => {
|
||
it("exportiert die aufgelösten Schritte und keinen Verweis", async () => {
|
||
// Eine Kennung aus dieser Installation bedeutet in einer anderen nichts.
|
||
const { adminId } = await grundbestand();
|
||
const { versionId: bausteinVersionId } = await bausteinMitSchritten(
|
||
"Datensicherung prüfen",
|
||
"Datensicherung",
|
||
["Sicherung läuft"],
|
||
adminId,
|
||
);
|
||
const { versionId } = await vorlageMitBaustein("Zum Ausfuhren", bausteinVersionId, adminId);
|
||
|
||
const austausch = await vorlageExportieren(versionId);
|
||
expect(JSON.stringify(austausch)).not.toContain(bausteinVersionId);
|
||
const abschnitte = austausch.struktur.abschnitte.map((abschnitt) => ({
|
||
titel: abschnitt.titel,
|
||
schritte: abschnitt.schritte.map((schritt) => schritt.titel),
|
||
}));
|
||
expect(abschnitte).toEqual([
|
||
{ titel: "Eigener Abschnitt", schritte: ["Eigener Schritt"] },
|
||
{ titel: "Datensicherung", schritte: ["Sicherung läuft"] },
|
||
]);
|
||
});
|
||
|
||
it("übernimmt beim Import keinen mitgeschickten Verweis", async () => {
|
||
const { adminId } = await grundbestand();
|
||
const { versionId: bausteinVersionId } = await bausteinMitSchritten(
|
||
"Datensicherung prüfen",
|
||
"Datensicherung",
|
||
["Sicherung läuft"],
|
||
adminId,
|
||
);
|
||
const { versionId } = await vorlageMitBaustein("Quelle", bausteinVersionId, adminId);
|
||
const austausch = await vorlageExportieren(versionId);
|
||
|
||
const { versionId: kopie } = await vorlageImportieren(
|
||
{
|
||
...austausch,
|
||
name: "Kopie",
|
||
struktur: {
|
||
...austausch.struktur,
|
||
abschnitte: austausch.struktur.abschnitte.map((abschnitt) => ({
|
||
...abschnitt,
|
||
bausteinVersionId,
|
||
})),
|
||
},
|
||
},
|
||
adminId,
|
||
);
|
||
|
||
const abschnitte = await testPrisma.vorlagenAbschnitt.findMany({ where: { versionId: kopie } });
|
||
expect(abschnitte.every((abschnitt) => abschnitt.bausteinVersionId === null)).toBe(true);
|
||
// Die Schritte sind trotzdem alle da – sie stehen in der Datei.
|
||
expect(await schritteVon(kopie)).toEqual([
|
||
"# Eigener Abschnitt",
|
||
"Eigener Schritt",
|
||
"# Datensicherung",
|
||
"Sicherung läuft",
|
||
]);
|
||
});
|
||
});
|
||
|
||
it("wirft eigene Fehlerklassen, damit die Actions sie unterscheiden können", async () => {
|
||
const { adminId } = await grundbestand();
|
||
await expect(bausteinAnlegen({ name: " " }, adminId)).rejects.toThrow(BausteinFehler);
|
||
await expect(versionVeroeffentlichen("gibt-es-nicht", null, adminId)).rejects.toThrow(VorlagenFehler);
|
||
});
|
||
});
|