/** * Unit tests for the Object Visibility Membrane. * * Run: bun test shared/membrane.test.ts */ import { describe, expect, it } from "bun:test"; import { isVisibleTo, filterByVisibility, filterArrayByVisibility, DEFAULT_VISIBILITY, type ObjectVisibility, } from "./membrane"; // ── isVisibleTo ── describe("isVisibleTo", () => { it("treats undefined/null as viewer (open default)", () => { expect(isVisibleTo(undefined, "viewer")).toBe(true); expect(isVisibleTo(null, "viewer")).toBe(true); expect(isVisibleTo(undefined, "member")).toBe(true); expect(isVisibleTo(null, "admin")).toBe(true); }); it("viewer visibility is visible to all roles", () => { expect(isVisibleTo("viewer", "viewer")).toBe(true); expect(isVisibleTo("viewer", "member")).toBe(true); expect(isVisibleTo("viewer", "moderator")).toBe(true); expect(isVisibleTo("viewer", "admin")).toBe(true); }); it("member visibility is hidden from viewers", () => { expect(isVisibleTo("member", "viewer")).toBe(false); expect(isVisibleTo("member", "member")).toBe(true); expect(isVisibleTo("member", "moderator")).toBe(true); expect(isVisibleTo("member", "admin")).toBe(true); }); it("moderator visibility is hidden from viewers and members", () => { expect(isVisibleTo("moderator", "viewer")).toBe(false); expect(isVisibleTo("moderator", "member")).toBe(false); expect(isVisibleTo("moderator", "moderator")).toBe(true); expect(isVisibleTo("moderator", "admin")).toBe(true); }); it("admin visibility is only visible to admins", () => { expect(isVisibleTo("admin", "viewer")).toBe(false); expect(isVisibleTo("admin", "member")).toBe(false); expect(isVisibleTo("admin", "moderator")).toBe(false); expect(isVisibleTo("admin", "admin")).toBe(true); }); it("unknown roles default to level 0", () => { expect(isVisibleTo("viewer", "unknown")).toBe(true); // level 0 >= 0 expect(isVisibleTo("member", "unknown")).toBe(false); // level 0 < 1 }); }); // ── filterByVisibility ── describe("filterByVisibility", () => { const items: Record = { a: { id: "a" }, // undefined → viewer b: { id: "b", visibility: "viewer" }, c: { id: "c", visibility: "member" }, d: { id: "d", visibility: "moderator" }, e: { id: "e", visibility: "admin" }, }; it("viewer sees only viewer-level items", () => { const result = filterByVisibility(items, "viewer"); expect(Object.keys(result).sort()).toEqual(["a", "b"]); }); it("member sees viewer + member items", () => { const result = filterByVisibility(items, "member"); expect(Object.keys(result).sort()).toEqual(["a", "b", "c"]); }); it("moderator sees viewer + member + moderator items", () => { const result = filterByVisibility(items, "moderator"); expect(Object.keys(result).sort()).toEqual(["a", "b", "c", "d"]); }); it("admin sees all items", () => { const result = filterByVisibility(items, "admin"); expect(Object.keys(result).sort()).toEqual(["a", "b", "c", "d", "e"]); }); it("handles empty record", () => { const result = filterByVisibility({}, "admin"); expect(Object.keys(result)).toEqual([]); }); it("supports custom getVis accessor", () => { const calEvents: Record = { x: { id: "x", accessVisibility: "admin" }, y: { id: "y" }, }; const result = filterByVisibility(calEvents, "viewer", (e) => e.accessVisibility as ObjectVisibility | undefined); expect(Object.keys(result)).toEqual(["y"]); }); }); // ── filterArrayByVisibility ── describe("filterArrayByVisibility", () => { const items = [ { id: "1", visibility: undefined as ObjectVisibility | undefined }, { id: "2", visibility: "viewer" as ObjectVisibility }, { id: "3", visibility: "member" as ObjectVisibility }, { id: "4", visibility: "admin" as ObjectVisibility }, ]; it("filters array correctly for viewer", () => { const result = filterArrayByVisibility(items, "viewer"); expect(result.map((r) => r.id)).toEqual(["1", "2"]); }); it("filters array correctly for member", () => { const result = filterArrayByVisibility(items, "member"); expect(result.map((r) => r.id)).toEqual(["1", "2", "3"]); }); it("admin sees all", () => { const result = filterArrayByVisibility(items, "admin"); expect(result.map((r) => r.id)).toEqual(["1", "2", "3", "4"]); }); it("handles empty array", () => { const result = filterArrayByVisibility([], "admin"); expect(result).toEqual([]); }); it("supports custom accessor for non-standard field names", () => { const events = [ { id: "e1", accessVisibility: "moderator" as ObjectVisibility }, { id: "e2" }, ]; const result = filterArrayByVisibility(events, "viewer", (e) => (e as any).accessVisibility); expect(result.map((r) => r.id)).toEqual(["e2"]); }); }); // ── DEFAULT_VISIBILITY ── describe("DEFAULT_VISIBILITY", () => { it("is viewer", () => { expect(DEFAULT_VISIBILITY).toBe("viewer"); }); });