feat(home): 添加市场数据概览

This commit is contained in:
yuxuanhui
2026-08-07 13:29:31 +08:00
parent 9023e00213
commit b0e846d79c
33 changed files with 2229 additions and 18 deletions
@@ -0,0 +1,154 @@
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(<HomePage />)
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("button", { name: "选股策略" })).toBeDisabled()
})
it("opens and closes the accessible failed-stock dialog", () => {
render(<HomePage />)
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(<HomePage />)
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(<HomePage />)
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(<HomePage />)
expect(screen.getByText(label)).toBeInTheDocument()
})
it("closes the failed-stock dialog with Escape", () => {
render(<HomePage />)
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(<HomePage />)
expect(screen.getByText("暂无市场数据")).toBeInTheDocument()
expect(screen.getByText(/当前目标股票池:/)).toBeInTheDocument()
})
})