You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

92 lines
3.3 KiB
TypeScript

// frontend/tests/settings/SettingsClient.test.tsx — 설정 탭 레일 + 전환
import { cleanup, render, screen, fireEvent } from "@testing-library/react";
import { afterEach, beforeEach, describe, expect, it, vi } from "vitest";
import { SettingsClient } from "@/components/settings/SettingsClient";
// 네트워크 무력화 — URL 별 적절한 형태의 ok 응답(섹션 헤더 렌더만 검증).
function bodyFor(url: string): unknown {
if (url.includes("/api/me/tokens")) return [];
if (url.includes("/api/connectors")) return [];
if (url.includes("/api/settings/system"))
return {
env: "dev",
auth_enabled: false,
worker_enabled: false,
database: "sqlite",
sync_interval_minutes: 15,
sync_page_size: 50,
web_search_provider: "mock",
connector_modes: { mail: "mock", calendar: "mock" },
};
if (url.includes("/api/settings/llm"))
return {
provider: "auto",
model: "llama3.1",
host: "http://localhost:11434",
timeout: 20,
provider_options: ["auto", "ollama", "heuristic"],
overridden: false,
embed_provider: "ollama",
embed_model: "nomic-embed-text",
agent_provider: "auto",
stt_provider: "auto",
vision_provider: "auto",
};
if (url.includes("/api/me"))
return { id: "jiwoo", name: "지우", initial: "지", email: "jiwoo@lumi.co", role: "member" };
return {};
}
beforeEach(() => {
vi.stubGlobal(
"fetch",
vi.fn(async (input: string) => ({
ok: true,
status: 200,
statusText: "OK",
json: async () => bodyFor(String(input)),
})),
);
localStorage.clear();
});
afterEach(() => {
cleanup();
vi.unstubAllGlobals();
});
describe("SettingsClient", () => {
it("제목과 6개 탭을 렌더한다", () => {
render(<SettingsClient />);
expect(screen.getByRole("heading", { level: 1, name: "설정" })).toBeInTheDocument();
// 탭 라벨은 버튼 접근명의 접두사 — ^ 앵커로 설명 텍스트 오매칭 방지.
["계정", "메일", "연결", "AI · LLM", "외관", "데이터 · 보안"].forEach((t) =>
expect(screen.getByRole("button", { name: new RegExp("^" + t) })).toBeInTheDocument(),
);
});
it("기본은 계정 탭(active + aria-current)", () => {
render(<SettingsClient />);
const account = screen.getByRole("button", { name: /^계정/ });
expect(account).toHaveClass("active");
expect(account).toHaveAttribute("aria-current", "page");
expect(screen.getByRole("heading", { level: 2, name: "계정" })).toBeInTheDocument();
});
it("탭 전환: 메일 → AI·LLM 섹션이 바뀐다", () => {
render(<SettingsClient />);
fireEvent.click(screen.getByRole("button", { name: /^메일/ }));
expect(screen.getByRole("heading", { level: 2, name: "메일 계정" })).toBeInTheDocument();
fireEvent.click(screen.getByRole("button", { name: /^AI · LLM/ }));
expect(screen.getByRole("heading", { level: 2, name: "AI · LLM 연결" })).toBeInTheDocument();
});
it("?tab= 쿼리로 초기 탭을 연다", () => {
window.history.pushState({}, "", "/settings?tab=data");
render(<SettingsClient />);
expect(screen.getByRole("heading", { level: 2, name: "데이터 · 보안" })).toBeInTheDocument();
window.history.pushState({}, "", "/settings");
});
});