@datarailsshared/dr_renderer 1.3.59 → 1.4.6
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/.github/workflows/release.yml +44 -0
- package/.whitesource +3 -0
- package/README.md +44 -3
- package/package.json +5 -6
- package/src/charts/dr_donut_chart.js +3 -3
- package/src/charts/dr_gauge_categories_summary_chart.js +17 -17
- package/src/charts/dr_gauge_chart.js +226 -64
- package/src/dr-renderer-helpers.js +30 -13
- package/src/dr_pivottable.js +21 -29
- package/src/errors.js +174 -0
- package/src/highcharts_renderer.js +530 -343
- package/src/index.d.ts +63 -0
- package/src/index.js +14 -1
- package/src/pivot.css +0 -11
- package/src/pivottable.js +469 -508
- package/src/seriesPointStyles-helper.js +1 -1
- package/src/smart_queries_helper.js +62 -14
- package/src/types/errors.d.ts +120 -0
- package/src/types/index.d.ts +2 -0
- package/src/value.formatter.js +41 -0
- package/tests/dr-renderer-helpers.test.js +33 -0
- package/tests/dr_gauge_chart.test.js +88 -0
- package/tests/errors.test.js +157 -0
- package/tests/highcharts_renderer.test.js +1029 -67
- package/tests/mock/widgets.json +1 -3
- package/tests/ptCreateDrillDownSeriesToDrilldownChart.test.js +511 -0
- package/tests/value.formatter.test.js +143 -0
- package/tsconfig.json +2 -2
- package/tsconfig.tsbuildinfo +7 -0
- package/.github/workflows/build-deploy.yml +0 -28
- package/types/index.d.ts +0 -1
- /package/{types → src/types}/graph-table-renderer.d.ts +0 -0
package/tests/mock/widgets.json
CHANGED
@@ -314,7 +314,6 @@
|
|
314
314
|
},
|
315
315
|
"seriesOptions": []
|
316
316
|
},
|
317
|
-
"error_params": null,
|
318
317
|
"chart_title": "New Widget234",
|
319
318
|
"chartLabels": {
|
320
319
|
"legend": "Data series",
|
@@ -371,8 +370,7 @@
|
|
371
370
|
"is_end_of_period": true,
|
372
371
|
"is_formatting_by_aggregation_method": true
|
373
372
|
}
|
374
|
-
]
|
375
|
-
"error_has_occurred": false
|
373
|
+
]
|
376
374
|
},
|
377
375
|
"vals": [
|
378
376
|
{
|
@@ -0,0 +1,511 @@
|
|
1
|
+
import * as JQuery from "jquery";
|
2
|
+
import * as lodash from 'lodash';
|
3
|
+
import moment from 'moment/min/moment.min';
|
4
|
+
import initPivotTable from "../src/pivottable";
|
5
|
+
import initDRPivotTable from "../src/dr_pivottable";
|
6
|
+
|
7
|
+
const getHighchartsRenderer = require('../src/highcharts_renderer');
|
8
|
+
const DataFormatter = require('../src/dataformatter');
|
9
|
+
|
10
|
+
global.$ = JQuery;
|
11
|
+
global.lodash = lodash;
|
12
|
+
|
13
|
+
const Highcharts = {
|
14
|
+
Color: jest.fn(),
|
15
|
+
chart: jest.fn(),
|
16
|
+
setOptions: jest.fn(),
|
17
|
+
wrap: jest.fn(),
|
18
|
+
Tooltip: {
|
19
|
+
prototype: {
|
20
|
+
hide: jest.fn()
|
21
|
+
}
|
22
|
+
},
|
23
|
+
Point: {
|
24
|
+
prototype: {
|
25
|
+
setState: jest.fn()
|
26
|
+
}
|
27
|
+
},
|
28
|
+
Series: {
|
29
|
+
prototype: {
|
30
|
+
setState: jest.fn()
|
31
|
+
}
|
32
|
+
},
|
33
|
+
defaultOptions: {
|
34
|
+
global: {
|
35
|
+
useUTC: false
|
36
|
+
}
|
37
|
+
},
|
38
|
+
merge: jest.fn((target, source) => Object.assign({}, target, source))
|
39
|
+
};
|
40
|
+
|
41
|
+
const _document = {
|
42
|
+
createElement: jest.fn(() => ({
|
43
|
+
style: {},
|
44
|
+
setAttribute: jest.fn(),
|
45
|
+
appendChild: jest.fn()
|
46
|
+
})),
|
47
|
+
body: {
|
48
|
+
appendChild: jest.fn()
|
49
|
+
}
|
50
|
+
};
|
51
|
+
|
52
|
+
function createMockAggregator(value) {
|
53
|
+
return {
|
54
|
+
value: () => value
|
55
|
+
};
|
56
|
+
}
|
57
|
+
|
58
|
+
|
59
|
+
let highchartsRenderer = {};
|
60
|
+
|
61
|
+
describe('ptCreateDrillDownSeriesToDrilldownChart', () => {
|
62
|
+
let mockPivotData;
|
63
|
+
let mockChartOptions;
|
64
|
+
let mockAdditionOptions;
|
65
|
+
let mockOpts;
|
66
|
+
|
67
|
+
beforeAll(() => {
|
68
|
+
const _window = {
|
69
|
+
DataFormatter: DataFormatter
|
70
|
+
};
|
71
|
+
|
72
|
+
initPivotTable(JQuery, _window, _document);
|
73
|
+
initDRPivotTable(JQuery, _window, _document);
|
74
|
+
|
75
|
+
const DEFAULT_USER_COLORS = ['#7cb5ec', '#434348', '#90ed7d', '#f7a35c', '#8085e9', '#f15c80', '#e4d354', '#2b908f', '#f45b5b', '#91e8e1'];
|
76
|
+
highchartsRenderer = getHighchartsRenderer(JQuery, _document, Highcharts, lodash.cloneDeep(DEFAULT_USER_COLORS), highchartsRenderer, DataFormatter, lodash, moment, false);
|
77
|
+
});
|
78
|
+
|
79
|
+
beforeEach(() => {
|
80
|
+
const createMockAggregator = (value) => ({
|
81
|
+
value: () => value
|
82
|
+
});
|
83
|
+
|
84
|
+
mockPivotData = {
|
85
|
+
getRowKeys: jest.fn(() => [
|
86
|
+
['CITY SERVICE DEPTS'],
|
87
|
+
['MID-SOUTH'],
|
88
|
+
['NORTH TX'],
|
89
|
+
['SOUTH TX'],
|
90
|
+
['VIRGINIA'],
|
91
|
+
['CAROLINA']
|
92
|
+
]),
|
93
|
+
getColKeys: jest.fn(() => [
|
94
|
+
['003-NATIONAL ACCOUNTS'],
|
95
|
+
['015-MEMPHIS'],
|
96
|
+
['016-WICHITA FALLS'],
|
97
|
+
['017-AMARILLO'],
|
98
|
+
['019-AUSTIN'],
|
99
|
+
['020-NORFOLK'],
|
100
|
+
['023-NEWPORT NEWS'],
|
101
|
+
['035-CHARLOTTE CITY SERVICE']
|
102
|
+
]),
|
103
|
+
getAggregator: jest.fn((rowKey, colKey) => {
|
104
|
+
const rowStr = Array.isArray(rowKey) ? rowKey[0] : rowKey;
|
105
|
+
const colStr = Array.isArray(colKey) ? colKey[0] : colKey;
|
106
|
+
|
107
|
+
const dataMap = {
|
108
|
+
'CITY SERVICE DEPTS,003-NATIONAL ACCOUNTS': 305550.96,
|
109
|
+
'MID-SOUTH,015-MEMPHIS': 78827.94,
|
110
|
+
'NORTH TX,016-WICHITA FALLS': 28926.52,
|
111
|
+
'NORTH TX,017-AMARILLO': 92653.77,
|
112
|
+
'SOUTH TX,019-AUSTIN': 103645.51,
|
113
|
+
'VIRGINIA,020-NORFOLK': 0,
|
114
|
+
'VIRGINIA,023-NEWPORT NEWS': 19997.5,
|
115
|
+
'CAROLINA,035-CHARLOTTE CITY SERVICE': 124248.97
|
116
|
+
};
|
117
|
+
|
118
|
+
const key = `${rowStr},${colStr}`;
|
119
|
+
const value = dataMap[key] || null;
|
120
|
+
|
121
|
+
return createMockAggregator(value);
|
122
|
+
}),
|
123
|
+
colFormats: [
|
124
|
+
{
|
125
|
+
type: "Text",
|
126
|
+
name: "Br number & Name",
|
127
|
+
format: null,
|
128
|
+
val_not_convert: []
|
129
|
+
}
|
130
|
+
],
|
131
|
+
rowFormats: [
|
132
|
+
{
|
133
|
+
type: "Text",
|
134
|
+
name: "Area",
|
135
|
+
format: null,
|
136
|
+
val_not_convert: []
|
137
|
+
}
|
138
|
+
]
|
139
|
+
};
|
140
|
+
|
141
|
+
mockChartOptions = {
|
142
|
+
chart: {
|
143
|
+
type: 'pie'
|
144
|
+
}
|
145
|
+
};
|
146
|
+
|
147
|
+
mockAdditionOptions = {
|
148
|
+
dataLabels: {
|
149
|
+
color: '#151a41'
|
150
|
+
}
|
151
|
+
};
|
152
|
+
|
153
|
+
mockOpts = {
|
154
|
+
total_value_options: {
|
155
|
+
filter_options: {
|
156
|
+
filteredOutFieldName: 'Others'
|
157
|
+
}
|
158
|
+
}
|
159
|
+
};
|
160
|
+
|
161
|
+
jest.spyOn(highchartsRenderer, 'getFormattedColKey').mockImplementation((name) => name);
|
162
|
+
jest.spyOn(highchartsRenderer, 'getFormattedRowKey').mockImplementation((name) => Array.isArray(name) ? name : [name]);
|
163
|
+
jest.spyOn(highchartsRenderer, 'moveSeriesToSecondYAxisIfNeeded').mockImplementation(() => {});
|
164
|
+
jest.spyOn(highchartsRenderer, 'getDataLabelsStylesForDrillDown').mockReturnValue({
|
165
|
+
activeDataLabelStyle: {
|
166
|
+
color: '#151a41'
|
167
|
+
}
|
168
|
+
});
|
169
|
+
});
|
170
|
+
|
171
|
+
afterEach(() => {
|
172
|
+
jest.restoreAllMocks();
|
173
|
+
});
|
174
|
+
|
175
|
+
describe('with valid pivot data', () => {
|
176
|
+
it('should create drill-down series correctly', () => {
|
177
|
+
const result = highchartsRenderer.ptCreateDrillDownSeriesToDrilldownChart(
|
178
|
+
mockPivotData,
|
179
|
+
mockChartOptions,
|
180
|
+
mockAdditionOptions,
|
181
|
+
mockOpts
|
182
|
+
);
|
183
|
+
|
184
|
+
// Verify the structure of the result
|
185
|
+
expect(result).toHaveProperty('activeDataLabelStyle');
|
186
|
+
expect(result).toHaveProperty('series');
|
187
|
+
expect(result.activeDataLabelStyle).toEqual({
|
188
|
+
color: '#151a41'
|
189
|
+
});
|
190
|
+
|
191
|
+
// Verify series structure
|
192
|
+
expect(Array.isArray(result.series)).toBe(true);
|
193
|
+
expect(result.series.length).toBe(7);
|
194
|
+
|
195
|
+
// Check first series (003-NATIONAL ACCOUNTS)
|
196
|
+
const firstSeries = result.series[0];
|
197
|
+
expect(firstSeries).toMatchObject({
|
198
|
+
id: '003-NATIONAL ACCOUNTS',
|
199
|
+
initialName: '003-NATIONAL ACCOUNTS',
|
200
|
+
name: '003-NATIONAL ACCOUNTS',
|
201
|
+
data: expect.any(Array)
|
202
|
+
});
|
203
|
+
|
204
|
+
// Verify data points in first series
|
205
|
+
expect(firstSeries.data).toHaveLength(1);
|
206
|
+
expect(firstSeries.data[0]).toMatchObject({
|
207
|
+
name: ['CITY SERVICE DEPTS'],
|
208
|
+
initialName: ['CITY SERVICE DEPTS'],
|
209
|
+
y: 305550.96
|
210
|
+
});
|
211
|
+
});
|
212
|
+
|
213
|
+
it('should handle numeric column IDs correctly', () => {
|
214
|
+
// Test with numeric column keys
|
215
|
+
mockPivotData.getColKeys.mockReturnValue([
|
216
|
+
[123],
|
217
|
+
[456]
|
218
|
+
]);
|
219
|
+
|
220
|
+
mockPivotData.getAggregator.mockImplementation(() => createMockAggregator(100));
|
221
|
+
|
222
|
+
const result = highchartsRenderer.ptCreateDrillDownSeriesToDrilldownChart(
|
223
|
+
mockPivotData,
|
224
|
+
mockChartOptions,
|
225
|
+
mockAdditionOptions,
|
226
|
+
mockOpts
|
227
|
+
);
|
228
|
+
|
229
|
+
expect(result.series[0].id).toBe(123);
|
230
|
+
expect(result.series[1].id).toBe(456);
|
231
|
+
});
|
232
|
+
|
233
|
+
it('should handle boolean column IDs correctly', () => {
|
234
|
+
// Test with boolean column keys
|
235
|
+
mockPivotData.getColKeys.mockReturnValue([
|
236
|
+
[true],
|
237
|
+
[false]
|
238
|
+
]);
|
239
|
+
|
240
|
+
mockPivotData.getAggregator.mockImplementation(() => createMockAggregator(100));
|
241
|
+
|
242
|
+
const result = highchartsRenderer.ptCreateDrillDownSeriesToDrilldownChart(
|
243
|
+
mockPivotData,
|
244
|
+
mockChartOptions,
|
245
|
+
mockAdditionOptions,
|
246
|
+
mockOpts
|
247
|
+
);
|
248
|
+
|
249
|
+
expect(result.series[0].id).toBe('true');
|
250
|
+
expect(result.series[1].id).toBe('false');
|
251
|
+
});
|
252
|
+
|
253
|
+
it('should filter out null values', () => {
|
254
|
+
mockPivotData.getAggregator.mockImplementation((rowKey, colKey) => {
|
255
|
+
const rowStr = Array.isArray(rowKey) ? rowKey[0] : rowKey;
|
256
|
+
const colStr = Array.isArray(colKey) ? colKey[0] : colKey;
|
257
|
+
|
258
|
+
// Return null for specific combinations
|
259
|
+
if (rowStr === 'CITY SERVICE DEPTS' && colStr === '015-MEMPHIS') {
|
260
|
+
return { value: () => null };
|
261
|
+
}
|
262
|
+
|
263
|
+
return { value: () => 100 };
|
264
|
+
});
|
265
|
+
|
266
|
+
const result = highchartsRenderer.ptCreateDrillDownSeriesToDrilldownChart(
|
267
|
+
mockPivotData,
|
268
|
+
mockChartOptions,
|
269
|
+
mockAdditionOptions,
|
270
|
+
mockOpts
|
271
|
+
);
|
272
|
+
|
273
|
+
// Find the series for '015-MEMPHIS'
|
274
|
+
const memphisSeries = result.series.find(s => s.id === '015-MEMPHIS');
|
275
|
+
|
276
|
+
// Should not include data point with null value
|
277
|
+
expect(memphisSeries.data).not.toContainEqual(
|
278
|
+
expect.objectContaining({
|
279
|
+
name: ['CITY SERVICE DEPTS']
|
280
|
+
})
|
281
|
+
);
|
282
|
+
});
|
283
|
+
|
284
|
+
it('should handle undefined column keys', () => {
|
285
|
+
mockPivotData.getColKeys.mockReturnValue([
|
286
|
+
[undefined],
|
287
|
+
['valid-key']
|
288
|
+
]);
|
289
|
+
|
290
|
+
mockPivotData.getAggregator.mockImplementation((rowKey, colKey) => {
|
291
|
+
return { value: () => 100 }; // Return valid value for all combinations
|
292
|
+
});
|
293
|
+
|
294
|
+
const result = highchartsRenderer.ptCreateDrillDownSeriesToDrilldownChart(
|
295
|
+
mockPivotData,
|
296
|
+
mockChartOptions,
|
297
|
+
mockAdditionOptions,
|
298
|
+
mockOpts
|
299
|
+
);
|
300
|
+
|
301
|
+
// Should only process series with defined column keys (undefined keys are filtered out)
|
302
|
+
expect(result.series).toHaveLength(1);
|
303
|
+
expect(result.series[0].id).toBe('valid-key');
|
304
|
+
});
|
305
|
+
|
306
|
+
it('should handle empty row keys', () => {
|
307
|
+
mockPivotData.getRowKeys.mockReturnValue([
|
308
|
+
[null],
|
309
|
+
[''],
|
310
|
+
['valid-row']
|
311
|
+
]);
|
312
|
+
|
313
|
+
mockPivotData.getAggregator.mockImplementation((rowKey) => {
|
314
|
+
const rowStr = Array.isArray(rowKey) ? rowKey[0] : rowKey;
|
315
|
+
if (!rowStr) {
|
316
|
+
return { value: () => 100 };
|
317
|
+
}
|
318
|
+
return { value: () => 200 };
|
319
|
+
});
|
320
|
+
|
321
|
+
const result = highchartsRenderer.ptCreateDrillDownSeriesToDrilldownChart(
|
322
|
+
mockPivotData,
|
323
|
+
mockChartOptions,
|
324
|
+
mockAdditionOptions,
|
325
|
+
mockOpts
|
326
|
+
);
|
327
|
+
|
328
|
+
// Should filter out data points with null/empty row keys
|
329
|
+
result.series.forEach(series => {
|
330
|
+
series.data.forEach(dataPoint => {
|
331
|
+
expect(dataPoint.name[0]).toBeTruthy();
|
332
|
+
});
|
333
|
+
});
|
334
|
+
});
|
335
|
+
|
336
|
+
it('should convert string numbers to float', () => {
|
337
|
+
mockPivotData.getAggregator.mockImplementation(() => ({
|
338
|
+
value: () => '123.45' // Return string number
|
339
|
+
}));
|
340
|
+
|
341
|
+
const result = highchartsRenderer.ptCreateDrillDownSeriesToDrilldownChart(
|
342
|
+
mockPivotData,
|
343
|
+
mockChartOptions,
|
344
|
+
mockAdditionOptions,
|
345
|
+
mockOpts
|
346
|
+
);
|
347
|
+
|
348
|
+
result.series.forEach(series => {
|
349
|
+
series.data.forEach(dataPoint => {
|
350
|
+
expect(typeof dataPoint.y).toBe('number');
|
351
|
+
expect(dataPoint.y).toBe(123.45);
|
352
|
+
});
|
353
|
+
});
|
354
|
+
});
|
355
|
+
|
356
|
+
it('should remove duplicate data points', () => {
|
357
|
+
// Mock duplicate row keys
|
358
|
+
mockPivotData.getRowKeys.mockReturnValue([
|
359
|
+
['DUPLICATE'],
|
360
|
+
['DUPLICATE'],
|
361
|
+
['UNIQUE']
|
362
|
+
]);
|
363
|
+
|
364
|
+
mockPivotData.getAggregator.mockImplementation(() => ({
|
365
|
+
value: () => 100
|
366
|
+
}));
|
367
|
+
|
368
|
+
// Mock getFormattedRowKey to return same name for duplicates
|
369
|
+
jest.spyOn(highchartsRenderer, 'getFormattedRowKey').mockImplementation((name) => {
|
370
|
+
if (Array.isArray(name) && name[0] === 'DUPLICATE') {
|
371
|
+
return ['DUPLICATE'];
|
372
|
+
}
|
373
|
+
return Array.isArray(name) ? name : [name];
|
374
|
+
});
|
375
|
+
|
376
|
+
const result = highchartsRenderer.ptCreateDrillDownSeriesToDrilldownChart(
|
377
|
+
mockPivotData,
|
378
|
+
mockChartOptions,
|
379
|
+
mockAdditionOptions,
|
380
|
+
mockOpts
|
381
|
+
);
|
382
|
+
|
383
|
+
// Each series should have unique data points
|
384
|
+
result.series.forEach(series => {
|
385
|
+
const names = series.data.map(d => d.name.join(','));
|
386
|
+
const uniqueNames = [...new Set(names)];
|
387
|
+
expect(names.length).toBe(uniqueNames.length);
|
388
|
+
});
|
389
|
+
});
|
390
|
+
|
391
|
+
it('should call helper functions with correct parameters', () => {
|
392
|
+
highchartsRenderer.ptCreateDrillDownSeriesToDrilldownChart(
|
393
|
+
mockPivotData,
|
394
|
+
mockChartOptions,
|
395
|
+
mockAdditionOptions,
|
396
|
+
mockOpts
|
397
|
+
);
|
398
|
+
|
399
|
+
expect(highchartsRenderer.moveSeriesToSecondYAxisIfNeeded).toHaveBeenCalledWith(
|
400
|
+
expect.any(Array),
|
401
|
+
mockPivotData,
|
402
|
+
mockChartOptions,
|
403
|
+
mockAdditionOptions,
|
404
|
+
mockOpts
|
405
|
+
);
|
406
|
+
expect(highchartsRenderer.getDataLabelsStylesForDrillDown).toHaveBeenCalledWith(mockAdditionOptions);
|
407
|
+
});
|
408
|
+
|
409
|
+
it('should merge values when row name is a plain string (not array)', () => {
|
410
|
+
jest.spyOn(highchartsRenderer, 'getFormattedRowKey').mockImplementation(name => name);
|
411
|
+
|
412
|
+
mockPivotData.getRowKeys.mockReturnValue([ 'PLAIN_STRING_NAME' ]);
|
413
|
+
mockPivotData.getColKeys.mockReturnValue([ ['valid-key'] ]);
|
414
|
+
mockPivotData.getAggregator.mockImplementation(() => ({ value: () => 100 }));
|
415
|
+
|
416
|
+
const result = highchartsRenderer.ptCreateDrillDownSeriesToDrilldownChart(
|
417
|
+
mockPivotData,
|
418
|
+
mockChartOptions,
|
419
|
+
mockAdditionOptions,
|
420
|
+
mockOpts
|
421
|
+
);
|
422
|
+
|
423
|
+
expect(result.series).toHaveLength(1);
|
424
|
+
const dataPoint = result.series[0].data[0];
|
425
|
+
expect(dataPoint.name).toEqual(['PLAIN_STRING_NAME']);
|
426
|
+
expect(dataPoint.y).toBe(100);
|
427
|
+
});
|
428
|
+
});
|
429
|
+
|
430
|
+
describe('edge cases', () => {
|
431
|
+
it('should handle empty column keys', () => {
|
432
|
+
mockPivotData.getColKeys.mockReturnValue([]);
|
433
|
+
|
434
|
+
const result = highchartsRenderer.ptCreateDrillDownSeriesToDrilldownChart(
|
435
|
+
mockPivotData,
|
436
|
+
mockChartOptions,
|
437
|
+
mockAdditionOptions,
|
438
|
+
mockOpts
|
439
|
+
);
|
440
|
+
|
441
|
+
expect(result.series).toHaveLength(0);
|
442
|
+
});
|
443
|
+
|
444
|
+
it('should handle empty row keys', () => {
|
445
|
+
mockPivotData.getRowKeys.mockReturnValue([]);
|
446
|
+
|
447
|
+
const result = highchartsRenderer.ptCreateDrillDownSeriesToDrilldownChart(
|
448
|
+
mockPivotData,
|
449
|
+
mockChartOptions,
|
450
|
+
mockAdditionOptions,
|
451
|
+
mockOpts
|
452
|
+
);
|
453
|
+
|
454
|
+
// Series should exist but have no data
|
455
|
+
result.series.forEach(series => {
|
456
|
+
expect(series.data).toHaveLength(0);
|
457
|
+
});
|
458
|
+
});
|
459
|
+
|
460
|
+
it('should filter out series with no data', () => {
|
461
|
+
// Mock aggregator to return null for all combinations
|
462
|
+
mockPivotData.getAggregator.mockImplementation(() => ({
|
463
|
+
value: () => null
|
464
|
+
}));
|
465
|
+
|
466
|
+
const result = highchartsRenderer.ptCreateDrillDownSeriesToDrilldownChart(
|
467
|
+
mockPivotData,
|
468
|
+
mockChartOptions,
|
469
|
+
mockAdditionOptions,
|
470
|
+
mockOpts
|
471
|
+
);
|
472
|
+
|
473
|
+
expect(result.series).toHaveLength(0);
|
474
|
+
});
|
475
|
+
});
|
476
|
+
|
477
|
+
describe('with Others key handling', () => {
|
478
|
+
it('should replace DR_OTHERS_KEY with othersName', () => {
|
479
|
+
// Mock DR_OTHERS_KEY constant
|
480
|
+
highchartsRenderer.DR_OTHERS_KEY = 'DR_OTHERS_KEY';
|
481
|
+
|
482
|
+
mockPivotData.getColKeys.mockReturnValue([
|
483
|
+
['DR_OTHERS_KEY'],
|
484
|
+
['normal-key']
|
485
|
+
]);
|
486
|
+
|
487
|
+
mockPivotData.getRowKeys.mockReturnValue([
|
488
|
+
['DR_OTHERS_KEY'],
|
489
|
+
['normal-row']
|
490
|
+
]);
|
491
|
+
|
492
|
+
// Mock aggregator to return valid data
|
493
|
+
mockPivotData.getAggregator.mockImplementation((rowKey, colKey) => {
|
494
|
+
return { value: () => 100 }; // Return valid value for all combinations
|
495
|
+
});
|
496
|
+
|
497
|
+
const result = highchartsRenderer.ptCreateDrillDownSeriesToDrilldownChart(
|
498
|
+
mockPivotData,
|
499
|
+
mockChartOptions,
|
500
|
+
mockAdditionOptions,
|
501
|
+
mockOpts
|
502
|
+
);
|
503
|
+
|
504
|
+
// Check that DR_OTHERS_KEY is replaced with Others name
|
505
|
+
const othersColSeries = result.series.find(s => s.initialName === 'Others');
|
506
|
+
expect(othersColSeries).toBeDefined();
|
507
|
+
expect(othersColSeries.name).toBe('Others');
|
508
|
+
});
|
509
|
+
});
|
510
|
+
});
|
511
|
+
|
@@ -0,0 +1,143 @@
|
|
1
|
+
const { getAggregatorPercentageValueIfRequired, getRelatedValue, isAbsoluteValue } = require('../src/value.formatter');
|
2
|
+
|
3
|
+
describe('Function getAggregatorPercentageValueIfRequired', () => {
|
4
|
+
let render_options, rowKey, colKey;
|
5
|
+
|
6
|
+
beforeEach(() => {
|
7
|
+
render_options = {
|
8
|
+
comboOptions: { secondaryAxisSettings: { is_percentage: true } },
|
9
|
+
chartOptions: {
|
10
|
+
delta_column: {
|
11
|
+
name: 'Variance',
|
12
|
+
formula: 'x2-x1',
|
13
|
+
is_percentage: false
|
14
|
+
}
|
15
|
+
}
|
16
|
+
};
|
17
|
+
rowKey = ['Variance'];
|
18
|
+
colKey = ['SomeCol'];
|
19
|
+
});
|
20
|
+
|
21
|
+
it('should return percentage string when secondaryAxisSettings.is_percentage is true but delta_column.is_percentage is false', () => {
|
22
|
+
const data = {
|
23
|
+
rowKeys: ['Variance'],
|
24
|
+
getAggregator: jest.fn(() => ({
|
25
|
+
value: () => 200
|
26
|
+
}))
|
27
|
+
};
|
28
|
+
const result = getAggregatorPercentageValueIfRequired(50, render_options, data, rowKey, colKey);
|
29
|
+
expect(result).toBe('25%');
|
30
|
+
});
|
31
|
+
|
32
|
+
it('should return percentage string when secondaryAxisSettings.is_percentage is false but delta_column.is_percentage is true', () => {
|
33
|
+
const data = {
|
34
|
+
rowKeys: ['Variance'],
|
35
|
+
getAggregator: jest.fn(() => ({
|
36
|
+
value: () => 200
|
37
|
+
}))
|
38
|
+
};
|
39
|
+
render_options.comboOptions.secondaryAxisSettings.is_percentage = false;
|
40
|
+
render_options.chartOptions.delta_column.is_percentage = true;
|
41
|
+
const result = getAggregatorPercentageValueIfRequired(50, render_options, data, rowKey, colKey);
|
42
|
+
expect(result).toBe('25%');
|
43
|
+
});
|
44
|
+
|
45
|
+
it('should return null if is_percentage is false', () => {
|
46
|
+
const data = {
|
47
|
+
rowKeys: ['Variance'],
|
48
|
+
getAggregator: jest.fn()
|
49
|
+
};
|
50
|
+
render_options.comboOptions.secondaryAxisSettings.is_percentage = false;
|
51
|
+
const result = getAggregatorPercentageValueIfRequired(50, render_options, data, rowKey, colKey);
|
52
|
+
expect(result).toBeNull();
|
53
|
+
});
|
54
|
+
|
55
|
+
it('should return null if isVariance is false', () => {
|
56
|
+
const data = {
|
57
|
+
rowKeys: ['NotVariance'],
|
58
|
+
getAggregator: jest.fn()
|
59
|
+
};
|
60
|
+
rowKey = ['NotVariance'];
|
61
|
+
const result = getAggregatorPercentageValueIfRequired(50, render_options, data, rowKey, colKey);
|
62
|
+
expect(result).toBeNull();
|
63
|
+
});
|
64
|
+
|
65
|
+
it('should return null if baseRowKey is missing', () => {
|
66
|
+
const data = {
|
67
|
+
rowKeys: [],
|
68
|
+
getAggregator: jest.fn()
|
69
|
+
};
|
70
|
+
const result = getAggregatorPercentageValueIfRequired(50, render_options, data, rowKey, colKey);
|
71
|
+
expect(result).toBeNull();
|
72
|
+
});
|
73
|
+
|
74
|
+
it('should return null if agg is missing', () => {
|
75
|
+
const data = {
|
76
|
+
rowKeys: ['Variance'],
|
77
|
+
getAggregator: jest.fn(() => null)
|
78
|
+
};
|
79
|
+
const result = getAggregatorPercentageValueIfRequired(50, render_options, data, rowKey, colKey);
|
80
|
+
expect(result).toBeNull();
|
81
|
+
});
|
82
|
+
|
83
|
+
it('should return null if data is null', () => {
|
84
|
+
const result = getAggregatorPercentageValueIfRequired(50, render_options, null, rowKey, colKey);
|
85
|
+
expect(result).toBeNull();
|
86
|
+
});
|
87
|
+
|
88
|
+
it('should return null if data is undefined', () => {
|
89
|
+
const result = getAggregatorPercentageValueIfRequired(50, render_options, undefined, rowKey, colKey);
|
90
|
+
expect(result).toBeNull();
|
91
|
+
});
|
92
|
+
|
93
|
+
it('should return null if baseRowKey is null even when data exists', () => {
|
94
|
+
const data = {
|
95
|
+
rowKeys: [null],
|
96
|
+
getAggregator: jest.fn()
|
97
|
+
};
|
98
|
+
const result = getAggregatorPercentageValueIfRequired(50, render_options, data, rowKey, colKey);
|
99
|
+
expect(result).toBeNull();
|
100
|
+
expect(data.getAggregator).not.toHaveBeenCalled();
|
101
|
+
});
|
102
|
+
});
|
103
|
+
|
104
|
+
describe('Function getRelatedValue', () => {
|
105
|
+
it('should return -1 when baseValue is falsy and value < 0', () => {
|
106
|
+
expect(getRelatedValue(-50, 0)).toBe(-1);
|
107
|
+
});
|
108
|
+
|
109
|
+
it('should return 1 when baseValue is falsy and value >= 0', () => {
|
110
|
+
expect(getRelatedValue(50, null)).toBe(1);
|
111
|
+
});
|
112
|
+
|
113
|
+
it('should return related value when baseValue is truthy', () => {
|
114
|
+
expect(getRelatedValue(50, 200)).toBe(0.25);
|
115
|
+
expect(getRelatedValue(200, 200)).toBe(1);
|
116
|
+
});
|
117
|
+
});
|
118
|
+
|
119
|
+
describe('Function isAbsoluteValue', () => {
|
120
|
+
it('should return false if formula is undefined', () => {
|
121
|
+
expect(isAbsoluteValue(undefined)).toBe(false);
|
122
|
+
});
|
123
|
+
|
124
|
+
it('should return false if formula is null', () => {
|
125
|
+
expect(isAbsoluteValue(null)).toBe(false);
|
126
|
+
});
|
127
|
+
|
128
|
+
it('should return false if formula contains "/"', () => {
|
129
|
+
expect(isAbsoluteValue('/')).toBe(false);
|
130
|
+
expect(isAbsoluteValue(' / ')).toBe(false);
|
131
|
+
});
|
132
|
+
|
133
|
+
it('should return true if formula does not contain "/"', () => {
|
134
|
+
expect(isAbsoluteValue('x2-x1')).toBe(true);
|
135
|
+
expect(isAbsoluteValue(' x1 - x2 ')).toBe(true);
|
136
|
+
expect(isAbsoluteValue('some text x2-x1 more text')).toBe(true);
|
137
|
+
});
|
138
|
+
|
139
|
+
it('should ignore spaces in formula', () => {
|
140
|
+
expect(isAbsoluteValue('x2 - x1')).toBe(true);
|
141
|
+
expect(isAbsoluteValue(' x1 - x2 ')).toBe(true);
|
142
|
+
});
|
143
|
+
});
|
package/tsconfig.json
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
"compilerOptions": {
|
3
3
|
"declaration": true,
|
4
4
|
"allowJs": true,
|
5
|
-
"declarationDir": "./types",
|
5
|
+
"declarationDir": "./src/types",
|
6
6
|
"checkJs": true,
|
7
7
|
"moduleResolution": "Node16",
|
8
8
|
"module": "Node16",
|
@@ -10,6 +10,6 @@
|
|
10
10
|
"emitDeclarationOnly": true,
|
11
11
|
"strict": true
|
12
12
|
},
|
13
|
-
"include": ["./src/graph-table-renderer.js"],
|
13
|
+
"include": ["./src/graph-table-renderer.js", "./src/errors.js"],
|
14
14
|
"exclude": ["node_modules"]
|
15
15
|
}
|