Co-authored-by: Jason Woltje <jason@diversecanvas.com> Co-committed-by: Jason Woltje <jason@diversecanvas.com>
122 lines
4.3 KiB
TypeScript
122 lines
4.3 KiB
TypeScript
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<WorkspaceMemberWithUser> & { 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<void>>();
|
|
const mockOnRemove = vi.fn<(userId: string) => Promise<void>>();
|
|
|
|
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(<MemberList {...defaultProps} members={members} />);
|
|
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(<MemberList {...defaultProps} members={members} />);
|
|
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(<MemberList {...defaultProps} members={members} />);
|
|
expect(screen.getByText("(you)")).toBeInTheDocument();
|
|
});
|
|
|
|
it("should call onRoleChange with validated role when admin changes a member role", async (): Promise<void> => {
|
|
const user = userEvent.setup();
|
|
const members = [
|
|
makeMember({ userId: "user-1" }),
|
|
makeMember({ userId: "user-2", role: WorkspaceMemberRole.MEMBER }),
|
|
];
|
|
render(<MemberList {...defaultProps} members={members} />);
|
|
|
|
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(<MemberList {...defaultProps} members={members} />);
|
|
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(<MemberList {...defaultProps} members={members} />);
|
|
expect(screen.queryByLabelText("Remove member")).not.toBeInTheDocument();
|
|
});
|
|
});
|