feat(sector-radar): 支持排名列表滚动加载
This commit is contained in:
@@ -1,12 +1,13 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest"
|
||||
|
||||
const useQuery = vi.hoisted(() => vi.fn())
|
||||
const useInfiniteQuery = vi.hoisted(() => vi.fn())
|
||||
const api = vi.hoisted(() => ({
|
||||
getSectorRadarDates: vi.fn(),
|
||||
getSectorRadarRankings: vi.fn(),
|
||||
}))
|
||||
|
||||
vi.mock("@tanstack/react-query", () => ({ useQuery }))
|
||||
vi.mock("@tanstack/react-query", () => ({ useInfiniteQuery, useQuery }))
|
||||
vi.mock("./sector-radar.api", () => api)
|
||||
|
||||
import {
|
||||
@@ -32,9 +33,10 @@ describe("sector radar query hooks", () => {
|
||||
beforeEach(() => {
|
||||
vi.clearAllMocks()
|
||||
useQuery.mockImplementation((options) => options)
|
||||
useInfiniteQuery.mockImplementation((options) => options)
|
||||
})
|
||||
|
||||
it("keeps every server-affecting filter in the ranking query key", () => {
|
||||
it("keeps filters in one ranking key without splitting cached pages", () => {
|
||||
expect(sectorRadarDatesQueryKey).toEqual(["sectorRadar", "dates"])
|
||||
expect(sectorRadarRankingsQueryKey(query)).toEqual([
|
||||
"sectorRadar",
|
||||
@@ -46,9 +48,11 @@ describe("sector radar query hooks", () => {
|
||||
3,
|
||||
"bottom",
|
||||
"银行",
|
||||
2,
|
||||
50,
|
||||
])
|
||||
expect(
|
||||
sectorRadarRankingsQueryKey({ ...query, page: query.page + 1 }),
|
||||
).toEqual(sectorRadarRankingsQueryKey(query))
|
||||
})
|
||||
|
||||
it("forwards React Query cancellation signals to both adapters", async () => {
|
||||
@@ -57,15 +61,98 @@ describe("sector radar query hooks", () => {
|
||||
const datesOptions = useQuery.mock.calls[0]?.[0] as {
|
||||
queryFn: (context: { signal: AbortSignal }) => unknown
|
||||
}
|
||||
const rankingsOptions = useQuery.mock.calls[1]?.[0] as {
|
||||
queryFn: (context: { signal: AbortSignal }) => unknown
|
||||
const rankingsOptions = useInfiniteQuery.mock.calls[0]?.[0] as {
|
||||
queryFn: (context: { pageParam: number; signal: AbortSignal }) => unknown
|
||||
}
|
||||
const signal = new AbortController().signal
|
||||
|
||||
await datesOptions.queryFn({ signal })
|
||||
await rankingsOptions.queryFn({ signal })
|
||||
await rankingsOptions.queryFn({ pageParam: 3, signal })
|
||||
|
||||
expect(api.getSectorRadarDates).toHaveBeenCalledWith(signal)
|
||||
expect(api.getSectorRadarRankings).toHaveBeenCalledWith(query, signal)
|
||||
expect(api.getSectorRadarRankings).toHaveBeenCalledWith(
|
||||
{ ...query, page: 3 },
|
||||
signal,
|
||||
)
|
||||
})
|
||||
|
||||
it("starts from page one and stops after loaded rows cover total", () => {
|
||||
useSectorRadarRankings(query)
|
||||
const rankingsOptions = useInfiniteQuery.mock.calls[0]?.[0] as {
|
||||
getNextPageParam: (
|
||||
lastPage: { page: number; rows: unknown[]; total: number },
|
||||
pages: { page: number; rows: unknown[]; total: number }[],
|
||||
lastPageParam: number,
|
||||
) => number | undefined
|
||||
initialPageParam: number
|
||||
}
|
||||
const firstPage = {
|
||||
page: 1,
|
||||
rows: Array(50).fill(null),
|
||||
status: "success",
|
||||
total: 75,
|
||||
}
|
||||
const secondPage = {
|
||||
page: 2,
|
||||
rows: Array(25).fill(null),
|
||||
status: "success",
|
||||
total: 75,
|
||||
}
|
||||
|
||||
expect(rankingsOptions.initialPageParam).toBe(1)
|
||||
expect(rankingsOptions.getNextPageParam(firstPage, [firstPage], 1)).toBe(2)
|
||||
expect(
|
||||
rankingsOptions.getNextPageParam(secondPage, [firstPage, secondPage], 2),
|
||||
).toBeUndefined()
|
||||
})
|
||||
|
||||
it("stops when a page is empty or does not match its requested page param", () => {
|
||||
useSectorRadarRankings(query)
|
||||
const rankingsOptions = useInfiniteQuery.mock.calls[0]?.[0] as {
|
||||
getNextPageParam: (
|
||||
lastPage: {
|
||||
page: number
|
||||
rows: unknown[]
|
||||
status: "success" | "no_data"
|
||||
total: number
|
||||
},
|
||||
pages: {
|
||||
page: number
|
||||
rows: unknown[]
|
||||
status: "success" | "no_data"
|
||||
total: number
|
||||
}[],
|
||||
lastPageParam: number,
|
||||
) => number | undefined
|
||||
}
|
||||
const firstPage = {
|
||||
page: 1,
|
||||
rows: Array(50).fill(null),
|
||||
status: "success" as const,
|
||||
total: 75,
|
||||
}
|
||||
const emptyPage = {
|
||||
page: 2,
|
||||
rows: [],
|
||||
status: "success" as const,
|
||||
total: 75,
|
||||
}
|
||||
const mismatchedPage = {
|
||||
page: 1,
|
||||
rows: Array(25).fill(null),
|
||||
status: "success" as const,
|
||||
total: 75,
|
||||
}
|
||||
|
||||
expect(
|
||||
rankingsOptions.getNextPageParam(emptyPage, [firstPage, emptyPage], 2),
|
||||
).toBeUndefined()
|
||||
expect(
|
||||
rankingsOptions.getNextPageParam(
|
||||
mismatchedPage,
|
||||
[firstPage, mismatchedPage],
|
||||
2,
|
||||
),
|
||||
).toBeUndefined()
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user