@datarailsshared/dr_renderer 1.3.57 → 1.4.5
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 +45 -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
@@ -30,7 +30,7 @@ function setInitialPointStyles(opts, series) {
|
|
30
30
|
const isSelected =
|
31
31
|
item && opts.selectedPoint &&
|
32
32
|
item.initialName === opts.selectedPoint.initialName &&
|
33
|
-
item.y.toFixed(2) === opts.selectedPoint.y.toFixed(2);
|
33
|
+
item.y != null && item.y.toFixed(2) === opts.selectedPoint.y != null && opts.selectedPoint.y.toFixed(2);
|
34
34
|
item = Object.assign(item, getSeriesPointStyles(isSelected));
|
35
35
|
});
|
36
36
|
}
|
@@ -5,37 +5,40 @@ const DR_SCENARIO = {
|
|
5
5
|
Forecast: 'Forecast',
|
6
6
|
};
|
7
7
|
|
8
|
-
function createSingleDataSeriesForForecast(chart_series, chartOptions, pivotData) {
|
8
|
+
function createSingleDataSeriesForForecast(chart_series, chartOptions, pivotData, isChartCombiLine) {
|
9
|
+
if (!chartOptions || !chartOptions.chart) return null;
|
10
|
+
|
9
11
|
const { actuals, forecast, smart_query } = chartOptions.chart;
|
10
12
|
const input = pivotData.input;
|
11
13
|
|
12
|
-
const hasSQActuals =
|
14
|
+
const hasSQActuals = lodash.some(input, item => lodash.includes(item.Scenario, DR_SCENARIO.SQ_Actuals));
|
13
15
|
chartOptions.isSmartQueriesEnabled = hasSQActuals;
|
14
16
|
if (!smart_query || !hasSQActuals) return null;
|
15
17
|
|
16
18
|
const midMonthOffset = 0.5
|
17
|
-
|
18
|
-
|
19
|
-
|
19
|
+
return chart_series.length === 1
|
20
|
+
? buildChartSeriesFromPivotInputOnly(input, actuals, forecast, midMonthOffset, chart_series[0].name)
|
21
|
+
: (isChartCombiLine ?
|
22
|
+
buildChartSeriesForMultipleSeriesCombinedLine(chart_series, input, actuals, forecast, midMonthOffset) :
|
23
|
+
buildChartSeriesFromSeries(chart_series, actuals, forecast, midMonthOffset));
|
20
24
|
}
|
21
25
|
|
22
|
-
function buildChartSeriesFromPivotInputOnly(input, actuals, forecast, midMonthOffset) {
|
26
|
+
function buildChartSeriesFromPivotInputOnly(input, actuals, forecast, midMonthOffset, name) {
|
23
27
|
const filtered = input.filter(item =>
|
24
|
-
(item.Scenario === DR_SCENARIO.SQ_Actuals || item.Scenario === DR_SCENARIO.Forecast) &&
|
25
|
-
item.Amount !== 0
|
28
|
+
(item.Scenario === DR_SCENARIO.SQ_Actuals || item.Scenario === DR_SCENARIO.Forecast) && !!item['Reporting Month']
|
26
29
|
);
|
27
30
|
|
28
|
-
const data =
|
31
|
+
const data = lodash.map(filtered, item => ({
|
29
32
|
y: item.Amount,
|
30
|
-
name: item
|
31
|
-
initialName: item
|
33
|
+
name: item['Reporting Month'],
|
34
|
+
initialName: item['Reporting Month'],
|
32
35
|
type: item.Scenario,
|
33
|
-
})).sort((a, b) =>
|
36
|
+
})).sort((a, b) => sortRowValuesByName(a, b));
|
34
37
|
|
35
|
-
const sqCount =
|
38
|
+
const sqCount = lodash.filter(input, item => item.Scenario === DR_SCENARIO.SQ_Actuals).length;
|
36
39
|
|
37
40
|
return {
|
38
|
-
name
|
41
|
+
name,
|
39
42
|
data,
|
40
43
|
zoneAxis: "x",
|
41
44
|
zones: [
|
@@ -45,6 +48,51 @@ function buildChartSeriesFromPivotInputOnly(input, actuals, forecast, midMonthOf
|
|
45
48
|
};
|
46
49
|
}
|
47
50
|
|
51
|
+
function buildChartSeriesForMultipleSeriesCombinedLine(chart_series, input, actuals, forecast, midMonthOffset) {
|
52
|
+
const resultingSeries = [];
|
53
|
+
for (let i = 0; i < chart_series.length; i++) {
|
54
|
+
const series = chart_series[i];
|
55
|
+
if (!series || !series.data || !series.data.length) continue;
|
56
|
+
|
57
|
+
const data = lodash.chain(input)
|
58
|
+
.filter(item => item['Scenario Cycle'] === series.name &&
|
59
|
+
(item['Scenario'] === DR_SCENARIO.SQ_Actuals || item['Scenario'] === DR_SCENARIO.Forecast) && !!item['Reporting Month'])
|
60
|
+
.map(item => ({
|
61
|
+
y: item.Amount,
|
62
|
+
name: item['Reporting Month'],
|
63
|
+
initialName: item['Reporting Month'],
|
64
|
+
type: item.Scenario,
|
65
|
+
}))
|
66
|
+
.value().sort((a, b) => {
|
67
|
+
return sortRowValuesByName(a, b);
|
68
|
+
});
|
69
|
+
if (!data.length) {
|
70
|
+
resultingSeries.push(series);
|
71
|
+
continue;
|
72
|
+
}
|
73
|
+
|
74
|
+
const sqCount = lodash.filter(data, item => item.type === DR_SCENARIO.SQ_Actuals).length;
|
75
|
+
resultingSeries.push(
|
76
|
+
{
|
77
|
+
name: series.name,
|
78
|
+
data,
|
79
|
+
zoneAxis: "x",
|
80
|
+
zones: [
|
81
|
+
{ value: sqCount - midMonthOffset, dashStyle: actuals },
|
82
|
+
{ dashStyle: forecast },
|
83
|
+
],
|
84
|
+
}
|
85
|
+
)
|
86
|
+
}
|
87
|
+
return resultingSeries;
|
88
|
+
}
|
89
|
+
|
90
|
+
function sortRowValuesByName(rowValueA, rowValueB) {
|
91
|
+
const aDate = new Date(rowValueA.name);
|
92
|
+
const bDate = new Date(rowValueB.name);
|
93
|
+
return !isNaN(aDate.getTime()) && !isNaN(bDate.getTime()) ? aDate - bDate : rowValueA.name.localeCompare(rowValueB.name);
|
94
|
+
}
|
95
|
+
|
48
96
|
function buildChartSeriesFromSeries(chart_series, actuals, forecast, midMonthOffset) {
|
49
97
|
const seriesA = lodash.find(chart_series, s => s.name && lodash.includes(s.name, DR_SCENARIO.SQ_Actuals));
|
50
98
|
const seriesB = lodash.find(chart_series, s => s.name && lodash.includes(s.name, DR_SCENARIO.Forecast));
|
@@ -0,0 +1,120 @@
|
|
1
|
+
/**
|
2
|
+
* Enum for dr renderer error codes.
|
3
|
+
*/
|
4
|
+
export type RendererErrorCodes = number;
|
5
|
+
export namespace RendererErrorCodes {
|
6
|
+
let NoDataError: number;
|
7
|
+
let TooMuchDataError: number;
|
8
|
+
let DataConflictError: number;
|
9
|
+
let GaugeConfigurationError: number;
|
10
|
+
let GenericRenderingError: number;
|
11
|
+
let GenericComputationalError: number;
|
12
|
+
}
|
13
|
+
/**
|
14
|
+
* Base error class for all renderer-related errors.
|
15
|
+
* @class BaseRendererError
|
16
|
+
* @extends Error
|
17
|
+
*/
|
18
|
+
export class BaseRendererError extends Error {
|
19
|
+
/**
|
20
|
+
* Creates a new BaseRendererError instance.
|
21
|
+
* @param {Object} config - Error configuration object
|
22
|
+
* @param {number} config.code - Unique error code
|
23
|
+
* @param {string} config.title - Error title/message
|
24
|
+
* @param {Object} [config.options={}] - Additional error options or context
|
25
|
+
*/
|
26
|
+
constructor({ code, title, options }: {
|
27
|
+
code: number;
|
28
|
+
title: string;
|
29
|
+
options?: Object | undefined;
|
30
|
+
});
|
31
|
+
/**
|
32
|
+
* Error code for identification purposes
|
33
|
+
* @type {number}
|
34
|
+
*/
|
35
|
+
code: number;
|
36
|
+
/**
|
37
|
+
* Human-readable error title
|
38
|
+
* @type {string}
|
39
|
+
*/
|
40
|
+
title: string;
|
41
|
+
/**
|
42
|
+
* Additional options or context for the error
|
43
|
+
* @type {Object}
|
44
|
+
*/
|
45
|
+
options: Object;
|
46
|
+
}
|
47
|
+
/**
|
48
|
+
* Error thrown when there is too much data to render efficiently.
|
49
|
+
* @class TooMuchDataError
|
50
|
+
* @extends BaseRendererError
|
51
|
+
*/
|
52
|
+
export class TooMuchDataError extends BaseRendererError {
|
53
|
+
/**
|
54
|
+
* Creates a new TooMuchDataError instance.
|
55
|
+
* This error is thrown when the dataset exceeds the renderer's capacity
|
56
|
+
* and requires the user to edit the widget.
|
57
|
+
*/
|
58
|
+
constructor();
|
59
|
+
}
|
60
|
+
/**
|
61
|
+
* Error thrown when no data is available.
|
62
|
+
* @class NoDataError
|
63
|
+
* @extends BaseRendererError
|
64
|
+
*/
|
65
|
+
export class NoDataError extends BaseRendererError {
|
66
|
+
/**
|
67
|
+
* Creates a new NoDataError instance.
|
68
|
+
* This error is thrown when a widget or component has no available data.
|
69
|
+
*/
|
70
|
+
constructor();
|
71
|
+
}
|
72
|
+
/**
|
73
|
+
* Error thrown when there are conflicts in the data being processed.
|
74
|
+
* @class DataConflictError
|
75
|
+
* @extends BaseRendererError
|
76
|
+
*/
|
77
|
+
export class DataConflictError extends BaseRendererError {
|
78
|
+
/**
|
79
|
+
* Creates a new DataConflictError instance.
|
80
|
+
* @param {Object} [options] - Additional context about the data conflict.
|
81
|
+
*/
|
82
|
+
constructor(options?: Object);
|
83
|
+
}
|
84
|
+
/**
|
85
|
+
* Error thrown when a gauge chart is missing required info.
|
86
|
+
* @class GaugeConfigurationError
|
87
|
+
* @extends BaseRendererError
|
88
|
+
*/
|
89
|
+
export class GaugeConfigurationError extends BaseRendererError {
|
90
|
+
/**
|
91
|
+
* Creates a new GaugeConfigurationError instance.
|
92
|
+
*/
|
93
|
+
constructor();
|
94
|
+
}
|
95
|
+
/**
|
96
|
+
* Generic error for rendering failures in PivotTable components.
|
97
|
+
* @class GenericRenderingError
|
98
|
+
* @extends BaseRendererError
|
99
|
+
*/
|
100
|
+
export class GenericRenderingError extends BaseRendererError {
|
101
|
+
/**
|
102
|
+
* Creates a new GenericRenderingError instance.
|
103
|
+
* This error is thrown when an unexpected error occurs during
|
104
|
+
* the rendering process of PivotTable results.
|
105
|
+
*/
|
106
|
+
constructor();
|
107
|
+
}
|
108
|
+
/**
|
109
|
+
* Generic error for computational failures in PivotTable components.
|
110
|
+
* @class GenericComputationalError
|
111
|
+
* @extends BaseRendererError
|
112
|
+
*/
|
113
|
+
export class GenericComputationalError extends BaseRendererError {
|
114
|
+
/**
|
115
|
+
* Creates a new GenericComputationalError instance.
|
116
|
+
* This error is thrown when an unexpected error occurs during
|
117
|
+
* the computation process of PivotTable results.
|
118
|
+
*/
|
119
|
+
constructor();
|
120
|
+
}
|
@@ -0,0 +1,41 @@
|
|
1
|
+
const lodash = require('lodash');
|
2
|
+
|
3
|
+
function getAggregatorPercentageValueIfRequired(value, render_options, data, rowKey, colKey) {
|
4
|
+
const deltaColumn = lodash.get(render_options, 'chartOptions.delta_column', null);
|
5
|
+
const isPercentage = lodash.get(render_options, 'comboOptions.secondaryAxisSettings.is_percentage', false) || deltaColumn && deltaColumn.is_percentage;
|
6
|
+
const currentRowName = rowKey && rowKey.length ? String(rowKey[0]) : '';
|
7
|
+
const isVariance = deltaColumn && currentRowName.replace('_', '').toLowerCase() === deltaColumn.name.replace('_', '').toLowerCase();
|
8
|
+
const baseRowKey = data && data.rowKeys && data.rowKeys.length ? data.rowKeys[0] : null;
|
9
|
+
const currentColKey = colKey ? colKey : [];
|
10
|
+
const agg = data && baseRowKey ? data.getAggregator(baseRowKey, currentColKey) : null;
|
11
|
+
|
12
|
+
if (isPercentage && isVariance && baseRowKey && agg) {
|
13
|
+
if (deltaColumn && isAbsoluteValue(deltaColumn.formula)) {
|
14
|
+
value = getRelatedValue(value, agg.value());
|
15
|
+
}
|
16
|
+
|
17
|
+
return Math.round(value * 100) + '%';
|
18
|
+
}
|
19
|
+
|
20
|
+
return null;
|
21
|
+
};
|
22
|
+
|
23
|
+
function getRelatedValue(value, baseValue) {
|
24
|
+
if (!baseValue)
|
25
|
+
return value < 0 ? -1 : 1;
|
26
|
+
|
27
|
+
return value / baseValue;
|
28
|
+
};
|
29
|
+
|
30
|
+
function isAbsoluteValue(formula) {
|
31
|
+
if (!formula)
|
32
|
+
return false;
|
33
|
+
|
34
|
+
return !lodash.includes(formula.replace(/\s+/g, ''), '/');
|
35
|
+
};
|
36
|
+
|
37
|
+
module.exports = {
|
38
|
+
getAggregatorPercentageValueIfRequired,
|
39
|
+
getRelatedValue,
|
40
|
+
isAbsoluteValue
|
41
|
+
};
|
@@ -73,6 +73,39 @@ describe('dr-renderer-helpers', () => {
|
|
73
73
|
expect(drRendererHelpers.mergeDeep({ a: 1 }, 'string')).toEqual({ a: 1 });
|
74
74
|
});
|
75
75
|
|
76
|
+
it('does not mutate sources', () => {
|
77
|
+
const src1 = { a: { x: 1 }, arr: [1,2] };
|
78
|
+
const src2 = { a: { y: 2 }, arr: [3] };
|
79
|
+
const res = drRendererHelpers.mergeDeep({}, src1, src2);
|
80
|
+
|
81
|
+
res.a.x = 42;
|
82
|
+
res.arr.push(99);
|
83
|
+
|
84
|
+
expect(src1).toEqual({ a: { x: 1 }, arr: [1,2] });
|
85
|
+
expect(src2).toEqual({ a: { y: 2 }, arr: [3] });
|
86
|
+
});
|
87
|
+
|
88
|
+
it('replaces arrays by clone, not by reference', () => {
|
89
|
+
const src = { a: [1,2,3] };
|
90
|
+
const res = drRendererHelpers.mergeDeep({}, src);
|
91
|
+
expect(res.a).not.toBe(src.a);
|
92
|
+
});
|
93
|
+
|
94
|
+
it('ignores non-plain objects', () => {
|
95
|
+
const d = new Date();
|
96
|
+
const res = drRendererHelpers.mergeDeep({}, { when: d });
|
97
|
+
expect(res.when).toBe(d);
|
98
|
+
});
|
99
|
+
|
100
|
+
it('last source wins (and arrays are replaced)', () => {
|
101
|
+
const res = drRendererHelpers.mergeDeep(
|
102
|
+
{ a: { x: 1 }, arr: [1] },
|
103
|
+
{ a: { y: 2 }, arr: [2] },
|
104
|
+
{ a: { z: 3 }, arr: [3] },
|
105
|
+
);
|
106
|
+
expect(res).toEqual({ a: { x:1, y:2, z:3 }, arr: [3] });
|
107
|
+
});
|
108
|
+
|
76
109
|
it('should not merge arrays and replace instead', () => {
|
77
110
|
expect(drRendererHelpers.mergeDeep({
|
78
111
|
a: [1, 2, 3]
|
@@ -23,6 +23,7 @@ DrGaugeChart.highchartsRenderer = {
|
|
23
23
|
}),
|
24
24
|
disableChartAnimations: jest.fn((value) => disableChartAnimation = value),
|
25
25
|
chartAnimationsDisabled: jest.fn(() => disableChartAnimation),
|
26
|
+
hasFeature: jest.fn().mockReturnValue(false),
|
26
27
|
};
|
27
28
|
|
28
29
|
const mockAggregationValue = 1000;
|
@@ -309,6 +310,93 @@ describe("DrGaugeChart", () => {
|
|
309
310
|
},
|
310
311
|
]);
|
311
312
|
});
|
313
|
+
|
314
|
+
it("scales by needle magnitude when goal is 0 in percentage mode", () => {
|
315
|
+
chart.value = 250;
|
316
|
+
expect(
|
317
|
+
chart.createPlotBands({
|
318
|
+
isAbsoluteValue: false,
|
319
|
+
gauge: { thickness: 10 },
|
320
|
+
goal: { value: 0 },
|
321
|
+
segments: [
|
322
|
+
{ from: 0, to: 50, color: "red", title: "Title 1" },
|
323
|
+
{ from: 50, to: 100, color: "blue", title: "Title 2" },
|
324
|
+
],
|
325
|
+
})
|
326
|
+
).toEqual([
|
327
|
+
{ from: 0, to: 125, color: "red", thickness: 10, title: "Title 1" },
|
328
|
+
{ from: 125, to: 250, color: "blue", thickness: 10, title: "Title 2" },
|
329
|
+
]);
|
330
|
+
});
|
331
|
+
|
332
|
+
it("scales by absolute needle magnitude when goal is not a number", () => {
|
333
|
+
const featureSpy = jest
|
334
|
+
.spyOn(DrGaugeChart.highchartsRenderer, "hasFeature")
|
335
|
+
.mockReturnValue(true);
|
336
|
+
|
337
|
+
chart.value = -300;
|
338
|
+
const res = chart.createPlotBands({
|
339
|
+
isAbsoluteValue: false,
|
340
|
+
gauge: { thickness: 8 },
|
341
|
+
goal: { value: undefined },
|
342
|
+
segments: [
|
343
|
+
{ from: 0, to: 50, color: "#1", title: "A" },
|
344
|
+
{ from: 50, to: 100, color: "#2", title: "B" },
|
345
|
+
],
|
346
|
+
});
|
347
|
+
|
348
|
+
expect(res).toEqual([
|
349
|
+
{ from: 0, to: 150, color: "#1", thickness: 8, title: "A" },
|
350
|
+
{ from: 150, to: 300, color: "#2", thickness: 8, title: "B" },
|
351
|
+
]);
|
352
|
+
|
353
|
+
featureSpy.mockRestore();
|
354
|
+
});
|
355
|
+
|
356
|
+
it("normalizes bands when goal is negative in percentage mode", () => {
|
357
|
+
const res = chart.createPlotBands({
|
358
|
+
isAbsoluteValue: false,
|
359
|
+
gauge: { thickness: 12 },
|
360
|
+
goal: { value: -1000 },
|
361
|
+
segments: [
|
362
|
+
{ from: 0, to: 50, color: "r", title: "S1" },
|
363
|
+
{ from: 50, to: 100, color: "b", title: "S2" },
|
364
|
+
],
|
365
|
+
});
|
366
|
+
|
367
|
+
expect(res[0].from).toBe(-500);
|
368
|
+
expect(Math.abs(res[0].to)).toBe(0);
|
369
|
+
expect(res[0].color).toBe("r");
|
370
|
+
expect(res[0].thickness).toBe(12);
|
371
|
+
expect(res[0].title).toBe("S1");
|
372
|
+
|
373
|
+
expect(res[1]).toEqual({ from: -1000, to: -500, color: "b", thickness: 12, title: "S2" });
|
374
|
+
});
|
375
|
+
|
376
|
+
it("does not clamp last segment when dynamic goal feature is enabled", () => {
|
377
|
+
const featureSpy = jest
|
378
|
+
.spyOn(DrGaugeChart.highchartsRenderer, "hasFeature")
|
379
|
+
.mockReturnValue(true);
|
380
|
+
|
381
|
+
const res = chart.createPlotBands({
|
382
|
+
isAbsoluteValue: true,
|
383
|
+
gauge: { thickness: 10 },
|
384
|
+
goal: { value: 1800 },
|
385
|
+
segments: [
|
386
|
+
{ from: 100, to: 200, color: "red", title: "Title 1" },
|
387
|
+
{ from: 200, to: 400, color: "blue", title: "Title 2" },
|
388
|
+
{ from: 400, to: 800, color: "green", title: "Title 3" },
|
389
|
+
],
|
390
|
+
});
|
391
|
+
|
392
|
+
expect(res).toEqual([
|
393
|
+
{ from: 100, to: 200, color: "red", thickness: 10, title: "Title 1" },
|
394
|
+
{ from: 200, to: 400, color: "blue", thickness: 10, title: "Title 2" },
|
395
|
+
{ from: 400, to: 800, color: "green", thickness: 10, title: "Title 3" },
|
396
|
+
]);
|
397
|
+
|
398
|
+
featureSpy.mockRestore();
|
399
|
+
});
|
312
400
|
});
|
313
401
|
|
314
402
|
describe("createTicks", () => {
|
@@ -0,0 +1,157 @@
|
|
1
|
+
const {
|
2
|
+
BaseRendererError,
|
3
|
+
NoDataError,
|
4
|
+
TooMuchDataError,
|
5
|
+
DataConflictError,
|
6
|
+
GaugeConfigurationError,
|
7
|
+
GenericRenderingError,
|
8
|
+
GenericComputationalError
|
9
|
+
} = require('../src/errors');
|
10
|
+
|
11
|
+
describe('Error Classes', () => {
|
12
|
+
describe('BaseRendererError', () => {
|
13
|
+
it('should create instance with provided code and title', () => {
|
14
|
+
const error = new BaseRendererError({ code: 5, title: 'Test Error' });
|
15
|
+
|
16
|
+
expect(error.code).toBe(5);
|
17
|
+
expect(error.title).toBe('Test Error');
|
18
|
+
});
|
19
|
+
|
20
|
+
it('should create instance with options parameter', () => {
|
21
|
+
const options = { isBreakdown: true, minCategories: 5 };
|
22
|
+
const error = new BaseRendererError({ code: 5, title: 'Test Error', options });
|
23
|
+
|
24
|
+
expect(error.code).toBe(5);
|
25
|
+
expect(error.title).toBe('Test Error');
|
26
|
+
expect(error.options).toEqual(options);
|
27
|
+
});
|
28
|
+
|
29
|
+
it('should set empty options object when no options provided', () => {
|
30
|
+
const error = new BaseRendererError({ code: 1, title: 'Test' });
|
31
|
+
|
32
|
+
expect(error.options).toEqual({});
|
33
|
+
});
|
34
|
+
|
35
|
+
it('should be instance of BaseRendererError', () => {
|
36
|
+
const error = new BaseRendererError({ code: 1, title: 'Test' });
|
37
|
+
expect(error).toBeInstanceOf(BaseRendererError);
|
38
|
+
});
|
39
|
+
|
40
|
+
it('should be instance of Error', () => {
|
41
|
+
const error = new BaseRendererError({ code: 1, title: 'Test' });
|
42
|
+
expect(error).toBeInstanceOf(Error);
|
43
|
+
});
|
44
|
+
});
|
45
|
+
|
46
|
+
describe('NoDataError', () => {
|
47
|
+
it('should create instance with correct code and title', () => {
|
48
|
+
const error = new NoDataError();
|
49
|
+
|
50
|
+
expect(error.code).toBe(1);
|
51
|
+
expect(error.title).toBe('No Data Available');
|
52
|
+
});
|
53
|
+
|
54
|
+
it('should be instance of BaseRendererError', () => {
|
55
|
+
const error = new NoDataError();
|
56
|
+
expect(error).toBeInstanceOf(BaseRendererError);
|
57
|
+
});
|
58
|
+
});
|
59
|
+
|
60
|
+
describe('TooMuchDataError', () => {
|
61
|
+
it('should create instance with correct code and title', () => {
|
62
|
+
const error = new TooMuchDataError();
|
63
|
+
|
64
|
+
expect(error.code).toBe(3);
|
65
|
+
expect(error.title).toBe('There is too much data. Please edit this widget');
|
66
|
+
});
|
67
|
+
|
68
|
+
it('should be instance of BaseRendererError', () => {
|
69
|
+
const error = new TooMuchDataError();
|
70
|
+
expect(error).toBeInstanceOf(BaseRendererError);
|
71
|
+
});
|
72
|
+
});
|
73
|
+
|
74
|
+
describe('DataConflictError', () => {
|
75
|
+
it('should create instance with correct code and title', () => {
|
76
|
+
const error = new DataConflictError();
|
77
|
+
|
78
|
+
expect(error.code).toBe(5);
|
79
|
+
expect(error.title).toBe('Data Conflict');
|
80
|
+
});
|
81
|
+
|
82
|
+
it('should create instance with options parameter', () => {
|
83
|
+
const options = {
|
84
|
+
isBreakdown: true,
|
85
|
+
uniqueCategories: ['A', 'B'],
|
86
|
+
minCategories: 5,
|
87
|
+
maxCategories: 10
|
88
|
+
};
|
89
|
+
const error = new DataConflictError(options);
|
90
|
+
|
91
|
+
expect(error.code).toBe(5);
|
92
|
+
expect(error.title).toBe('Data Conflict');
|
93
|
+
expect(error.options).toEqual(options);
|
94
|
+
});
|
95
|
+
|
96
|
+
it('should create instance with empty options when none provided', () => {
|
97
|
+
const error = new DataConflictError();
|
98
|
+
|
99
|
+
expect(error.options).toEqual({});
|
100
|
+
});
|
101
|
+
});
|
102
|
+
|
103
|
+
describe('GaugeConfigurationError', () => {
|
104
|
+
it('should create instance with correct code and title', () => {
|
105
|
+
const error = new GaugeConfigurationError();
|
106
|
+
|
107
|
+
expect(error.code).toBe(6);
|
108
|
+
expect(error.title).toBe('Please configure goal and needle');
|
109
|
+
});
|
110
|
+
|
111
|
+
it('should create instance with empty options', () => {
|
112
|
+
const error = new GaugeConfigurationError();
|
113
|
+
|
114
|
+
expect(error.options).toEqual({});
|
115
|
+
});
|
116
|
+
});
|
117
|
+
|
118
|
+
describe('GenericRenderingError', () => {
|
119
|
+
it('should create instance with correct code and title', () => {
|
120
|
+
const error = new GenericRenderingError();
|
121
|
+
|
122
|
+
expect(error.code).toBe(7);
|
123
|
+
expect(error.title).toBe('An error occurred rendering the PivotTable results.');
|
124
|
+
});
|
125
|
+
|
126
|
+
it('should create instance with empty options', () => {
|
127
|
+
const error = new GenericRenderingError();
|
128
|
+
|
129
|
+
expect(error.options).toEqual({});
|
130
|
+
});
|
131
|
+
|
132
|
+
it('should be instance of BaseRendererError', () => {
|
133
|
+
const error = new GenericRenderingError();
|
134
|
+
expect(error).toBeInstanceOf(BaseRendererError);
|
135
|
+
});
|
136
|
+
});
|
137
|
+
|
138
|
+
describe('GenericComputationalError', () => {
|
139
|
+
it('should create instance with correct code and title', () => {
|
140
|
+
const error = new GenericComputationalError();
|
141
|
+
|
142
|
+
expect(error.code).toBe(8);
|
143
|
+
expect(error.title).toBe('An error occurred computing the PivotTable results.');
|
144
|
+
});
|
145
|
+
|
146
|
+
it('should create instance with empty options', () => {
|
147
|
+
const error = new GenericComputationalError();
|
148
|
+
|
149
|
+
expect(error.options).toEqual({});
|
150
|
+
});
|
151
|
+
|
152
|
+
it('should be instance of BaseRendererError', () => {
|
153
|
+
const error = new GenericComputationalError();
|
154
|
+
expect(error).toBeInstanceOf(BaseRendererError);
|
155
|
+
});
|
156
|
+
});
|
157
|
+
});
|