@cdc/dashboard 4.26.1 → 4.26.3
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/LICENSE +201 -0
- package/dist/cdcdashboard-8NmHlKRI.es.js +15 -0
- package/dist/cdcdashboard-BPoPzKPz.es.js +6 -0
- package/dist/{cdcdashboard-dgT_1dIT.es.js → cdcdashboard-DQ00cQCm.es.js} +1 -20
- package/dist/cdcdashboard-jiQQPkty.es.js +6 -0
- package/dist/cdcdashboard-vr9HZwRt.es.js +6 -0
- package/dist/cdcdashboard.js +80971 -83096
- package/examples/custom/css/respiratory.css +1 -1
- package/examples/data/data-with-metadata.json +18 -0
- package/examples/default.json +492 -132
- package/examples/nested-dropdown.json +6985 -0
- package/examples/private/abc.json +467 -0
- package/examples/private/dash.json +12696 -0
- package/examples/private/inline-markup.json +775 -0
- package/examples/private/npcr.json +1 -0
- package/examples/private/recent-update.json +1456 -0
- package/examples/private/test.json +125407 -0
- package/examples/private/timeline-data.json +4994 -0
- package/examples/private/timeline.json +1708 -0
- package/examples/private/toggle.json +10137 -0
- package/examples/test-api-filter-reset.json +8 -4
- package/examples/tp5-gauges.json +196 -0
- package/examples/tp5-test.json +266 -0
- package/index.html +1 -29
- package/package.json +38 -40
- package/src/CdcDashboard.tsx +2 -1
- package/src/CdcDashboardComponent.tsx +47 -30
- package/src/_stories/Dashboard.DataSetup.stories.tsx +8 -2
- package/src/_stories/Dashboard.Pages.stories.tsx +22 -0
- package/src/_stories/Dashboard.stories.tsx +4501 -80
- package/src/_stories/_mock/dashboard-line-chart-angles.json +1030 -0
- package/src/_stories/_mock/tab-simple-filter.json +153 -0
- package/src/_stories/_mock/tp5-test.json +267 -0
- package/src/components/DashboardFilters/DashboardFilters.tsx +19 -3
- package/src/components/DashboardFilters/DashboardFiltersEditor/DashboardFiltersEditor.tsx +10 -4
- package/src/components/DashboardFilters/DashboardFiltersEditor/components/APIModal.tsx +1 -1
- package/src/components/DashboardFilters/DashboardFiltersEditor/components/FilterEditor.tsx +6 -3
- package/src/components/DashboardFilters/DashboardFiltersEditor/components/NestedDropDownDashboard.tsx +13 -8
- package/src/components/DashboardFilters/DashboardFiltersWrapper.tsx +8 -8
- package/src/components/DashboardFilters/_stories/DashboardFilters.stories.tsx +1 -1
- package/src/components/DashboardFilters/dashboardfilter.styles.css +3 -3
- package/src/components/DataDesignerModal.tsx +2 -2
- package/src/components/Header/Header.tsx +27 -5
- package/src/components/Header/index.scss +1 -1
- package/src/components/MultiConfigTabs/multiconfigtabs.styles.css +6 -6
- package/src/components/Row.tsx +21 -0
- package/src/components/Toggle/toggle-style.css +7 -7
- package/src/components/VisualizationRow.tsx +42 -29
- package/src/components/VisualizationsPanel/VisualizationsPanel.tsx +1 -71
- package/src/components/VisualizationsPanel/visualizations-panel-styles.css +2 -2
- package/src/components/Widget/Widget.tsx +2 -2
- package/src/components/Widget/widget.styles.css +12 -12
- package/src/data/initial-state.js +1 -1
- package/src/helpers/addValuesToDashboardFilters.ts +17 -11
- package/src/helpers/addVisualization.ts +71 -0
- package/src/helpers/apiFilterHelpers.ts +28 -32
- package/src/helpers/formatConfigBeforeSave.ts +1 -1
- package/src/helpers/getVizConfig.ts +13 -3
- package/src/helpers/iconHash.tsx +45 -36
- package/src/helpers/processDataLegacy.ts +19 -14
- package/src/helpers/tests/addValuesToDashboardFilters.test.ts +141 -44
- package/src/helpers/tests/addVisualization.test.ts +52 -0
- package/src/helpers/tests/apiFilterHelpers.test.ts +523 -420
- package/src/helpers/tests/formatConfigBeforeSave.test.ts +81 -1
- package/src/scss/editor-panel.scss +1 -1
- package/src/scss/main.scss +169 -41
- package/src/store/dashboard.reducer.ts +1 -1
- package/src/test/CdcDashboard.test.jsx +2 -2
- package/src/test/CdcDashboardComponent.test.tsx +74 -0
- package/src/types/FilterStyles.ts +2 -1
- package/tests/fixtures/dashboard-config-with-metadata.json +89 -0
- package/vite.config.js +7 -1
- package/dist/cdcdashboard-BnB1QM5d.es.js +0 -361528
- package/dist/cdcdashboard-Ct2SB0vL.es.js +0 -231049
- package/dist/cdcdashboard-D6CG2-Hb.es.js +0 -39377
- package/dist/cdcdashboard-MXgURbdZ.es.js +0 -39194
|
@@ -1,420 +1,523 @@
|
|
|
1
|
-
import {
|
|
2
|
-
setAutoLoadDefaultValue,
|
|
3
|
-
getToFetch,
|
|
4
|
-
getFilterValues,
|
|
5
|
-
getLoadingFilterMemo,
|
|
6
|
-
getParentParams,
|
|
7
|
-
setActiveNestedDropdown,
|
|
8
|
-
setActiveMultiDropdown
|
|
9
|
-
} from '../apiFilterHelpers'
|
|
10
|
-
import _ from 'lodash'
|
|
11
|
-
import type { APIFilterDropdowns } from '../../components/DashboardFilters'
|
|
12
|
-
import { SharedFilter } from '../../types/SharedFilter'
|
|
13
|
-
import { FILTER_STYLE } from '../../types/FilterStyles'
|
|
14
|
-
|
|
15
|
-
describe('getLoadingFilterMemo', () => {
|
|
16
|
-
it('should return correct APIFilterDropdowns for valid inputs', () => {
|
|
17
|
-
const sharedAPIFilters = ['endpoint1', 'endpoint2']
|
|
18
|
-
const apiFilterDropdowns: APIFilterDropdowns = {
|
|
19
|
-
endpoint1: { text: 'text1', value: 'value1' }
|
|
20
|
-
}
|
|
21
|
-
const expectedOutput: APIFilterDropdowns = {
|
|
22
|
-
endpoint1: { text: 'text1', value: 'value1' },
|
|
23
|
-
endpoint2: undefined
|
|
24
|
-
}
|
|
25
|
-
expect(getLoadingFilterMemo(sharedAPIFilters, apiFilterDropdowns)).toEqual(expectedOutput)
|
|
26
|
-
})
|
|
27
|
-
|
|
28
|
-
it('should return an empty object for empty sharedAPIFilters', () => {
|
|
29
|
-
const sharedAPIFilters: string[] = []
|
|
30
|
-
const apiFilterDropdowns: APIFilterDropdowns = {
|
|
31
|
-
endpoint1: { text: 'text1', value: 'value1' }
|
|
32
|
-
}
|
|
33
|
-
const expectedOutput: APIFilterDropdowns = {}
|
|
34
|
-
expect(getLoadingFilterMemo(sharedAPIFilters, apiFilterDropdowns)).toEqual(expectedOutput)
|
|
35
|
-
})
|
|
36
|
-
|
|
37
|
-
it('should return APIFilterDropdowns with null values for empty apiFilterDropdowns', () => {
|
|
38
|
-
const sharedAPIFilters = ['endpoint1', 'endpoint2']
|
|
39
|
-
const apiFilterDropdowns: APIFilterDropdowns = {}
|
|
40
|
-
const expectedOutput: APIFilterDropdowns = {
|
|
41
|
-
endpoint1: undefined,
|
|
42
|
-
endpoint2: undefined
|
|
43
|
-
}
|
|
44
|
-
expect(getLoadingFilterMemo(sharedAPIFilters, apiFilterDropdowns)).toEqual(expectedOutput)
|
|
45
|
-
})
|
|
46
|
-
|
|
47
|
-
it('should not overwrite existing data in apiFilterDropdowns, so return original dropdowns', () => {
|
|
48
|
-
const sharedAPIFilters = ['endpoint1', 'endpoint2']
|
|
49
|
-
const apiFilterDropdowns: APIFilterDropdowns = {
|
|
50
|
-
endpoint1: { text: 'text1', value: 'value1' },
|
|
51
|
-
endpoint2: { text: 'text2', value: 'value2' }
|
|
52
|
-
}
|
|
53
|
-
expect(getLoadingFilterMemo(sharedAPIFilters, apiFilterDropdowns)).toEqual(apiFilterDropdowns)
|
|
54
|
-
})
|
|
55
|
-
})
|
|
56
|
-
|
|
57
|
-
describe('getParentParams', () => {
|
|
58
|
-
it('should return null when there are no parent filters', () => {
|
|
59
|
-
const childFilter: SharedFilter = {
|
|
60
|
-
key: 'child',
|
|
61
|
-
parents: [],
|
|
62
|
-
apiFilter: {}
|
|
63
|
-
}
|
|
64
|
-
const sharedFilters: SharedFilter[] = []
|
|
65
|
-
|
|
66
|
-
const result = getParentParams(childFilter, sharedFilters)
|
|
67
|
-
expect(result).toBeNull()
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
it('should return key-value pairs for nestedDropdown parent filters', () => {
|
|
71
|
-
const childFilter: SharedFilter = {
|
|
72
|
-
key: 'child',
|
|
73
|
-
parents: ['parent1'],
|
|
74
|
-
apiFilter: {}
|
|
75
|
-
}
|
|
76
|
-
const sharedFilters: SharedFilter[] = [
|
|
77
|
-
{
|
|
78
|
-
key: 'parent1',
|
|
79
|
-
filterStyle: FILTER_STYLE.nestedDropdown,
|
|
80
|
-
apiFilter: {
|
|
81
|
-
valueSelector: 'parent1Value',
|
|
82
|
-
subgroupValueSelector: 'parent1SubValue'
|
|
83
|
-
},
|
|
84
|
-
active: 'activeValue1',
|
|
85
|
-
subGrouping: {
|
|
86
|
-
active: 'activeSubValue1'
|
|
87
|
-
}
|
|
88
|
-
}
|
|
89
|
-
]
|
|
90
|
-
|
|
91
|
-
const expectedOutput = [
|
|
92
|
-
{ key: 'parent1Value', value: 'activeValue1' },
|
|
93
|
-
{ key: 'parent1SubValue', value: 'activeSubValue1' }
|
|
94
|
-
]
|
|
95
|
-
|
|
96
|
-
const result = getParentParams(childFilter, sharedFilters)
|
|
97
|
-
expect(result).toEqual(expectedOutput)
|
|
98
|
-
})
|
|
99
|
-
|
|
100
|
-
it('should return key-value pairs for non-nestedDropdown parent filters', () => {
|
|
101
|
-
const childFilter: SharedFilter = {
|
|
102
|
-
key: 'child',
|
|
103
|
-
parents: ['parent1'],
|
|
104
|
-
apiFilter: {}
|
|
105
|
-
}
|
|
106
|
-
const sharedFilters: SharedFilter[] = [
|
|
107
|
-
{
|
|
108
|
-
key: 'parent1',
|
|
109
|
-
filterStyle: 'someOtherStyle',
|
|
110
|
-
apiFilter: {
|
|
111
|
-
valueSelector: 'parent1Value'
|
|
112
|
-
},
|
|
113
|
-
active: 'activeValue1'
|
|
114
|
-
}
|
|
115
|
-
]
|
|
116
|
-
|
|
117
|
-
const expectedOutput = [{ key: 'parent1Value', value: 'activeValue1' }]
|
|
118
|
-
|
|
119
|
-
const result = getParentParams(childFilter, sharedFilters)
|
|
120
|
-
expect(result).toEqual(expectedOutput)
|
|
121
|
-
})
|
|
122
|
-
|
|
123
|
-
it('should handle queuedActive values for nestedDropdown parent filters', () => {
|
|
124
|
-
const childFilter: SharedFilter = {
|
|
125
|
-
key: 'child',
|
|
126
|
-
parents: ['parent1'],
|
|
127
|
-
apiFilter: {}
|
|
128
|
-
}
|
|
129
|
-
const sharedFilters: SharedFilter[] = [
|
|
130
|
-
{
|
|
131
|
-
key: 'parent1',
|
|
132
|
-
filterStyle: FILTER_STYLE.nestedDropdown,
|
|
133
|
-
apiFilter: {
|
|
134
|
-
valueSelector: 'parent1Value',
|
|
135
|
-
subgroupValueSelector: 'parent1SubValue'
|
|
136
|
-
},
|
|
137
|
-
queuedActive: ['queuedActiveValue1', 'queuedActiveSubValue1']
|
|
138
|
-
}
|
|
139
|
-
]
|
|
140
|
-
|
|
141
|
-
const expectedOutput = [
|
|
142
|
-
{ key: 'parent1Value', value: 'queuedActiveValue1' },
|
|
143
|
-
{ key: 'parent1SubValue', value: 'queuedActiveSubValue1' }
|
|
144
|
-
]
|
|
145
|
-
|
|
146
|
-
const result = getParentParams(childFilter, sharedFilters)
|
|
147
|
-
expect(result).toEqual(expectedOutput)
|
|
148
|
-
})
|
|
149
|
-
|
|
150
|
-
it('should handle queuedActive values for non-nestedDropdown parent filters', () => {
|
|
151
|
-
const childFilter: SharedFilter = {
|
|
152
|
-
key: 'child',
|
|
153
|
-
parents: ['parent1'],
|
|
154
|
-
apiFilter: {}
|
|
155
|
-
}
|
|
156
|
-
const sharedFilters: SharedFilter[] = [
|
|
157
|
-
{
|
|
158
|
-
key: 'parent1',
|
|
159
|
-
filterStyle: 'someOtherStyle',
|
|
160
|
-
apiFilter: {
|
|
161
|
-
valueSelector: 'parent1Value'
|
|
162
|
-
},
|
|
163
|
-
queuedActive: 'queuedActiveValue1'
|
|
164
|
-
}
|
|
165
|
-
]
|
|
166
|
-
|
|
167
|
-
const expectedOutput = [{ key: 'parent1Value', value: 'queuedActiveValue1' }]
|
|
168
|
-
|
|
169
|
-
const result = getParentParams(childFilter, sharedFilters)
|
|
170
|
-
expect(result).toEqual(expectedOutput)
|
|
171
|
-
})
|
|
172
|
-
|
|
173
|
-
it('should handle array values for non-nestedDropdown parent filters', () => {
|
|
174
|
-
const childFilter: SharedFilter = {
|
|
175
|
-
key: 'child',
|
|
176
|
-
parents: ['parent1'],
|
|
177
|
-
apiFilter: {}
|
|
178
|
-
}
|
|
179
|
-
const sharedFilters: SharedFilter[] = [
|
|
180
|
-
{
|
|
181
|
-
key: 'parent1',
|
|
182
|
-
filterStyle: 'someOtherStyle',
|
|
183
|
-
apiFilter: {
|
|
184
|
-
valueSelector: 'parent1Value'
|
|
185
|
-
},
|
|
186
|
-
active: ['activeValue1', 'activeValue2']
|
|
187
|
-
}
|
|
188
|
-
]
|
|
189
|
-
|
|
190
|
-
const expectedOutput = [
|
|
191
|
-
{ key: 'parent1Value', value: 'activeValue1' },
|
|
192
|
-
{ key: 'parent1Value', value: 'activeValue2' }
|
|
193
|
-
]
|
|
194
|
-
|
|
195
|
-
const result = getParentParams(childFilter, sharedFilters)
|
|
196
|
-
expect(result).toEqual(expectedOutput)
|
|
197
|
-
})
|
|
198
|
-
})
|
|
199
|
-
|
|
200
|
-
describe('getFilterValues', () => {
|
|
201
|
-
it('should return correct filter values for valid inputs', () => {
|
|
202
|
-
const data = [{ key1: 'value1', key2: 'value2' }]
|
|
203
|
-
const apiFilter = { textSelector: 'key1', valueSelector: 'key2' }
|
|
204
|
-
const expectedOutput = [{ text: 'value1', value: 'value2' }]
|
|
205
|
-
expect(getFilterValues(data, apiFilter)).toEqual(expectedOutput)
|
|
206
|
-
delete apiFilter.textSelector
|
|
207
|
-
const expectedOutput2 = [{ text: 'value2', value: 'value2' }]
|
|
208
|
-
expect(getFilterValues(data, apiFilter)).toEqual(expectedOutput2)
|
|
209
|
-
})
|
|
210
|
-
|
|
211
|
-
it('should return nested dropdown options when subgroupValueSelector is provided', () => {
|
|
212
|
-
const data = [
|
|
213
|
-
{ id: 1, name: 'Group 1', subId: 101, subName: 'Subgroup 1-1' },
|
|
214
|
-
{ id: 1, name: 'Group 1', subId: 102, subName: 'Subgroup 1-2' },
|
|
215
|
-
{ id: 2, name: 'Group 2', subId: 201, subName: 'Subgroup 2-1' }
|
|
216
|
-
]
|
|
217
|
-
|
|
218
|
-
const apiFilter = {
|
|
219
|
-
textSelector: 'name',
|
|
220
|
-
valueSelector: 'id',
|
|
221
|
-
subgroupTextSelector: 'subName',
|
|
222
|
-
subgroupValueSelector: 'subId'
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
const expectedOutput = [
|
|
226
|
-
{
|
|
227
|
-
text: 'Group 1',
|
|
228
|
-
value: 1,
|
|
229
|
-
subOptions: [
|
|
230
|
-
{ text: 'Subgroup 1-1', value: 101 },
|
|
231
|
-
{ text: 'Subgroup 1-2', value: 102 }
|
|
232
|
-
]
|
|
233
|
-
},
|
|
234
|
-
{
|
|
235
|
-
text: 'Group 2',
|
|
236
|
-
value: 2,
|
|
237
|
-
subOptions: [{ text: 'Subgroup 2-1', value: 201 }]
|
|
238
|
-
}
|
|
239
|
-
]
|
|
240
|
-
|
|
241
|
-
expect(getFilterValues(data, apiFilter)).toEqual(expectedOutput)
|
|
242
|
-
})
|
|
243
|
-
})
|
|
244
|
-
|
|
245
|
-
describe('getToFetch', () => {
|
|
246
|
-
it('should return an empty object when sharedAPIFilters is empty', () => {
|
|
247
|
-
const result = getToFetch([], {})
|
|
248
|
-
expect(result).toEqual({})
|
|
249
|
-
})
|
|
250
|
-
|
|
251
|
-
it('should return an object with endpoints when apiFilterDropdowns is empty', () => {
|
|
252
|
-
const sharedAPIFilters = [{ apiFilter: { apiEndpoint: '/endpoint1' }, parents: [] }]
|
|
253
|
-
const result = getToFetch(sharedAPIFilters, {})
|
|
254
|
-
expect(result).toEqual({ '/endpoint1': ['/endpoint1', 0] })
|
|
255
|
-
})
|
|
256
|
-
|
|
257
|
-
it('should return and empty object when sharedAPIFilters contains filters with no parents', () => {
|
|
258
|
-
const sharedAPIFilters = [{ apiFilter: { apiEndpoint: '/endpoint1' }, parents: [] }]
|
|
259
|
-
const apiFilterDropdowns = { '/endpoint1': true }
|
|
260
|
-
const result = getToFetch(sharedAPIFilters, apiFilterDropdowns)
|
|
261
|
-
expect(result).toEqual({})
|
|
262
|
-
})
|
|
263
|
-
|
|
264
|
-
it('should return an empty object when parentParams contains an empty value', () => {
|
|
265
|
-
const sharedAPIFilters = [
|
|
266
|
-
{ key: 'parent1', apiFilter: { apiEndpoint: '/endpoint1' }, parents: [] },
|
|
267
|
-
{ apiFilter: { apiEndpoint: '/endpoint1' }, parents: ['parent1'] }
|
|
268
|
-
]
|
|
269
|
-
const apiFilterDropdowns = { '/endpoint1': true }
|
|
270
|
-
const result = getToFetch(sharedAPIFilters, apiFilterDropdowns)
|
|
271
|
-
expect(result).toEqual({})
|
|
272
|
-
})
|
|
273
|
-
|
|
274
|
-
it('should return an empty object when parentParams contains an empty value', () => {
|
|
275
|
-
const sharedAPIFilters = [
|
|
276
|
-
{ key: 'parent1', value: '', apiFilter: { apiEndpoint: '/endpoint1' }, parents: [] },
|
|
277
|
-
{ apiFilter: { apiEndpoint: '/endpoint1' }, parents: ['parent1'] }
|
|
278
|
-
]
|
|
279
|
-
const apiFilterDropdowns = { '/endpoint1': true }
|
|
280
|
-
const result = getToFetch(sharedAPIFilters, apiFilterDropdowns)
|
|
281
|
-
expect(result).toEqual({})
|
|
282
|
-
})
|
|
283
|
-
})
|
|
284
|
-
|
|
285
|
-
describe('setActiveNestedDropdown', () => {
|
|
286
|
-
const dropdownOptions = [
|
|
287
|
-
{ value: 'option1', subOptions: [{ value: 'subOption1' }], label: 'Option 1' },
|
|
288
|
-
{ value: 'option2', subOptions: [{ value: 'subOption2' }], label: 'Option 2' }
|
|
289
|
-
]
|
|
290
|
-
|
|
291
|
-
const sharedFilters = [
|
|
292
|
-
{
|
|
293
|
-
key: 'filter1',
|
|
294
|
-
active: null,
|
|
295
|
-
filterStyle: FILTER_STYLE.nestedDropdown,
|
|
296
|
-
subGrouping: {},
|
|
297
|
-
queuedActive: null,
|
|
298
|
-
parents: []
|
|
299
|
-
},
|
|
300
|
-
{
|
|
301
|
-
key: 'filter2',
|
|
302
|
-
active: null,
|
|
303
|
-
setByQueryParameter: 'group',
|
|
304
|
-
filterStyle: FILTER_STYLE.nestedDropdown,
|
|
305
|
-
subGrouping: { setByQueryParameter: 'subgroup' },
|
|
306
|
-
queuedActive: null,
|
|
307
|
-
parents: ['filter1']
|
|
308
|
-
}
|
|
309
|
-
] as SharedFilter[]
|
|
310
|
-
|
|
311
|
-
it('should set the active value for a nested dropdown', () => {
|
|
312
|
-
setActiveNestedDropdown(dropdownOptions, sharedFilters[0])
|
|
313
|
-
expect(sharedFilters[0].active).toEqual('option1')
|
|
314
|
-
expect(sharedFilters[0].subGrouping.active).toEqual('subOption1')
|
|
315
|
-
})
|
|
316
|
-
it('should set the active value for nested dropdown with query parameters', () => {
|
|
317
|
-
delete window.location
|
|
318
|
-
window.location = new URL('https://www.example.com?group=option2&subgroup=subOption2')
|
|
319
|
-
setActiveNestedDropdown(dropdownOptions, sharedFilters[1])
|
|
320
|
-
expect(sharedFilters[1].active).toEqual('option2')
|
|
321
|
-
expect(sharedFilters[1].subGrouping.active).toEqual('subOption2')
|
|
322
|
-
})
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
expect(
|
|
361
|
-
})
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
1
|
+
import {
|
|
2
|
+
setAutoLoadDefaultValue,
|
|
3
|
+
getToFetch,
|
|
4
|
+
getFilterValues,
|
|
5
|
+
getLoadingFilterMemo,
|
|
6
|
+
getParentParams,
|
|
7
|
+
setActiveNestedDropdown,
|
|
8
|
+
setActiveMultiDropdown
|
|
9
|
+
} from '../apiFilterHelpers'
|
|
10
|
+
import _ from 'lodash'
|
|
11
|
+
import type { APIFilterDropdowns } from '../../components/DashboardFilters'
|
|
12
|
+
import { SharedFilter } from '../../types/SharedFilter'
|
|
13
|
+
import { FILTER_STYLE } from '../../types/FilterStyles'
|
|
14
|
+
|
|
15
|
+
describe('getLoadingFilterMemo', () => {
|
|
16
|
+
it('should return correct APIFilterDropdowns for valid inputs', () => {
|
|
17
|
+
const sharedAPIFilters = ['endpoint1', 'endpoint2']
|
|
18
|
+
const apiFilterDropdowns: APIFilterDropdowns = {
|
|
19
|
+
endpoint1: { text: 'text1', value: 'value1' }
|
|
20
|
+
}
|
|
21
|
+
const expectedOutput: APIFilterDropdowns = {
|
|
22
|
+
endpoint1: { text: 'text1', value: 'value1' },
|
|
23
|
+
endpoint2: undefined
|
|
24
|
+
}
|
|
25
|
+
expect(getLoadingFilterMemo(sharedAPIFilters, apiFilterDropdowns)).toEqual(expectedOutput)
|
|
26
|
+
})
|
|
27
|
+
|
|
28
|
+
it('should return an empty object for empty sharedAPIFilters', () => {
|
|
29
|
+
const sharedAPIFilters: string[] = []
|
|
30
|
+
const apiFilterDropdowns: APIFilterDropdowns = {
|
|
31
|
+
endpoint1: { text: 'text1', value: 'value1' }
|
|
32
|
+
}
|
|
33
|
+
const expectedOutput: APIFilterDropdowns = {}
|
|
34
|
+
expect(getLoadingFilterMemo(sharedAPIFilters, apiFilterDropdowns)).toEqual(expectedOutput)
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
it('should return APIFilterDropdowns with null values for empty apiFilterDropdowns', () => {
|
|
38
|
+
const sharedAPIFilters = ['endpoint1', 'endpoint2']
|
|
39
|
+
const apiFilterDropdowns: APIFilterDropdowns = {}
|
|
40
|
+
const expectedOutput: APIFilterDropdowns = {
|
|
41
|
+
endpoint1: undefined,
|
|
42
|
+
endpoint2: undefined
|
|
43
|
+
}
|
|
44
|
+
expect(getLoadingFilterMemo(sharedAPIFilters, apiFilterDropdowns)).toEqual(expectedOutput)
|
|
45
|
+
})
|
|
46
|
+
|
|
47
|
+
it('should not overwrite existing data in apiFilterDropdowns, so return original dropdowns', () => {
|
|
48
|
+
const sharedAPIFilters = ['endpoint1', 'endpoint2']
|
|
49
|
+
const apiFilterDropdowns: APIFilterDropdowns = {
|
|
50
|
+
endpoint1: { text: 'text1', value: 'value1' },
|
|
51
|
+
endpoint2: { text: 'text2', value: 'value2' }
|
|
52
|
+
}
|
|
53
|
+
expect(getLoadingFilterMemo(sharedAPIFilters, apiFilterDropdowns)).toEqual(apiFilterDropdowns)
|
|
54
|
+
})
|
|
55
|
+
})
|
|
56
|
+
|
|
57
|
+
describe('getParentParams', () => {
|
|
58
|
+
it('should return null when there are no parent filters', () => {
|
|
59
|
+
const childFilter: SharedFilter = {
|
|
60
|
+
key: 'child',
|
|
61
|
+
parents: [],
|
|
62
|
+
apiFilter: {}
|
|
63
|
+
}
|
|
64
|
+
const sharedFilters: SharedFilter[] = []
|
|
65
|
+
|
|
66
|
+
const result = getParentParams(childFilter, sharedFilters)
|
|
67
|
+
expect(result).toBeNull()
|
|
68
|
+
})
|
|
69
|
+
|
|
70
|
+
it('should return key-value pairs for nestedDropdown parent filters', () => {
|
|
71
|
+
const childFilter: SharedFilter = {
|
|
72
|
+
key: 'child',
|
|
73
|
+
parents: ['parent1'],
|
|
74
|
+
apiFilter: {}
|
|
75
|
+
}
|
|
76
|
+
const sharedFilters: SharedFilter[] = [
|
|
77
|
+
{
|
|
78
|
+
key: 'parent1',
|
|
79
|
+
filterStyle: FILTER_STYLE.nestedDropdown,
|
|
80
|
+
apiFilter: {
|
|
81
|
+
valueSelector: 'parent1Value',
|
|
82
|
+
subgroupValueSelector: 'parent1SubValue'
|
|
83
|
+
},
|
|
84
|
+
active: 'activeValue1',
|
|
85
|
+
subGrouping: {
|
|
86
|
+
active: 'activeSubValue1'
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
]
|
|
90
|
+
|
|
91
|
+
const expectedOutput = [
|
|
92
|
+
{ key: 'parent1Value', value: 'activeValue1' },
|
|
93
|
+
{ key: 'parent1SubValue', value: 'activeSubValue1' }
|
|
94
|
+
]
|
|
95
|
+
|
|
96
|
+
const result = getParentParams(childFilter, sharedFilters)
|
|
97
|
+
expect(result).toEqual(expectedOutput)
|
|
98
|
+
})
|
|
99
|
+
|
|
100
|
+
it('should return key-value pairs for non-nestedDropdown parent filters', () => {
|
|
101
|
+
const childFilter: SharedFilter = {
|
|
102
|
+
key: 'child',
|
|
103
|
+
parents: ['parent1'],
|
|
104
|
+
apiFilter: {}
|
|
105
|
+
}
|
|
106
|
+
const sharedFilters: SharedFilter[] = [
|
|
107
|
+
{
|
|
108
|
+
key: 'parent1',
|
|
109
|
+
filterStyle: 'someOtherStyle',
|
|
110
|
+
apiFilter: {
|
|
111
|
+
valueSelector: 'parent1Value'
|
|
112
|
+
},
|
|
113
|
+
active: 'activeValue1'
|
|
114
|
+
}
|
|
115
|
+
]
|
|
116
|
+
|
|
117
|
+
const expectedOutput = [{ key: 'parent1Value', value: 'activeValue1' }]
|
|
118
|
+
|
|
119
|
+
const result = getParentParams(childFilter, sharedFilters)
|
|
120
|
+
expect(result).toEqual(expectedOutput)
|
|
121
|
+
})
|
|
122
|
+
|
|
123
|
+
it('should handle queuedActive values for nestedDropdown parent filters', () => {
|
|
124
|
+
const childFilter: SharedFilter = {
|
|
125
|
+
key: 'child',
|
|
126
|
+
parents: ['parent1'],
|
|
127
|
+
apiFilter: {}
|
|
128
|
+
}
|
|
129
|
+
const sharedFilters: SharedFilter[] = [
|
|
130
|
+
{
|
|
131
|
+
key: 'parent1',
|
|
132
|
+
filterStyle: FILTER_STYLE.nestedDropdown,
|
|
133
|
+
apiFilter: {
|
|
134
|
+
valueSelector: 'parent1Value',
|
|
135
|
+
subgroupValueSelector: 'parent1SubValue'
|
|
136
|
+
},
|
|
137
|
+
queuedActive: ['queuedActiveValue1', 'queuedActiveSubValue1']
|
|
138
|
+
}
|
|
139
|
+
]
|
|
140
|
+
|
|
141
|
+
const expectedOutput = [
|
|
142
|
+
{ key: 'parent1Value', value: 'queuedActiveValue1' },
|
|
143
|
+
{ key: 'parent1SubValue', value: 'queuedActiveSubValue1' }
|
|
144
|
+
]
|
|
145
|
+
|
|
146
|
+
const result = getParentParams(childFilter, sharedFilters)
|
|
147
|
+
expect(result).toEqual(expectedOutput)
|
|
148
|
+
})
|
|
149
|
+
|
|
150
|
+
it('should handle queuedActive values for non-nestedDropdown parent filters', () => {
|
|
151
|
+
const childFilter: SharedFilter = {
|
|
152
|
+
key: 'child',
|
|
153
|
+
parents: ['parent1'],
|
|
154
|
+
apiFilter: {}
|
|
155
|
+
}
|
|
156
|
+
const sharedFilters: SharedFilter[] = [
|
|
157
|
+
{
|
|
158
|
+
key: 'parent1',
|
|
159
|
+
filterStyle: 'someOtherStyle',
|
|
160
|
+
apiFilter: {
|
|
161
|
+
valueSelector: 'parent1Value'
|
|
162
|
+
},
|
|
163
|
+
queuedActive: 'queuedActiveValue1'
|
|
164
|
+
}
|
|
165
|
+
]
|
|
166
|
+
|
|
167
|
+
const expectedOutput = [{ key: 'parent1Value', value: 'queuedActiveValue1' }]
|
|
168
|
+
|
|
169
|
+
const result = getParentParams(childFilter, sharedFilters)
|
|
170
|
+
expect(result).toEqual(expectedOutput)
|
|
171
|
+
})
|
|
172
|
+
|
|
173
|
+
it('should handle array values for non-nestedDropdown parent filters', () => {
|
|
174
|
+
const childFilter: SharedFilter = {
|
|
175
|
+
key: 'child',
|
|
176
|
+
parents: ['parent1'],
|
|
177
|
+
apiFilter: {}
|
|
178
|
+
}
|
|
179
|
+
const sharedFilters: SharedFilter[] = [
|
|
180
|
+
{
|
|
181
|
+
key: 'parent1',
|
|
182
|
+
filterStyle: 'someOtherStyle',
|
|
183
|
+
apiFilter: {
|
|
184
|
+
valueSelector: 'parent1Value'
|
|
185
|
+
},
|
|
186
|
+
active: ['activeValue1', 'activeValue2']
|
|
187
|
+
}
|
|
188
|
+
]
|
|
189
|
+
|
|
190
|
+
const expectedOutput = [
|
|
191
|
+
{ key: 'parent1Value', value: 'activeValue1' },
|
|
192
|
+
{ key: 'parent1Value', value: 'activeValue2' }
|
|
193
|
+
]
|
|
194
|
+
|
|
195
|
+
const result = getParentParams(childFilter, sharedFilters)
|
|
196
|
+
expect(result).toEqual(expectedOutput)
|
|
197
|
+
})
|
|
198
|
+
})
|
|
199
|
+
|
|
200
|
+
describe('getFilterValues', () => {
|
|
201
|
+
it('should return correct filter values for valid inputs', () => {
|
|
202
|
+
const data = [{ key1: 'value1', key2: 'value2' }]
|
|
203
|
+
const apiFilter = { textSelector: 'key1', valueSelector: 'key2' }
|
|
204
|
+
const expectedOutput = [{ text: 'value1', value: 'value2' }]
|
|
205
|
+
expect(getFilterValues(data, apiFilter)).toEqual(expectedOutput)
|
|
206
|
+
delete apiFilter.textSelector
|
|
207
|
+
const expectedOutput2 = [{ text: 'value2', value: 'value2' }]
|
|
208
|
+
expect(getFilterValues(data, apiFilter)).toEqual(expectedOutput2)
|
|
209
|
+
})
|
|
210
|
+
|
|
211
|
+
it('should return nested dropdown options when subgroupValueSelector is provided', () => {
|
|
212
|
+
const data = [
|
|
213
|
+
{ id: 1, name: 'Group 1', subId: 101, subName: 'Subgroup 1-1' },
|
|
214
|
+
{ id: 1, name: 'Group 1', subId: 102, subName: 'Subgroup 1-2' },
|
|
215
|
+
{ id: 2, name: 'Group 2', subId: 201, subName: 'Subgroup 2-1' }
|
|
216
|
+
]
|
|
217
|
+
|
|
218
|
+
const apiFilter = {
|
|
219
|
+
textSelector: 'name',
|
|
220
|
+
valueSelector: 'id',
|
|
221
|
+
subgroupTextSelector: 'subName',
|
|
222
|
+
subgroupValueSelector: 'subId'
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
const expectedOutput = [
|
|
226
|
+
{
|
|
227
|
+
text: 'Group 1',
|
|
228
|
+
value: 1,
|
|
229
|
+
subOptions: [
|
|
230
|
+
{ text: 'Subgroup 1-1', value: 101 },
|
|
231
|
+
{ text: 'Subgroup 1-2', value: 102 }
|
|
232
|
+
]
|
|
233
|
+
},
|
|
234
|
+
{
|
|
235
|
+
text: 'Group 2',
|
|
236
|
+
value: 2,
|
|
237
|
+
subOptions: [{ text: 'Subgroup 2-1', value: 201 }]
|
|
238
|
+
}
|
|
239
|
+
]
|
|
240
|
+
|
|
241
|
+
expect(getFilterValues(data, apiFilter)).toEqual(expectedOutput)
|
|
242
|
+
})
|
|
243
|
+
})
|
|
244
|
+
|
|
245
|
+
describe('getToFetch', () => {
|
|
246
|
+
it('should return an empty object when sharedAPIFilters is empty', () => {
|
|
247
|
+
const result = getToFetch([], {})
|
|
248
|
+
expect(result).toEqual({})
|
|
249
|
+
})
|
|
250
|
+
|
|
251
|
+
it('should return an object with endpoints when apiFilterDropdowns is empty', () => {
|
|
252
|
+
const sharedAPIFilters = [{ apiFilter: { apiEndpoint: '/endpoint1' }, parents: [] }]
|
|
253
|
+
const result = getToFetch(sharedAPIFilters, {})
|
|
254
|
+
expect(result).toEqual({ '/endpoint1': ['/endpoint1', 0] })
|
|
255
|
+
})
|
|
256
|
+
|
|
257
|
+
it('should return and empty object when sharedAPIFilters contains filters with no parents', () => {
|
|
258
|
+
const sharedAPIFilters = [{ apiFilter: { apiEndpoint: '/endpoint1' }, parents: [] }]
|
|
259
|
+
const apiFilterDropdowns = { '/endpoint1': true }
|
|
260
|
+
const result = getToFetch(sharedAPIFilters, apiFilterDropdowns)
|
|
261
|
+
expect(result).toEqual({})
|
|
262
|
+
})
|
|
263
|
+
|
|
264
|
+
it('should return an empty object when parentParams contains an empty value', () => {
|
|
265
|
+
const sharedAPIFilters = [
|
|
266
|
+
{ key: 'parent1', apiFilter: { apiEndpoint: '/endpoint1' }, parents: [] },
|
|
267
|
+
{ apiFilter: { apiEndpoint: '/endpoint1' }, parents: ['parent1'] }
|
|
268
|
+
]
|
|
269
|
+
const apiFilterDropdowns = { '/endpoint1': true }
|
|
270
|
+
const result = getToFetch(sharedAPIFilters, apiFilterDropdowns)
|
|
271
|
+
expect(result).toEqual({})
|
|
272
|
+
})
|
|
273
|
+
|
|
274
|
+
it('should return an empty object when parentParams contains an empty value', () => {
|
|
275
|
+
const sharedAPIFilters = [
|
|
276
|
+
{ key: 'parent1', value: '', apiFilter: { apiEndpoint: '/endpoint1' }, parents: [] },
|
|
277
|
+
{ apiFilter: { apiEndpoint: '/endpoint1' }, parents: ['parent1'] }
|
|
278
|
+
]
|
|
279
|
+
const apiFilterDropdowns = { '/endpoint1': true }
|
|
280
|
+
const result = getToFetch(sharedAPIFilters, apiFilterDropdowns)
|
|
281
|
+
expect(result).toEqual({})
|
|
282
|
+
})
|
|
283
|
+
})
|
|
284
|
+
|
|
285
|
+
describe('setActiveNestedDropdown', () => {
|
|
286
|
+
const dropdownOptions = [
|
|
287
|
+
{ value: 'option1', subOptions: [{ value: 'subOption1' }], label: 'Option 1' },
|
|
288
|
+
{ value: 'option2', subOptions: [{ value: 'subOption2' }], label: 'Option 2' }
|
|
289
|
+
]
|
|
290
|
+
|
|
291
|
+
const sharedFilters = [
|
|
292
|
+
{
|
|
293
|
+
key: 'filter1',
|
|
294
|
+
active: null,
|
|
295
|
+
filterStyle: FILTER_STYLE.nestedDropdown,
|
|
296
|
+
subGrouping: {},
|
|
297
|
+
queuedActive: null,
|
|
298
|
+
parents: []
|
|
299
|
+
},
|
|
300
|
+
{
|
|
301
|
+
key: 'filter2',
|
|
302
|
+
active: null,
|
|
303
|
+
setByQueryParameter: 'group',
|
|
304
|
+
filterStyle: FILTER_STYLE.nestedDropdown,
|
|
305
|
+
subGrouping: { setByQueryParameter: 'subgroup' },
|
|
306
|
+
queuedActive: null,
|
|
307
|
+
parents: ['filter1']
|
|
308
|
+
}
|
|
309
|
+
] as SharedFilter[]
|
|
310
|
+
|
|
311
|
+
it('should set the active value for a nested dropdown', () => {
|
|
312
|
+
setActiveNestedDropdown(dropdownOptions, sharedFilters[0])
|
|
313
|
+
expect(sharedFilters[0].active).toEqual('option1')
|
|
314
|
+
expect(sharedFilters[0].subGrouping.active).toEqual('subOption1')
|
|
315
|
+
})
|
|
316
|
+
it('should set the active value for nested dropdown with query parameters', () => {
|
|
317
|
+
delete window.location
|
|
318
|
+
window.location = new URL('https://www.example.com?group=option2&subgroup=subOption2')
|
|
319
|
+
setActiveNestedDropdown(dropdownOptions, sharedFilters[1])
|
|
320
|
+
expect(sharedFilters[1].active).toEqual('option2')
|
|
321
|
+
expect(sharedFilters[1].subGrouping.active).toEqual('subOption2')
|
|
322
|
+
})
|
|
323
|
+
|
|
324
|
+
it('should respect configured defaultValue for nested dropdown group', () => {
|
|
325
|
+
const filter = {
|
|
326
|
+
key: 'filter1',
|
|
327
|
+
active: null,
|
|
328
|
+
defaultValue: 'option2',
|
|
329
|
+
filterStyle: FILTER_STYLE.nestedDropdown,
|
|
330
|
+
subGrouping: { active: null },
|
|
331
|
+
queuedActive: null,
|
|
332
|
+
parents: []
|
|
333
|
+
} as SharedFilter
|
|
334
|
+
|
|
335
|
+
setActiveNestedDropdown(dropdownOptions, filter)
|
|
336
|
+
expect(filter.active).toEqual('option2')
|
|
337
|
+
expect(filter.subGrouping.active).toEqual('subOption2')
|
|
338
|
+
})
|
|
339
|
+
|
|
340
|
+
it('should respect configured defaultValue for nested dropdown subgroup', () => {
|
|
341
|
+
const options = [
|
|
342
|
+
{
|
|
343
|
+
value: 'option1',
|
|
344
|
+
subOptions: [{ value: 'subA' }, { value: 'subB' }, { value: 'subC' }]
|
|
345
|
+
}
|
|
346
|
+
]
|
|
347
|
+
|
|
348
|
+
const filter = {
|
|
349
|
+
key: 'filter1',
|
|
350
|
+
active: null,
|
|
351
|
+
defaultValue: 'option1',
|
|
352
|
+
filterStyle: FILTER_STYLE.nestedDropdown,
|
|
353
|
+
subGrouping: { active: null, defaultValue: 'subC' },
|
|
354
|
+
queuedActive: null,
|
|
355
|
+
parents: []
|
|
356
|
+
} as SharedFilter
|
|
357
|
+
|
|
358
|
+
setActiveNestedDropdown(options, filter)
|
|
359
|
+
expect(filter.active).toEqual('option1')
|
|
360
|
+
expect(filter.subGrouping.active).toEqual('subC')
|
|
361
|
+
})
|
|
362
|
+
|
|
363
|
+
it('should prioritize query parameter over defaultValue', () => {
|
|
364
|
+
delete window.location
|
|
365
|
+
window.location = new URL('https://www.example.com?year=option2&quarter=subOption2')
|
|
366
|
+
|
|
367
|
+
const filter = {
|
|
368
|
+
key: 'filter1',
|
|
369
|
+
active: null,
|
|
370
|
+
defaultValue: 'option1',
|
|
371
|
+
setByQueryParameter: 'year',
|
|
372
|
+
filterStyle: FILTER_STYLE.nestedDropdown,
|
|
373
|
+
subGrouping: { active: null, defaultValue: 'subOption1', setByQueryParameter: 'quarter' },
|
|
374
|
+
queuedActive: null,
|
|
375
|
+
parents: []
|
|
376
|
+
} as SharedFilter
|
|
377
|
+
|
|
378
|
+
setActiveNestedDropdown(dropdownOptions, filter)
|
|
379
|
+
expect(filter.active).toEqual('option2')
|
|
380
|
+
expect(filter.subGrouping.active).toEqual('subOption2')
|
|
381
|
+
})
|
|
382
|
+
|
|
383
|
+
it('should handle type coercion for number and string values (loose equality)', () => {
|
|
384
|
+
// Simulate dropdown with numeric values but string query params
|
|
385
|
+
const numericOptions = [
|
|
386
|
+
{ value: 2023, subOptions: [{ value: 1 }, { value: 2 }] },
|
|
387
|
+
{ value: 2024, subOptions: [{ value: 1 }, { value: 2 }] }
|
|
388
|
+
]
|
|
389
|
+
|
|
390
|
+
delete window.location
|
|
391
|
+
window.location = new URL('https://www.example.com?year=2023&quarter=2')
|
|
392
|
+
|
|
393
|
+
const filter = {
|
|
394
|
+
key: 'filter1',
|
|
395
|
+
active: null,
|
|
396
|
+
setByQueryParameter: 'year',
|
|
397
|
+
filterStyle: FILTER_STYLE.nestedDropdown,
|
|
398
|
+
subGrouping: { active: null, setByQueryParameter: 'quarter' },
|
|
399
|
+
queuedActive: null,
|
|
400
|
+
parents: []
|
|
401
|
+
} as SharedFilter
|
|
402
|
+
|
|
403
|
+
setActiveNestedDropdown(numericOptions, filter)
|
|
404
|
+
// Should match '2023' (string) with 2023 (number) using loose equality
|
|
405
|
+
expect(filter.active).toEqual('2023')
|
|
406
|
+
// Should match '2' (string) with 2 (number) using loose equality
|
|
407
|
+
expect(filter.subGrouping.active).toEqual('2')
|
|
408
|
+
})
|
|
409
|
+
})
|
|
410
|
+
|
|
411
|
+
describe('setActiveMultiDropdown', () => {
|
|
412
|
+
const dropdownOptions = [
|
|
413
|
+
{ value: 'option1', label: 'Option 1' },
|
|
414
|
+
{ value: 'option2', label: 'Option 2' }
|
|
415
|
+
]
|
|
416
|
+
|
|
417
|
+
const sharedFilters = [
|
|
418
|
+
{
|
|
419
|
+
key: 'filter1',
|
|
420
|
+
active: null,
|
|
421
|
+
filterStyle: FILTER_STYLE.multiSelect,
|
|
422
|
+
queuedActive: null,
|
|
423
|
+
parents: []
|
|
424
|
+
},
|
|
425
|
+
{
|
|
426
|
+
key: 'filter2',
|
|
427
|
+
active: null,
|
|
428
|
+
filterStyle: FILTER_STYLE.multiSelect,
|
|
429
|
+
setByQueryParameter: 'group',
|
|
430
|
+
queuedActive: null,
|
|
431
|
+
parents: ['filter1']
|
|
432
|
+
}
|
|
433
|
+
] as SharedFilter[]
|
|
434
|
+
it('should set the active value for a multi dropdown', () => {
|
|
435
|
+
setActiveMultiDropdown(dropdownOptions, sharedFilters[0])
|
|
436
|
+
expect(sharedFilters[0].active).toEqual(['option1'])
|
|
437
|
+
})
|
|
438
|
+
it('should set the active value for a multi dropdown with queryParameters', () => {
|
|
439
|
+
delete window.location
|
|
440
|
+
window.location = new URL('https://www.example.com?group=option1&group=option2')
|
|
441
|
+
setActiveMultiDropdown(dropdownOptions, sharedFilters[1])
|
|
442
|
+
expect(sharedFilters[1].active).toEqual(['option1', 'option2'])
|
|
443
|
+
delete window.location
|
|
444
|
+
window.location = new URL('https://www.example.com?group=option1,option2')
|
|
445
|
+
setActiveMultiDropdown(dropdownOptions, sharedFilters[1])
|
|
446
|
+
expect(sharedFilters[1].active).toEqual(['option1', 'option2'])
|
|
447
|
+
})
|
|
448
|
+
|
|
449
|
+
it('should fallback to first option when query parameter is empty array', () => {
|
|
450
|
+
const filter = {
|
|
451
|
+
key: 'filter',
|
|
452
|
+
active: null,
|
|
453
|
+
filterStyle: FILTER_STYLE.multiSelect,
|
|
454
|
+
setByQueryParameter: 'group',
|
|
455
|
+
queuedActive: null,
|
|
456
|
+
parents: []
|
|
457
|
+
} as SharedFilter
|
|
458
|
+
|
|
459
|
+
// Mock getQueryParam to return empty array
|
|
460
|
+
delete window.location
|
|
461
|
+
window.location = new URL('https://www.example.com?group=')
|
|
462
|
+
setActiveMultiDropdown(dropdownOptions, filter)
|
|
463
|
+
expect(filter.active).toEqual(['option1'])
|
|
464
|
+
})
|
|
465
|
+
})
|
|
466
|
+
|
|
467
|
+
describe('setAutoLoadDefaultValue', () => {
|
|
468
|
+
const dropdownOptions = [
|
|
469
|
+
{ value: 'option1', label: 'Option 1' },
|
|
470
|
+
{ value: 'option2', label: 'Option 2' }
|
|
471
|
+
]
|
|
472
|
+
|
|
473
|
+
const sharedFilters = [
|
|
474
|
+
{ key: 'filter1', active: null, queuedActive: null, parents: [] },
|
|
475
|
+
{ key: 'filter2', active: null, queuedActive: null, parents: ['filter1'] }
|
|
476
|
+
]
|
|
477
|
+
|
|
478
|
+
it('should return the original filter when autoLoadFilterIndexes is empty', () => {
|
|
479
|
+
const result = setAutoLoadDefaultValue(0, dropdownOptions, sharedFilters, [])
|
|
480
|
+
expect(result).toEqual(sharedFilters[0])
|
|
481
|
+
})
|
|
482
|
+
|
|
483
|
+
it('should return the original filter when dropdownOptions is empty', () => {
|
|
484
|
+
const result = setAutoLoadDefaultValue(0, [], sharedFilters, [0])
|
|
485
|
+
expect(result).toEqual(sharedFilters[0])
|
|
486
|
+
})
|
|
487
|
+
|
|
488
|
+
it('should return the original filter when dropdownOptions is undefined', () => {
|
|
489
|
+
const result = setAutoLoadDefaultValue(0, undefined, sharedFilters, [0])
|
|
490
|
+
expect(result).toEqual(sharedFilters[0])
|
|
491
|
+
})
|
|
492
|
+
|
|
493
|
+
it('should return the original filter when sharedFilterIndex is not in autoLoadFilterIndexes', () => {
|
|
494
|
+
const result = setAutoLoadDefaultValue(0, dropdownOptions, sharedFilters, [1])
|
|
495
|
+
expect(result).toEqual(sharedFilters[0])
|
|
496
|
+
})
|
|
497
|
+
|
|
498
|
+
it('should return the original filter when not all parent filters are selected', () => {
|
|
499
|
+
const result = setAutoLoadDefaultValue(1, dropdownOptions, sharedFilters, [1])
|
|
500
|
+
expect(result).toEqual(sharedFilters[1])
|
|
501
|
+
})
|
|
502
|
+
|
|
503
|
+
it('should assign the default value from dropdownOptions when no active value is set', () => {
|
|
504
|
+
const sharedFiltersCopy = _.cloneDeep(sharedFilters)
|
|
505
|
+
sharedFiltersCopy[0].active = null
|
|
506
|
+
const result = setAutoLoadDefaultValue(0, dropdownOptions, sharedFiltersCopy, [0])
|
|
507
|
+
expect(result.active).toEqual('option1')
|
|
508
|
+
})
|
|
509
|
+
|
|
510
|
+
it('should retain the current active value if it exists in dropdownOptions', () => {
|
|
511
|
+
const sharedFiltersCopy = _.cloneDeep(sharedFilters)
|
|
512
|
+
sharedFiltersCopy[0].active = 'option1'
|
|
513
|
+
const result = setAutoLoadDefaultValue(0, dropdownOptions, sharedFiltersCopy, [0])
|
|
514
|
+
expect(result.active).toEqual('option1')
|
|
515
|
+
})
|
|
516
|
+
|
|
517
|
+
it('should assign the default value if the current active value does not exist in dropdownOptions', () => {
|
|
518
|
+
const sharedFiltersCopy = _.cloneDeep(sharedFilters)
|
|
519
|
+
sharedFiltersCopy[0].active = 'nonexistent'
|
|
520
|
+
const result = setAutoLoadDefaultValue(0, dropdownOptions, sharedFiltersCopy, [0])
|
|
521
|
+
expect(result.active).toEqual('option1')
|
|
522
|
+
})
|
|
523
|
+
})
|