clean bar line tests

This commit is contained in:
dal 2025-08-12 11:32:28 -06:00
parent 31c3cbc1b7
commit 72150c2ee1
No known key found for this signature in database
GPG Key ID: 16F4B0E1E9F61122
1 changed files with 116 additions and 224 deletions

View File

@ -1,285 +1,177 @@
import { type MetricYml, MetricYmlSchema } from '@buster/server-shared/metrics';
import { describe, expect, it } from 'vitest'; import { describe, expect, it } from 'vitest';
import { validateAndAdjustBarLineAxes } from './bar-line-axis-validator'; import { validateAndAdjustBarLineAxes } from './bar-line-axis-validator';
import type { ChartConfigProps } from '@buster/server-shared/metrics';
describe('validateAndAdjustBarLineAxes', () => { describe('validateAndAdjustBarLineAxes', () => {
it('should return unchanged config for non-bar/line charts', () => { it('should return unchanged config for non-bar/line charts', () => {
const metricYml = MetricYmlSchema.parse({ const chartConfig = {
name: 'Pie Chart', selectedChartType: 'pie',
description: 'Test pie chart', columnLabelFormats: {},
timeFrame: '2024', } as ChartConfigProps;
sql: 'SELECT category, count FROM data',
chartConfig: {
selectedChartType: 'pie',
columnLabelFormats: {},
},
});
const result = validateAndAdjustBarLineAxes(metricYml.chartConfig); const result = validateAndAdjustBarLineAxes(chartConfig);
expect(result).toEqual(metricYml.chartConfig); expect(result).toEqual(chartConfig);
}); });
it('should return valid when Y axis has numeric columns', () => { it('should return valid when Y axis has numeric columns', () => {
const metricYml = MetricYmlSchema.parse({ const chartConfig = {
name: 'Sales by Month', selectedChartType: 'line',
description: 'Monthly sales data', columnLabelFormats: {
timeFrame: '2024', month: {
sql: 'SELECT month, sales FROM data', columnType: 'date',
chartConfig: {
selectedChartType: 'line',
columnLabelFormats: {
month: {
columnType: 'date',
style: 'date',
replaceMissingDataWith: null,
numberSeparatorStyle: null,
},
sales: {
columnType: 'number',
style: 'currency',
replaceMissingDataWith: 0,
numberSeparatorStyle: ',',
},
}, },
barAndLineAxis: { sales: {
x: ['month'], columnType: 'number',
y: ['sales'],
}, },
}, },
}); barAndLineAxis: {
x: ['month'],
y: ['sales'],
},
} as any;
const result = validateAndAdjustBarLineAxes(metricYml.chartConfig); const result = validateAndAdjustBarLineAxes(chartConfig);
// Function returns the config directly if valid, not an object with isValid property expect(result).toEqual(chartConfig);
expect(result).toEqual(metricYml.chartConfig);
}); });
it('should swap axes when Y has non-numeric and X has numeric columns', () => { it('should swap axes when Y has non-numeric and X has numeric columns', () => {
const metricYml = MetricYmlSchema.parse({ const chartConfig = {
name: 'Sales Rep by Revenue', selectedChartType: 'bar',
description: 'Revenue by sales rep', columnLabelFormats: {
timeFrame: '2024', revenue: {
sql: 'SELECT revenue, sales_rep FROM data', columnType: 'number',
chartConfig: {
selectedChartType: 'bar',
columnLabelFormats: {
revenue: {
columnType: 'number',
style: 'currency',
replaceMissingDataWith: 0,
numberSeparatorStyle: ',',
},
sales_rep: {
columnType: 'string',
style: 'string',
replaceMissingDataWith: null,
numberSeparatorStyle: null,
},
}, },
barAndLineAxis: { sales_rep: {
x: ['revenue'], columnType: 'string',
y: ['sales_rep'],
}, },
}, },
}); barAndLineAxis: {
x: ['revenue'],
y: ['sales_rep'],
},
} as any;
const result = validateAndAdjustBarLineAxes(metricYml.chartConfig); const result = validateAndAdjustBarLineAxes(chartConfig);
// Function returns adjusted config with swapped axes
expect(result.barAndLineAxis?.x).toEqual(['sales_rep']); expect(result.barAndLineAxis?.x).toEqual(['sales_rep']);
expect(result.barAndLineAxis?.y).toEqual(['revenue']); expect(result.barAndLineAxis?.y).toEqual(['revenue']);
}); });
it('should throw error when Y has non-numeric and X also has non-numeric columns', () => { it('should throw error when Y has non-numeric and X also has non-numeric columns', () => {
const metricYml = MetricYmlSchema.parse({ const chartConfig = {
name: 'Categories by Region', selectedChartType: 'line',
description: 'Product categories by region', columnLabelFormats: {
timeFrame: '2024', region: {
sql: 'SELECT region, category FROM data', columnType: 'string',
chartConfig: {
selectedChartType: 'line',
columnLabelFormats: {
region: {
columnType: 'string',
style: 'string',
replaceMissingDataWith: null,
numberSeparatorStyle: null,
},
category: {
columnType: 'string',
style: 'string',
replaceMissingDataWith: null,
numberSeparatorStyle: null,
},
}, },
barAndLineAxis: { category: {
x: ['region'], columnType: 'string',
y: ['category'],
}, },
}, },
}); barAndLineAxis: {
x: ['region'],
y: ['category'],
},
} as any;
// Function throws an error for invalid configurations expect(() => validateAndAdjustBarLineAxes(chartConfig)).toThrowError(
expect(() => validateAndAdjustBarLineAxes(metricYml.chartConfig)).toThrowError(
/Bar and line charts require numeric values on the Y axis.*category \(string\)/ /Bar and line charts require numeric values on the Y axis.*category \(string\)/
); );
}); });
it('should handle multiple columns on axes', () => { it('should handle multiple columns on axes', () => {
const metricYml = MetricYmlSchema.parse({ const chartConfig = {
name: 'Multi Column Chart', selectedChartType: 'line',
description: 'Chart with multiple columns', columnLabelFormats: {
timeFrame: '2024', date: {
sql: 'SELECT date, region, sales, profit FROM data', columnType: 'date',
chartConfig: {
selectedChartType: 'line',
columnLabelFormats: {
date: {
columnType: 'date',
style: 'date',
replaceMissingDataWith: null,
numberSeparatorStyle: null,
},
region: {
columnType: 'string',
style: 'string',
replaceMissingDataWith: null,
numberSeparatorStyle: null,
},
sales: {
columnType: 'number',
style: 'currency',
replaceMissingDataWith: 0,
numberSeparatorStyle: ',',
},
profit: {
columnType: 'number',
style: 'currency',
replaceMissingDataWith: 0,
numberSeparatorStyle: ',',
},
}, },
barAndLineAxis: { region: {
x: ['date'], columnType: 'string',
y: ['sales', 'profit'], },
sales: {
columnType: 'number',
},
profit: {
columnType: 'number',
}, },
}, },
}); barAndLineAxis: {
x: ['date'],
y: ['sales', 'profit'],
},
} as any;
const result = validateAndAdjustBarLineAxes(metricYml.chartConfig); const result = validateAndAdjustBarLineAxes(chartConfig);
expect(result).toEqual(metricYml.chartConfig); expect(result).toEqual(chartConfig);
}); });
it('should return error when Y has mixed numeric and non-numeric columns', () => { it('should throw error when Y has mixed numeric and non-numeric columns', () => {
const metricYml: MetricYml = { const chartConfig = {
name: 'Mixed Y Axis', selectedChartType: 'bar',
description: 'Chart with mixed column types on Y', columnLabelFormats: {
timeFrame: '2024', month: {
sql: 'SELECT month, sales, category FROM data', columnType: 'date',
chartConfig: {
selectedChartType: 'bar',
columnLabelFormats: {
month: {
columnType: 'date',
style: 'date',
replaceMissingDataWith: null,
numberSeparatorStyle: null,
},
sales: {
columnType: 'number',
style: 'currency',
replaceMissingDataWith: 0,
numberSeparatorStyle: ',',
},
category: {
columnType: 'string',
style: 'string',
replaceMissingDataWith: null,
numberSeparatorStyle: null,
},
}, },
barAndLineAxis: { sales: {
x: ['month'], columnType: 'number',
y: ['sales', 'category'], },
category: {
columnType: 'string',
}, },
}, },
}; barAndLineAxis: {
x: ['month'],
y: ['sales', 'category'],
},
} as any;
const result = validateAndAdjustBarLineAxes(metricYml); expect(() => validateAndAdjustBarLineAxes(chartConfig)).toThrowError(/category \(string\)/);
expect(result.isValid).toBe(false);
expect(result.shouldSwapAxes).toBe(false);
expect(result.error).toContain('category (string)');
}); });
it('should handle date columns as non-numeric', () => { it('should handle date columns as non-numeric', () => {
const metricYml: MetricYml = { const chartConfig = {
name: 'Date on Y Axis', selectedChartType: 'line',
description: 'Chart with date on Y axis', columnLabelFormats: {
timeFrame: '2024', sales: {
sql: 'SELECT sales, order_date FROM data', columnType: 'number',
chartConfig: {
selectedChartType: 'line',
columnLabelFormats: {
sales: {
columnType: 'number',
style: 'currency',
replaceMissingDataWith: 0,
numberSeparatorStyle: ',',
},
order_date: {
columnType: 'date',
style: 'date',
replaceMissingDataWith: null,
numberSeparatorStyle: null,
},
}, },
barAndLineAxis: { order_date: {
x: ['sales'], columnType: 'date',
y: ['order_date'],
}, },
}, },
}; barAndLineAxis: {
x: ['sales'],
y: ['order_date'],
},
} as any;
const result = validateAndAdjustBarLineAxes(metricYml); const result = validateAndAdjustBarLineAxes(chartConfig);
expect(result.isValid).toBe(true); expect(result.barAndLineAxis?.x).toEqual(['order_date']);
expect(result.shouldSwapAxes).toBe(true); expect(result.barAndLineAxis?.y).toEqual(['sales']);
expect(result.adjustedYml?.chartConfig?.barAndLineAxis?.x).toEqual(['order_date']);
expect(result.adjustedYml?.chartConfig?.barAndLineAxis?.y).toEqual(['sales']);
}); });
it('should handle missing barAndLineAxis gracefully', () => { it('should handle missing barAndLineAxis gracefully', () => {
const metricYml: MetricYml = { const chartConfig = {
name: 'Missing Axis Config', selectedChartType: 'bar',
description: 'Chart without axis config', columnLabelFormats: {},
timeFrame: '2024', } as any;
sql: 'SELECT * FROM data',
chartConfig: {
selectedChartType: 'bar',
columnLabelFormats: {},
},
};
const result = validateAndAdjustBarLineAxes(metricYml); const result = validateAndAdjustBarLineAxes(chartConfig);
expect(result.isValid).toBe(true); expect(result).toEqual(chartConfig);
expect(result.shouldSwapAxes).toBe(false);
}); });
it('should handle empty axis arrays', () => { it('should throw error for empty axis arrays', () => {
const metricYml: MetricYml = { const chartConfig = {
name: 'Empty Axes', selectedChartType: 'line',
description: 'Chart with empty axes', columnLabelFormats: {},
timeFrame: '2024', barAndLineAxis: {
sql: 'SELECT * FROM data', x: [],
chartConfig: { y: [],
selectedChartType: 'line',
columnLabelFormats: {},
barAndLineAxis: {
x: [],
y: [],
},
}, },
}; } as any;
const result = validateAndAdjustBarLineAxes(metricYml); expect(() => validateAndAdjustBarLineAxes(chartConfig)).toThrowError(
expect(result.isValid).toBe(false); /Bar and line charts require at least one column for each axis/
expect(result.shouldSwapAxes).toBe(false); );
}); });
}); });