import type { UserWorkspace, WorkspaceMemberEntry } from "@/lib/api/workspaces"; import type { ReactElement, ReactNode } from "react"; import { WorkspaceMemberRole } from "@mosaic/shared"; import { render, screen, waitFor } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { beforeEach, describe, expect, it, vi } from "vitest"; import { createWorkspace, fetchUserWorkspaces, fetchWorkspaceMembers } from "@/lib/api/workspaces"; import WorkspacesPage from "./page"; vi.mock("next/link", () => ({ default: function LinkMock({ children, href, }: { children: ReactNode; href: string; }): ReactElement { return {children}; }, })); vi.mock("@/lib/api/workspaces", () => ({ fetchUserWorkspaces: vi.fn(), createWorkspace: vi.fn(), fetchWorkspaceMembers: vi.fn(), addWorkspaceMember: vi.fn(), removeWorkspaceMember: vi.fn(), })); vi.mock("@/lib/api/admin", () => ({ fetchAdminUsers: vi.fn(), })); const fetchUserWorkspacesMock = vi.mocked(fetchUserWorkspaces); const createWorkspaceMock = vi.mocked(createWorkspace); const fetchWorkspaceMembersMock = vi.mocked(fetchWorkspaceMembers); const workspaceA: UserWorkspace = { id: "workspace-1", name: "Personal Workspace", ownerId: "owner-1", role: WorkspaceMemberRole.OWNER, createdAt: "2026-01-01T00:00:00.000Z", }; const workspaceB: UserWorkspace = { id: "workspace-2", name: "Client Workspace", ownerId: "owner-2", role: WorkspaceMemberRole.ADMIN, createdAt: "2026-01-02T00:00:00.000Z", }; const membersA: WorkspaceMemberEntry[] = [ { workspaceId: "workspace-1", userId: "user-a", role: WorkspaceMemberRole.OWNER, joinedAt: "2026-01-03T00:00:00.000Z", user: { id: "user-a", email: "alice@example.com", name: "Alice", image: null, }, }, ]; const membersB: WorkspaceMemberEntry[] = [ { workspaceId: "workspace-2", userId: "user-b", role: WorkspaceMemberRole.MEMBER, joinedAt: "2026-01-04T00:00:00.000Z", user: { id: "user-b", email: "bob@example.com", name: "Bob", image: null, }, }, ]; describe("WorkspacesPage", () => { beforeEach(() => { vi.clearAllMocks(); }); it("loads workspaces and fetches members for the first workspace", async () => { fetchUserWorkspacesMock.mockResolvedValue([workspaceA, workspaceB]); fetchWorkspaceMembersMock.mockResolvedValue(membersA); render(); expect(await screen.findByText("Your Workspaces (2)")).toBeInTheDocument(); expect(await screen.findByText("Personal Workspace Members")).toBeInTheDocument(); await waitFor(() => { expect(fetchWorkspaceMembersMock).toHaveBeenCalledWith("workspace-1"); }); expect(screen.getByText("alice@example.com")).toBeInTheDocument(); }); it("switches selected workspace and reloads member list", async () => { fetchUserWorkspacesMock.mockResolvedValue([workspaceA, workspaceB]); fetchWorkspaceMembersMock.mockResolvedValueOnce(membersA).mockResolvedValueOnce(membersB); const user = userEvent.setup(); render(); expect(await screen.findByText("Personal Workspace Members")).toBeInTheDocument(); await user.click(screen.getByRole("button", { name: /client workspace/i })); await waitFor(() => { expect(fetchWorkspaceMembersMock).toHaveBeenLastCalledWith("workspace-2"); }); expect(await screen.findByText("Client Workspace Members")).toBeInTheDocument(); expect(screen.getByText("bob@example.com")).toBeInTheDocument(); }); it("creates a workspace and refreshes the list", async () => { fetchUserWorkspacesMock .mockResolvedValueOnce([workspaceA]) .mockResolvedValueOnce([workspaceA, workspaceB]); fetchWorkspaceMembersMock.mockResolvedValue(membersA); createWorkspaceMock.mockResolvedValue({ id: "workspace-2", name: "Client Workspace", ownerId: "owner-2", settings: {}, createdAt: "2026-01-02T00:00:00.000Z", updatedAt: "2026-01-02T00:00:00.000Z", memberCount: 1, }); const user = userEvent.setup(); render(); expect(await screen.findByText("Your Workspaces (1)")).toBeInTheDocument(); await user.type(screen.getByPlaceholderText("Enter workspace name..."), "Client Workspace"); await user.click(screen.getByRole("button", { name: "Create Workspace" })); await waitFor(() => { expect(createWorkspaceMock).toHaveBeenCalledWith({ name: "Client Workspace" }); }); await waitFor(() => { expect(fetchUserWorkspacesMock).toHaveBeenCalledTimes(2); }); expect(await screen.findByText("Your Workspaces (2)")).toBeInTheDocument(); }); });