1
0
forked from baron/baron-sso

custom claim 권한체크 확인

This commit is contained in:
2026-06-11 08:29:25 +09:00
parent 839ca9d407
commit 4d77060b5d
79 changed files with 4268 additions and 670 deletions

View File

@@ -7,6 +7,7 @@ import TenantUsersPage from "./TenantUsersPage";
const exportUsersCSVMock = vi.hoisted(() => vi.fn());
const updateUserMock = vi.hoisted(() => vi.fn());
const bulkUpdateUsersMock = vi.hoisted(() => vi.fn());
const fetchUsersMock = vi.hoisted(() => vi.fn());
vi.mock("../../../lib/i18n", () => createI18nMock());
@@ -18,6 +19,7 @@ vi.mock("../../../lib/adminApi", () => ({
slug: "tech-planning",
})),
fetchUsers: fetchUsersMock,
bulkUpdateUsers: bulkUpdateUsersMock,
exportUsersCSV: exportUsersCSVMock,
updateUser: updateUserMock,
}));
@@ -26,8 +28,7 @@ function renderTenantUsersPage() {
const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false } },
});
return render(
const result = render(
<QueryClientProvider client={queryClient}>
<MemoryRouter initialEntries={["/tenants/tenant-team-id/users"]}>
<Routes>
@@ -39,12 +40,15 @@ function renderTenantUsersPage() {
</MemoryRouter>
</QueryClientProvider>,
);
return { ...result, queryClient };
}
describe("TenantUsersPage export", () => {
beforeEach(() => {
exportUsersCSVMock.mockReset();
updateUserMock.mockReset();
bulkUpdateUsersMock.mockReset();
fetchUsersMock.mockReset();
fetchUsersMock.mockResolvedValue({
items: [
@@ -64,10 +68,12 @@ describe("TenantUsersPage export", () => {
}),
filename: "users_export_20260609.csv",
});
updateUserMock.mockResolvedValue({});
vi.spyOn(window.URL, "createObjectURL").mockReturnValue(
"blob:tenant-users-export",
);
vi.spyOn(window.URL, "revokeObjectURL").mockImplementation(() => {});
bulkUpdateUsersMock.mockResolvedValue({ results: [] });
});
it("exports only the currently opened tenant users by tenant slug", async () => {
@@ -135,14 +141,121 @@ describe("TenantUsersPage export", () => {
fireEvent.click(screen.getByTestId("tenant-member-add-submit-btn"));
await waitFor(() => {
expect(updateUserMock).toHaveBeenCalledWith("user-2", {
expect(bulkUpdateUsersMock).toHaveBeenCalledWith({
userIds: ["user-2", "user-3"],
tenantSlug: "tech-planning",
isAddTenant: true,
});
expect(updateUserMock).toHaveBeenCalledWith("user-3", {
});
expect(updateUserMock).not.toHaveBeenCalledWith(
expect.any(String),
expect.objectContaining({ isAddTenant: true }),
);
});
it("queues orgfront multi picker users and adds them with one bulk request", async () => {
fetchUsersMock
.mockResolvedValueOnce({
items: [
{
id: "existing-user",
name: "Existing",
email: "existing@example.com",
role: "user",
status: "active",
},
],
total: 1,
})
.mockResolvedValue({ items: [], total: 0 });
renderTenantUsersPage();
const addButton = await screen.findByTestId(
"tenant-member-add-existing-btn",
);
await waitFor(() => expect(addButton).not.toBeDisabled());
fireEvent.click(addButton);
const picker = await screen.findByTitle("조직도에서 구성원 선택");
expect(decodeURIComponent(picker.getAttribute("src") ?? "")).toContain(
"/embed/picker?mode=multiple&select=user",
);
fireEvent(
window,
new MessageEvent("message", {
data: {
type: "orgfront:picker:confirm",
payload: {
mode: "multiple",
selections: [
{ type: "tenant", id: "team-1", name: "플랫폼팀" },
{
type: "user",
id: "picked-user-1",
name: "Picked One",
email: "picked1@example.com",
},
{
type: "user",
id: "picked-user-2",
name: "Picked Two",
},
{
type: "user",
id: "existing-user",
name: "Existing",
email: "existing@example.com",
},
],
},
},
}),
);
expect(screen.getByTestId("tenant-member-add-queue")).toHaveTextContent(
"Picked One",
);
expect(screen.getByTestId("tenant-member-add-queue")).toHaveTextContent(
"Picked Two",
);
expect(screen.getByTestId("tenant-member-add-queue")).not.toHaveTextContent(
"Existing",
);
fireEvent.click(screen.getByTestId("tenant-member-add-submit-btn"));
await waitFor(() => {
expect(bulkUpdateUsersMock).toHaveBeenCalledWith({
userIds: ["picked-user-1", "picked-user-2"],
tenantSlug: "tech-planning",
isAddTenant: true,
});
});
});
it("removes a member from the tenant and invalidates the user detail cache", async () => {
const confirmSpy = vi.spyOn(window, "confirm").mockReturnValue(true);
const { queryClient } = renderTenantUsersPage();
queryClient.setQueryData(["user", "user-1"], {
id: "user-1",
name: "Alice",
});
await screen.findByText("Alice");
fireEvent.click(screen.getByTestId("tenant-member-remove-user-1"));
await waitFor(() => {
expect(updateUserMock).toHaveBeenCalledWith("user-1", {
tenantSlug: "tech-planning",
isRemoveTenant: true,
});
});
expect(queryClient.getQueryState(["user", "user-1"])?.isInvalidated).toBe(
true,
);
confirmSpy.mockRestore();
});
});