Skip to content

Commit 2c3f31b

Browse files
authored
test: add test to ensure querykey matches for searchtotalcount & DBSearchPage histogram chart (#1491)
Closes HDX-3054
1 parent b58c52e commit 2c3f31b

File tree

2 files changed

+179
-1
lines changed

2 files changed

+179
-1
lines changed

CLAUDE.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ The project uses **Yarn 4.5.1** workspaces. Docker Compose manages ClickHouse, M
4242
2. **Type safety**: Use TypeScript strictly; Zod schemas for validation
4343
3. **Existing patterns**: Follow established patterns in the codebase - explore similar files before implementing
4444
4. **Component size**: Keep files under 300 lines; break down large components
45-
5. **Testing**: Tests live in `__tests__/` directories; use Jest for unit/integration tests
45+
5. **Testing**: Tests live in `__tests__/` directories; use Jest for unit/integration tests, `cd packages/app && yarn ci:unit` for unit tests, and `cd packages/app && yarn ci:int` for integration tests
4646

4747
## Important Context
4848

Lines changed: 178 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,178 @@
1+
import React from 'react';
2+
import objectHash from 'object-hash';
3+
import {
4+
ChartConfigWithDateRange,
5+
DisplayType,
6+
} from '@hyperdx/common-utils/dist/types';
7+
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
8+
9+
import { DBTimeChart } from '@/components/DBTimeChart';
10+
import SearchTotalCountChart from '@/components/SearchTotalCountChart';
11+
12+
// Mock the API and hooks
13+
jest.mock('@/api', () => ({
14+
__esModule: true,
15+
default: {
16+
useMe: () => ({
17+
data: { team: { parallelizeWhenPossible: false } },
18+
isLoading: false,
19+
}),
20+
},
21+
}));
22+
23+
jest.mock('@/hooks/useChartConfig', () => ({
24+
useQueriedChartConfig: jest.fn(() => ({
25+
data: { data: [], isComplete: true },
26+
isLoading: false,
27+
isError: false,
28+
isPlaceholderData: false,
29+
isSuccess: true,
30+
})),
31+
}));
32+
33+
jest.mock('@/source', () => ({
34+
useSource: () => ({ data: null, isLoading: false }),
35+
}));
36+
37+
jest.mock('@/ChartUtils', () => ({
38+
useTimeChartSettings: () => ({
39+
displayType: DisplayType.StackedBar,
40+
dateRange: [new Date('2024-01-01'), new Date('2024-01-02')],
41+
granularity: 'auto',
42+
fillNulls: true,
43+
}),
44+
formatResponseForTimeChart: () => ({
45+
graphResults: [],
46+
timestampColumn: undefined,
47+
lineData: [],
48+
groupColumns: [],
49+
valueColumns: [],
50+
isSingleValueColumn: true,
51+
}),
52+
getPreviousDateRange: (dateRange: [Date, Date]) => [
53+
new Date('2023-12-31'),
54+
new Date('2024-01-01'),
55+
],
56+
getPreviousPeriodOffsetSeconds: () => 86400,
57+
}));
58+
59+
describe('DBSearchPage QueryKey Consistency', () => {
60+
let queryClient: QueryClient;
61+
let mockUseQueriedChartConfig: jest.Mock;
62+
63+
beforeEach(async () => {
64+
queryClient = new QueryClient({
65+
defaultOptions: {
66+
queries: {
67+
retry: false,
68+
},
69+
},
70+
});
71+
72+
mockUseQueriedChartConfig = (await import('@/hooks/useChartConfig'))
73+
.useQueriedChartConfig as any;
74+
mockUseQueriedChartConfig.mockClear();
75+
});
76+
77+
it('should use matching queryKeys between SearchTotalCountChart and DBTimeChart', () => {
78+
const config: ChartConfigWithDateRange = {
79+
select: 'count()',
80+
from: { databaseName: 'test', tableName: 'logs' },
81+
where: '',
82+
timestampValueExpression: 'timestamp',
83+
connection: 'test-connection',
84+
displayType: DisplayType.StackedBar,
85+
dateRange: [new Date('2024-01-01'), new Date('2024-01-02')],
86+
};
87+
88+
const queryKeyPrefix = 'search';
89+
90+
// Render SearchTotalCountChart
91+
renderWithMantine(
92+
<SearchTotalCountChart
93+
config={config}
94+
queryKeyPrefix={queryKeyPrefix}
95+
enableParallelQueries={true}
96+
/>,
97+
);
98+
99+
// Render DBTimeChart
100+
renderWithMantine(
101+
<DBTimeChart
102+
config={config}
103+
queryKeyPrefix={queryKeyPrefix}
104+
enableParallelQueries={true}
105+
/>,
106+
);
107+
108+
// Get all calls to useQueriedChartConfig
109+
const calls = mockUseQueriedChartConfig.mock.calls;
110+
111+
// Should have at least 2 calls (one for each component)
112+
expect(calls.length).toBeGreaterThanOrEqual(2);
113+
114+
// Extract queryKey from each call
115+
const searchTotalCountQueryKey = calls[0][1]?.queryKey;
116+
const dbTimeChartQueryKey = calls[1][1]?.queryKey;
117+
118+
// Both should exist
119+
expect(searchTotalCountQueryKey).toBeDefined();
120+
expect(dbTimeChartQueryKey).toBeDefined();
121+
122+
// The key structure should be identical for both components
123+
// This ensures React Query can properly dedupe the queries
124+
expect(searchTotalCountQueryKey).toEqual(dbTimeChartQueryKey);
125+
126+
// Additional object hash check for deep equality verification
127+
const searchQueryKeyHash = objectHash(searchTotalCountQueryKey);
128+
const chartQueryKeyHash = objectHash(dbTimeChartQueryKey);
129+
expect(searchQueryKeyHash).toBe(chartQueryKeyHash);
130+
});
131+
132+
it('should use consistent queryKeys when disableQueryChunking is set', () => {
133+
const config: ChartConfigWithDateRange = {
134+
select: 'count()',
135+
from: { databaseName: 'test', tableName: 'logs' },
136+
where: '',
137+
timestampValueExpression: 'timestamp',
138+
connection: 'test-connection',
139+
displayType: DisplayType.StackedBar,
140+
dateRange: [new Date('2024-01-01'), new Date('2024-01-02')],
141+
};
142+
143+
const queryKeyPrefix = 'search';
144+
145+
// Render both components with disableQueryChunking
146+
renderWithMantine(
147+
<SearchTotalCountChart
148+
config={config}
149+
queryKeyPrefix={queryKeyPrefix}
150+
disableQueryChunking={true}
151+
/>,
152+
);
153+
154+
renderWithMantine(
155+
<DBTimeChart
156+
config={config}
157+
queryKeyPrefix={queryKeyPrefix}
158+
disableQueryChunking={true}
159+
/>,
160+
);
161+
162+
const calls = mockUseQueriedChartConfig.mock.calls;
163+
const searchQueryKey = calls[0][1]?.queryKey;
164+
const chartQueryKey = calls[1][1]?.queryKey;
165+
166+
// Verify the options include disableQueryChunking
167+
expect(searchQueryKey[3]).toHaveProperty('disableQueryChunking', true);
168+
expect(chartQueryKey[3]).toHaveProperty('disableQueryChunking', true);
169+
170+
// Keys should still match
171+
expect(searchQueryKey).toEqual(chartQueryKey);
172+
173+
// Additional object hash check for deep equality verification
174+
const searchQueryKeyHash = objectHash(searchQueryKey);
175+
const chartQueryKeyHash = objectHash(chartQueryKey);
176+
expect(searchQueryKeyHash).toBe(chartQueryKeyHash);
177+
});
178+
});

0 commit comments

Comments
 (0)