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
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");
|
|
});
|
|
});
|