@parca/profile 0.19.140 → 0.19.142
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +5 -1
- package/dist/GraphTooltipArrow/Content.js +224 -30
- package/dist/GraphTooltipArrow/DockedGraphTooltip/index.js +192 -33
- package/dist/GraphTooltipArrow/ExpandOnHoverValue.js +53 -3
- package/dist/GraphTooltipArrow/index.d.ts.map +1 -1
- package/dist/GraphTooltipArrow/index.js +86 -56
- package/dist/GraphTooltipArrow/useGraphTooltip/index.js +37 -37
- package/dist/GraphTooltipArrow/useGraphTooltipMetaInfo/index.d.ts.map +1 -1
- package/dist/GraphTooltipArrow/useGraphTooltipMetaInfo/index.js +104 -72
- package/dist/MatchersInput/SuggestionItem.js +91 -12
- package/dist/MatchersInput/SuggestionsList.d.ts +2 -1
- package/dist/MatchersInput/SuggestionsList.d.ts.map +1 -1
- package/dist/MatchersInput/SuggestionsList.js +371 -157
- package/dist/MatchersInput/SuggestionsList.test.d.ts +2 -0
- package/dist/MatchersInput/SuggestionsList.test.d.ts.map +1 -0
- package/dist/MatchersInput/index.js +308 -115
- package/dist/MetricsCircle/index.js +39 -3
- package/dist/MetricsGraph/MetricsContextMenu/index.js +119 -19
- package/dist/MetricsGraph/MetricsInfoPanel/index.js +81 -20
- package/dist/MetricsGraph/MetricsTooltip/index.d.ts.map +1 -1
- package/dist/MetricsGraph/MetricsTooltip/index.js +107 -74
- package/dist/MetricsGraph/index.js +552 -203
- package/dist/MetricsGraph/useMetricsGraphDimensions.js +46 -25
- package/dist/MetricsGraph/utils/colorMapping.js +24 -17
- package/dist/MetricsSeries/index.js +70 -7
- package/dist/PreSelectedMatchers/index.d.ts.map +1 -1
- package/dist/PreSelectedMatchers/index.js +249 -102
- package/dist/ProfileExplorer/ProfileExplorerCompare.d.ts.map +1 -1
- package/dist/ProfileExplorer/ProfileExplorerCompare.js +241 -45
- package/dist/ProfileExplorer/ProfileExplorerSingle.js +98 -11
- package/dist/ProfileExplorer/index.js +183 -32
- package/dist/ProfileFlameChart/SamplesStrips/SamplesGraph/index.js +333 -148
- package/dist/ProfileFlameChart/SamplesStrips/SamplesStrips.stories.js +69 -35
- package/dist/ProfileFlameChart/SamplesStrips/index.d.ts +2 -2
- package/dist/ProfileFlameChart/SamplesStrips/index.d.ts.map +1 -1
- package/dist/ProfileFlameChart/SamplesStrips/index.js +645 -134
- package/dist/ProfileFlameChart/SamplesStrips/labelSetUtils.js +114 -55
- package/dist/ProfileFlameChart/index.d.ts.map +1 -1
- package/dist/ProfileFlameChart/index.js +267 -129
- package/dist/ProfileFlameGraph/FlameGraphArrow/ContextMenu.d.ts.map +1 -1
- package/dist/ProfileFlameGraph/FlameGraphArrow/ContextMenu.js +288 -89
- package/dist/ProfileFlameGraph/FlameGraphArrow/ContextMenuWrapper.js +56 -20
- package/dist/ProfileFlameGraph/FlameGraphArrow/FlameGraphNodes.js +211 -140
- package/dist/ProfileFlameGraph/FlameGraphArrow/MemoizedTooltip.js +133 -38
- package/dist/ProfileFlameGraph/FlameGraphArrow/MiniMap.js +261 -216
- package/dist/ProfileFlameGraph/FlameGraphArrow/TextWithEllipsis.d.ts.map +1 -1
- package/dist/ProfileFlameGraph/FlameGraphArrow/TextWithEllipsis.js +72 -47
- package/dist/ProfileFlameGraph/FlameGraphArrow/TooltipContext.d.ts.map +1 -1
- package/dist/ProfileFlameGraph/FlameGraphArrow/TooltipContext.js +58 -28
- package/dist/ProfileFlameGraph/FlameGraphArrow/ZoomControls.d.ts.map +1 -1
- package/dist/ProfileFlameGraph/FlameGraphArrow/ZoomControls.js +59 -8
- package/dist/ProfileFlameGraph/FlameGraphArrow/index.js +396 -179
- package/dist/ProfileFlameGraph/FlameGraphArrow/useBatchedRendering.d.ts.map +1 -1
- package/dist/ProfileFlameGraph/FlameGraphArrow/useBatchedRendering.js +68 -50
- package/dist/ProfileFlameGraph/FlameGraphArrow/useMappingList.js +62 -38
- package/dist/ProfileFlameGraph/FlameGraphArrow/useNodeColor.js +14 -6
- package/dist/ProfileFlameGraph/FlameGraphArrow/useScrollViewport.js +124 -82
- package/dist/ProfileFlameGraph/FlameGraphArrow/useVisibleNodes.js +160 -98
- package/dist/ProfileFlameGraph/FlameGraphArrow/useZoom.js +232 -112
- package/dist/ProfileFlameGraph/FlameGraphArrow/utils.js +137 -114
- package/dist/ProfileFlameGraph/benchmarks/benchdata/populateData.js +85 -0
- package/dist/ProfileFlameGraph/index.d.ts.map +1 -1
- package/dist/ProfileFlameGraph/index.js +324 -150
- package/dist/ProfileMetricsGraph/hooks/useQueryRange.js +140 -32
- package/dist/ProfileMetricsGraph/index.d.ts.map +1 -1
- package/dist/ProfileMetricsGraph/index.js +519 -258
- package/dist/ProfileSelector/CompareButton.js +132 -12
- package/dist/ProfileSelector/MetricsGraphSection.d.ts.map +1 -1
- package/dist/ProfileSelector/MetricsGraphSection.js +236 -64
- package/dist/ProfileSelector/index.d.ts.map +1 -1
- package/dist/ProfileSelector/index.js +727 -141
- package/dist/ProfileSelector/useAutoQuerySelector.js +249 -130
- package/dist/ProfileSource.js +230 -163
- package/dist/ProfileTypeSelector/index.js +214 -125
- package/dist/ProfileView/components/ActionButtons/GroupByDropdown.js +50 -4
- package/dist/ProfileView/components/ActionButtons/SortByDropdown.d.ts.map +1 -1
- package/dist/ProfileView/components/ActionButtons/SortByDropdown.js +141 -35
- package/dist/ProfileView/components/ColorStackLegend.d.ts.map +1 -1
- package/dist/ProfileView/components/ColorStackLegend.js +185 -55
- package/dist/ProfileView/components/DashboardItems/index.js +87 -28
- package/dist/ProfileView/components/DashboardLayout/index.js +108 -16
- package/dist/ProfileView/components/DiffLegend.js +172 -29
- package/dist/ProfileView/components/GroupByLabelsDropdown/index.js +199 -55
- package/dist/ProfileView/components/InvertCallStack/index.d.ts.map +1 -1
- package/dist/ProfileView/components/InvertCallStack/index.js +100 -12
- package/dist/ProfileView/components/ProfileFilters/filterPresets.js +260 -315
- package/dist/ProfileView/components/ProfileFilters/index.js +518 -215
- package/dist/ProfileView/components/ProfileFilters/useProfileFilters.js +370 -306
- package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.d.ts +2 -1
- package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.d.ts.map +1 -1
- package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.js +188 -118
- package/dist/ProfileView/components/ProfileHeader/index.js +105 -11
- package/dist/ProfileView/components/ShareButton/ResultBox.js +119 -16
- package/dist/ProfileView/components/ShareButton/index.js +352 -62
- package/dist/ProfileView/components/Toolbars/MultiLevelDropdown.d.ts.map +1 -1
- package/dist/ProfileView/components/Toolbars/MultiLevelDropdown.js +678 -194
- package/dist/ProfileView/components/Toolbars/SwitchMenuItem.js +94 -7
- package/dist/ProfileView/components/Toolbars/TableColumnsDropdown.d.ts.map +1 -1
- package/dist/ProfileView/components/Toolbars/TableColumnsDropdown.js +199 -157
- package/dist/ProfileView/components/Toolbars/index.d.ts +2 -2
- package/dist/ProfileView/components/Toolbars/index.d.ts.map +1 -1
- package/dist/ProfileView/components/Toolbars/index.js +441 -21
- package/dist/ProfileView/components/ViewSelector/Dropdown.js +233 -22
- package/dist/ProfileView/components/ViewSelector/index.d.ts.map +1 -1
- package/dist/ProfileView/components/ViewSelector/index.js +212 -86
- package/dist/ProfileView/components/VisualizationContainer/index.d.ts.map +1 -1
- package/dist/ProfileView/components/VisualizationContainer/index.js +52 -7
- package/dist/ProfileView/components/VisualizationPanel.js +185 -8
- package/dist/ProfileView/context/DashboardContext.d.ts.map +1 -1
- package/dist/ProfileView/context/DashboardContext.js +85 -29
- package/dist/ProfileView/context/ProfileViewContext.js +56 -15
- package/dist/ProfileView/hooks/useAutoSelectDimension.js +71 -41
- package/dist/ProfileView/hooks/useProfileMetadata.js +50 -18
- package/dist/ProfileView/hooks/useResetFlameGraphState.d.ts.map +1 -1
- package/dist/ProfileView/hooks/useResetFlameGraphState.js +32 -12
- package/dist/ProfileView/hooks/useResetStateOnProfileTypeChange.d.ts.map +1 -1
- package/dist/ProfileView/hooks/useResetStateOnProfileTypeChange.js +71 -27
- package/dist/ProfileView/hooks/useResetStateOnSeriesChange.d.ts.map +1 -1
- package/dist/ProfileView/hooks/useResetStateOnSeriesChange.js +40 -19
- package/dist/ProfileView/hooks/useVisualizationState.d.ts +3 -3
- package/dist/ProfileView/hooks/useVisualizationState.d.ts.map +1 -1
- package/dist/ProfileView/hooks/useVisualizationState.js +258 -67
- package/dist/ProfileView/index.js +383 -45
- package/dist/ProfileView/types/visualization.js +1 -13
- package/dist/ProfileView/utils/colorUtils.js +8 -7
- package/dist/ProfileViewWithData.d.ts.map +1 -1
- package/dist/ProfileViewWithData.js +332 -228
- package/dist/QueryControls/index.js +418 -47
- package/dist/Sandwich/components/CalleesSection.js +54 -4
- package/dist/Sandwich/components/CallersSection.js +97 -27
- package/dist/Sandwich/components/TableSection.js +77 -4
- package/dist/Sandwich/index.d.ts.map +1 -1
- package/dist/Sandwich/index.js +126 -14
- package/dist/Sandwich/utils/processRowData.js +48 -39
- package/dist/SelectWithRefresh/index.js +102 -28
- package/dist/SimpleMatchers/Select.js +520 -187
- package/dist/SimpleMatchers/index.js +590 -288
- package/dist/SourceView/Highlighter.js +230 -70
- package/dist/SourceView/LineNo.js +72 -17
- package/dist/SourceView/index.d.ts.map +1 -1
- package/dist/SourceView/index.js +178 -104
- package/dist/SourceView/lang-detector/ext-to-lang.json +798 -798
- package/dist/SourceView/lang-detector/index.js +28 -14
- package/dist/SourceView/useSelectedLineRange.d.ts.map +1 -1
- package/dist/SourceView/useSelectedLineRange.js +99 -23
- package/dist/Table/ColorCell.js +42 -1
- package/dist/Table/ColumnsVisibility.js +114 -6
- package/dist/Table/MoreDropdown.d.ts.map +1 -1
- package/dist/Table/MoreDropdown.js +122 -25
- package/dist/Table/TableContextMenu.d.ts.map +1 -1
- package/dist/Table/TableContextMenu.js +151 -137
- package/dist/Table/TableContextMenuWrapper.js +59 -14
- package/dist/Table/hooks/useColorManagement.js +58 -16
- package/dist/Table/hooks/useTableConfiguration.d.ts.map +1 -1
- package/dist/Table/hooks/useTableConfiguration.js +333 -169
- package/dist/Table/index.d.ts.map +1 -1
- package/dist/Table/index.js +222 -128
- package/dist/Table/utils/functions.js +169 -144
- package/dist/Table/utils/topAndBottomExpandedRowModel.js +69 -52
- package/dist/TimelineGuide/index.js +209 -16
- package/dist/TopTable/benchmarks/benchdata/populateData.js +91 -0
- package/dist/TopTable/index.d.ts.map +1 -1
- package/dist/TopTable/index.js +342 -123
- package/dist/contexts/LabelsQueryProvider.js +94 -32
- package/dist/contexts/UnifiedLabelsContext.js +114 -49
- package/dist/contexts/utils.js +37 -15
- package/dist/hooks/useCompareModeMeta.d.ts.map +1 -1
- package/dist/hooks/useCompareModeMeta.js +158 -64
- package/dist/hooks/useLabels.js +295 -52
- package/dist/hooks/useQueryState.d.ts +3 -3
- package/dist/hooks/useQueryState.d.ts.map +1 -1
- package/dist/hooks/useQueryState.js +373 -332
- package/dist/index.d.ts +2 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +22 -8
- package/dist/testdata/fg-diff.json +3750 -0
- package/dist/testdata/fg-simple.json +1879 -0
- package/dist/testdata/link_data.json +56 -0
- package/dist/testdata/tabular.json +30 -0
- package/dist/testdata/test_flamegraph.json +26846 -0
- package/dist/testdata/test_graph.json +53 -0
- package/dist/useDelayedLoader.js +32 -18
- package/dist/useGrpcQuery/index.js +71 -11
- package/dist/useHasProfileData.js +90 -12
- package/dist/useQuery.js +205 -64
- package/dist/useSumBy.d.ts +1 -1
- package/dist/useSumBy.d.ts.map +1 -1
- package/dist/useSumBy.js +294 -138
- package/dist/utils.js +62 -30
- package/package.json +9 -10
- package/src/GraphTooltipArrow/index.tsx +3 -0
- package/src/GraphTooltipArrow/useGraphTooltipMetaInfo/index.ts +13 -11
- package/src/MatchersInput/SuggestionsList.test.tsx +70 -0
- package/src/MatchersInput/SuggestionsList.tsx +11 -10
- package/src/MatchersInput/index.tsx +1 -1
- package/src/MetricsGraph/MetricsTooltip/index.tsx +22 -34
- package/src/PreSelectedMatchers/index.tsx +3 -0
- package/src/ProfileExplorer/ProfileExplorerCompare.tsx +9 -4
- package/src/ProfileFlameChart/SamplesStrips/index.tsx +2 -2
- package/src/ProfileFlameChart/index.tsx +28 -21
- package/src/ProfileFlameGraph/FlameGraphArrow/ContextMenu.tsx +9 -10
- package/src/ProfileFlameGraph/FlameGraphArrow/TextWithEllipsis.tsx +6 -5
- package/src/ProfileFlameGraph/FlameGraphArrow/TooltipContext.tsx +3 -0
- package/src/ProfileFlameGraph/FlameGraphArrow/ZoomControls.tsx +3 -0
- package/src/ProfileFlameGraph/FlameGraphArrow/useBatchedRendering.ts +3 -0
- package/src/ProfileFlameGraph/index.tsx +9 -6
- package/src/ProfileMetricsGraph/index.tsx +8 -6
- package/src/ProfileSelector/MetricsGraphSection.tsx +10 -5
- package/src/ProfileSelector/index.tsx +61 -39
- package/src/ProfileView/components/ActionButtons/SortByDropdown.tsx +6 -10
- package/src/ProfileView/components/ColorStackLegend.tsx +4 -2
- package/src/ProfileView/components/InvertCallStack/index.tsx +4 -5
- package/src/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.test.tsx +192 -94
- package/src/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.ts +21 -21
- package/src/ProfileView/components/Toolbars/MultiLevelDropdown.tsx +28 -24
- package/src/ProfileView/components/Toolbars/TableColumnsDropdown.tsx +5 -4
- package/src/ProfileView/components/Toolbars/index.tsx +3 -3
- package/src/ProfileView/components/ViewSelector/index.tsx +16 -9
- package/src/ProfileView/components/VisualizationContainer/index.tsx +3 -0
- package/src/ProfileView/context/DashboardContext.tsx +6 -6
- package/src/ProfileView/hooks/useResetFlameGraphState.ts +4 -6
- package/src/ProfileView/hooks/useResetStateOnProfileTypeChange.ts +26 -24
- package/src/ProfileView/hooks/useResetStateOnSeriesChange.ts +8 -16
- package/src/ProfileView/hooks/useVisualizationState.ts +69 -61
- package/src/ProfileViewWithData.tsx +35 -29
- package/src/Sandwich/index.tsx +3 -4
- package/src/SourceView/index.tsx +2 -4
- package/src/SourceView/useSelectedLineRange.ts +19 -34
- package/src/Table/MoreDropdown.tsx +11 -9
- package/src/Table/TableContextMenu.tsx +13 -10
- package/src/Table/hooks/useTableConfiguration.tsx +11 -16
- package/src/Table/index.tsx +21 -12
- package/src/TopTable/index.tsx +4 -3
- package/src/hooks/useCompareModeMeta.ts +91 -61
- package/src/hooks/useQueryState.test.tsx +345 -275
- package/src/hooks/useQueryState.ts +118 -136
- package/src/index.tsx +15 -16
- package/src/useDelayedLoader.ts +10 -10
- package/src/useSumBy.ts +15 -21
- package/dist/ProfileView/components/ProfileFilters/useProfileFiltersUrlState.test.js +0 -455
- package/dist/hooks/urlParsers.d.ts +0 -18
- package/dist/hooks/urlParsers.d.ts.map +0 -1
- package/dist/hooks/urlParsers.js +0 -32
- package/dist/hooks/useColorBy.d.ts +0 -5
- package/dist/hooks/useColorBy.d.ts.map +0 -1
- package/dist/hooks/useColorBy.js +0 -26
- package/dist/hooks/useDashboardItems.d.ts +0 -5
- package/dist/hooks/useDashboardItems.d.ts.map +0 -1
- package/dist/hooks/useDashboardItems.js +0 -27
- package/dist/hooks/useQueryState.test.js +0 -868
- package/src/hooks/urlParsers.ts +0 -38
- package/src/hooks/useColorBy.ts +0 -42
- package/src/hooks/useDashboardItems.ts +0 -46
|
@@ -17,13 +17,59 @@ import {ReactNode, act} from 'react';
|
|
|
17
17
|
import {QueryClient, QueryClientProvider} from '@tanstack/react-query';
|
|
18
18
|
// eslint-disable-next-line import/named
|
|
19
19
|
import {renderHook, waitFor} from '@testing-library/react';
|
|
20
|
-
// eslint-disable-next-line import/no-unresolved
|
|
21
|
-
import {NuqsTestingAdapter} from 'nuqs/adapters/testing';
|
|
22
20
|
import {beforeEach, describe, expect, it, vi} from 'vitest';
|
|
23
21
|
|
|
22
|
+
import {URLStateProvider} from '@parca/components';
|
|
23
|
+
|
|
24
24
|
import {useQueryState} from './useQueryState';
|
|
25
25
|
|
|
26
|
-
|
|
26
|
+
// Mock window.location
|
|
27
|
+
const mockLocation = {
|
|
28
|
+
pathname: '/test',
|
|
29
|
+
search: '',
|
|
30
|
+
};
|
|
31
|
+
|
|
32
|
+
// Mock the navigate function that actually updates the mock location
|
|
33
|
+
const mockNavigateTo = vi.fn((path: string, params: Record<string, string | string[]>) => {
|
|
34
|
+
// Convert params object to query string
|
|
35
|
+
const searchParams = new URLSearchParams();
|
|
36
|
+
Object.entries(params).forEach(([key, value]) => {
|
|
37
|
+
if (value !== undefined && value !== null) {
|
|
38
|
+
if (Array.isArray(value)) {
|
|
39
|
+
// For arrays, join with commas
|
|
40
|
+
searchParams.set(key, value.join(','));
|
|
41
|
+
} else {
|
|
42
|
+
searchParams.set(key, String(value));
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
});
|
|
46
|
+
mockLocation.search = `?${searchParams.toString()}`;
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
// Mock the getQueryParamsFromURL function
|
|
50
|
+
vi.mock('@parca/components/src/hooks/URLState/utils', async () => {
|
|
51
|
+
const actual = await vi.importActual('@parca/components/src/hooks/URLState/utils');
|
|
52
|
+
return {
|
|
53
|
+
...actual,
|
|
54
|
+
getQueryParamsFromURL: () => {
|
|
55
|
+
if (mockLocation.search === '') return {};
|
|
56
|
+
const params = new URLSearchParams(mockLocation.search);
|
|
57
|
+
const result: Record<string, string | string[]> = {};
|
|
58
|
+
for (const [key, value] of params.entries()) {
|
|
59
|
+
const decodedValue = decodeURIComponent(value);
|
|
60
|
+
const existing = result[key];
|
|
61
|
+
if (existing !== undefined) {
|
|
62
|
+
result[key] = Array.isArray(existing)
|
|
63
|
+
? [...existing, decodedValue]
|
|
64
|
+
: [existing, decodedValue];
|
|
65
|
+
} else {
|
|
66
|
+
result[key] = decodedValue;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
return result;
|
|
70
|
+
},
|
|
71
|
+
};
|
|
72
|
+
});
|
|
27
73
|
|
|
28
74
|
// Mock useSumBy with stateful behavior using React's useState
|
|
29
75
|
vi.mock('../useSumBy', async () => {
|
|
@@ -92,10 +138,9 @@ const setProfileTypesData = (data: typeof mockProfileTypesData): void => {
|
|
|
92
138
|
mockProfileTypesData = data;
|
|
93
139
|
};
|
|
94
140
|
|
|
95
|
-
// Helper to create wrapper with
|
|
141
|
+
// Helper to create wrapper with URLStateProvider
|
|
96
142
|
const createWrapper = (
|
|
97
|
-
|
|
98
|
-
searchParams: string | Record<string, string> = {}
|
|
143
|
+
paramPreferences = {}
|
|
99
144
|
): (({children}: {children: ReactNode}) => JSX.Element) => {
|
|
100
145
|
const queryClient = new QueryClient({
|
|
101
146
|
defaultOptions: {
|
|
@@ -105,17 +150,24 @@ const createWrapper = (
|
|
|
105
150
|
},
|
|
106
151
|
});
|
|
107
152
|
const Wrapper = ({children}: {children: ReactNode}): JSX.Element => (
|
|
108
|
-
<
|
|
109
|
-
<
|
|
110
|
-
|
|
153
|
+
<QueryClientProvider client={queryClient}>
|
|
154
|
+
<URLStateProvider navigateTo={mockNavigateTo} paramPreferences={paramPreferences}>
|
|
155
|
+
{children}
|
|
156
|
+
</URLStateProvider>
|
|
157
|
+
</QueryClientProvider>
|
|
111
158
|
);
|
|
112
|
-
Wrapper.displayName = '
|
|
159
|
+
Wrapper.displayName = 'URLStateProviderWrapper';
|
|
113
160
|
return Wrapper;
|
|
114
161
|
};
|
|
115
162
|
|
|
116
163
|
describe('useQueryState', () => {
|
|
117
164
|
beforeEach(() => {
|
|
118
165
|
mockNavigateTo.mockClear();
|
|
166
|
+
Object.defineProperty(window, 'location', {
|
|
167
|
+
value: mockLocation,
|
|
168
|
+
writable: true,
|
|
169
|
+
});
|
|
170
|
+
mockLocation.search = '';
|
|
119
171
|
// Reset profile types mock state
|
|
120
172
|
setProfileTypesLoading(false);
|
|
121
173
|
setProfileTypesData(undefined);
|
|
@@ -143,12 +195,10 @@ describe('useQueryState', () => {
|
|
|
143
195
|
});
|
|
144
196
|
|
|
145
197
|
it('should handle suffix for comparison mode', () => {
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
),
|
|
151
|
-
});
|
|
198
|
+
mockLocation.search =
|
|
199
|
+
'?expression_a=process_cpu:cpu:nanoseconds:cpu:nanoseconds:delta{}&from_a=1000&to_a=2000';
|
|
200
|
+
|
|
201
|
+
const {result} = renderHook(() => useQueryState({suffix: '_a'}), {wrapper: createWrapper()});
|
|
152
202
|
|
|
153
203
|
const {querySelection} = result.current;
|
|
154
204
|
expect(querySelection.expression).toBe('process_cpu:cpu:nanoseconds:cpu:nanoseconds:delta{}');
|
|
@@ -186,11 +236,14 @@ describe('useQueryState', () => {
|
|
|
186
236
|
});
|
|
187
237
|
|
|
188
238
|
await waitFor(() => {
|
|
189
|
-
expect(
|
|
190
|
-
|
|
191
|
-
);
|
|
192
|
-
|
|
193
|
-
expect(
|
|
239
|
+
expect(mockNavigateTo).toHaveBeenCalled();
|
|
240
|
+
const [, params] = mockNavigateTo.mock.calls[mockNavigateTo.mock.calls.length - 1];
|
|
241
|
+
expect(params.expression).toBe('memory:alloc_objects:count:space:bytes:delta{}');
|
|
242
|
+
// Should set merge parameters for delta profile
|
|
243
|
+
expect(params).toHaveProperty('merge_from');
|
|
244
|
+
expect(params).toHaveProperty('merge_to');
|
|
245
|
+
expect(params.merge_from).toBe('1000000000');
|
|
246
|
+
expect(params.merge_to).toBe('2000000000');
|
|
194
247
|
});
|
|
195
248
|
});
|
|
196
249
|
|
|
@@ -211,9 +264,11 @@ describe('useQueryState', () => {
|
|
|
211
264
|
});
|
|
212
265
|
|
|
213
266
|
await waitFor(() => {
|
|
214
|
-
expect(
|
|
215
|
-
|
|
216
|
-
expect(
|
|
267
|
+
expect(mockNavigateTo).toHaveBeenCalled();
|
|
268
|
+
const [, params] = mockNavigateTo.mock.calls[mockNavigateTo.mock.calls.length - 1];
|
|
269
|
+
expect(params.from).toBe('3000');
|
|
270
|
+
expect(params.to).toBe('4000');
|
|
271
|
+
expect(params.time_selection).toBe('relative:minute|5');
|
|
217
272
|
});
|
|
218
273
|
});
|
|
219
274
|
|
|
@@ -234,8 +289,9 @@ describe('useQueryState', () => {
|
|
|
234
289
|
});
|
|
235
290
|
|
|
236
291
|
await waitFor(() => {
|
|
237
|
-
|
|
238
|
-
|
|
292
|
+
expect(mockNavigateTo).toHaveBeenCalled();
|
|
293
|
+
const [, params] = mockNavigateTo.mock.calls[mockNavigateTo.mock.calls.length - 1];
|
|
294
|
+
expect(params.sum_by).toBe('namespace,container');
|
|
239
295
|
});
|
|
240
296
|
});
|
|
241
297
|
|
|
@@ -257,8 +313,10 @@ describe('useQueryState', () => {
|
|
|
257
313
|
});
|
|
258
314
|
|
|
259
315
|
await waitFor(() => {
|
|
260
|
-
expect(
|
|
261
|
-
|
|
316
|
+
expect(mockNavigateTo).toHaveBeenCalled();
|
|
317
|
+
const [, params] = mockNavigateTo.mock.calls[mockNavigateTo.mock.calls.length - 1];
|
|
318
|
+
expect(params.merge_from).toBe('5000000000');
|
|
319
|
+
expect(params.merge_to).toBe('6000000000');
|
|
262
320
|
});
|
|
263
321
|
});
|
|
264
322
|
});
|
|
@@ -287,25 +345,22 @@ describe('useQueryState', () => {
|
|
|
287
345
|
});
|
|
288
346
|
|
|
289
347
|
await waitFor(() => {
|
|
290
|
-
//
|
|
291
|
-
expect(
|
|
292
|
-
|
|
293
|
-
);
|
|
294
|
-
expect(
|
|
295
|
-
expect(
|
|
296
|
-
expect(
|
|
297
|
-
|
|
298
|
-
expect(result.current.draftSelection.sumBy).toEqual(['pod', 'node']);
|
|
348
|
+
// Should only navigate once for all updates
|
|
349
|
+
expect(mockNavigateTo).toHaveBeenCalledTimes(1);
|
|
350
|
+
const [, params] = mockNavigateTo.mock.calls[0];
|
|
351
|
+
expect(params.expression).toBe('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
352
|
+
expect(params.from).toBe('7000');
|
|
353
|
+
expect(params.to).toBe('8000');
|
|
354
|
+
expect(params.time_selection).toBe('relative:minute|30');
|
|
355
|
+
expect(params.sum_by).toBe('pod,node');
|
|
299
356
|
});
|
|
300
357
|
});
|
|
301
358
|
|
|
302
359
|
it('should handle partial updates', async () => {
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
),
|
|
308
|
-
});
|
|
360
|
+
mockLocation.search =
|
|
361
|
+
'?expression=process_cpu:cpu:nanoseconds:cpu:nanoseconds:delta{}&from=1000&to=2000&time_selection=relative:hour|1';
|
|
362
|
+
|
|
363
|
+
const {result} = renderHook(() => useQueryState(), {wrapper: createWrapper()});
|
|
309
364
|
|
|
310
365
|
act(() => {
|
|
311
366
|
// Only update expression, other values should remain
|
|
@@ -324,12 +379,12 @@ describe('useQueryState', () => {
|
|
|
324
379
|
});
|
|
325
380
|
|
|
326
381
|
await waitFor(() => {
|
|
327
|
-
expect(
|
|
328
|
-
|
|
329
|
-
);
|
|
330
|
-
expect(
|
|
331
|
-
expect(
|
|
332
|
-
expect(
|
|
382
|
+
expect(mockNavigateTo).toHaveBeenCalled();
|
|
383
|
+
const [, params] = mockNavigateTo.mock.calls[mockNavigateTo.mock.calls.length - 1];
|
|
384
|
+
expect(params.expression).toBe('memory:inuse_space:bytes:space:bytes{}');
|
|
385
|
+
expect(params.from).toBe('1000');
|
|
386
|
+
expect(params.to).toBe('2000');
|
|
387
|
+
expect(params.time_selection).toBe('relative:hour|1');
|
|
333
388
|
});
|
|
334
389
|
});
|
|
335
390
|
|
|
@@ -350,23 +405,21 @@ describe('useQueryState', () => {
|
|
|
350
405
|
});
|
|
351
406
|
|
|
352
407
|
await waitFor(() => {
|
|
353
|
-
expect(
|
|
354
|
-
|
|
355
|
-
);
|
|
356
|
-
expect(
|
|
357
|
-
expect(
|
|
408
|
+
expect(mockNavigateTo).toHaveBeenCalled();
|
|
409
|
+
const [, params] = mockNavigateTo.mock.calls[mockNavigateTo.mock.calls.length - 1];
|
|
410
|
+
expect(params.expression).toBe('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
411
|
+
expect(params.merge_from).toBe('9000000000');
|
|
412
|
+
expect(params.merge_to).toBe('10000000000');
|
|
358
413
|
});
|
|
359
414
|
});
|
|
360
415
|
});
|
|
361
416
|
|
|
362
417
|
describe('Helper functions', () => {
|
|
363
418
|
it('should set profile name correctly', async () => {
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
),
|
|
369
|
-
});
|
|
419
|
+
mockLocation.search =
|
|
420
|
+
'?expression=process_cpu:cpu:nanoseconds:cpu:nanoseconds:delta{job="parca"}';
|
|
421
|
+
|
|
422
|
+
const {result} = renderHook(() => useQueryState(), {wrapper: createWrapper()});
|
|
370
423
|
|
|
371
424
|
act(() => {
|
|
372
425
|
result.current.setDraftProfileName('memory:inuse_space:bytes:space:bytes');
|
|
@@ -382,19 +435,16 @@ describe('useQueryState', () => {
|
|
|
382
435
|
});
|
|
383
436
|
|
|
384
437
|
await waitFor(() => {
|
|
385
|
-
expect(
|
|
386
|
-
|
|
387
|
-
);
|
|
438
|
+
expect(mockNavigateTo).toHaveBeenCalled();
|
|
439
|
+
const [, params] = mockNavigateTo.mock.calls[mockNavigateTo.mock.calls.length - 1];
|
|
440
|
+
expect(params.expression).toBe('memory:inuse_space:bytes:space:bytes{job="parca"}');
|
|
388
441
|
});
|
|
389
442
|
});
|
|
390
443
|
|
|
391
444
|
it('should set matchers correctly using draft', async () => {
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
'?expression=process_cpu:cpu:nanoseconds:cpu:nanoseconds:delta{}'
|
|
396
|
-
),
|
|
397
|
-
});
|
|
445
|
+
mockLocation.search = '?expression=process_cpu:cpu:nanoseconds:cpu:nanoseconds:delta{}';
|
|
446
|
+
|
|
447
|
+
const {result} = renderHook(() => useQueryState(), {wrapper: createWrapper()});
|
|
398
448
|
|
|
399
449
|
act(() => {
|
|
400
450
|
result.current.setDraftMatchers('namespace="default",pod="my-pod"');
|
|
@@ -404,6 +454,7 @@ describe('useQueryState', () => {
|
|
|
404
454
|
expect(result.current.draftSelection.expression).toBe(
|
|
405
455
|
'process_cpu:cpu:nanoseconds:cpu:nanoseconds:delta{namespace="default",pod="my-pod"}'
|
|
406
456
|
);
|
|
457
|
+
expect(mockNavigateTo).not.toHaveBeenCalled();
|
|
407
458
|
|
|
408
459
|
// Commit the draft
|
|
409
460
|
act(() => {
|
|
@@ -411,7 +462,9 @@ describe('useQueryState', () => {
|
|
|
411
462
|
});
|
|
412
463
|
|
|
413
464
|
await waitFor(() => {
|
|
414
|
-
expect(
|
|
465
|
+
expect(mockNavigateTo).toHaveBeenCalled();
|
|
466
|
+
const [, params] = mockNavigateTo.mock.calls[mockNavigateTo.mock.calls.length - 1];
|
|
467
|
+
expect(params.expression).toBe(
|
|
415
468
|
'process_cpu:cpu:nanoseconds:cpu:nanoseconds:delta{namespace="default",pod="my-pod"}'
|
|
416
469
|
);
|
|
417
470
|
});
|
|
@@ -435,13 +488,12 @@ describe('useQueryState', () => {
|
|
|
435
488
|
});
|
|
436
489
|
|
|
437
490
|
await waitFor(() => {
|
|
438
|
-
expect(
|
|
439
|
-
|
|
440
|
-
);
|
|
441
|
-
expect(
|
|
442
|
-
expect(
|
|
443
|
-
|
|
444
|
-
expect(result.current.draftSelection.sumBy).toEqual(['label_a']);
|
|
491
|
+
expect(mockNavigateTo).toHaveBeenCalled();
|
|
492
|
+
const [, params] = mockNavigateTo.mock.calls[mockNavigateTo.mock.calls.length - 1];
|
|
493
|
+
expect(params.expression_a).toBe('process_cpu:cpu:nanoseconds:cpu:nanoseconds:delta{}');
|
|
494
|
+
expect(params.from_a).toBe('1111');
|
|
495
|
+
expect(params.to_a).toBe('2222');
|
|
496
|
+
expect(params.sum_by_a).toBe('label_a');
|
|
445
497
|
});
|
|
446
498
|
});
|
|
447
499
|
|
|
@@ -461,13 +513,12 @@ describe('useQueryState', () => {
|
|
|
461
513
|
});
|
|
462
514
|
|
|
463
515
|
await waitFor(() => {
|
|
464
|
-
expect(
|
|
465
|
-
|
|
466
|
-
);
|
|
467
|
-
expect(
|
|
468
|
-
expect(
|
|
469
|
-
|
|
470
|
-
expect(result.current.draftSelection.sumBy).toEqual(['label_b']);
|
|
516
|
+
expect(mockNavigateTo).toHaveBeenCalled();
|
|
517
|
+
const [, params] = mockNavigateTo.mock.calls[mockNavigateTo.mock.calls.length - 1];
|
|
518
|
+
expect(params.expression_b).toBe('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
519
|
+
expect(params.from_b).toBe('3333');
|
|
520
|
+
expect(params.to_b).toBe('4444');
|
|
521
|
+
expect(params.sum_by_b).toBe('label_b');
|
|
471
522
|
});
|
|
472
523
|
});
|
|
473
524
|
});
|
|
@@ -483,30 +534,30 @@ describe('useQueryState', () => {
|
|
|
483
534
|
result.current.setDraftSumBy(['namespace', 'pod']);
|
|
484
535
|
});
|
|
485
536
|
|
|
537
|
+
// URL should not be updated yet
|
|
538
|
+
expect(mockNavigateTo).not.toHaveBeenCalled();
|
|
539
|
+
|
|
486
540
|
// Commit all changes at once
|
|
487
541
|
act(() => {
|
|
488
542
|
result.current.commitDraft();
|
|
489
543
|
});
|
|
490
544
|
|
|
491
|
-
//
|
|
545
|
+
// Now URL should be updated exactly once with all changes
|
|
492
546
|
await waitFor(() => {
|
|
493
|
-
expect(
|
|
494
|
-
|
|
495
|
-
);
|
|
496
|
-
expect(
|
|
497
|
-
expect(
|
|
498
|
-
|
|
499
|
-
expect(result.current.draftSelection.sumBy).toEqual(['namespace', 'pod']);
|
|
547
|
+
expect(mockNavigateTo).toHaveBeenCalledTimes(1);
|
|
548
|
+
const [, params] = mockNavigateTo.mock.calls[0];
|
|
549
|
+
expect(params.expression).toBe('memory:alloc_space:bytes:space:bytes:delta{}');
|
|
550
|
+
expect(params.from).toBe('5000');
|
|
551
|
+
expect(params.to).toBe('6000');
|
|
552
|
+
expect(params.sum_by).toBe('namespace,pod');
|
|
500
553
|
});
|
|
501
554
|
});
|
|
502
555
|
|
|
503
556
|
it('should handle draft profile name changes', () => {
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
),
|
|
509
|
-
});
|
|
557
|
+
mockLocation.search =
|
|
558
|
+
'?expression=process_cpu:cpu:nanoseconds:cpu:nanoseconds:delta{job="test"}';
|
|
559
|
+
|
|
560
|
+
const {result} = renderHook(() => useQueryState(), {wrapper: createWrapper()});
|
|
510
561
|
|
|
511
562
|
// Change profile name in draft
|
|
512
563
|
act(() => {
|
|
@@ -517,6 +568,9 @@ describe('useQueryState', () => {
|
|
|
517
568
|
expect(result.current.draftSelection.expression).toBe(
|
|
518
569
|
'memory:inuse_space:bytes:space:bytes{job="test"}'
|
|
519
570
|
);
|
|
571
|
+
|
|
572
|
+
// URL should not be updated yet
|
|
573
|
+
expect(mockNavigateTo).not.toHaveBeenCalled();
|
|
520
574
|
});
|
|
521
575
|
});
|
|
522
576
|
|
|
@@ -562,12 +616,10 @@ describe('useQueryState', () => {
|
|
|
562
616
|
});
|
|
563
617
|
|
|
564
618
|
it('should clear merge params for non-delta profiles', async () => {
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
),
|
|
570
|
-
});
|
|
619
|
+
mockLocation.search =
|
|
620
|
+
'?expression=memory:alloc_objects:count:space:bytes:delta{}&merge_from=1000000000&merge_to=2000000000';
|
|
621
|
+
|
|
622
|
+
const {result} = renderHook(() => useQueryState(), {wrapper: createWrapper()});
|
|
571
623
|
|
|
572
624
|
// Switch to non-delta profile (without :delta suffix) using draft
|
|
573
625
|
act(() => {
|
|
@@ -580,22 +632,19 @@ describe('useQueryState', () => {
|
|
|
580
632
|
});
|
|
581
633
|
|
|
582
634
|
await waitFor(() => {
|
|
583
|
-
expect(
|
|
584
|
-
|
|
585
|
-
);
|
|
586
|
-
|
|
587
|
-
expect(
|
|
588
|
-
expect(result.current.querySelection.mergeTo).toBeUndefined();
|
|
635
|
+
expect(mockNavigateTo).toHaveBeenCalled();
|
|
636
|
+
const [, params] = mockNavigateTo.mock.calls[mockNavigateTo.mock.calls.length - 1];
|
|
637
|
+
expect(params.expression).toBe('memory:inuse_space:bytes:space:bytes{}');
|
|
638
|
+
expect(params).not.toHaveProperty('merge_from');
|
|
639
|
+
expect(params).not.toHaveProperty('merge_to');
|
|
589
640
|
});
|
|
590
641
|
});
|
|
591
642
|
|
|
592
643
|
it('should preserve other URL parameters when updating', async () => {
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
),
|
|
598
|
-
});
|
|
644
|
+
mockLocation.search =
|
|
645
|
+
'?expression=process_cpu:cpu:nanoseconds:cpu:nanoseconds:delta{}&other_param=value&unrelated=test';
|
|
646
|
+
|
|
647
|
+
const {result} = renderHook(() => useQueryState(), {wrapper: createWrapper()});
|
|
599
648
|
|
|
600
649
|
// Update draft and commit
|
|
601
650
|
act(() => {
|
|
@@ -607,21 +656,21 @@ describe('useQueryState', () => {
|
|
|
607
656
|
});
|
|
608
657
|
|
|
609
658
|
await waitFor(() => {
|
|
610
|
-
expect(
|
|
611
|
-
|
|
612
|
-
);
|
|
659
|
+
expect(mockNavigateTo).toHaveBeenCalled();
|
|
660
|
+
const [, params] = mockNavigateTo.mock.calls[mockNavigateTo.mock.calls.length - 1];
|
|
661
|
+
expect(params.expression).toBe('memory:inuse_space:bytes:space:bytes{}');
|
|
662
|
+
expect(params.other_param).toBe('value');
|
|
663
|
+
expect(params.unrelated).toBe('test');
|
|
613
664
|
});
|
|
614
665
|
});
|
|
615
666
|
});
|
|
616
667
|
|
|
617
668
|
describe('Commit with refreshed time range (time range re-evaluation)', () => {
|
|
618
669
|
it('should use refreshed time range values instead of draft state when provided', async () => {
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
),
|
|
624
|
-
});
|
|
670
|
+
mockLocation.search =
|
|
671
|
+
'?expression=process_cpu:cpu:nanoseconds:cpu:nanoseconds{}&from=1000&to=2000&time_selection=relative:minute|15';
|
|
672
|
+
|
|
673
|
+
const {result} = renderHook(() => useQueryState(), {wrapper: createWrapper()});
|
|
625
674
|
|
|
626
675
|
// Draft state has original values
|
|
627
676
|
expect(result.current.draftSelection.from).toBe(1000);
|
|
@@ -638,10 +687,12 @@ describe('useQueryState', () => {
|
|
|
638
687
|
});
|
|
639
688
|
|
|
640
689
|
await waitFor(() => {
|
|
690
|
+
expect(mockNavigateTo).toHaveBeenCalled();
|
|
691
|
+
const [, params] = mockNavigateTo.mock.calls[mockNavigateTo.mock.calls.length - 1];
|
|
641
692
|
// Should use refreshed time range values, not draft values
|
|
642
|
-
expect(
|
|
643
|
-
expect(
|
|
644
|
-
expect(
|
|
693
|
+
expect(params.from).toBe('5000');
|
|
694
|
+
expect(params.to).toBe('6000');
|
|
695
|
+
expect(params.time_selection).toBe('relative:minute|15');
|
|
645
696
|
});
|
|
646
697
|
});
|
|
647
698
|
|
|
@@ -667,8 +718,7 @@ describe('useQueryState', () => {
|
|
|
667
718
|
});
|
|
668
719
|
|
|
669
720
|
await waitFor(() => {
|
|
670
|
-
expect(
|
|
671
|
-
expect(String(result.current.querySelection.to)).toBe('4000');
|
|
721
|
+
expect(mockNavigateTo).toHaveBeenCalled();
|
|
672
722
|
});
|
|
673
723
|
|
|
674
724
|
// Draft state should be updated with the refreshed time range
|
|
@@ -677,12 +727,12 @@ describe('useQueryState', () => {
|
|
|
677
727
|
});
|
|
678
728
|
|
|
679
729
|
it('should trigger navigation even when expression unchanged (time re-evaluation)', async () => {
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
730
|
+
mockLocation.search =
|
|
731
|
+
'?expression=process_cpu:cpu:nanoseconds:cpu:nanoseconds{}&from=1000&to=2000&time_selection=relative:minute|5';
|
|
732
|
+
|
|
733
|
+
const {result} = renderHook(() => useQueryState(), {wrapper: createWrapper()});
|
|
734
|
+
|
|
735
|
+
mockNavigateTo.mockClear();
|
|
686
736
|
|
|
687
737
|
// First commit with new time values
|
|
688
738
|
act(() => {
|
|
@@ -694,10 +744,15 @@ describe('useQueryState', () => {
|
|
|
694
744
|
});
|
|
695
745
|
|
|
696
746
|
await waitFor(() => {
|
|
697
|
-
expect(
|
|
698
|
-
expect(String(result.current.querySelection.to)).toBe('6000');
|
|
747
|
+
expect(mockNavigateTo).toHaveBeenCalledTimes(1);
|
|
699
748
|
});
|
|
700
749
|
|
|
750
|
+
const firstCallParams = mockNavigateTo.mock.calls[0][1];
|
|
751
|
+
expect(firstCallParams.from).toBe('5000');
|
|
752
|
+
expect(firstCallParams.to).toBe('6000');
|
|
753
|
+
|
|
754
|
+
mockNavigateTo.mockClear();
|
|
755
|
+
|
|
701
756
|
// Second commit with different time values (simulating clicking Search again)
|
|
702
757
|
act(() => {
|
|
703
758
|
result.current.commitDraft({
|
|
@@ -708,9 +763,15 @@ describe('useQueryState', () => {
|
|
|
708
763
|
});
|
|
709
764
|
|
|
710
765
|
await waitFor(() => {
|
|
711
|
-
expect(
|
|
712
|
-
expect(String(result.current.querySelection.to)).toBe('8000');
|
|
766
|
+
expect(mockNavigateTo).toHaveBeenCalledTimes(1);
|
|
713
767
|
});
|
|
768
|
+
|
|
769
|
+
const secondCallParams = mockNavigateTo.mock.calls[0][1];
|
|
770
|
+
expect(secondCallParams.from).toBe('7000');
|
|
771
|
+
expect(secondCallParams.to).toBe('8000');
|
|
772
|
+
|
|
773
|
+
// Verify that navigation was called both times despite expression being unchanged
|
|
774
|
+
expect(firstCallParams.from).not.toBe(secondCallParams.from);
|
|
714
775
|
});
|
|
715
776
|
|
|
716
777
|
it('should auto-calculate merge params for delta profiles when using refreshed time range', async () => {
|
|
@@ -734,19 +795,20 @@ describe('useQueryState', () => {
|
|
|
734
795
|
});
|
|
735
796
|
|
|
736
797
|
await waitFor(() => {
|
|
798
|
+
expect(mockNavigateTo).toHaveBeenCalled();
|
|
799
|
+
const [, params] = mockNavigateTo.mock.calls[mockNavigateTo.mock.calls.length - 1];
|
|
800
|
+
|
|
737
801
|
// Verify merge params are calculated from refreshed time range
|
|
738
|
-
expect(
|
|
739
|
-
expect(
|
|
802
|
+
expect(params.merge_from).toBe('5000000000'); // 5000ms * 1_000_000
|
|
803
|
+
expect(params.merge_to).toBe('6000000000'); // 6000ms * 1_000_000
|
|
740
804
|
});
|
|
741
805
|
});
|
|
742
806
|
|
|
743
807
|
it('should use draft values when refreshedTimeRange is not provided', async () => {
|
|
744
|
-
|
|
745
|
-
|
|
746
|
-
|
|
747
|
-
|
|
748
|
-
),
|
|
749
|
-
});
|
|
808
|
+
mockLocation.search =
|
|
809
|
+
'?expression=memory:inuse_space:bytes:space:bytes{}&from=1000&to=2000&time_selection=relative:hour|1';
|
|
810
|
+
|
|
811
|
+
const {result} = renderHook(() => useQueryState(), {wrapper: createWrapper()});
|
|
750
812
|
|
|
751
813
|
// Change draft values
|
|
752
814
|
act(() => {
|
|
@@ -759,10 +821,13 @@ describe('useQueryState', () => {
|
|
|
759
821
|
});
|
|
760
822
|
|
|
761
823
|
await waitFor(() => {
|
|
824
|
+
expect(mockNavigateTo).toHaveBeenCalled();
|
|
825
|
+
const [, params] = mockNavigateTo.mock.calls[mockNavigateTo.mock.calls.length - 1];
|
|
826
|
+
|
|
762
827
|
// Should use updated draft values
|
|
763
|
-
expect(
|
|
764
|
-
expect(
|
|
765
|
-
expect(
|
|
828
|
+
expect(params.from).toBe('3000');
|
|
829
|
+
expect(params.to).toBe('4000');
|
|
830
|
+
expect(params.time_selection).toBe('relative:minute|30');
|
|
766
831
|
});
|
|
767
832
|
});
|
|
768
833
|
});
|
|
@@ -770,11 +835,11 @@ describe('useQueryState', () => {
|
|
|
770
835
|
describe('State persistence after page reload', () => {
|
|
771
836
|
it('should retain committed values after page reload simulation', async () => {
|
|
772
837
|
// Initial state (using delta profile since sumBy only applies to delta)
|
|
838
|
+
mockLocation.search =
|
|
839
|
+
'?expression=process_cpu:cpu:nanoseconds:cpu:nanoseconds:delta{}&from=1000&to=2000';
|
|
840
|
+
|
|
773
841
|
const {result: result1, unmount} = renderHook(() => useQueryState(), {
|
|
774
|
-
wrapper: createWrapper(
|
|
775
|
-
{},
|
|
776
|
-
'?expression=process_cpu:cpu:nanoseconds:cpu:nanoseconds:delta{}&from=1000&to=2000'
|
|
777
|
-
),
|
|
842
|
+
wrapper: createWrapper(),
|
|
778
843
|
});
|
|
779
844
|
|
|
780
845
|
// User makes changes to draft (using delta profile since sumBy only applies to delta)
|
|
@@ -790,30 +855,31 @@ describe('useQueryState', () => {
|
|
|
790
855
|
});
|
|
791
856
|
|
|
792
857
|
await waitFor(() => {
|
|
793
|
-
expect(
|
|
794
|
-
'memory:alloc_space:bytes:space:bytes:delta{}'
|
|
795
|
-
);
|
|
858
|
+
expect(mockNavigateTo).toHaveBeenCalled();
|
|
796
859
|
});
|
|
797
860
|
|
|
798
|
-
//
|
|
861
|
+
// Get the params that were committed to URL
|
|
862
|
+
const committedParams = mockNavigateTo.mock.calls[mockNavigateTo.mock.calls.length - 1][1];
|
|
863
|
+
|
|
864
|
+
// Simulate page reload by updating mockLocation.search with committed values
|
|
799
865
|
const queryString = new URLSearchParams({
|
|
800
|
-
expression:
|
|
801
|
-
from:
|
|
802
|
-
to:
|
|
803
|
-
time_selection:
|
|
804
|
-
sum_by:
|
|
866
|
+
expression: committedParams.expression as string,
|
|
867
|
+
from: committedParams.from as string,
|
|
868
|
+
to: committedParams.to as string,
|
|
869
|
+
time_selection: committedParams.time_selection as string,
|
|
870
|
+
sum_by: committedParams.sum_by as string,
|
|
805
871
|
}).toString();
|
|
806
872
|
|
|
873
|
+
mockLocation.search = `?${queryString}`;
|
|
874
|
+
|
|
807
875
|
// Unmount the old hook instance
|
|
808
876
|
unmount();
|
|
809
877
|
|
|
810
878
|
// Clear navigation mock to verify no new navigation on reload
|
|
811
879
|
mockNavigateTo.mockClear();
|
|
812
880
|
|
|
813
|
-
// Create new hook instance (simulating page reload)
|
|
814
|
-
const {result: result2} = renderHook(() => useQueryState(), {
|
|
815
|
-
wrapper: createWrapper({}, `?${queryString}`),
|
|
816
|
-
});
|
|
881
|
+
// Create new hook instance (simulating page reload)
|
|
882
|
+
const {result: result2} = renderHook(() => useQueryState(), {wrapper: createWrapper()});
|
|
817
883
|
|
|
818
884
|
// Verify state is loaded from URL after "reload"
|
|
819
885
|
expect(result2.current.querySelection.expression).toBe(
|
|
@@ -822,6 +888,7 @@ describe('useQueryState', () => {
|
|
|
822
888
|
expect(result2.current.querySelection.from).toBe(5000);
|
|
823
889
|
expect(result2.current.querySelection.to).toBe(6000);
|
|
824
890
|
expect(result2.current.querySelection.timeSelection).toBe('relative:minute|15');
|
|
891
|
+
expect(result2.current.querySelection.sumBy).toEqual(['namespace', 'pod']);
|
|
825
892
|
|
|
826
893
|
// Draft should be synced with URL state on page load
|
|
827
894
|
expect(result2.current.draftSelection.expression).toBe(
|
|
@@ -829,15 +896,19 @@ describe('useQueryState', () => {
|
|
|
829
896
|
);
|
|
830
897
|
expect(result2.current.draftSelection.from).toBe(5000);
|
|
831
898
|
expect(result2.current.draftSelection.to).toBe(6000);
|
|
899
|
+
expect(result2.current.draftSelection.sumBy).toEqual(['namespace', 'pod']);
|
|
900
|
+
|
|
901
|
+
// No navigation should occur on page load
|
|
902
|
+
expect(mockNavigateTo).not.toHaveBeenCalled();
|
|
832
903
|
});
|
|
833
904
|
|
|
834
905
|
it('should preserve delta profile merge params after reload', async () => {
|
|
835
906
|
// Initial state with delta profile
|
|
907
|
+
mockLocation.search =
|
|
908
|
+
'?expression=process_cpu:cpu:nanoseconds:cpu:nanoseconds:delta{}&from=1000&to=2000';
|
|
909
|
+
|
|
836
910
|
const {result: result1, unmount} = renderHook(() => useQueryState(), {
|
|
837
|
-
wrapper: createWrapper(
|
|
838
|
-
{},
|
|
839
|
-
'?expression=process_cpu:cpu:nanoseconds:cpu:nanoseconds:delta{}&from=1000&to=2000'
|
|
840
|
-
),
|
|
911
|
+
wrapper: createWrapper(),
|
|
841
912
|
});
|
|
842
913
|
|
|
843
914
|
// Commit with time override
|
|
@@ -850,27 +921,31 @@ describe('useQueryState', () => {
|
|
|
850
921
|
});
|
|
851
922
|
|
|
852
923
|
await waitFor(() => {
|
|
853
|
-
expect(
|
|
854
|
-
expect(result1.current.querySelection.mergeTo).toBe('6000000000');
|
|
924
|
+
expect(mockNavigateTo).toHaveBeenCalled();
|
|
855
925
|
});
|
|
856
926
|
|
|
927
|
+
const committedParams = mockNavigateTo.mock.calls[mockNavigateTo.mock.calls.length - 1][1];
|
|
928
|
+
|
|
929
|
+
// Verify merge params were set
|
|
930
|
+
expect(committedParams.merge_from).toBe('5000000000');
|
|
931
|
+
expect(committedParams.merge_to).toBe('6000000000');
|
|
932
|
+
|
|
857
933
|
// Simulate page reload with all params including merge params
|
|
858
934
|
const queryString = new URLSearchParams({
|
|
859
|
-
expression:
|
|
860
|
-
from:
|
|
861
|
-
to:
|
|
862
|
-
time_selection:
|
|
863
|
-
merge_from:
|
|
864
|
-
merge_to:
|
|
935
|
+
expression: committedParams.expression as string,
|
|
936
|
+
from: committedParams.from as string,
|
|
937
|
+
to: committedParams.to as string,
|
|
938
|
+
time_selection: committedParams.time_selection as string,
|
|
939
|
+
merge_from: committedParams.merge_from as string,
|
|
940
|
+
merge_to: committedParams.merge_to as string,
|
|
865
941
|
}).toString();
|
|
866
942
|
|
|
943
|
+
mockLocation.search = `?${queryString}`;
|
|
867
944
|
unmount();
|
|
868
945
|
mockNavigateTo.mockClear();
|
|
869
946
|
|
|
870
947
|
// Create new hook instance
|
|
871
|
-
const {result: result2} = renderHook(() => useQueryState(), {
|
|
872
|
-
wrapper: createWrapper({}, `?${queryString}`),
|
|
873
|
-
});
|
|
948
|
+
const {result: result2} = renderHook(() => useQueryState(), {wrapper: createWrapper()});
|
|
874
949
|
|
|
875
950
|
// Verify merge params are preserved
|
|
876
951
|
expect(result2.current.querySelection.mergeFrom).toBe('5000000000');
|
|
@@ -891,12 +966,10 @@ describe('useQueryState', () => {
|
|
|
891
966
|
|
|
892
967
|
it('should compute ProfileSelection from URL params', () => {
|
|
893
968
|
// Set URL with ProfileSelection params - using valid profile type
|
|
894
|
-
|
|
895
|
-
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
),
|
|
899
|
-
});
|
|
969
|
+
mockLocation.search =
|
|
970
|
+
'?merge_from_a=1234567890&merge_to_a=9876543210&selection_a=process_cpu:cpu:nanoseconds:cpu:nanoseconds:delta{pod="test"}';
|
|
971
|
+
|
|
972
|
+
const {result} = renderHook(() => useQueryState({suffix: '_a'}), {wrapper: createWrapper()});
|
|
900
973
|
|
|
901
974
|
const {profileSelection} = result.current;
|
|
902
975
|
expect(profileSelection).not.toBeNull();
|
|
@@ -933,14 +1006,13 @@ describe('useQueryState', () => {
|
|
|
933
1006
|
});
|
|
934
1007
|
|
|
935
1008
|
await waitFor(() => {
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
|
|
939
|
-
expect(historyParams?.selection).toBe(
|
|
1009
|
+
expect(mockNavigateTo).toHaveBeenCalled();
|
|
1010
|
+
const [, params] = mockNavigateTo.mock.calls[mockNavigateTo.mock.calls.length - 1];
|
|
1011
|
+
expect(params.selection_a).toBe(
|
|
940
1012
|
'memory:inuse_space:bytes:space:bytes{namespace="default"}'
|
|
941
1013
|
);
|
|
942
|
-
expect(
|
|
943
|
-
expect(
|
|
1014
|
+
expect(params.merge_from_a).toBe('5000000000');
|
|
1015
|
+
expect(params.merge_to_a).toBe('6000000000');
|
|
944
1016
|
});
|
|
945
1017
|
});
|
|
946
1018
|
|
|
@@ -962,25 +1034,20 @@ describe('useQueryState', () => {
|
|
|
962
1034
|
});
|
|
963
1035
|
|
|
964
1036
|
await waitFor(() => {
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
expect(
|
|
969
|
-
|
|
970
|
-
);
|
|
971
|
-
expect(historyParams?.merge_from).toBe('7000000000');
|
|
972
|
-
expect(historyParams?.merge_to).toBe('8000000000');
|
|
1037
|
+
expect(mockNavigateTo).toHaveBeenCalled();
|
|
1038
|
+
const [, params] = mockNavigateTo.mock.calls[mockNavigateTo.mock.calls.length - 1];
|
|
1039
|
+
expect(params.selection_b).toBe('process_cpu:cpu:nanoseconds:cpu:nanoseconds{job="test"}');
|
|
1040
|
+
expect(params.merge_from_b).toBe('7000000000');
|
|
1041
|
+
expect(params.merge_to_b).toBe('8000000000');
|
|
973
1042
|
});
|
|
974
1043
|
});
|
|
975
1044
|
|
|
976
1045
|
it('should clear ProfileSelection when commitDraft is called', async () => {
|
|
977
1046
|
// Start with a ProfileSelection in URL - using valid profile type
|
|
978
|
-
|
|
979
|
-
|
|
980
|
-
|
|
981
|
-
|
|
982
|
-
),
|
|
983
|
-
});
|
|
1047
|
+
mockLocation.search =
|
|
1048
|
+
'?expression_a=process_cpu:cpu:nanoseconds:cpu:nanoseconds{}&merge_from_a=1000000000&merge_to_a=2000000000&selection_a=process_cpu:cpu:nanoseconds:cpu:nanoseconds{pod="test"}';
|
|
1049
|
+
|
|
1050
|
+
const {result} = renderHook(() => useQueryState({suffix: '_a'}), {wrapper: createWrapper()});
|
|
984
1051
|
|
|
985
1052
|
// Verify ProfileSelection exists
|
|
986
1053
|
expect(result.current.profileSelection).not.toBeNull();
|
|
@@ -996,23 +1063,22 @@ describe('useQueryState', () => {
|
|
|
996
1063
|
});
|
|
997
1064
|
|
|
998
1065
|
await waitFor(() => {
|
|
999
|
-
|
|
1000
|
-
|
|
1066
|
+
expect(mockNavigateTo).toHaveBeenCalled();
|
|
1067
|
+
const [, params] = mockNavigateTo.mock.calls[mockNavigateTo.mock.calls.length - 1];
|
|
1068
|
+
|
|
1069
|
+
// ProfileSelection params should be cleared
|
|
1070
|
+
expect(params).not.toHaveProperty('selection_a');
|
|
1001
1071
|
|
|
1002
1072
|
// But QuerySelection params should still be present
|
|
1003
|
-
expect(
|
|
1004
|
-
'memory:inuse_space:bytes:space:bytes{}'
|
|
1005
|
-
);
|
|
1073
|
+
expect(params.expression_a).toBe('memory:inuse_space:bytes:space:bytes{}');
|
|
1006
1074
|
});
|
|
1007
1075
|
});
|
|
1008
1076
|
|
|
1009
1077
|
it('should handle ProfileSelection with delta profiles correctly', () => {
|
|
1010
|
-
|
|
1011
|
-
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
),
|
|
1015
|
-
});
|
|
1078
|
+
mockLocation.search =
|
|
1079
|
+
'?merge_from_a=1000000000&merge_to_a=2000000000&selection_a=process_cpu:cpu:nanoseconds:cpu:nanoseconds:delta{node="worker"}';
|
|
1080
|
+
|
|
1081
|
+
const {result} = renderHook(() => useQueryState({suffix: '_a'}), {wrapper: createWrapper()});
|
|
1016
1082
|
|
|
1017
1083
|
const {profileSelection} = result.current;
|
|
1018
1084
|
expect(profileSelection).not.toBeNull();
|
|
@@ -1047,27 +1113,24 @@ describe('useQueryState', () => {
|
|
|
1047
1113
|
});
|
|
1048
1114
|
|
|
1049
1115
|
await waitFor(() => {
|
|
1050
|
-
expect(
|
|
1116
|
+
expect(mockNavigateTo).toHaveBeenCalled();
|
|
1051
1117
|
});
|
|
1052
1118
|
|
|
1053
|
-
|
|
1054
|
-
const historyParams = result1.current.profileSelection?.HistoryParams();
|
|
1055
|
-
const selectionA = historyParams?.selection ?? '';
|
|
1056
|
-
const mergeFromA = historyParams?.merge_from ?? '';
|
|
1057
|
-
const mergeToA = historyParams?.merge_to ?? '';
|
|
1119
|
+
const committedParams = mockNavigateTo.mock.calls[mockNavigateTo.mock.calls.length - 1][1];
|
|
1058
1120
|
|
|
1121
|
+
// Simulate page reload by updating mockLocation.search
|
|
1122
|
+
const selectionA = String(committedParams.selection_a ?? '');
|
|
1123
|
+
const mergeFromA = String(committedParams.merge_from_a ?? '');
|
|
1124
|
+
const mergeToA = String(committedParams.merge_to_a ?? '');
|
|
1125
|
+
mockLocation.search = `?selection_a=${encodeURIComponent(
|
|
1126
|
+
selectionA
|
|
1127
|
+
)}&merge_from_a=${mergeFromA}&merge_to_a=${mergeToA}`;
|
|
1059
1128
|
unmount();
|
|
1060
1129
|
mockNavigateTo.mockClear();
|
|
1061
1130
|
|
|
1062
|
-
// Create new hook instance (simulating page reload)
|
|
1131
|
+
// Create new hook instance (simulating page reload)
|
|
1063
1132
|
const {result: result2} = renderHook(() => useQueryState({suffix: '_a'}), {
|
|
1064
|
-
wrapper: createWrapper(
|
|
1065
|
-
{},
|
|
1066
|
-
// eslint-disable-next-line @typescript-eslint/restrict-template-expressions
|
|
1067
|
-
`?selection_a=${encodeURIComponent(selectionA)}&merge_from_a=${
|
|
1068
|
-
mergeFromA as string
|
|
1069
|
-
}&merge_to_a=${mergeToA as string}`
|
|
1070
|
-
),
|
|
1133
|
+
wrapper: createWrapper(),
|
|
1071
1134
|
});
|
|
1072
1135
|
|
|
1073
1136
|
// Verify ProfileSelection is loaded from URL after reload
|
|
@@ -1076,12 +1139,13 @@ describe('useQueryState', () => {
|
|
|
1076
1139
|
|
|
1077
1140
|
// Use interface methods to test
|
|
1078
1141
|
expect(profileSelection?.Type()).toBe('merge');
|
|
1079
|
-
const
|
|
1080
|
-
expect(
|
|
1081
|
-
expect(
|
|
1082
|
-
expect(
|
|
1083
|
-
|
|
1084
|
-
|
|
1142
|
+
const historyParams = profileSelection?.HistoryParams();
|
|
1143
|
+
expect(historyParams?.merge_from).toBe('3000000000');
|
|
1144
|
+
expect(historyParams?.merge_to).toBe('4000000000');
|
|
1145
|
+
expect(historyParams?.selection).toBe('memory:alloc_objects:count:space:bytes{pod="test"}');
|
|
1146
|
+
|
|
1147
|
+
// No navigation should occur on page load
|
|
1148
|
+
expect(mockNavigateTo).not.toHaveBeenCalled();
|
|
1085
1149
|
});
|
|
1086
1150
|
|
|
1087
1151
|
it('should handle independent ProfileSelection for both sides in comparison mode', async () => {
|
|
@@ -1117,9 +1181,11 @@ describe('useQueryState', () => {
|
|
|
1117
1181
|
});
|
|
1118
1182
|
|
|
1119
1183
|
await waitFor(() => {
|
|
1120
|
-
expect(
|
|
1184
|
+
expect(mockNavigateTo).toHaveBeenCalled();
|
|
1121
1185
|
});
|
|
1122
1186
|
|
|
1187
|
+
mockNavigateTo.mockClear();
|
|
1188
|
+
|
|
1123
1189
|
// Set ProfileSelection for side B
|
|
1124
1190
|
act(() => {
|
|
1125
1191
|
result.current.stateB.setProfileSelection(
|
|
@@ -1129,7 +1195,19 @@ describe('useQueryState', () => {
|
|
|
1129
1195
|
);
|
|
1130
1196
|
});
|
|
1131
1197
|
|
|
1132
|
-
|
|
1198
|
+
await waitFor(() => {
|
|
1199
|
+
expect(mockNavigateTo).toHaveBeenCalled();
|
|
1200
|
+
const [, params] = mockNavigateTo.mock.calls[mockNavigateTo.mock.calls.length - 1];
|
|
1201
|
+
|
|
1202
|
+
// Both selections should be in URL with different suffixes
|
|
1203
|
+
expect(params.selection_a).toBe('process_cpu:cpu:nanoseconds:cpu:nanoseconds{pod="app-a"}');
|
|
1204
|
+
expect(params.selection_b).toBe('process_cpu:cpu:nanoseconds:cpu:nanoseconds{pod="app-b"}');
|
|
1205
|
+
expect(params.merge_from_a).toBe('1000000000');
|
|
1206
|
+
expect(params.merge_from_b).toBe('3000000000');
|
|
1207
|
+
});
|
|
1208
|
+
|
|
1209
|
+
// The mockNavigateTo automatically updates mockLocation.search, so the URL change
|
|
1210
|
+
// should propagate to the hooks automatically. Verify both ProfileSelections exist.
|
|
1133
1211
|
await waitFor(() => {
|
|
1134
1212
|
expect(result.current.stateA.profileSelection).not.toBeNull();
|
|
1135
1213
|
expect(result.current.stateB.profileSelection).not.toBeNull();
|
|
@@ -1138,9 +1216,9 @@ describe('useQueryState', () => {
|
|
|
1138
1216
|
|
|
1139
1217
|
it('should return null ProfileSelection when only partial params exist', () => {
|
|
1140
1218
|
// Missing selection param
|
|
1141
|
-
|
|
1142
|
-
|
|
1143
|
-
});
|
|
1219
|
+
mockLocation.search = '?merge_from_a=1000000000&merge_to_a=2000000000';
|
|
1220
|
+
|
|
1221
|
+
const {result} = renderHook(() => useQueryState({suffix: '_a'}), {wrapper: createWrapper()});
|
|
1144
1222
|
|
|
1145
1223
|
expect(result.current.profileSelection).toBeNull();
|
|
1146
1224
|
});
|
|
@@ -1159,12 +1237,10 @@ describe('useQueryState', () => {
|
|
|
1159
1237
|
});
|
|
1160
1238
|
|
|
1161
1239
|
await waitFor(() => {
|
|
1162
|
-
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
expect(historyParams?.selection).toBe(
|
|
1167
|
-
'memory:alloc_objects:count:space:bytes:delta{namespace="default", pod="app-1", container="main"}'
|
|
1240
|
+
expect(mockNavigateTo).toHaveBeenCalled();
|
|
1241
|
+
const [, params] = mockNavigateTo.mock.calls[mockNavigateTo.mock.calls.length - 1];
|
|
1242
|
+
expect(params.selection_a).toBe(
|
|
1243
|
+
'memory:alloc_objects:count:space:bytes:delta{namespace="default",pod="app-1",container="main"}'
|
|
1168
1244
|
);
|
|
1169
1245
|
});
|
|
1170
1246
|
});
|
|
@@ -1183,24 +1259,20 @@ describe('useQueryState', () => {
|
|
|
1183
1259
|
});
|
|
1184
1260
|
|
|
1185
1261
|
await waitFor(() => {
|
|
1186
|
-
|
|
1187
|
-
expect(
|
|
1188
|
-
const
|
|
1189
|
-
expect(
|
|
1190
|
-
|
|
1191
|
-
);
|
|
1192
|
-
expect(historyParams?.merge_from).toBe('1000000000');
|
|
1193
|
-
expect(historyParams?.merge_to).toBe('2000000000');
|
|
1262
|
+
// Should only navigate once despite setting 3 params (selection, merge_from, merge_to)
|
|
1263
|
+
expect(mockNavigateTo).toHaveBeenCalledTimes(1);
|
|
1264
|
+
const [, params] = mockNavigateTo.mock.calls[0];
|
|
1265
|
+
expect(params.selection_a).toBe('process_cpu:cpu:nanoseconds:cpu:nanoseconds{job="test"}');
|
|
1266
|
+
expect(params.merge_from_a).toBe('1000000000');
|
|
1267
|
+
expect(params.merge_to_a).toBe('2000000000');
|
|
1194
1268
|
});
|
|
1195
1269
|
});
|
|
1196
1270
|
|
|
1197
1271
|
it('should preserve other URL params when setting ProfileSelection', async () => {
|
|
1198
|
-
|
|
1199
|
-
|
|
1200
|
-
|
|
1201
|
-
|
|
1202
|
-
),
|
|
1203
|
-
});
|
|
1272
|
+
mockLocation.search =
|
|
1273
|
+
'?expression_a=process_cpu:cpu:nanoseconds:cpu:nanoseconds{}&other_param=value&unrelated=test';
|
|
1274
|
+
|
|
1275
|
+
const {result} = renderHook(() => useQueryState({suffix: '_a'}), {wrapper: createWrapper()});
|
|
1204
1276
|
|
|
1205
1277
|
const mockQuery = {
|
|
1206
1278
|
toString: () => 'process_cpu:cpu:nanoseconds:cpu:nanoseconds{pod="test"}',
|
|
@@ -1212,18 +1284,16 @@ describe('useQueryState', () => {
|
|
|
1212
1284
|
});
|
|
1213
1285
|
|
|
1214
1286
|
await waitFor(() => {
|
|
1287
|
+
expect(mockNavigateTo).toHaveBeenCalled();
|
|
1288
|
+
const [, params] = mockNavigateTo.mock.calls[mockNavigateTo.mock.calls.length - 1];
|
|
1289
|
+
|
|
1215
1290
|
// ProfileSelection params should be set
|
|
1216
|
-
|
|
1217
|
-
expect(profileSelection).not.toBeNull();
|
|
1218
|
-
const historyParams = profileSelection?.HistoryParams();
|
|
1219
|
-
expect(historyParams?.selection).toBe(
|
|
1220
|
-
'process_cpu:cpu:nanoseconds:cpu:nanoseconds{pod="test"}'
|
|
1221
|
-
);
|
|
1291
|
+
expect(params.selection_a).toBe('process_cpu:cpu:nanoseconds:cpu:nanoseconds{pod="test"}');
|
|
1222
1292
|
|
|
1223
|
-
//
|
|
1224
|
-
expect(
|
|
1225
|
-
|
|
1226
|
-
);
|
|
1293
|
+
// Other params should be preserved
|
|
1294
|
+
expect(params.expression_a).toBe('process_cpu:cpu:nanoseconds:cpu:nanoseconds{}');
|
|
1295
|
+
expect(params.other_param).toBe('value');
|
|
1296
|
+
expect(params.unrelated).toBe('test');
|
|
1227
1297
|
});
|
|
1228
1298
|
});
|
|
1229
1299
|
});
|