UNPKG

@gooddata/react-components

Version:

GoodData.UI - A powerful JavaScript library for building analytical applications

784 lines (738 loc) • 29.4 kB
// (C) 2007-2018 GoodData Corporation import { AFM } from "@gooddata/typings"; import Highcharts from "../highchartsEntryPoint"; import getOptionalStackingConfiguration, { convertMinMaxFromPercentToNumber, getParentAttributeConfiguration, getSanitizedStackingForSeries, getShowInPercentConfiguration, getStackMeasuresConfiguration, getYAxisConfiguration, setDrillConfigToXAxis, PERCENT_STACK, NORMAL_STACK, } from "../getOptionalStackingConfiguration"; import { IDrillConfig } from "../../../../../interfaces/DrillEvents"; import { IChartConfig, ISeriesItem, IChartOptions } from "../../../../../interfaces/Config"; import { VisualizationTypes } from "../../../../../constants/visualizationTypes"; import { BLACK_LABEL, WHITE_LABEL } from "../../../../../constants/label"; describe("getOptionalStackingConfiguration", () => { it("should return empty configuration to not supported chart type", () => { expect(getOptionalStackingConfiguration({ type: VisualizationTypes.LINE }, undefined)).toEqual({}); }); it("should set drillConfig to X axis", () => { const afm: AFM.IAfm = { attributes: [], measures: [], filters: [], }; const drillConfig: IDrillConfig = { afm, onFiredDrillEvent: () => false, }; const result = setDrillConfigToXAxis(drillConfig); expect(result.xAxis[0].drillConfig).toEqual(drillConfig); }); describe("getParentAttributeConfiguration", () => { it.each([ [ VisualizationTypes.COLUMN, { xAxis: [ { labels: { groupedOptions: [ { style: { fontWeight: "bold" }, }, ], }, }, ], }, ], [ VisualizationTypes.BAR, { xAxis: [ { labels: { groupedOptions: [ { style: { fontWeight: "bold" }, x: -5, }, ], }, }, ], }, ], ])( "should return parent attribute configuration for %s chart", (type: string, expectedConfig: any) => { const chartOptions = { type }; const config = { xAxis: [{}] }; const result = getParentAttributeConfiguration(chartOptions, config); expect(result).toEqual(expectedConfig); }, ); }); describe("getStackMeasuresConfiguration", () => { it.each([ ["undefined", {}], [ "false", { stackMeasures: false, stackMeasuresToPercent: false, }, ], ])( "should return empty configuration when stack options are %s", (_: string, chartConfig: IChartConfig) => { const result = getStackMeasuresConfiguration( { type: VisualizationTypes.COLUMN }, {}, chartConfig, ); expect(result).toEqual({}); }, ); it.each([[NORMAL_STACK, { stackMeasures: true }], [PERCENT_STACK, { stackMeasuresToPercent: true }]])( "should return series config with %s stacking", (type: string, chartConfig: IChartConfig) => { const chartOptions = { yAxes: [{}] }; const config = { series: Array(2).fill({ yAxis: 0 }) }; const result = getStackMeasuresConfiguration(chartOptions, config, chartConfig); expect(result).toEqual({ series: Array(2).fill({ yAxis: 0, stack: 0, stacking: type, }), }); }, ); it('should "stackMeasuresToPercent" always overwrite "stackMeasures" setting', () => { const chartOptions = { yAxes: [{}] }; const config = { series: Array(2).fill({ yAxis: 0 }) }; const chartConfig = { stackMeasures: true, stackMeasuresToPercent: true, }; const result = getStackMeasuresConfiguration(chartOptions, config, chartConfig); expect(result).toEqual({ series: Array(2).fill({ yAxis: 0, stack: 0, stacking: PERCENT_STACK, }), }); }); it("should return series with stacking config with normal stacking for dual axis", () => { const chartOptions = { type: VisualizationTypes.COLUMN, yAxes: [{}, {}], }; const config = { yAxis: [{}, {}], series: [...Array(2).fill({ yAxis: 0 }), ...Array(2).fill({ yAxis: 1 })], }; const chartConfig = { stackMeasures: true }; const result = getStackMeasuresConfiguration(chartOptions, config, chartConfig); expect(result).toEqual({ series: [ ...Array(2).fill({ yAxis: 0, // primary Y axis stack: 0, stacking: NORMAL_STACK, }), ...Array(2).fill({ yAxis: 1, // secondary Y axis // stack is reset for secondary Y axis stack: null, // stacking on secondary Y axis is reset when stackMeasures is false stacking: NORMAL_STACK, }), ], yAxis: Array(2).fill({ stackLabels: { enabled: true }, }), }); }); it('should return series without "stackMeasuresToPercent" config for measure on right axis of dual axis', () => { const chartOptions = { type: VisualizationTypes.COLUMN, yAxes: [{}, {}], }; const config = { yAxis: [{}, {}], series: [ { yAxis: 0, }, { yAxis: 1, }, ], }; const chartConfig = { stackMeasuresToPercent: true }; const result = getStackMeasuresConfiguration(chartOptions, config, chartConfig); expect(result).toEqual({ series: [ { yAxis: 0, // primary Y axis // stack + stacking on primary Y axis is keep as is stack: 0, stacking: PERCENT_STACK, }, { yAxis: 1, // secondary Y axis // stack is resetted for secondary Y axis stack: null, // stacking on secondary Y axis is resetted to "normal" stacking: NORMAL_STACK, }, ], yAxis: [ { stackLabels: { enabled: false }, }, { stackLabels: { enabled: true }, }, ], }); }); it('should return series with "stackMeasures" config with one measure in each axis for dual axis', () => { const chartOptions = { type: VisualizationTypes.COLUMN, yAxes: [{}, {}], }; const config = { yAxis: [{}, {}], series: [ { yAxis: 0, }, { yAxis: 1, }, ], }; const chartConfig = { stackMeasures: true }; const result = getStackMeasuresConfiguration(chartOptions, config, chartConfig); expect(result).toEqual({ series: [ { yAxis: 0, // primary Y axis // stack + stacking on primary Y axis is keep as is stack: 0, stacking: NORMAL_STACK, }, { yAxis: 1, // secondary Y axis // stack is resetted for secondary Y axis stack: null, // stacking on secondary Y axis is resetted when stackMeasuresToPercent is true stacking: NORMAL_STACK, }, ], yAxis: Array(2).fill({ stackLabels: { enabled: true }, }), }); }); it.each([["", true], ["", "auto"], [" not", false]])( 'should%s show stack label when "dataLabel.visible" is %s', (_negation: string, visible: boolean | string) => { const chartOptions = { type: VisualizationTypes.COLUMN, yAxes: [{}], }; const config = { series: [{ yAxis: 0 }], yAxis: [{}], }; const chartConfig = { stackMeasures: true, dataLabels: { visible }, }; const { yAxis }: any = getStackMeasuresConfiguration(chartOptions, config, chartConfig); expect(yAxis).toEqual( Array(1).fill({ stackLabels: { enabled: Boolean(visible) }, }), ); }, ); it('should not return "yAxis.stackLabels" to bar chart by default', () => { // the template in 'barConfiguration.ts' turns stackLabels off by default const chartOptions = { type: VisualizationTypes.BAR, yAxes: [{}], }; const config = { series: [{ yAxis: 0 }], yAxis: [{}], }; const chartConfig = { stackMeasures: true, }; const result = getStackMeasuresConfiguration(chartOptions, config, chartConfig); expect(result).not.toHaveProperty("yAxis.stackLabels"); }); describe("Stack Measures in Combo chart", () => { const chartOptions = { type: VisualizationTypes.COMBO, yAxes: [{ opposite: false }, { opposite: true }], }; it.each([ ["stackMeasures", VisualizationTypes.COLUMN, NORMAL_STACK, WHITE_LABEL], ["stackMeasures", VisualizationTypes.AREA, NORMAL_STACK, BLACK_LABEL], ["stackMeasuresToPercent", VisualizationTypes.COLUMN, PERCENT_STACK, WHITE_LABEL], ["stackMeasuresToPercent", VisualizationTypes.AREA, PERCENT_STACK, BLACK_LABEL], ])( "should return series with %s config if series type is %s", (stackConfig: string, type: string, stackType: string, labelStyle: Highcharts.CSSObject) => { const config = { yAxis: [{}, {}], series: [ { yAxis: 0, type, }, { yAxis: 1, type: VisualizationTypes.LINE, }, ], }; const chartConfig = { [stackConfig]: true }; const { series } = getStackMeasuresConfiguration(chartOptions, config, chartConfig); expect(series).toEqual([ { yAxis: 0, stack: 0, stacking: stackType, type, dataLabels: { style: labelStyle }, }, { yAxis: 1, stack: null, stacking: null, type: VisualizationTypes.LINE, dataLabels: { style: BLACK_LABEL }, }, ]); }, ); it.each(["stackMeasures", "stackMeasuresToPercent"])( "should NOT apply %s if series type is Line chart", (stackConfig: string) => { const config = { yAxis: [{}, {}], series: [ { yAxis: 0, type: VisualizationTypes.LINE, }, { yAxis: 1, type: VisualizationTypes.AREA, }, ], }; const chartConfig = { [stackConfig]: true }; const { series } = getStackMeasuresConfiguration(chartOptions, config, chartConfig); expect(series).toEqual([ { yAxis: 0, stack: 0, stacking: null, type: VisualizationTypes.LINE, dataLabels: { style: BLACK_LABEL }, }, { yAxis: 1, stack: null, stacking: null, type: VisualizationTypes.AREA, dataLabels: { style: BLACK_LABEL }, }, ]); }, ); it.each([["stackMeasures", NORMAL_STACK], ["stackMeasuresToPercent", PERCENT_STACK]])( "should NOT apply %s on secondary y-axis", (stackConfig: string, stackType: string) => { const config = { yAxis: [{}, {}], series: [ { yAxis: 0, type: VisualizationTypes.COLUMN, }, { yAxis: 1, type: VisualizationTypes.AREA, }, ], }; const chartConfig = { [stackConfig]: true }; const { series } = getStackMeasuresConfiguration(chartOptions, config, chartConfig); expect(series).toEqual([ { yAxis: 0, stack: 0, stacking: stackType, type: VisualizationTypes.COLUMN, dataLabels: { style: WHITE_LABEL }, }, { yAxis: 1, stack: null, stacking: null, type: VisualizationTypes.AREA, dataLabels: { style: BLACK_LABEL }, }, ]); }, ); it("should return series with no stack config", () => { const chartOptions = { type: VisualizationTypes.COMBO, yAxes: [{}], }; const config = { yAxis: [{}], series: [ { yAxis: 0, type: VisualizationTypes.COLUMN, }, { yAxis: 0, type: VisualizationTypes.LINE, }, ], }; const chartConfig = { stackMeasuresToPercent: true }; const { series } = getStackMeasuresConfiguration(chartOptions, config, chartConfig); expect(series).toEqual([ { yAxis: 0, type: VisualizationTypes.COLUMN, dataLabels: { style: BLACK_LABEL }, }, { yAxis: 0, type: VisualizationTypes.LINE, dataLabels: { style: BLACK_LABEL }, }, ]); }); it("should return series with 'normal' stack config", () => { const chartOptions = { type: VisualizationTypes.COMBO, yAxes: [{}], }; const config = { yAxis: [{}], series: [ { yAxis: 0, type: VisualizationTypes.COLUMN, }, { yAxis: 0, type: VisualizationTypes.LINE, }, ], }; const chartConfig = { stackMeasures: true, stackMeasuresToPercent: true }; const { series } = getStackMeasuresConfiguration(chartOptions, config, chartConfig); expect(series).toEqual([ { stack: 0, stacking: NORMAL_STACK, yAxis: 0, type: VisualizationTypes.COLUMN, dataLabels: { style: WHITE_LABEL }, }, { stack: 0, stacking: null, yAxis: 0, type: VisualizationTypes.LINE, dataLabels: { style: BLACK_LABEL }, }, ]); }); }); describe("getYAxisConfiguration", () => { it("should return empty config with not column chart type", () => { const chartOptions = { type: VisualizationTypes.BAR }; const config = {}; const chartConfig = {}; const result = getYAxisConfiguration(chartOptions, config, chartConfig); expect(result).toEqual({}); }); it('should disable stack labels when "stackMeasuresToPercent" is on', () => { const chartOptions = { type: VisualizationTypes.COLUMN }; const config = { yAxis: [{}], series: [ { yAxis: 0, data: [ { y: 100, }, { y: -50, }, ], }, ], }; const chartConfig = { stackMeasuresToPercent: true, dataLabels: { visible: true }, }; const result = getYAxisConfiguration(chartOptions, config, chartConfig); expect(result).toEqual({ yAxis: [ { stackLabels: { enabled: false }, }, ], }); }); it("should disable stack labels only on left axis with dual chart", () => { const chartOptions = { type: VisualizationTypes.COLUMN }; const config = { yAxis: [{}, {}], // dual axis chart series: [ { yAxis: 0, // left measure data: [ { y: 100, }, { y: -50, // has negative value }, ], }, { yAxis: 1, // right measure data: [ { y: 100, }, { y: 50, }, ], }, ], }; const chartConfig = { stackMeasuresToPercent: true, dataLabels: { visible: true }, }; const result = getYAxisConfiguration(chartOptions, config, chartConfig); expect(result).toEqual({ yAxis: [ { stackLabels: { enabled: false }, }, { stackLabels: { enabled: true }, }, ], }); }); }); }); describe("getSanitizedStackingForSeries", () => { it.each([["primary axis", 0], ["secondary axis", 1]])( "should return the same series if series belong to %s", (_axisName: string, axisIndex: number) => { const series: ISeriesItem[] = [{ yAxis: axisIndex }]; const result = getSanitizedStackingForSeries(series); expect(result).toEqual(series); }, ); it.each([[PERCENT_STACK], [NORMAL_STACK]])( "should return the sanitized series if secondary axis has %s stack", (stacking: null | string) => { const series: ISeriesItem[] = [{ yAxis: 0 }, { yAxis: 1, stacking }]; const result = getSanitizedStackingForSeries(series); expect(result).toEqual([ // stack + stacking on primary Y axis is keep as is { yAxis: 0, }, { yAxis: 1, // stack is resetted for secondary Y axis stack: null, // stacking on secondary Y axis is resetted when stackMeasuresToPercent is true stacking: NORMAL_STACK, }, ]); }, ); }); describe("getShowInPercentConfiguration", () => { it('should not add formatter when "stackMeasuresToPercent" is false', () => { const chartConfig = { stackMeasuresToPercent: false, }; const result = getShowInPercentConfiguration(undefined, undefined, chartConfig); expect(result).toEqual({}); }); it('should add formatter when "stackMeasuresToPercent" is true and one measure', () => { const chartOptions = { yAxes: [{}], data: { series: [{ yAxis: 0 }], }, }; const chartConfig = { stackMeasuresToPercent: true, }; const result: any = getShowInPercentConfiguration(chartOptions, undefined, chartConfig); expect(result.yAxis[0]).toHaveProperty("labels.formatter"); }); it('should add formatter when "stackMeasuresToPercent" is true and two measures', () => { const chartOptions = { yAxes: [{}], data: { series: Array(2).fill({ yAxis: 0 }), }, }; const chartConfig = { stackMeasuresToPercent: true, }; const result: any = getShowInPercentConfiguration(chartOptions, undefined, chartConfig); expect(result.yAxis[0]).toHaveProperty("labels.formatter"); }); it("should NOT add formatter for secondary y-axis in combo chart", () => { const chartOptions = { type: VisualizationTypes.COMBO, yAxes: [{ opposite: false }, { opposite: true }], data: { series: Array(2).fill({ yAxis: 0 }), }, }; const chartConfig = { stackMeasuresToPercent: true, }; const result: any = getShowInPercentConfiguration(chartOptions, undefined, chartConfig); expect(result.yAxis[0]).toHaveProperty("labels.formatter"); expect(result.yAxis[1]).toEqual({}); }); it("should NOT add formatter when primary y-axis is line chart type in combo chart", () => { const chartOptions: IChartOptions = { type: VisualizationTypes.COMBO, yAxes: [{ opposite: false }], data: { series: Array(2).fill({ yAxis: 0 }), }, }; const chartConfig: IChartConfig = { stackMeasuresToPercent: true, primaryChartType: VisualizationTypes.LINE, }; const result = getShowInPercentConfiguration(chartOptions, undefined, chartConfig); expect(result).toEqual({}); }); }); describe("convertMinMaxFromPercentToNumber", () => { it("should not convert min/max to percent", () => { const chartConfig = { stackMeasuresToPercent: false, }; const result = convertMinMaxFromPercentToNumber(undefined, undefined, chartConfig); expect(result).toEqual({}); }); it.each([ [ "left Y axis for single axis chart", { yAxis: [ { min: 0.1, max: 0.9, opposite: false, }, ], }, { yAxis: [ { min: 10, max: 90, }, ], }, ], [ "right Y axis for single axis chart", { yAxis: [ { min: 0.1, max: 0.9, opposite: true, }, ], }, { yAxis: [ { min: 10, max: 90, }, ], }, ], [ "primary Y axis for dual axis chart", { yAxis: [ { min: 0.1, max: 0.9, opposite: false, }, { min: 1000, max: 9000, opposite: true, }, ], }, { yAxis: [ { min: 10, max: 90, }, {}, ], }, ], ])("should convert min/max for %s", (_: string, config: any, expectedConfig: any) => { const result = convertMinMaxFromPercentToNumber(undefined, config, { stackMeasuresToPercent: true, }); expect(result).toEqual(expectedConfig); }); }); });