feat(home): 添加市场数据概览
This commit is contained in:
@@ -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()
|
||||
})
|
||||
})
|
||||
Reference in New Issue
Block a user