64 lines
2.3 KiB
TypeScript
64 lines
2.3 KiB
TypeScript
import { CatalogError, foundationErrors } from "@hivegrid/foundation";
|
|
import { beforeEach, describe, expect, it, vi } from "vitest";
|
|
|
|
const mocks = vi.hoisted(() => ({
|
|
loadChatContext: vi.fn(),
|
|
findMemberProjectChatLink: vi.fn(),
|
|
}));
|
|
|
|
vi.mock("../routes/chatAccess.server", () => ({
|
|
loadChatContext: mocks.loadChatContext,
|
|
}));
|
|
|
|
vi.mock("@hivegrid/chat/project-link.server", () => ({
|
|
findMemberProjectChatLink: mocks.findMemberProjectChatLink,
|
|
}));
|
|
|
|
import { loadOptionalProjectChatLink } from "./projectChatLink.server";
|
|
|
|
const request = new Request("https://app.example.test/demo/projects/project_1");
|
|
const params = { tenant: "demo", id: "project_1" };
|
|
const context = {
|
|
tenantId: "tenant_1",
|
|
userId: "user_1",
|
|
tenantUserId: "tenant_user_1",
|
|
permissions: ["chat.read_own_channels"],
|
|
hasModule: true as const,
|
|
};
|
|
|
|
describe("optional project chat link", () => {
|
|
beforeEach(() => {
|
|
vi.clearAllMocks();
|
|
mocks.loadChatContext.mockResolvedValue(context);
|
|
mocks.findMemberProjectChatLink.mockResolvedValue({ chatId: "chat_1", archivedAtIso: null, canWrite: true });
|
|
});
|
|
|
|
it("gates the repository lookup through the tenant chat context", async () => {
|
|
await expect(loadOptionalProjectChatLink({ request, params, projectId: "project_1" })).resolves.toEqual({
|
|
chatId: "chat_1",
|
|
archivedAtIso: null,
|
|
canWrite: true,
|
|
});
|
|
expect(mocks.loadChatContext).toHaveBeenCalledWith({ request, params });
|
|
expect(mocks.findMemberProjectChatLink).toHaveBeenCalledWith({
|
|
tenantId: "tenant_1",
|
|
userId: "user_1",
|
|
permissions: ["chat.read_own_channels"],
|
|
projectId: "project_1",
|
|
});
|
|
});
|
|
|
|
it("hides the affordance when the module, permission or membership is unavailable", async () => {
|
|
mocks.loadChatContext.mockRejectedValue(new CatalogError(foundationErrors.notFound));
|
|
|
|
await expect(loadOptionalProjectChatLink({ request, params, projectId: "project_1" })).resolves.toBeNull();
|
|
expect(mocks.findMemberProjectChatLink).not.toHaveBeenCalled();
|
|
});
|
|
|
|
it("does not swallow operational failures", async () => {
|
|
mocks.findMemberProjectChatLink.mockRejectedValue(new Error("database unavailable"));
|
|
|
|
await expect(loadOptionalProjectChatLink({ request, params, projectId: "project_1" })).rejects.toThrow("database unavailable");
|
|
});
|
|
});
|