import { describe, it, expect, vi, beforeEach } from "vitest"; import { render, screen } from "@testing-library/react"; import userEvent from "@testing-library/user-event"; import { WorkspaceMemberRole } from "@mosaic/shared"; import { MemberList } from "./MemberList"; import type { WorkspaceMemberWithUser } from "./MemberList"; const makeMember = ( overrides: Partial & { userId: string } ): WorkspaceMemberWithUser => ({ workspaceId: overrides.workspaceId ?? "ws-1", userId: overrides.userId, role: overrides.role ?? WorkspaceMemberRole.MEMBER, joinedAt: overrides.joinedAt ?? new Date("2025-01-01"), user: overrides.user ?? { id: overrides.userId, name: `User ${overrides.userId}`, email: `${overrides.userId}@example.com`, emailVerified: true, image: null, authProviderId: `auth-${overrides.userId}`, preferences: {}, deactivatedAt: null, isLocalAuth: false, passwordHash: null, invitedBy: null, invitationToken: null, invitedAt: null, createdAt: new Date("2025-01-01"), updatedAt: new Date("2025-01-01"), }, }); describe("MemberList", (): void => { const mockOnRoleChange = vi.fn<(userId: string, newRole: WorkspaceMemberRole) => Promise>(); const mockOnRemove = vi.fn<(userId: string) => Promise>(); const defaultProps = { currentUserId: "user-1", currentUserRole: WorkspaceMemberRole.ADMIN, workspaceOwnerId: "owner-1", onRoleChange: mockOnRoleChange, onRemove: mockOnRemove, }; beforeEach((): void => { mockOnRoleChange.mockReset(); mockOnRoleChange.mockResolvedValue(undefined); mockOnRemove.mockReset(); mockOnRemove.mockResolvedValue(undefined); }); it("should render member list with correct count", (): void => { const members = [makeMember({ userId: "user-1" }), makeMember({ userId: "user-2" })]; render(); expect(screen.getByText("Members (2)")).toBeInTheDocument(); }); it("should display member name and email", (): void => { const members = [ makeMember({ userId: "user-2", user: { id: "user-2", name: "Jane Doe", email: "jane@example.com", emailVerified: true, image: null, authProviderId: "auth-2", preferences: {}, deactivatedAt: null, isLocalAuth: false, passwordHash: null, invitedBy: null, invitationToken: null, invitedAt: null, createdAt: new Date("2025-01-01"), updatedAt: new Date("2025-01-01"), }, }), ]; render(); expect(screen.getByText("Jane Doe")).toBeInTheDocument(); expect(screen.getByText("jane@example.com")).toBeInTheDocument(); }); it("should show (you) indicator for current user", (): void => { const members = [makeMember({ userId: "user-1" })]; render(); expect(screen.getByText("(you)")).toBeInTheDocument(); }); it("should call onRoleChange with validated role when admin changes a member role", async (): Promise => { const user = userEvent.setup(); const members = [ makeMember({ userId: "user-1" }), makeMember({ userId: "user-2", role: WorkspaceMemberRole.MEMBER }), ]; render(); const roleSelect = screen.getByDisplayValue("Member"); await user.selectOptions(roleSelect, WorkspaceMemberRole.GUEST); expect(mockOnRoleChange).toHaveBeenCalledWith("user-2", WorkspaceMemberRole.GUEST); }); it("should not show role select for the workspace owner", (): void => { const members = [ makeMember({ userId: "owner-1", role: WorkspaceMemberRole.OWNER }), makeMember({ userId: "user-1", role: WorkspaceMemberRole.ADMIN }), ]; render(); expect(screen.getByText("OWNER")).toBeInTheDocument(); }); it("should not show remove button for the workspace owner", (): void => { const members = [makeMember({ userId: "owner-1", role: WorkspaceMemberRole.OWNER })]; render(); expect(screen.queryByLabelText("Remove member")).not.toBeInTheDocument(); }); });