1
0
forked from baron/baron-sso
Files
baron-sso/adminfront/src/features/tenants/hooks/useTenantPermission.test.tsx

185 lines
4.8 KiB
TypeScript

import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { render, renderHook, screen, waitFor } from "@testing-library/react";
import type React from "react";
import { describe, expect, it, vi } from "vitest";
import {
fetchMe,
fetchTenant,
type TenantSummary,
type UserProfileResponse,
} from "../../../lib/adminApi";
import { TenantPermissionGuard } from "../components/TenantPermissionGuard";
import { useTenantPermission } from "./useTenantPermission";
vi.mock("../../../lib/adminApi", () => ({
fetchMe: vi.fn(),
fetchTenant: vi.fn(),
}));
function createWrapper() {
const queryClient = new QueryClient({
defaultOptions: {
queries: { retry: false },
},
});
return ({ children }: { children: React.ReactNode }) => (
<QueryClientProvider client={queryClient}>{children}</QueryClientProvider>
);
}
function mockProfile(
overrides: Partial<UserProfileResponse>,
): UserProfileResponse {
return {
id: "user-id",
email: "user@example.com",
name: "Test User",
phone: "",
role: "user",
department: "",
affiliationType: "general",
...overrides,
};
}
function mockTenant(overrides: Partial<TenantSummary>): TenantSummary {
return {
id: "tenant-id",
type: "COMPANY",
name: "Test Tenant",
slug: "test-tenant",
description: "",
status: "active",
memberCount: 0,
createdAt: "2026-01-01T00:00:00Z",
updatedAt: "2026-01-01T00:00:00Z",
...overrides,
};
}
describe("useTenantPermission", () => {
it("returns true for all permissions if user is super_admin", async () => {
vi.mocked(fetchMe).mockResolvedValue(
mockProfile({
id: "user-super",
role: "super_admin",
}),
);
vi.mocked(fetchTenant).mockResolvedValue(
mockTenant({
id: "tenant-1",
name: "Super Tenant",
userPermissions: { view: false, manage: false, manage_admins: false },
}),
);
const { result } = renderHook(() => useTenantPermission("tenant-1"), {
wrapper: createWrapper(),
});
await waitFor(() => {
expect(result.current.isLoading).toBe(false);
});
expect(result.current.hasPermission("view")).toBe(true);
expect(result.current.hasPermission("manage")).toBe(true);
expect(result.current.hasPermission("manage_admins")).toBe(true);
});
it("returns permissions mapped from userPermissions for normal admins/users", async () => {
vi.mocked(fetchMe).mockResolvedValue(
mockProfile({
id: "user-admin",
role: "tenant_admin",
}),
);
vi.mocked(fetchTenant).mockResolvedValue(
mockTenant({
id: "tenant-2",
name: "Tenant Admin Corp",
userPermissions: { view: true, manage: true, manage_admins: false },
}),
);
const { result } = renderHook(() => useTenantPermission("tenant-2"), {
wrapper: createWrapper(),
});
await waitFor(() => {
expect(result.current.isLoading).toBe(false);
});
expect(result.current.hasPermission("view")).toBe(true);
expect(result.current.hasPermission("manage")).toBe(true);
expect(result.current.hasPermission("manage_admins")).toBe(false);
});
});
describe("TenantPermissionGuard", () => {
it("renders children when user has permission", async () => {
vi.mocked(fetchMe).mockResolvedValue(
mockProfile({
id: "user-admin",
role: "tenant_admin",
}),
);
vi.mocked(fetchTenant).mockResolvedValue(
mockTenant({
id: "tenant-3",
userPermissions: { view: true, manage: true, manage_admins: false },
}),
);
render(
<TenantPermissionGuard
tenantId="tenant-3"
relation="manage"
fallback={<div>Access Denied</div>}
>
<div>Access Granted</div>
</TenantPermissionGuard>,
{ wrapper: createWrapper() },
);
await waitFor(() => {
expect(screen.getByText("Access Granted")).toBeInTheDocument();
});
expect(screen.queryByText("Access Denied")).not.toBeInTheDocument();
});
it("renders fallback when user lacks permission", async () => {
vi.mocked(fetchMe).mockResolvedValue(
mockProfile({
id: "user-admin",
role: "tenant_admin",
}),
);
vi.mocked(fetchTenant).mockResolvedValue(
mockTenant({
id: "tenant-4",
userPermissions: { view: true, manage: false, manage_admins: false },
}),
);
render(
<TenantPermissionGuard
tenantId="tenant-4"
relation="manage"
fallback={<div>Access Denied</div>}
>
<div>Access Granted</div>
</TenantPermissionGuard>,
{ wrapper: createWrapper() },
);
await waitFor(() => {
expect(screen.getByText("Access Denied")).toBeInTheDocument();
});
expect(screen.queryByText("Access Granted")).not.toBeInTheDocument();
});
});