Kuma/tests/marketing/graph.test.ts
2026-10-02 17:31:08 +02:00

122 lines
3.7 KiB
TypeScript

import { describe, it, expect } from "vitest";
import {
diffGraph,
normalizeGraph,
validateGraph,
type GraphNode,
} from "@/src/modules/marketing/lib/graph";
import { EMAIL_TEMPLATES } from "@/src/modules/marketing/lib/node-config";
const ids = {
birthday: "11111111-1111-4111-8111-111111111111",
milestone: "22222222-2222-4222-8222-222222222222",
mail: "33333333-3333-4333-8333-333333333333",
mail2: "44444444-4444-4444-8444-444444444444",
};
const mail = (
id = ids.mail,
config: Record<string, unknown> = { ...EMAIL_TEMPLATES.birthday }
): GraphNode => ({
id,
kind: "email",
config,
position: { x: 300, y: 0 },
emailNodeId: null,
isActive: false,
});
const birthday = (overrides: Partial<GraphNode> = {}): GraphNode => ({
id: ids.birthday,
kind: "birthday",
config: {},
position: { x: 0, y: 0 },
emailNodeId: ids.mail,
isActive: true,
...overrides,
});
describe("validateGraph", () => {
it("akzeptiert einen verbundenen Trigger mit gültiger E-Mail", () => {
expect(validateGraph([birthday(), mail()])).toBeNull();
});
it("erlaubt Geburtstag nur einmal", () => {
const second = birthday({ id: ids.milestone });
expect(validateGraph([birthday(), second, mail()])?.message).toMatch(/nur einmal/);
});
it("lehnt Verbindungen zu fehlenden E-Mails ab", () => {
expect(validateGraph([birthday({ emailNodeId: ids.mail2 }), mail()])?.message).toMatch(
/nicht gefunden/
);
});
it("prüft die Werte der Trigger", () => {
const milestone: GraphNode = {
...birthday({ id: ids.milestone }),
kind: "milestone",
config: { bookings: 0 },
};
expect(validateGraph([milestone, mail()])?.nodeId).toBe(ids.milestone);
});
it("verlangt einen Rabatt für {code}", () => {
const invalid = mail(ids.mail, {
...EMAIL_TEMPLATES.birthday,
reward: null,
body: "Ihr Code: {code}",
});
expect(validateGraph([invalid])?.message).toMatch(/\{code\}/);
});
it("lehnt Bausteine ohne gültige ID ab", () => {
expect(validateGraph([mail("abc")])?.message).toMatch(/Ungültig/);
});
});
describe("diffGraph", () => {
it("protokolliert Anlegen, Verbinden und Einschalten", () => {
const actions = diffGraph([], [birthday(), mail()]).map((c) => c.action);
expect(actions).toEqual(
expect.arrayContaining(["node.created", "trigger.connected", "trigger.activated"])
);
});
it("ignoriert reines Verschieben", () => {
const before = [birthday(), mail()];
const after = [birthday({ position: { x: 99, y: 99 } }), mail()];
expect(diffGraph(before, after)).toEqual([]);
});
it("nennt geänderte Felder einer E-Mail", () => {
const before = [mail()];
const after = [mail(ids.mail, { ...EMAIL_TEMPLATES.birthday, subject: "Neu" })];
const [change] = diffGraph(before, after);
expect(change.action).toBe("node.updated");
expect(change.summary).toContain("Betreff");
});
it("protokolliert Ausschalten und Löschen", () => {
const before = [birthday(), mail(), mail(ids.mail2)];
const after = [birthday({ isActive: false }), mail()];
const actions = diffGraph(before, after).map((c) => c.action);
expect(actions).toEqual(expect.arrayContaining(["node.deleted", "trigger.deactivated"]));
});
});
describe("normalizeGraph", () => {
it("speichert nur geprüfte Werte", () => {
const [trigger, email] = normalizeGraph([
birthday({ config: { fremd: "x" } }),
{
...mail(ids.mail, { ...EMAIL_TEMPLATES.birthday, subject: " Hallo ", extra: 1 }),
isActive: true,
},
]);
expect(trigger.config).toEqual({});
expect(email.config).not.toHaveProperty("extra");
expect(email.config.subject).toBe("Hallo");
expect(email.isActive).toBe(false);
});
});