1
0
forked from baron/baron-sso

chore: consolidate local integration changes

This commit is contained in:
2026-06-09 21:03:05 +09:00
parent aa2848c3b6
commit 1341f07ef9
158 changed files with 10995 additions and 1490 deletions

View File

@@ -0,0 +1,148 @@
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { fireEvent, render, screen, waitFor } from "@testing-library/react";
import { MemoryRouter, Route, Routes } from "react-router-dom";
import { beforeEach, describe, expect, it, vi } from "vitest";
import { createI18nMock } from "../../../test/i18nMock";
import TenantUsersPage from "./TenantUsersPage";
const exportUsersCSVMock = vi.hoisted(() => vi.fn());
const updateUserMock = vi.hoisted(() => vi.fn());
const fetchUsersMock = vi.hoisted(() => vi.fn());
vi.mock("../../../lib/i18n", () => createI18nMock());
vi.mock("../../../lib/adminApi", () => ({
fetchTenant: vi.fn(async () => ({
id: "tenant-team-id",
name: "기술기획팀",
slug: "tech-planning",
})),
fetchUsers: fetchUsersMock,
exportUsersCSV: exportUsersCSVMock,
updateUser: updateUserMock,
}));
function renderTenantUsersPage() {
const queryClient = new QueryClient({
defaultOptions: { queries: { retry: false } },
});
return render(
<QueryClientProvider client={queryClient}>
<MemoryRouter initialEntries={["/tenants/tenant-team-id/users"]}>
<Routes>
<Route
path="/tenants/:tenantId/users"
element={<TenantUsersPage />}
/>
</Routes>
</MemoryRouter>
</QueryClientProvider>,
);
}
describe("TenantUsersPage export", () => {
beforeEach(() => {
exportUsersCSVMock.mockReset();
updateUserMock.mockReset();
fetchUsersMock.mockReset();
fetchUsersMock.mockResolvedValue({
items: [
{
id: "user-1",
name: "Alice",
email: "alice@example.com",
role: "user",
status: "active",
},
],
total: 1,
});
exportUsersCSVMock.mockResolvedValue({
blob: new Blob(["email,name\nalice@example.com,Alice\n"], {
type: "text/csv",
}),
filename: "users_export_20260609.csv",
});
vi.spyOn(window.URL, "createObjectURL").mockReturnValue(
"blob:tenant-users-export",
);
vi.spyOn(window.URL, "revokeObjectURL").mockImplementation(() => {});
});
it("exports only the currently opened tenant users by tenant slug", async () => {
renderTenantUsersPage();
await screen.findByText("Alice");
fireEvent.click(screen.getByTestId("tenant-users-export-menu-item"));
await waitFor(() => {
expect(exportUsersCSVMock).toHaveBeenCalledWith(
"",
"tech-planning",
false,
);
});
});
it("queues searched users and adds all queued users to the tenant at once", async () => {
fetchUsersMock
.mockResolvedValueOnce({ items: [], total: 0 })
.mockResolvedValueOnce({
items: [
{
id: "user-2",
name: "Bob",
email: "bob@example.com",
role: "user",
status: "active",
},
{
id: "user-3",
name: "Carol",
email: "carol@example.com",
role: "user",
status: "active",
},
],
total: 2,
})
.mockResolvedValue({ items: [], total: 0 });
updateUserMock.mockResolvedValue({});
renderTenantUsersPage();
const addButton = await screen.findByTestId(
"tenant-member-add-existing-btn",
);
await waitFor(() => expect(addButton).not.toBeDisabled());
fireEvent.click(addButton);
fireEvent.change(screen.getByTestId("tenant-member-search-input"), {
target: { value: "bo" },
});
fireEvent.click(await screen.findByText("Bob"));
fireEvent.click(await screen.findByText("Carol"));
expect(screen.getByTestId("tenant-member-add-queue")).toHaveTextContent(
"Bob",
);
expect(screen.getByTestId("tenant-member-add-queue")).toHaveTextContent(
"Carol",
);
fireEvent.click(screen.getByTestId("tenant-member-add-submit-btn"));
await waitFor(() => {
expect(updateUserMock).toHaveBeenCalledWith("user-2", {
tenantSlug: "tech-planning",
isAddTenant: true,
});
expect(updateUserMock).toHaveBeenCalledWith("user-3", {
tenantSlug: "tech-planning",
isAddTenant: true,
});
});
});
});