import { fireEvent, render, screen, within } from "@testing-library/react" import { beforeEach, describe, expect, it, vi } from "vitest" import { HomePage } from "./home-page" const useHomeOverview = vi.fn() vi.mock("@/features/home/api/home.query", () => ({ useHomeOverview: () => useHomeOverview(), })) const overview = { status: "partial_success" as const, stock_pool_count: 3, latest_update: { trade_date: "2026-08-06", completed_at: "2026-08-07T08:30:00Z", status: "partial_success" as const, target_count: 3, successful_count: 1, failed_count: 2, valid_count: 1, coverage_rate: 1 / 3, failures: [ { ts_code: "000001.SZ", name: "平安银行", failure_type: "missing_daily_bar", reason: "目标交易日缺少日线行情", trade_date: "2026-08-06", }, { ts_code: "600000.SH", name: "浦发银行", failure_type: "recorded_stock_failure", reason: "供应商请求失败", trade_date: "2026-08-06", }, ], batch_errors: [], }, } describe("HomePage", () => { beforeEach(() => { useHomeOverview.mockReturnValue({ data: overview, isError: false, isPending: false, refetch: vi.fn(), }) }) it("renders the management shell and partial overview", () => { render() expect(screen.getByRole("heading", { name: "首页" })).toBeInTheDocument() expect(screen.getByText("市场数据概览")).toBeInTheDocument() expect(screen.getByText("部分更新")).toBeInTheDocument() expect(screen.getByText("当前目标股票池")).toBeInTheDocument() expect(screen.getByText("33.33%")).toBeInTheDocument() expect(screen.getByRole("button", { name: "行情数据" })).toBeDisabled() expect(screen.getByRole("button", { name: "同步任务" })).toBeDisabled() expect(screen.getByRole("link", { name: "选股策略" })).toHaveAttribute( "href", "/selection", ) }) it("opens and closes the accessible failed-stock dialog", () => { render() fireEvent.click(screen.getByRole("button", { name: "查看失败股票" })) const dialog = screen.getByRole("dialog", { name: "失败股票详情" }) expect(dialog).toBeInTheDocument() expect(within(dialog).getByText("平安银行")).toBeInTheDocument() expect(within(dialog).getByText("缺少日线行情")).toBeInTheDocument() expect(within(dialog).getAllByText("目标交易日:2026-08-06")).toHaveLength( 2, ) fireEvent.click(screen.getByRole("button", { name: "关闭" })) expect(screen.queryByRole("dialog")).not.toBeInTheDocument() }) it("renders a loading placeholder", () => { useHomeOverview.mockReturnValue({ data: undefined, isError: false, isPending: true, }) render() expect(screen.getByLabelText("正在加载市场数据概览")).toBeInTheDocument() }) it("offers retry when the overview request fails", () => { const refetch = vi.fn() useHomeOverview.mockReturnValue({ data: undefined, isError: true, isPending: false, refetch, }) render() fireEvent.click(screen.getByRole("button", { name: "重试" })) expect(refetch).toHaveBeenCalledOnce() }) it.each([ ["updating", "更新中"], ["success", "已更新"], ["failed", "未更新"], ] as const)("renders the %s overview status", (status, label) => { useHomeOverview.mockReturnValue({ data: { ...overview, status, latest_update: { ...overview.latest_update, status }, }, isError: false, isPending: false, }) render() expect(screen.getByText(label)).toBeInTheDocument() }) it("closes the failed-stock dialog with Escape", () => { render() fireEvent.click(screen.getByRole("button", { name: "查看失败股票" })) const dialog = screen.getByRole("dialog", { name: "失败股票详情" }) fireEvent.keyDown(dialog, { key: "Escape" }) expect(screen.queryByRole("dialog")).not.toBeInTheDocument() }) it("keeps the shell and explains the no-data state", () => { useHomeOverview.mockReturnValue({ data: { status: "no_data", stock_pool_count: 7, latest_update: null }, isError: false, isPending: false, }) render() expect(screen.getByText("暂无市场数据")).toBeInTheDocument() expect(screen.getByText(/当前目标股票池:/)).toBeInTheDocument() }) })