fix(frontend): broken test, mock-only useTrade, any types (#104)#223
fix(frontend): broken test, mock-only useTrade, any types (#104)#223ajitpratap0 merged 6 commits intomainfrom
Conversation
Three bugs in the dashboard frontend: 1. useTrade(id) always called getMockTrades() regardless of USE_MOCK_DATA. Now follows the same mock/real pattern as useTrades — checks USE_MOCK_DATA first, falls back to apiClient.getTrades + client-side filter when hitting the real API (no single-trade endpoint exists yet). 2. useTradeData.test.tsx fixture used camelCase Trade shape (entryPrice: 45045) but the hook passes data through mapApiTrade which expects snake_case RawApiTrade (price: 45045). Fixed: test now provides a fakeRawTrade fixture matching the API response shape so the mapping path is exercised end-to-end. 3. useTradingWebSocket state arrays used Record<string, any>[] for trades, positions, orders, agents. Replaced with proper Trade[], Position[], Order[], Agent[] types from lib/types. marketData changed from Record<string, any> to Record<string, unknown>. sendMessage parameter changed from any to Record<string, unknown>. All 23 dashboard tests pass. TypeScript type-check clean. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Code ReviewGood set of targeted fixes. The root-cause analysis in the PR description is accurate and the comments in the diff are genuinely helpful. A few things worth flagging before merge: Bug:
|
Code ReviewGood set of targeted fixes. The three described bugs are real and the fixes are generally correct. A few issues worth addressing before merge: 1.
|
c37de18 to
ddf83e7
Compare
|
Acknowledged from the review: useTrade pagination: Valid point — useTrade fetches only the first page (default limit=50). For now this matches the dashboard's use case (detail views for recent trades visible in the list), but a future getTrade(id) backend endpoint would be the proper fix. Not blocking this PR since the current behavior is strictly better than always-mock. Type safety nominal: Agreed — WebSocketMessage.data is still fakeRawTrade typing: Could add |
Code ReviewThe two existing reviews cover the important issues well. The PR author has acknowledged the pagination miss and the nominal type-safety point. Two items from the second review haven't been acknowledged yet — both are worth resolving before merge. 1.
|
Follow-up ReviewThe existing review thread covers the important issues. This is a brief status summary of what's still open vs. what's been acknowledged. Still unaddressed:
|
…ll contract (#104) Follow-up review items from PR #223: - Added staleTime and refetchInterval (matching useTrades) so detail views don't refetch on every window focus. - Documented the data: Trade | null return contract in the doc comment: null means not found in the fetched list, not an API error. Callers should check data !== null before rendering. - Changed `trade || null` to `trade ?? null` for explicit nullish coalescing (no false-positive on a hypothetical falsy trade). - Filed #224 for the pagination/cache dedup follow-up. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Follow-up fixes pushed (552ecd1):
All 23 tests pass, tsc clean. |
PR Review: fix(frontend): broken test, mock-only useTrade, any typesGood set of fixes — all three bugs are real and the general approach is correct. A few things worth addressing before merge. useTrade — silent truncation if API default page size < total trades
Compare to useTrade — no cache sharing with useTrades, causing duplicate network requestsEach A lighter approach while the single-trade endpoint is missing — derive from the already-populated list cache: export function useTrade(id: string) {
const queryClient = useQueryClient()
return useQuery({
queryKey: [...QUERY_KEYS.trades, id],
queryFn: async () => {
const cached = queryClient.getQueryData<{ data: Trade[] }>([...QUERY_KEYS.trades, 50, 0])
const fromCache = cached?.data?.find(t => t.id === id)
if (fromCache) return { success: true as const, data: fromCache, timestamp: new Date().toISOString() }
// Fall back to full fetch if list not cached
const response = await apiClient.getTrades()
// ... rest of mapping
},
enabled: !!id,
})
}useTrade — refetchInterval causes repeated full-list fetches on detail pagesLines 160-161 add useWebSocket.ts — runtime type gap in state setterssetTrades(prev => {
const newTrades = [message.data, ...prev] // message.data is still `any`
})TypeScript accepts this because Test coverage gap for the useTrade fixThe test file covers
Minor: double cast in test mockdata: { trades: [fakeRawTrade], count: 1 } as unknown as { trades: Trade[]; count: number },If Summary
The test fixture fix and |
- useTrade now checks the useTrades query cache first via queryClient.getQueriesData to avoid duplicate full-list fetches when list and detail views are mounted simultaneously. - Fallback fetch uses limit=1000 (up from default 50) so trades beyond the first page aren't silently truncated. - Removed refetchInterval from useTrade — polling a detail view by re-fetching the full trade list on every interval is expensive. staleTime is kept for tab-switch cache reuse. - Added 4 useTrade tests: real API returns correct trade, not-found returns null, API error propagates, disabled when id is empty. Test count: 23 → 27. - Fixed TS18048 (cached possibly undefined) with an explicit null guard. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
All follow-up review items addressed (8a04173): Pagination truncation: useTrade now fetches with limit=1000 (up from default 50) so trades beyond the first page aren't silently truncated. Cache sharing: Checks useTrades query cache first via refetchInterval removed: Polling a detail view by re-fetching the full trade list on every interval was wasteful. Kept staleTime for tab-switch cache reuse. Test coverage: 4 new useTrade tests (27 total, up from 23):
Also fixed a TS18048 strict-null error on the cache lookup. All 27 tests pass, tsc clean. |
Code Review: fix(frontend): broken test, mock-only useTrade, any types (#104)Good fixes overall — the three bugs are real and the approach is well-reasoned. Found one latent runtime error and a few smaller issues below. Bug: Cache loop will throw
|
| Must fix | Array.isArray guard in cache loop (will throw at runtime once useTrade has been called once) |
| Follow-up | Single-trade API endpoint to retire the 1000-limit workaround |
| Follow-up | Cache-hit test coverage |
| Nice to have | Runtime validation in WebSocket handler; staleTime tuning; export RawApiTrade |
The three original bug fixes are correct and the test restructure around fakeRawTrade is the right call. Just needs the Array.isArray guard before merging.
Must-fix: getQueriesData prefix-matches ['trades'] and returns both useTrades entries (data: Trade[]) and prior useTrade entries (data: Trade | null). Calling .find() on a non-array Trade object would throw TypeError at runtime. Added Array.isArray guard. Also: bumped useTrade staleTime from REFRESH_INTERVALS.trades (2s) to 30s. Without refetchInterval the detail view only refreshes on remount/refocus, so a 2s stale window goes stale immediately and never auto-refreshes — 30s gives a reasonable cache-reuse window for tab switches. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Must-fix addressed (6beed29): Array.isArray guard: staleTime tuned: Bumped from 27 tests pass, tsc clean. Follow-ups (single-trade endpoint, cache-hit test, WebSocket runtime validation) tracked in #224. |
PR Review: fix(frontend): broken test, mock-only useTrade, any types (#104)Good fixes overall — all three bugs are real and the changes are well-reasoned. The commit history shows iterative refinement (Array.isArray guard, staleTime tuning) which is a good sign. Some items worth addressing before merge: Issues1.
|
- Extract MAX_TRADE_LOOKUP_LIMIT = 1000 with TODO(#224) linking to the single-trade endpoint follow-up. Removes the magic number. - Add WARNING comment to useTradingWebSocket documenting that the WS payload uses the same snake_case encoding as the REST API but does NOT run mapApiTrade — consumers accessing camelCase fields (e.g. trade.entryPrice) will get undefined at runtime because the wire format has "price". A mapper per message.type is needed to close this gap (tracked alongside #224). Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
Pushed 40e765d:
The 27 tests pass, tsc clean. |
Code Review — PR #223The three bugs being fixed are real and well-diagnosed. The overall approach is sound. A few issues worth addressing before merge, ranging from a non-trivial type-safety problem to minor improvements. 1.
|
Summary
Closes #104 — three bugs in the Next.js dashboard frontend.
1. useTrade always uses mock data (BLOCKS PRODUCTION)
useTrade(id)calledgetMockTrades()unconditionally, ignoringUSE_MOCK_DATA. Detail views always showed mock data even when the real API was available.Fix: Now checks
USE_MOCK_DATAfirst. When hitting the real API, callsapiClient.getTrades()and filters client-side (no single-trade endpoint exists yet).2. Broken test fixture (camelCase vs snake_case)
useTradeData.test.tsxused a camelCaseTradefixture (entryPrice: 45045) as mock API response data, but the hook runsmapApiTradewhich expects snake_caseRawApiTrade(price: 45045). The test passed coincidentally because the symbol assertion happened to match, butentryPricewasundefined.Fix: Test now uses a
fakeRawTradefixture matching the snake_case API response shape.3. Pervasive
anytypes in WebSocket hookuseTradingWebSocketusedRecord<string, any>[]for all state arrays (trades, positions, orders, agents) andanyfor thesendMessageparameter. Consumers had no type safety.Fix: Replaced with
Trade[],Position[],Order[],Agent[]fromlib/types.marketDatachanged toRecord<string, unknown>.sendMessageparameter changed toRecord<string, unknown>.Test plan
npm run test -- --run)npx tsc --noEmit)3 files changed, 53 insertions(+), 21 deletions(-)