Support swing radar metrics and sector detail dialogs
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import { fireEvent, render, screen } from "@testing-library/react"
|
||||
import { fireEvent, render, screen, within } from "@testing-library/react"
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest"
|
||||
|
||||
import type {
|
||||
@@ -13,6 +13,7 @@ const navigate = vi.hoisted(() => vi.fn())
|
||||
const useSectorRadarDates = vi.fn()
|
||||
const useSectorRadarRankings = vi.fn()
|
||||
const useSectorRadarHistory = vi.fn()
|
||||
const useSectorRadarDetail = vi.fn()
|
||||
const refetchDates = vi.fn()
|
||||
const refetchRankings = vi.fn()
|
||||
const fetchNextPage = vi.fn()
|
||||
@@ -25,6 +26,7 @@ vi.mock("@tanstack/react-router", () => ({
|
||||
}))
|
||||
|
||||
vi.mock("@/features/sector-radar/api/sector-radar.query", () => ({
|
||||
useSectorRadarDetail: (...args: unknown[]) => useSectorRadarDetail(...args),
|
||||
useSectorRadarHistory: (...args: unknown[]) => useSectorRadarHistory(...args),
|
||||
useSectorRadarDates: () => useSectorRadarDates(),
|
||||
useSectorRadarRankings: (...args: unknown[]) =>
|
||||
@@ -180,6 +182,7 @@ describe("SectorRadarPage", () => {
|
||||
isError: false,
|
||||
data: { status: "no_data" },
|
||||
})
|
||||
useSectorRadarDetail.mockReturnValue({ isPending: true })
|
||||
navigate.mockReset()
|
||||
refetchDates.mockReset()
|
||||
refetchRankings.mockReset()
|
||||
@@ -230,65 +233,130 @@ describe("SectorRadarPage", () => {
|
||||
).not.toBeInTheDocument()
|
||||
})
|
||||
|
||||
it("mirrors ratio columns and expands only the selected sector history, resetting on date change", () => {
|
||||
routeSearch = { ...routeSearch, view: "ratio" }
|
||||
const ratioPage = {
|
||||
...rankingsResponse,
|
||||
view: "ratio",
|
||||
rows: rankingsResponse.rows.map((row) => ({
|
||||
...row,
|
||||
unit: "ratio",
|
||||
metric_value: -0.01,
|
||||
})),
|
||||
}
|
||||
useSectorRadarRankings.mockReturnValue(
|
||||
rankingQueryResult({ data: { pages: [ratioPage], pageParams: [1] } }),
|
||||
)
|
||||
const { rerender } = render(<SectorRadarPage />)
|
||||
expect(screen.getAllByRole("columnheader", { name: "在榜" })).toHaveLength(
|
||||
2,
|
||||
)
|
||||
expect(screen.getAllByText("-1%")).toHaveLength(4)
|
||||
const trigger = screen.getAllByRole("button", {
|
||||
name: "机器人展开在榜历史",
|
||||
})[0]!
|
||||
fireEvent.click(trigger)
|
||||
expect(trigger).toHaveAttribute("aria-expanded", "true")
|
||||
expect(useSectorRadarHistory).toHaveBeenLastCalledWith({
|
||||
sectorType: "concept",
|
||||
sectorCode: "BK0001.DC",
|
||||
tradeDate: "2026-08-28",
|
||||
})
|
||||
expect(screen.getByText("暂无在榜历史数据。")).toBeInTheDocument()
|
||||
fireEvent.click(trigger)
|
||||
expect(screen.queryByText("暂无在榜历史数据。")).not.toBeInTheDocument()
|
||||
fireEvent.click(trigger)
|
||||
useSectorRadarRankings.mockReturnValue(
|
||||
rankingQueryResult({
|
||||
data: {
|
||||
pages: [
|
||||
{
|
||||
...ratioPage,
|
||||
publication: {
|
||||
...successPublication,
|
||||
publication_id: "next-day",
|
||||
it.each(["ratio", "swing"] as const)(
|
||||
"mirrors %s columns and expands only the selected sector history, resetting on date change",
|
||||
(view) => {
|
||||
routeSearch = { ...routeSearch, view }
|
||||
const ratioPage = {
|
||||
...rankingsResponse,
|
||||
view,
|
||||
rows: rankingsResponse.rows.map((row) => ({
|
||||
...row,
|
||||
unit: "ratio",
|
||||
metric_value: -0.01,
|
||||
})),
|
||||
}
|
||||
useSectorRadarRankings.mockReturnValue(
|
||||
rankingQueryResult({ data: { pages: [ratioPage], pageParams: [1] } }),
|
||||
)
|
||||
const { rerender } = render(<SectorRadarPage />)
|
||||
expect(
|
||||
screen.getAllByRole("columnheader", { name: "在榜" }),
|
||||
).toHaveLength(2)
|
||||
if (view === "swing") {
|
||||
expect(
|
||||
within(screen.getAllByRole("row")[1]!)
|
||||
.getAllByRole("columnheader")
|
||||
.map((cell) => cell.textContent),
|
||||
).toEqual([
|
||||
"板块/排名",
|
||||
"涨跌幅",
|
||||
"净额",
|
||||
"在榜",
|
||||
"流入",
|
||||
"流出",
|
||||
"在榜",
|
||||
"净额",
|
||||
"涨跌幅",
|
||||
"板块/排名",
|
||||
])
|
||||
expect(screen.getAllByText("-1.25%")).toHaveLength(2)
|
||||
expect(screen.getAllByText("+12.5 亿元")).toHaveLength(2)
|
||||
}
|
||||
expect(screen.getAllByText("-1%")).toHaveLength(4)
|
||||
const trigger = screen.getAllByRole("button", {
|
||||
name: "机器人展开在榜历史",
|
||||
})[0]!
|
||||
fireEvent.click(trigger)
|
||||
expect(trigger).toHaveAttribute("aria-expanded", "true")
|
||||
expect(useSectorRadarHistory).toHaveBeenLastCalledWith({
|
||||
sectorType: "concept",
|
||||
sectorCode: "BK0001.DC",
|
||||
tradeDate: "2026-08-28",
|
||||
})
|
||||
expect(screen.getByText("暂无在榜历史数据。")).toBeInTheDocument()
|
||||
fireEvent.click(trigger)
|
||||
expect(screen.queryByText("暂无在榜历史数据。")).not.toBeInTheDocument()
|
||||
fireEvent.click(trigger)
|
||||
useSectorRadarRankings.mockReturnValue(
|
||||
rankingQueryResult({
|
||||
data: {
|
||||
pages: [
|
||||
{
|
||||
...ratioPage,
|
||||
publication: {
|
||||
...successPublication,
|
||||
publication_id: "next-day",
|
||||
},
|
||||
rows: ratioPage.rows.map((row) => ({
|
||||
...row,
|
||||
trade_date: "2026-08-31",
|
||||
})),
|
||||
},
|
||||
rows: ratioPage.rows.map((row) => ({
|
||||
...row,
|
||||
trade_date: "2026-08-31",
|
||||
})),
|
||||
},
|
||||
],
|
||||
pageParams: [1],
|
||||
},
|
||||
}),
|
||||
)
|
||||
rerender(<SectorRadarPage />)
|
||||
expect(screen.queryByText("暂无在榜历史数据。")).not.toBeInTheDocument()
|
||||
expect(
|
||||
screen.getAllByRole("button", { name: "机器人展开在榜历史" })[0],
|
||||
).toHaveAttribute("aria-expanded", "false")
|
||||
})
|
||||
],
|
||||
pageParams: [1],
|
||||
},
|
||||
}),
|
||||
)
|
||||
rerender(<SectorRadarPage />)
|
||||
expect(screen.queryByText("暂无在榜历史数据。")).not.toBeInTheDocument()
|
||||
expect(
|
||||
screen.getAllByRole("button", { name: "机器人展开在榜历史" })[0],
|
||||
).toHaveAttribute("aria-expanded", "false")
|
||||
},
|
||||
)
|
||||
|
||||
it.each(["swing", "ratio", "amount", "rank_change"] as const)(
|
||||
"opens sector details from both sides of the %s list",
|
||||
async (view) => {
|
||||
routeSearch = { ...routeSearch, view }
|
||||
useSectorRadarRankings.mockImplementation((query: { side: string }) =>
|
||||
rankingQueryResult({
|
||||
data: {
|
||||
pageParams: [1],
|
||||
pages: [
|
||||
{
|
||||
...(query.side === "top"
|
||||
? rankingsResponse
|
||||
: bottomRankingsResponse),
|
||||
view,
|
||||
},
|
||||
],
|
||||
},
|
||||
}),
|
||||
)
|
||||
render(<SectorRadarPage />)
|
||||
expect(screen.queryByText("BK0001.DC")).not.toBeInTheDocument()
|
||||
for (const [name, code] of [
|
||||
["机器人", "BK0001.DC"],
|
||||
["新能源", "BOTTOM-1"],
|
||||
]) {
|
||||
const trigger = screen.getByRole("button", { name })
|
||||
expect(trigger.closest("td")).toHaveTextContent(`1${name}`)
|
||||
fireEvent.click(trigger)
|
||||
const dialog = await screen.findByRole("dialog")
|
||||
expect(
|
||||
within(dialog).getByRole("heading", { name }),
|
||||
).toBeInTheDocument()
|
||||
expect(useSectorRadarDetail).toHaveBeenLastCalledWith({
|
||||
sectorType: "concept",
|
||||
sectorCode: code,
|
||||
tradeDate: "2026-08-28",
|
||||
})
|
||||
fireEvent.click(within(dialog).getByRole("button", { name: "Close" }))
|
||||
}
|
||||
},
|
||||
)
|
||||
|
||||
it("resets filters to the first batch in router search state", () => {
|
||||
routeSearch = { ...routeSearch, page: 3 }
|
||||
|
||||
Reference in New Issue
Block a user