mirror of https://github.com/buster-so/buster.git
Add some unit tests
This commit is contained in:
parent
043d2654b0
commit
0d114ee850
|
@ -8,7 +8,9 @@
|
||||||
"build": "tsc --build",
|
"build": "tsc --build",
|
||||||
"dev": "tsc --watch",
|
"dev": "tsc --watch",
|
||||||
"lint": "biome check",
|
"lint": "biome check",
|
||||||
"typecheck": "tsc --noEmit"
|
"typecheck": "tsc --noEmit",
|
||||||
|
"test": "vitest run",
|
||||||
|
"test:watch": "vitest"
|
||||||
},
|
},
|
||||||
"exports": {
|
"exports": {
|
||||||
".": {
|
".": {
|
||||||
|
@ -37,7 +39,11 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@buster/vitest-config": "workspace:*",
|
||||||
"@buster/typescript-config": "workspace:*",
|
"@buster/typescript-config": "workspace:*",
|
||||||
"zod": "catalog:"
|
"zod": "catalog:"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"vitest": "catalog:"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,235 @@
|
||||||
|
import { describe, expect, it } from 'vitest';
|
||||||
|
import {
|
||||||
|
type ChartConfigProps,
|
||||||
|
ChartConfigPropsSchema,
|
||||||
|
DEFAULT_CHART_CONFIG,
|
||||||
|
DEFAULT_CHART_CONFIG_ENTRIES,
|
||||||
|
} from './chartConfigProps';
|
||||||
|
import { DEFAULT_CHART_THEME } from './configColors';
|
||||||
|
|
||||||
|
describe('chartConfigProps', () => {
|
||||||
|
describe('DEFAULT_CHART_CONFIG', () => {
|
||||||
|
it('should have the correct default values', () => {
|
||||||
|
expect(DEFAULT_CHART_CONFIG).toBeDefined();
|
||||||
|
expect(DEFAULT_CHART_CONFIG).toMatchObject({
|
||||||
|
selectedChartType: 'table',
|
||||||
|
columnSettings: {},
|
||||||
|
columnLabelFormats: {},
|
||||||
|
colors: DEFAULT_CHART_THEME,
|
||||||
|
showLegend: null,
|
||||||
|
gridLines: true,
|
||||||
|
goalLines: [],
|
||||||
|
trendlines: [],
|
||||||
|
disableTooltip: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be a valid ChartConfigProps object', () => {
|
||||||
|
// This should not throw
|
||||||
|
expect(() => ChartConfigPropsSchema.parse(DEFAULT_CHART_CONFIG)).not.toThrow();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have the expected color palette', () => {
|
||||||
|
expect(DEFAULT_CHART_CONFIG.colors).toHaveLength(10);
|
||||||
|
expect(DEFAULT_CHART_CONFIG.colors).toEqual([
|
||||||
|
'#B399FD',
|
||||||
|
'#FC8497',
|
||||||
|
'#FBBC30',
|
||||||
|
'#279EFF',
|
||||||
|
'#E83562',
|
||||||
|
'#41F8FF',
|
||||||
|
'#F3864F',
|
||||||
|
'#C82184',
|
||||||
|
'#31FCB4',
|
||||||
|
'#E83562',
|
||||||
|
]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have empty objects for column configurations', () => {
|
||||||
|
expect(DEFAULT_CHART_CONFIG.columnSettings).toEqual({});
|
||||||
|
expect(DEFAULT_CHART_CONFIG.columnLabelFormats).toEqual({});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have empty arrays for annotations', () => {
|
||||||
|
expect(DEFAULT_CHART_CONFIG.goalLines).toEqual([]);
|
||||||
|
expect(DEFAULT_CHART_CONFIG.trendlines).toEqual([]);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have correct boolean defaults', () => {
|
||||||
|
expect(DEFAULT_CHART_CONFIG.gridLines).toBe(true);
|
||||||
|
expect(DEFAULT_CHART_CONFIG.disableTooltip).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have null as default for showLegend', () => {
|
||||||
|
expect(DEFAULT_CHART_CONFIG.showLegend).toBeNull();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('DEFAULT_CHART_CONFIG_ENTRIES', () => {
|
||||||
|
it('should be an array of key-value pairs', () => {
|
||||||
|
expect(DEFAULT_CHART_CONFIG_ENTRIES).toBeDefined();
|
||||||
|
expect(Array.isArray(DEFAULT_CHART_CONFIG_ENTRIES)).toBe(true);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should contain all keys from DEFAULT_CHART_CONFIG', () => {
|
||||||
|
const configKeys = Object.keys(DEFAULT_CHART_CONFIG);
|
||||||
|
const entriesKeys = DEFAULT_CHART_CONFIG_ENTRIES.map(([key]) => key);
|
||||||
|
|
||||||
|
expect(entriesKeys).toHaveLength(configKeys.length);
|
||||||
|
expect(entriesKeys.sort()).toEqual(configKeys.sort());
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have matching values with DEFAULT_CHART_CONFIG', () => {
|
||||||
|
for (const [key, value] of DEFAULT_CHART_CONFIG_ENTRIES) {
|
||||||
|
expect(DEFAULT_CHART_CONFIG[key as keyof typeof DEFAULT_CHART_CONFIG]).toEqual(value);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should be reconstructable to DEFAULT_CHART_CONFIG', () => {
|
||||||
|
const reconstructed = Object.fromEntries(DEFAULT_CHART_CONFIG_ENTRIES);
|
||||||
|
expect(reconstructed).toEqual(DEFAULT_CHART_CONFIG);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should contain specific expected entries', () => {
|
||||||
|
const entriesMap = new Map(DEFAULT_CHART_CONFIG_ENTRIES);
|
||||||
|
|
||||||
|
expect(entriesMap.get('selectedChartType')).toBe('table');
|
||||||
|
expect(entriesMap.get('colors')).toEqual(DEFAULT_CHART_THEME);
|
||||||
|
expect(entriesMap.get('gridLines')).toBe(true);
|
||||||
|
expect(entriesMap.get('showLegend')).toBeNull();
|
||||||
|
expect(entriesMap.get('disableTooltip')).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should have the correct number of entries', () => {
|
||||||
|
// Count the number of properties we expect
|
||||||
|
const expectedKeys = [
|
||||||
|
'selectedChartType',
|
||||||
|
'columnSettings',
|
||||||
|
'columnLabelFormats',
|
||||||
|
'colors',
|
||||||
|
'showLegend',
|
||||||
|
'gridLines',
|
||||||
|
'goalLines',
|
||||||
|
'trendlines',
|
||||||
|
'disableTooltip',
|
||||||
|
// Plus any additional properties from the spread schemas
|
||||||
|
];
|
||||||
|
|
||||||
|
// The actual count will depend on what's in the spread schemas
|
||||||
|
expect(DEFAULT_CHART_CONFIG_ENTRIES.length).toBeGreaterThanOrEqual(expectedKeys.length);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('ChartConfigPropsSchema defaults', () => {
|
||||||
|
it('should create valid defaults when parsing empty object', () => {
|
||||||
|
const result = ChartConfigPropsSchema.parse({});
|
||||||
|
|
||||||
|
expect(result).toMatchObject({
|
||||||
|
selectedChartType: 'table',
|
||||||
|
columnSettings: {},
|
||||||
|
columnLabelFormats: {},
|
||||||
|
colors: DEFAULT_CHART_THEME,
|
||||||
|
showLegend: null,
|
||||||
|
gridLines: true,
|
||||||
|
goalLines: [],
|
||||||
|
trendlines: [],
|
||||||
|
disableTooltip: false,
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should override defaults when values are provided', () => {
|
||||||
|
const customConfig = {
|
||||||
|
selectedChartType: 'bar' as const,
|
||||||
|
gridLines: false,
|
||||||
|
colors: ['#FF0000', '#00FF00'],
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = ChartConfigPropsSchema.parse(customConfig);
|
||||||
|
|
||||||
|
expect(result.selectedChartType).toBe('bar');
|
||||||
|
expect(result.gridLines).toBe(false);
|
||||||
|
expect(result.colors).toEqual(['#FF0000', '#00FF00']);
|
||||||
|
// Other defaults should remain
|
||||||
|
expect(result.showLegend).toBeNull();
|
||||||
|
expect(result.disableTooltip).toBe(false);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle partial configurations correctly', () => {
|
||||||
|
const partialConfig = {
|
||||||
|
showLegend: true,
|
||||||
|
disableTooltip: true,
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = ChartConfigPropsSchema.parse(partialConfig);
|
||||||
|
|
||||||
|
expect(result.showLegend).toBe(true);
|
||||||
|
expect(result.disableTooltip).toBe(true);
|
||||||
|
// Defaults should be applied for missing fields
|
||||||
|
expect(result.selectedChartType).toBe('table');
|
||||||
|
expect(result.colors).toEqual(DEFAULT_CHART_THEME);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should handle complex column configurations', () => {
|
||||||
|
const configWithColumns = {
|
||||||
|
columnSettings: {
|
||||||
|
revenue: { showDataLabels: true, columnVisualization: 'line' as const },
|
||||||
|
profit: { showDataLabels: false, barRoundness: 12 },
|
||||||
|
},
|
||||||
|
columnLabelFormats: {
|
||||||
|
revenue: { prefix: '$', suffix: 'M' },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
const result = ChartConfigPropsSchema.parse(configWithColumns);
|
||||||
|
|
||||||
|
// Check that our custom settings are preserved
|
||||||
|
expect(result.columnSettings.revenue).toMatchObject({
|
||||||
|
showDataLabels: true,
|
||||||
|
columnVisualization: 'line',
|
||||||
|
});
|
||||||
|
expect(result.columnSettings.profit).toMatchObject({
|
||||||
|
showDataLabels: false,
|
||||||
|
barRoundness: 12,
|
||||||
|
});
|
||||||
|
|
||||||
|
// Check that defaults are applied to column settings
|
||||||
|
expect(result.columnSettings.revenue.lineWidth).toBe(2);
|
||||||
|
expect(result.columnSettings.profit.columnVisualization).toBe('bar');
|
||||||
|
|
||||||
|
expect(result.columnLabelFormats.revenue).toMatchObject({
|
||||||
|
prefix: '$',
|
||||||
|
suffix: 'M',
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
describe('Type safety', () => {
|
||||||
|
it('should maintain type safety for DEFAULT_CHART_CONFIG', () => {
|
||||||
|
// This is a compile-time test - if it compiles, it passes
|
||||||
|
const config: ChartConfigProps = DEFAULT_CHART_CONFIG;
|
||||||
|
|
||||||
|
// Test that we can access typed properties
|
||||||
|
const chartType: ChartConfigProps['selectedChartType'] = config.selectedChartType;
|
||||||
|
const colors: string[] = config.colors;
|
||||||
|
const showLegend: boolean | null = config.showLegend;
|
||||||
|
|
||||||
|
expect(chartType).toBeDefined();
|
||||||
|
expect(colors).toBeDefined();
|
||||||
|
expect(showLegend).toBeDefined();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('should ensure DEFAULT_CHART_CONFIG_ENTRIES maintains proper typing', () => {
|
||||||
|
// Verify entries can be used in typed contexts
|
||||||
|
for (const [key, value] of DEFAULT_CHART_CONFIG_ENTRIES) {
|
||||||
|
expect(typeof key).toBe('string');
|
||||||
|
expect(value).toBeDefined();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify reconstruction maintains type
|
||||||
|
const reconstructed: Record<string, unknown> = Object.fromEntries(
|
||||||
|
DEFAULT_CHART_CONFIG_ENTRIES
|
||||||
|
);
|
||||||
|
expect(reconstructed).toBeDefined();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
|
@ -0,0 +1,3 @@
|
||||||
|
import { baseConfig } from '@buster/vitest-config';
|
||||||
|
|
||||||
|
export default baseConfig;
|
|
@ -760,9 +760,16 @@ importers:
|
||||||
'@buster/typescript-config':
|
'@buster/typescript-config':
|
||||||
specifier: workspace:*
|
specifier: workspace:*
|
||||||
version: link:../typescript-config
|
version: link:../typescript-config
|
||||||
|
'@buster/vitest-config':
|
||||||
|
specifier: workspace:*
|
||||||
|
version: link:../vitest-config
|
||||||
zod:
|
zod:
|
||||||
specifier: 'catalog:'
|
specifier: 'catalog:'
|
||||||
version: 3.25.67
|
version: 3.25.67
|
||||||
|
devDependencies:
|
||||||
|
vitest:
|
||||||
|
specifier: 'catalog:'
|
||||||
|
version: 3.2.4(@edge-runtime/vm@3.2.0)(@types/debug@4.1.12)(@types/node@20.19.2)(@vitest/ui@3.2.4)(jiti@2.4.2)(jsdom@26.1.0)(lightningcss@1.30.1)(msw@2.10.2(@types/node@20.19.2)(typescript@5.8.3))(sass@1.89.2)(terser@5.43.1)(tsx@4.20.3)(yaml@2.8.0)
|
||||||
|
|
||||||
packages/slack:
|
packages/slack:
|
||||||
dependencies:
|
dependencies:
|
||||||
|
|
Loading…
Reference in New Issue