@datarailsshared/dr_renderer 1.4.67 → 1.4.80
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/README.md +38 -0
- package/package.json +1 -1
- package/src/dr_pivottable.js +17 -25
- package/src/errors.js +174 -0
- package/src/highcharts_renderer.js +92 -109
- package/src/index.d.ts +11 -0
- package/src/index.js +11 -0
- package/src/pivot.css +0 -11
- package/src/pivottable.js +14 -57
- package/src/types/errors.d.ts +120 -0
- package/src/types/index.d.ts +2 -1
- package/tests/errors.test.js +157 -0
- package/tests/highcharts_renderer.test.js +352 -92
- package/tests/mock/widgets.json +1 -3
- package/tsconfig.json +1 -1
- package/tsconfig.tsbuildinfo +2 -1
@@ -518,7 +518,7 @@ describe('highcharts_renderer', () => {
|
|
518
518
|
beforeEach(() => {
|
519
519
|
highchartsRenderer.enabledNewWidgetValueFormatting = false;
|
520
520
|
highchartsRenderer.delimer = ' , ';
|
521
|
-
|
521
|
+
|
522
522
|
funcContext = {
|
523
523
|
y: 12345.678,
|
524
524
|
series: {
|
@@ -586,10 +586,10 @@ describe('highcharts_renderer', () => {
|
|
586
586
|
|
587
587
|
it('should format value using pivot data aggregator when show_value is true', () => {
|
588
588
|
opts = { chartOptions: { label: { show_value: true } } };
|
589
|
-
|
589
|
+
|
590
590
|
let fn = highchartsRenderer.defaultDataLabelFormatter(mockPivotData, opts);
|
591
591
|
let result = fn.call(funcContext);
|
592
|
-
|
592
|
+
|
593
593
|
expect(highchartsRenderer.getSeriesNameInFormatterContext).toHaveBeenCalledWith(funcContext);
|
594
594
|
expect(highchartsRenderer.getColsInFormatterContext).toHaveBeenCalledWith(funcContext);
|
595
595
|
expect(mockPivotData.getAggregator).toHaveBeenCalled();
|
@@ -600,7 +600,7 @@ describe('highcharts_renderer', () => {
|
|
600
600
|
opts = { chartOptions: { label: { show_value: false } } };
|
601
601
|
let fn = highchartsRenderer.defaultDataLabelFormatter(mockPivotData, opts);
|
602
602
|
let result = fn.call(funcContext);
|
603
|
-
|
603
|
+
|
604
604
|
expect(result).toBe('');
|
605
605
|
});
|
606
606
|
|
@@ -716,9 +716,9 @@ describe('highcharts_renderer', () => {
|
|
716
716
|
it('should return raw value when show_out_of_x_axis is true but percentage logic is not triggered', () => {
|
717
717
|
opts = {
|
718
718
|
chartOptions: {
|
719
|
-
label: {
|
719
|
+
label: {
|
720
720
|
show_value: true,
|
721
|
-
show_out_of_x_axis: true
|
721
|
+
show_out_of_x_axis: true
|
722
722
|
}
|
723
723
|
}
|
724
724
|
};
|
@@ -735,9 +735,9 @@ describe('highcharts_renderer', () => {
|
|
735
735
|
it('should return raw value when show_out_of_data_series is true but percentage logic is not triggered', () => {
|
736
736
|
opts = {
|
737
737
|
chartOptions: {
|
738
|
-
label: {
|
738
|
+
label: {
|
739
739
|
show_value: true,
|
740
|
-
show_out_of_data_series: true
|
740
|
+
show_out_of_data_series: true
|
741
741
|
}
|
742
742
|
}
|
743
743
|
};
|
@@ -778,9 +778,9 @@ describe('highcharts_renderer', () => {
|
|
778
778
|
it('should show only percentages without value when show_value is false but percentages are enabled', () => {
|
779
779
|
opts = {
|
780
780
|
chartOptions: {
|
781
|
-
label: {
|
781
|
+
label: {
|
782
782
|
show_value: false,
|
783
|
-
show_out_of_x_axis: true
|
783
|
+
show_out_of_x_axis: true
|
784
784
|
}
|
785
785
|
}
|
786
786
|
};
|
@@ -797,9 +797,9 @@ describe('highcharts_renderer', () => {
|
|
797
797
|
it('should not add percentage when value is falsy', () => {
|
798
798
|
opts = {
|
799
799
|
chartOptions: {
|
800
|
-
label: {
|
800
|
+
label: {
|
801
801
|
show_value: true,
|
802
|
-
show_out_of_x_axis: true
|
802
|
+
show_out_of_x_axis: true
|
803
803
|
}
|
804
804
|
}
|
805
805
|
};
|
@@ -816,9 +816,9 @@ describe('highcharts_renderer', () => {
|
|
816
816
|
it('should not add percentage when axisTotal is falsy', () => {
|
817
817
|
opts = {
|
818
818
|
chartOptions: {
|
819
|
-
label: {
|
819
|
+
label: {
|
820
820
|
show_value: true,
|
821
|
-
show_out_of_x_axis: true
|
821
|
+
show_out_of_x_axis: true
|
822
822
|
}
|
823
823
|
}
|
824
824
|
};
|
@@ -849,7 +849,7 @@ describe('highcharts_renderer', () => {
|
|
849
849
|
it('should initialize cols to empty array when cols is falsy after array check', () => {
|
850
850
|
spyOn(lodash, 'isArray').and.returnValue(true);
|
851
851
|
highchartsRenderer.getColsInFormatterContext.and.returnValue(null);
|
852
|
-
|
852
|
+
|
853
853
|
opts = { chartOptions: { label: { show_value: true } } };
|
854
854
|
let fn = highchartsRenderer.defaultDataLabelFormatter(mockPivotData, opts);
|
855
855
|
let result = fn.call(funcContext);
|
@@ -866,10 +866,10 @@ describe('highcharts_renderer', () => {
|
|
866
866
|
|
867
867
|
it('should transform rows and cols for waterfall breakdown', () => {
|
868
868
|
opts = { chartOptions: { label: { show_value: true } } };
|
869
|
-
|
869
|
+
|
870
870
|
let fn = highchartsRenderer.defaultDataLabelFormatter(mockPivotData, opts);
|
871
871
|
let result = fn.call(funcContext);
|
872
|
-
|
872
|
+
|
873
873
|
expect(highchartsRenderer.transformRowsAndColsForBreakdown).toHaveBeenCalled();
|
874
874
|
expect(result).toBe('12,345.678');
|
875
875
|
});
|
@@ -877,13 +877,13 @@ describe('highcharts_renderer', () => {
|
|
877
877
|
it('should return raw value for waterfall breakdown when show_out_of_data_series is true but percentage logic is not triggered', () => {
|
878
878
|
opts = {
|
879
879
|
chartOptions: {
|
880
|
-
label: {
|
880
|
+
label: {
|
881
881
|
show_value: true,
|
882
|
-
show_out_of_data_series: true
|
882
|
+
show_out_of_data_series: true
|
883
883
|
}
|
884
884
|
}
|
885
885
|
};
|
886
|
-
|
886
|
+
|
887
887
|
funcContext.y = 300;
|
888
888
|
mockPivotData.getRowKeys = jest.fn(() => ([['row1'], ['row2']]));
|
889
889
|
|
@@ -893,30 +893,30 @@ describe('highcharts_renderer', () => {
|
|
893
893
|
if (rows.length === 0 && cols.length > 0) return { value: () => 1200 };
|
894
894
|
return { value: () => 800 };
|
895
895
|
});
|
896
|
-
|
896
|
+
|
897
897
|
let fn = highchartsRenderer.defaultDataLabelFormatter(mockPivotData, opts);
|
898
898
|
let result = fn.call(funcContext);
|
899
|
-
|
899
|
+
|
900
900
|
expect(result).toBe('300');
|
901
901
|
});
|
902
902
|
|
903
903
|
it('should calculate percentage using dataSeriesTotal when axisTotal is falsy (waterfall breakdown)', () => {
|
904
904
|
opts = {
|
905
905
|
chartOptions: {
|
906
|
-
label: {
|
906
|
+
label: {
|
907
907
|
show_value: false,
|
908
|
-
show_out_of_data_series: true
|
908
|
+
show_out_of_data_series: true
|
909
909
|
}
|
910
910
|
}
|
911
911
|
};
|
912
|
-
|
912
|
+
|
913
913
|
funcContext.y = 200; // value = 200
|
914
914
|
mockPivotData.getRowKeys = jest.fn(() => ([['row1'], ['row2']]));
|
915
915
|
|
916
916
|
let callCount = 0;
|
917
917
|
mockPivotData.getAggregator = jest.fn((rows, cols) => {
|
918
918
|
callCount++;
|
919
|
-
|
919
|
+
|
920
920
|
if (rows.length === 1) {
|
921
921
|
return { value: () => 400 };
|
922
922
|
}
|
@@ -935,16 +935,16 @@ describe('highcharts_renderer', () => {
|
|
935
935
|
|
936
936
|
it('should not add percentage when dataSeriesTotal is falsy (non-waterfall breakdown)', () => {
|
937
937
|
funcContext.series.options.className = 'regularSeries';
|
938
|
-
|
938
|
+
|
939
939
|
opts = {
|
940
940
|
chartOptions: {
|
941
|
-
label: {
|
941
|
+
label: {
|
942
942
|
show_value: false,
|
943
|
-
show_out_of_data_series: true
|
943
|
+
show_out_of_data_series: true
|
944
944
|
}
|
945
945
|
}
|
946
946
|
};
|
947
|
-
|
947
|
+
|
948
948
|
funcContext.y = 200;
|
949
949
|
|
950
950
|
mockPivotData.getAggregator = jest.fn((rows, cols) => {
|
@@ -985,7 +985,7 @@ describe('highcharts_renderer', () => {
|
|
985
985
|
it('should handle empty options gracefully for drill-down pie', () => {
|
986
986
|
let fn = highchartsRenderer.defaultDataLabelFormatter(mockPivotData, {}, true);
|
987
987
|
let result = fn.call(funcContext);
|
988
|
-
|
988
|
+
|
989
989
|
expect(result).toBe('12,345.678');
|
990
990
|
});
|
991
991
|
});
|
@@ -994,9 +994,9 @@ describe('highcharts_renderer', () => {
|
|
994
994
|
it('should fallback to raw value formatting when useUnitAbbreviation is false and getFormattedNumber returns abbreviated value', () => {
|
995
995
|
opts = {
|
996
996
|
chartOptions: {
|
997
|
-
label: {
|
997
|
+
label: {
|
998
998
|
show_value: true,
|
999
|
-
useUnitAbbreviation: false
|
999
|
+
useUnitAbbreviation: false
|
1000
1000
|
}
|
1001
1001
|
}
|
1002
1002
|
};
|
@@ -1012,9 +1012,9 @@ describe('highcharts_renderer', () => {
|
|
1012
1012
|
it('should fallback to raw value formatting when useUnitAbbreviation is true and getFormattedNumber returns abbreviated value', () => {
|
1013
1013
|
opts = {
|
1014
1014
|
chartOptions: {
|
1015
|
-
label: {
|
1015
|
+
label: {
|
1016
1016
|
show_value: true,
|
1017
|
-
useUnitAbbreviation: true
|
1017
|
+
useUnitAbbreviation: true
|
1018
1018
|
}
|
1019
1019
|
}
|
1020
1020
|
};
|
@@ -1030,9 +1030,9 @@ describe('highcharts_renderer', () => {
|
|
1030
1030
|
it('should fallback to raw value formatting when getFormattedNumber returns M-abbreviated value regardless of useUnitAbbreviation setting', () => {
|
1031
1031
|
opts = {
|
1032
1032
|
chartOptions: {
|
1033
|
-
label: {
|
1033
|
+
label: {
|
1034
1034
|
show_value: true,
|
1035
|
-
useUnitAbbreviation: false
|
1035
|
+
useUnitAbbreviation: false
|
1036
1036
|
}
|
1037
1037
|
}
|
1038
1038
|
};
|
@@ -8188,36 +8188,6 @@ describe('highcharts_renderer', () => {
|
|
8188
8188
|
);
|
8189
8189
|
});
|
8190
8190
|
|
8191
|
-
it('should return no data result if series is empty', () => {
|
8192
|
-
const chartOptions = {
|
8193
|
-
chart: {},
|
8194
|
-
series: [{ data: [] }, { data: [] }, {}],
|
8195
|
-
};
|
8196
|
-
const options = {};
|
8197
|
-
const noDataFnSpy = jest.spyOn(highchartsRenderer, 'getNoDataResult').mockImplementation(() => {});
|
8198
|
-
|
8199
|
-
highchartsRenderer.ptCreateElementAndDraw(chartOptions, options);
|
8200
|
-
|
8201
|
-
expect(noDataFnSpy).toHaveBeenCalled();
|
8202
|
-
expect(options.error_has_occurred).toBeTruthy();
|
8203
|
-
expect(options.error_params).toBe(highchartsRenderer.widgetPlaceholders.nodata);
|
8204
|
-
});
|
8205
|
-
|
8206
|
-
it('should return too much data result if series is too long', () => {
|
8207
|
-
const chartOptions = {
|
8208
|
-
chart: {},
|
8209
|
-
series: [{ data: new Array(1000) }, { data: new Array(1000) }, {}],
|
8210
|
-
};
|
8211
|
-
const options = {};
|
8212
|
-
const noDataFnSpy = jest.spyOn(highchartsRenderer, 'getNoDataResult').mockImplementation(() => {});
|
8213
|
-
|
8214
|
-
highchartsRenderer.ptCreateElementAndDraw(chartOptions, options);
|
8215
|
-
|
8216
|
-
expect(noDataFnSpy).toHaveBeenCalled();
|
8217
|
-
expect(options.error_has_occurred).toBeTruthy();
|
8218
|
-
expect(options.error_params).toBe(highchartsRenderer.widgetPlaceholders.tooMuchData);
|
8219
|
-
});
|
8220
|
-
|
8221
8191
|
it('should set hcInstance on options with chart object for graph table renderer to use', () => {
|
8222
8192
|
jest.useFakeTimers();
|
8223
8193
|
jest.spyOn(Highcharts, 'chart').mockImplementation(() => ({ chart: true }));
|
@@ -8235,40 +8205,330 @@ describe('highcharts_renderer', () => {
|
|
8235
8205
|
});
|
8236
8206
|
});
|
8237
8207
|
|
8238
|
-
describe('
|
8239
|
-
const
|
8208
|
+
describe('Error Throwing Functionality', () => {
|
8209
|
+
const {
|
8210
|
+
NoDataError,
|
8211
|
+
TooMuchDataError,
|
8212
|
+
DataConflictError,
|
8213
|
+
GaugeConfigurationError,
|
8214
|
+
BaseRendererError,
|
8215
|
+
GenericRenderingError,
|
8216
|
+
GenericComputationalError
|
8217
|
+
} = require('../src/errors');
|
8240
8218
|
|
8241
|
-
|
8242
|
-
|
8243
|
-
const expected = container.clone().html(highchartsRenderer.getWidgetPlaceholder(placeholderMeta));
|
8244
|
-
expect(highchartsRenderer.getNoDataResult()).toEqual(expected);
|
8219
|
+
beforeEach(() => {
|
8220
|
+
jest.clearAllMocks();
|
8245
8221
|
});
|
8246
8222
|
|
8247
|
-
|
8248
|
-
|
8249
|
-
const expected = container.clone().html(highchartsRenderer.getWidgetPlaceholder(placeholderMeta));
|
8250
|
-
expect(highchartsRenderer.getNoDataResult(true)).toEqual(expected);
|
8223
|
+
afterAll(() => {
|
8224
|
+
jest.restoreAllMocks();
|
8251
8225
|
});
|
8252
8226
|
|
8253
|
-
|
8227
|
+
describe('ptCreateElementAndDraw - Error Throwing', () => {
|
8228
|
+
it('should throw NoDataError when series is empty and not onlyText', () => {
|
8229
|
+
const chartOptions = {
|
8230
|
+
chart: {},
|
8231
|
+
series: [{ data: [] }, { data: [] }, {}],
|
8232
|
+
};
|
8233
|
+
const options = {};
|
8234
|
+
|
8235
|
+
expect(() => {
|
8236
|
+
highchartsRenderer.ptCreateElementAndDraw(chartOptions, options);
|
8237
|
+
}).toThrow(NoDataError);
|
8238
|
+
});
|
8239
|
+
|
8240
|
+
it('should throw TooMuchDataError when series has too much data', () => {
|
8241
|
+
const chartOptions = {
|
8242
|
+
chart: {},
|
8243
|
+
series: [{ data: new Array(1000) }, { data: new Array(1000) }, {}],
|
8244
|
+
};
|
8245
|
+
const options = {};
|
8246
|
+
|
8247
|
+
expect(() => {
|
8248
|
+
highchartsRenderer.ptCreateElementAndDraw(chartOptions, options);
|
8249
|
+
}).toThrow(TooMuchDataError);
|
8250
|
+
});
|
8251
|
+
|
8252
|
+
it('should not throw errors when onlyText is true even if no data', () => {
|
8253
|
+
const chartOptions = {
|
8254
|
+
chart: {},
|
8255
|
+
series: [{ data: [] }],
|
8256
|
+
onlyText: true,
|
8257
|
+
};
|
8258
|
+
const options = {};
|
8259
|
+
|
8260
|
+
expect(() => {
|
8261
|
+
highchartsRenderer.ptCreateElementAndDraw(chartOptions, options);
|
8262
|
+
}).not.toThrow();
|
8263
|
+
});
|
8264
|
+
|
8265
|
+
it('should process normally when series has valid data', () => {
|
8266
|
+
jest.spyOn(Highcharts, 'chart').mockImplementation(() => ({ chart: true }));
|
8267
|
+
jest.useFakeTimers();
|
8268
|
+
|
8269
|
+
const chartOptions = {
|
8270
|
+
chart: {},
|
8271
|
+
series: [{ data: [1, 2, 3] }],
|
8272
|
+
};
|
8273
|
+
const options = {};
|
8274
|
+
|
8275
|
+
expect(() => {
|
8276
|
+
highchartsRenderer.ptCreateElementAndDraw(chartOptions, options);
|
8277
|
+
}).not.toThrow();
|
8278
|
+
|
8279
|
+
jest.runAllTimers();
|
8280
|
+
jest.restoreAllMocks();
|
8281
|
+
jest.useRealTimers();
|
8282
|
+
});
|
8283
|
+
});
|
8284
|
+
|
8285
|
+
describe('Data Conflict Error Throwing', () => {
|
8286
|
+
it('should throw DataConflictError when categories are below minimum in waterfall chart', () => {
|
8287
|
+
const options = {
|
8288
|
+
isBreakdown: true,
|
8289
|
+
uniqueCategories: ['A', 'B'], // Only 2 categories
|
8290
|
+
minCategories: 5,
|
8291
|
+
maxCategories: 10
|
8292
|
+
};
|
8293
|
+
|
8294
|
+
expect(() => {
|
8295
|
+
throw new DataConflictError({
|
8296
|
+
isBreakdown: options.isBreakdown,
|
8297
|
+
uniqueCategories: options.uniqueCategories,
|
8298
|
+
minCategories: options.minCategories,
|
8299
|
+
maxCategories: options.maxCategories
|
8300
|
+
});
|
8301
|
+
}).toThrow(DataConflictError);
|
8302
|
+
});
|
8303
|
+
|
8304
|
+
it('should throw DataConflictError when categories exceed maximum in waterfall chart', () => {
|
8305
|
+
const uniqueCategories = new Array(15).fill(0).map((_, i) => `Category${i}`); // 15 categories
|
8306
|
+
const options = {
|
8307
|
+
isBreakdown: false,
|
8308
|
+
uniqueCategories,
|
8309
|
+
minCategories: 3,
|
8310
|
+
maxCategories: 10
|
8311
|
+
};
|
8312
|
+
|
8313
|
+
expect(() => {
|
8314
|
+
throw new DataConflictError({
|
8315
|
+
isBreakdown: options.isBreakdown,
|
8316
|
+
uniqueCategories: options.uniqueCategories,
|
8317
|
+
minCategories: options.minCategories,
|
8318
|
+
maxCategories: options.maxCategories
|
8319
|
+
});
|
8320
|
+
}).toThrow(DataConflictError);
|
8321
|
+
});
|
8322
|
+
|
8323
|
+
it('should create DataConflictError with correct options for breakdown scenario', () => {
|
8324
|
+
const options = {
|
8325
|
+
isBreakdown: true,
|
8326
|
+
uniqueCategories: ['A'],
|
8327
|
+
minCategories: 5,
|
8328
|
+
maxCategories: 10
|
8329
|
+
};
|
8330
|
+
|
8331
|
+
try {
|
8332
|
+
throw new DataConflictError(options);
|
8333
|
+
} catch (error) {
|
8334
|
+
expect(error).toBeInstanceOf(DataConflictError);
|
8335
|
+
expect(error.code).toBe(5);
|
8336
|
+
expect(error.title).toBe('Data Conflict');
|
8337
|
+
expect(error.options).toEqual(options);
|
8338
|
+
expect(error.options.isBreakdown).toBe(true);
|
8339
|
+
expect(error.options.uniqueCategories).toEqual(['A']);
|
8340
|
+
expect(error.options.minCategories).toBe(5);
|
8341
|
+
expect(error.options.maxCategories).toBe(10);
|
8342
|
+
}
|
8343
|
+
});
|
8344
|
+
|
8345
|
+
it('should create DataConflictError with correct options for walkthrough scenario', () => {
|
8346
|
+
const options = {
|
8347
|
+
isBreakdown: false,
|
8348
|
+
uniqueCategories: ['A', 'B', 'C'],
|
8349
|
+
minCategories: 5,
|
8350
|
+
maxCategories: 8
|
8351
|
+
};
|
8352
|
+
|
8353
|
+
try {
|
8354
|
+
throw new DataConflictError(options);
|
8355
|
+
} catch (error) {
|
8356
|
+
expect(error).toBeInstanceOf(DataConflictError);
|
8357
|
+
expect(error.code).toBe(5);
|
8358
|
+
expect(error.title).toBe('Data Conflict');
|
8359
|
+
expect(error.options).toEqual(options);
|
8360
|
+
expect(error.options.isBreakdown).toBe(false);
|
8361
|
+
}
|
8362
|
+
});
|
8363
|
+
});
|
8254
8364
|
|
8255
|
-
|
8256
|
-
|
8257
|
-
|
8258
|
-
|
8365
|
+
describe('Gauge Configuration Error Throwing', () => {
|
8366
|
+
it('should create GaugeConfigurationError with correct properties', () => {
|
8367
|
+
try {
|
8368
|
+
throw new GaugeConfigurationError();
|
8369
|
+
} catch (error) {
|
8370
|
+
expect(error).toBeInstanceOf(GaugeConfigurationError);
|
8371
|
+
expect(error.code).toBe(6);
|
8372
|
+
expect(error.title).toBe('Please configure goal and needle');
|
8373
|
+
expect(error.options).toEqual({});
|
8374
|
+
}
|
8375
|
+
});
|
8259
8376
|
|
8260
|
-
|
8261
|
-
|
8262
|
-
|
8263
|
-
|
8377
|
+
it('should be instance of BaseRendererError', () => {
|
8378
|
+
const error = new GaugeConfigurationError();
|
8379
|
+
expect(error).toBeInstanceOf(require('../src/errors').BaseRendererError);
|
8380
|
+
});
|
8264
8381
|
});
|
8265
8382
|
|
8266
|
-
|
8267
|
-
|
8268
|
-
|
8269
|
-
|
8270
|
-
|
8271
|
-
|
8383
|
+
describe('Error handling in rhPivotView functions (testing private _handleComputationalError and _handleRenderingError)', () => {
|
8384
|
+
beforeEach(() => {
|
8385
|
+
jest.spyOn(console, 'error').mockImplementation(() => {});
|
8386
|
+
});
|
8387
|
+
|
8388
|
+
afterEach(() => {
|
8389
|
+
jest.restoreAllMocks();
|
8390
|
+
});
|
8391
|
+
|
8392
|
+
describe('Natural error conditions (testing private error handlers indirectly)', () => {
|
8393
|
+
it('should handle too much data error correctly', () => {
|
8394
|
+
// Create dataset that exceeds MAX_ROWS_FOR_SHOW_RESULTS to trigger TooMuchDataError
|
8395
|
+
const largeRowData = new Array(highchartsRenderer.MAX_ROWS_FOR_SHOW_RESULTS + 1)
|
8396
|
+
.fill({ field1: 'value1', field2: 'value2' });
|
8397
|
+
|
8398
|
+
const options = {
|
8399
|
+
onlyOptions: false,
|
8400
|
+
rendererOptions: {},
|
8401
|
+
renderer: jest.fn()
|
8402
|
+
};
|
8403
|
+
|
8404
|
+
expect(() => {
|
8405
|
+
highchartsRenderer.rhPivotView(largeRowData, options);
|
8406
|
+
}).toThrow(TooMuchDataError);
|
8407
|
+
});
|
8408
|
+
|
8409
|
+
it('should return empty object for too much data when onlyOptions is true', () => {
|
8410
|
+
// Create dataset that exceeds MAX_ROWS_FOR_SHOW_RESULTS
|
8411
|
+
const largeRowData = new Array(highchartsRenderer.MAX_ROWS_FOR_SHOW_RESULTS + 1)
|
8412
|
+
.fill({ field1: 'value1', field2: 'value2' });
|
8413
|
+
|
8414
|
+
const options = {
|
8415
|
+
onlyOptions: true,
|
8416
|
+
rendererOptions: {},
|
8417
|
+
renderer: jest.fn()
|
8418
|
+
};
|
8419
|
+
|
8420
|
+
const result = highchartsRenderer.rhPivotView(largeRowData, options);
|
8421
|
+
expect(result).toEqual({});
|
8422
|
+
});
|
8423
|
+
|
8424
|
+
it('should handle no data error correctly', () => {
|
8425
|
+
const options = {
|
8426
|
+
onlyOptions: false,
|
8427
|
+
rendererOptions: {},
|
8428
|
+
renderer: jest.fn()
|
8429
|
+
};
|
8430
|
+
|
8431
|
+
// Empty rowData should trigger NoDataError
|
8432
|
+
expect(() => {
|
8433
|
+
highchartsRenderer.rhPivotView([], options);
|
8434
|
+
}).toThrow(NoDataError);
|
8435
|
+
});
|
8436
|
+
|
8437
|
+
it('should return empty object for no data when onlyOptions is true', () => {
|
8438
|
+
const options = {
|
8439
|
+
onlyOptions: true,
|
8440
|
+
rendererOptions: {},
|
8441
|
+
renderer: jest.fn()
|
8442
|
+
};
|
8443
|
+
|
8444
|
+
const result = highchartsRenderer.rhPivotView([], options);
|
8445
|
+
expect(result).toEqual({});
|
8446
|
+
});
|
8447
|
+
|
8448
|
+
it('should handle renderer errors correctly', () => {
|
8449
|
+
const rowData = [{ field1: 'value1', field2: 'value2' }];
|
8450
|
+
const genericError = new Error('Renderer failed');
|
8451
|
+
|
8452
|
+
const options = {
|
8453
|
+
onlyOptions: false,
|
8454
|
+
rendererOptions: {},
|
8455
|
+
renderer: jest.fn().mockImplementation(() => {
|
8456
|
+
throw genericError;
|
8457
|
+
})
|
8458
|
+
};
|
8459
|
+
|
8460
|
+
// Generic errors from renderer should be wrapped in GenericRenderingError
|
8461
|
+
expect(() => {
|
8462
|
+
highchartsRenderer.rhPivotView(rowData, options);
|
8463
|
+
}).toThrow(GenericRenderingError);
|
8464
|
+
});
|
8465
|
+
|
8466
|
+
it('should return empty object for renderer errors when onlyOptions is true', () => {
|
8467
|
+
const rowData = [{ field1: 'value1', field2: 'value2' }];
|
8468
|
+
const genericError = new Error('Renderer failed');
|
8469
|
+
|
8470
|
+
const options = {
|
8471
|
+
onlyOptions: true,
|
8472
|
+
rendererOptions: {},
|
8473
|
+
renderer: jest.fn().mockImplementation(() => {
|
8474
|
+
throw genericError;
|
8475
|
+
})
|
8476
|
+
};
|
8477
|
+
|
8478
|
+
const result = highchartsRenderer.rhPivotView(rowData, options);
|
8479
|
+
expect(result).toEqual({});
|
8480
|
+
});
|
8481
|
+
|
8482
|
+
it('should re-throw BaseRendererError instances from renderer unchanged', () => {
|
8483
|
+
const rowData = [{ field1: 'value1', field2: 'value2' }];
|
8484
|
+
const originalError = new NoDataError();
|
8485
|
+
|
8486
|
+
const options = {
|
8487
|
+
onlyOptions: false,
|
8488
|
+
rendererOptions: {},
|
8489
|
+
renderer: jest.fn().mockImplementation(() => {
|
8490
|
+
throw originalError;
|
8491
|
+
})
|
8492
|
+
};
|
8493
|
+
|
8494
|
+
// BaseRendererError instances should be re-thrown unchanged
|
8495
|
+
expect(() => {
|
8496
|
+
highchartsRenderer.rhPivotView(rowData, options);
|
8497
|
+
}).toThrow(NoDataError);
|
8498
|
+
|
8499
|
+
expect(() => {
|
8500
|
+
highchartsRenderer.rhPivotView(rowData, options);
|
8501
|
+
}).toThrow(originalError);
|
8502
|
+
});
|
8503
|
+
|
8504
|
+
it('should handle null/undefined from renderer as GenericRenderingError', () => {
|
8505
|
+
const rowData = [{ field1: 'value1', field2: 'value2' }];
|
8506
|
+
|
8507
|
+
// Test null
|
8508
|
+
const nullOptions = {
|
8509
|
+
onlyOptions: false,
|
8510
|
+
rendererOptions: {},
|
8511
|
+
renderer: jest.fn().mockImplementation(() => {
|
8512
|
+
throw null;
|
8513
|
+
})
|
8514
|
+
};
|
8515
|
+
|
8516
|
+
expect(() => {
|
8517
|
+
highchartsRenderer.rhPivotView(rowData, nullOptions);
|
8518
|
+
}).toThrow(GenericRenderingError);
|
8519
|
+
|
8520
|
+
const undefinedOptions = {
|
8521
|
+
onlyOptions: false,
|
8522
|
+
rendererOptions: {},
|
8523
|
+
renderer: jest.fn().mockImplementation(() => {
|
8524
|
+
throw undefined;
|
8525
|
+
})
|
8526
|
+
};
|
8527
|
+
|
8528
|
+
expect(() => {
|
8529
|
+
highchartsRenderer.rhPivotView(rowData, undefinedOptions);
|
8530
|
+
}).toThrow(GenericRenderingError);
|
8531
|
+
});
|
8272
8532
|
});
|
8273
8533
|
});
|
8274
8534
|
});
|
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
|
{
|
package/tsconfig.json
CHANGED