Files
HiveGrid-Wireframes/03 Quellen und Referenzen/hivegrid-cloud/apps/web/app/modules/emailInbox/services/emailActivityMasking.server.test.ts
T
2026-07-08 16:15:37 +02:00

79 lines
3.5 KiB
TypeScript

import { describe, expect, it, vi } from "vitest";
const findMany = vi.fn();
vi.mock("~/utils/db.server", () => ({
db: { emailIntegrationMailbox: { findMany: (...args: unknown[]) => findMany(...args) } },
}));
import { maskEmailActivitiesForViewer, shouldMaskEmailActivity } from "./emailActivityMasking.server";
// VA-P23 — DoD 6: email.read_own vs read_all must filter the Activity-Stream,
// not just the inbox list. Foreign email activities collapse to the Klartext
// placeholder without subject/snippet details.
const OWN = new Set(["mb-own"]);
describe("shouldMaskEmailActivity (pure)", () => {
it("never masks non-email activities", () => {
expect(shouldMaskEmailActivity({ activityType: "note_added", summaryText: "x" }, { canReadAll: false, canReadOwn: false, ownMailboxIds: OWN })).toBe(false);
});
it("read_all sees everything", () => {
expect(
shouldMaskEmailActivity({ activityType: "email_received", summaryText: "x", metadata: { mailboxId: "mb-foreign" } }, { canReadAll: true, canReadOwn: true, ownMailboxIds: OWN }),
).toBe(false);
});
it("read_own sees own-mailbox activities but not foreign ones", () => {
const viewer = { canReadAll: false, canReadOwn: true, ownMailboxIds: OWN };
expect(shouldMaskEmailActivity({ activityType: "email_received", summaryText: "x", metadata: { mailboxId: "mb-own" } }, viewer)).toBe(false);
expect(shouldMaskEmailActivity({ activityType: "email_sent", summaryText: "x", metadata: { mailboxId: "mb-foreign" } }, viewer)).toBe(true);
});
it("masks conservatively when the mailbox reference is missing", () => {
expect(shouldMaskEmailActivity({ activityType: "email_received", summaryText: "x" }, { canReadAll: false, canReadOwn: true, ownMailboxIds: OWN })).toBe(true);
});
it("no email permission at all masks every email activity", () => {
expect(
shouldMaskEmailActivity({ activityType: "email_received", summaryText: "x", metadata: { mailboxId: "mb-own" } }, { canReadAll: false, canReadOwn: false, ownMailboxIds: new Set() }),
).toBe(true);
});
});
describe("maskEmailActivitiesForViewer", () => {
it("replaces masked rows with the Klartext placeholder and drops metadata", async () => {
findMany.mockResolvedValue([{ id: "mb-own" }]);
const rows = [
{ activityType: "email_received", summaryText: "Eingehende E-Mail: geheim", metadata: { mailboxId: "mb-foreign", snippet: "geheim" } },
{ activityType: "email_sent", summaryText: "Eigene Mail", metadata: { mailboxId: "mb-own" } },
{ activityType: "note_added", summaryText: "Notiz" },
];
const masked = await maskEmailActivitiesForViewer({
tenantId: "t1",
userId: "u1",
permissions: ["email.read_own", "email.write"],
rows,
maskedText: "E-Mail-Aktivität (nicht einsehbar)",
});
expect(masked[0].summaryText).toBe("E-Mail-Aktivität (nicht einsehbar)");
expect(masked[0].metadata).toBeUndefined();
expect(masked[1].summaryText).toBe("Eigene Mail");
expect(masked[2].summaryText).toBe("Notiz");
});
it("short-circuits without a DB query for read_all viewers", async () => {
findMany.mockClear();
const rows = [{ activityType: "email_received", summaryText: "x", metadata: { mailboxId: "mb-foreign" } }];
const result = await maskEmailActivitiesForViewer({
tenantId: "t1",
userId: "u1",
permissions: ["email.read_all"],
rows,
maskedText: "masked",
});
expect(result[0].summaryText).toBe("x");
expect(findMany).not.toHaveBeenCalled();
});
});