|
| 1 | +import { describe, it, expect } from 'vitest'; |
| 2 | +import { |
| 3 | + ChartTypeSchema, |
| 4 | + ChartConfigSchema, |
| 5 | + type ChartType, |
| 6 | + type ChartConfig, |
| 7 | +} from './chart.zod'; |
| 8 | + |
| 9 | +describe('ChartTypeSchema', () => { |
| 10 | + it('should accept all comparison chart types', () => { |
| 11 | + const types = ['bar', 'horizontal-bar', 'column', 'grouped-bar', 'stacked-bar'] as const; |
| 12 | + |
| 13 | + types.forEach(type => { |
| 14 | + expect(() => ChartTypeSchema.parse(type)).not.toThrow(); |
| 15 | + }); |
| 16 | + }); |
| 17 | + |
| 18 | + it('should accept all trend chart types', () => { |
| 19 | + const types = ['line', 'area', 'stacked-area', 'step-line'] as const; |
| 20 | + |
| 21 | + types.forEach(type => { |
| 22 | + expect(() => ChartTypeSchema.parse(type)).not.toThrow(); |
| 23 | + }); |
| 24 | + }); |
| 25 | + |
| 26 | + it('should accept all distribution chart types', () => { |
| 27 | + const types = ['pie', 'donut', 'funnel'] as const; |
| 28 | + |
| 29 | + types.forEach(type => { |
| 30 | + expect(() => ChartTypeSchema.parse(type)).not.toThrow(); |
| 31 | + }); |
| 32 | + }); |
| 33 | + |
| 34 | + it('should accept all relationship chart types', () => { |
| 35 | + const types = ['scatter', 'bubble'] as const; |
| 36 | + |
| 37 | + types.forEach(type => { |
| 38 | + expect(() => ChartTypeSchema.parse(type)).not.toThrow(); |
| 39 | + }); |
| 40 | + }); |
| 41 | + |
| 42 | + it('should accept all composition chart types', () => { |
| 43 | + const types = ['treemap', 'sunburst', 'sankey'] as const; |
| 44 | + |
| 45 | + types.forEach(type => { |
| 46 | + expect(() => ChartTypeSchema.parse(type)).not.toThrow(); |
| 47 | + }); |
| 48 | + }); |
| 49 | + |
| 50 | + it('should accept all performance chart types', () => { |
| 51 | + const types = ['gauge', 'metric', 'kpi'] as const; |
| 52 | + |
| 53 | + types.forEach(type => { |
| 54 | + expect(() => ChartTypeSchema.parse(type)).not.toThrow(); |
| 55 | + }); |
| 56 | + }); |
| 57 | + |
| 58 | + it('should accept all geo chart types', () => { |
| 59 | + const types = ['choropleth', 'bubble-map'] as const; |
| 60 | + |
| 61 | + types.forEach(type => { |
| 62 | + expect(() => ChartTypeSchema.parse(type)).not.toThrow(); |
| 63 | + }); |
| 64 | + }); |
| 65 | + |
| 66 | + it('should accept all advanced chart types', () => { |
| 67 | + const types = ['heatmap', 'radar', 'waterfall', 'box-plot', 'violin'] as const; |
| 68 | + |
| 69 | + types.forEach(type => { |
| 70 | + expect(() => ChartTypeSchema.parse(type)).not.toThrow(); |
| 71 | + }); |
| 72 | + }); |
| 73 | + |
| 74 | + it('should accept all tabular chart types', () => { |
| 75 | + const types = ['table', 'pivot'] as const; |
| 76 | + |
| 77 | + types.forEach(type => { |
| 78 | + expect(() => ChartTypeSchema.parse(type)).not.toThrow(); |
| 79 | + }); |
| 80 | + }); |
| 81 | + |
| 82 | + it('should reject invalid chart type', () => { |
| 83 | + expect(() => ChartTypeSchema.parse('invalid-chart')).toThrow(); |
| 84 | + }); |
| 85 | +}); |
| 86 | + |
| 87 | +describe('ChartConfigSchema', () => { |
| 88 | + it('should accept minimal chart config', () => { |
| 89 | + const config: ChartConfig = { |
| 90 | + type: 'bar', |
| 91 | + }; |
| 92 | + const result = ChartConfigSchema.parse(config); |
| 93 | + expect(result.type).toBe('bar'); |
| 94 | + expect(result.showLegend).toBe(true); |
| 95 | + expect(result.showDataLabels).toBe(false); |
| 96 | + }); |
| 97 | + |
| 98 | + it('should accept full chart config', () => { |
| 99 | + const config: ChartConfig = { |
| 100 | + type: 'line', |
| 101 | + title: 'Sales Trend', |
| 102 | + description: 'Monthly sales performance', |
| 103 | + showLegend: true, |
| 104 | + showDataLabels: true, |
| 105 | + colors: ['#FF6384', '#36A2EB', '#FFCE56'], |
| 106 | + }; |
| 107 | + expect(() => ChartConfigSchema.parse(config)).not.toThrow(); |
| 108 | + }); |
| 109 | + |
| 110 | + it('should apply default values', () => { |
| 111 | + const config: ChartConfig = { |
| 112 | + type: 'pie', |
| 113 | + title: 'Revenue by Region', |
| 114 | + }; |
| 115 | + const result = ChartConfigSchema.parse(config); |
| 116 | + expect(result.showLegend).toBe(true); |
| 117 | + expect(result.showDataLabels).toBe(false); |
| 118 | + }); |
| 119 | + |
| 120 | + it('should allow custom colors', () => { |
| 121 | + const config: ChartConfig = { |
| 122 | + type: 'donut', |
| 123 | + colors: ['#1f77b4', '#ff7f0e', '#2ca02c', '#d62728'], |
| 124 | + }; |
| 125 | + const result = ChartConfigSchema.parse(config); |
| 126 | + expect(result.colors).toHaveLength(4); |
| 127 | + }); |
| 128 | +}); |
| 129 | + |
| 130 | +describe('Real-World Chart Configuration Examples', () => { |
| 131 | + it('should accept bar chart for comparison', () => { |
| 132 | + const config: ChartConfig = { |
| 133 | + type: 'bar', |
| 134 | + title: 'Sales by Product Category', |
| 135 | + description: 'Comparison of sales across different product categories', |
| 136 | + showLegend: true, |
| 137 | + showDataLabels: true, |
| 138 | + colors: ['#4e79a7', '#f28e2c', '#e15759'], |
| 139 | + }; |
| 140 | + expect(() => ChartConfigSchema.parse(config)).not.toThrow(); |
| 141 | + }); |
| 142 | + |
| 143 | + it('should accept line chart for trends', () => { |
| 144 | + const config: ChartConfig = { |
| 145 | + type: 'line', |
| 146 | + title: 'Revenue Trend', |
| 147 | + description: 'Monthly revenue over the past year', |
| 148 | + showLegend: true, |
| 149 | + showDataLabels: false, |
| 150 | + }; |
| 151 | + expect(() => ChartConfigSchema.parse(config)).not.toThrow(); |
| 152 | + }); |
| 153 | + |
| 154 | + it('should accept pie chart for distribution', () => { |
| 155 | + const config: ChartConfig = { |
| 156 | + type: 'pie', |
| 157 | + title: 'Market Share', |
| 158 | + description: 'Market share by competitor', |
| 159 | + showLegend: true, |
| 160 | + showDataLabels: true, |
| 161 | + }; |
| 162 | + expect(() => ChartConfigSchema.parse(config)).not.toThrow(); |
| 163 | + }); |
| 164 | + |
| 165 | + it('should accept gauge for performance metrics', () => { |
| 166 | + const config: ChartConfig = { |
| 167 | + type: 'gauge', |
| 168 | + title: 'Customer Satisfaction Score', |
| 169 | + description: 'Current satisfaction rating (0-100)', |
| 170 | + showLegend: false, |
| 171 | + colors: ['#22c55e', '#eab308', '#ef4444'], |
| 172 | + }; |
| 173 | + expect(() => ChartConfigSchema.parse(config)).not.toThrow(); |
| 174 | + }); |
| 175 | + |
| 176 | + it('should accept heatmap for correlation analysis', () => { |
| 177 | + const config: ChartConfig = { |
| 178 | + type: 'heatmap', |
| 179 | + title: 'User Activity Heatmap', |
| 180 | + description: 'Hourly user activity by day of week', |
| 181 | + showLegend: true, |
| 182 | + showDataLabels: false, |
| 183 | + colors: ['#440154', '#31688e', '#35b779', '#fde724'], |
| 184 | + }; |
| 185 | + expect(() => ChartConfigSchema.parse(config)).not.toThrow(); |
| 186 | + }); |
| 187 | + |
| 188 | + it('should accept funnel chart for conversion tracking', () => { |
| 189 | + const config: ChartConfig = { |
| 190 | + type: 'funnel', |
| 191 | + title: 'Sales Funnel', |
| 192 | + description: 'Conversion rates at each stage', |
| 193 | + showLegend: false, |
| 194 | + showDataLabels: true, |
| 195 | + }; |
| 196 | + expect(() => ChartConfigSchema.parse(config)).not.toThrow(); |
| 197 | + }); |
| 198 | + |
| 199 | + it('should accept waterfall chart for financial analysis', () => { |
| 200 | + const config: ChartConfig = { |
| 201 | + type: 'waterfall', |
| 202 | + title: 'Profit & Loss Breakdown', |
| 203 | + description: 'Revenue, costs, and profit components', |
| 204 | + showLegend: false, |
| 205 | + showDataLabels: true, |
| 206 | + colors: ['#22c55e', '#ef4444', '#6366f1'], |
| 207 | + }; |
| 208 | + expect(() => ChartConfigSchema.parse(config)).not.toThrow(); |
| 209 | + }); |
| 210 | +}); |
0 commit comments