You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
574 lines
26 KiB
574 lines
26 KiB
import moment from 'moment-timezone';
|
|
import {STATS_RANGE_OPTIONS} from '@src/utils/constants';
|
|
import {
|
|
aggregateByMonthExact,
|
|
aggregateByWeek,
|
|
detectBulkImports,
|
|
determineAggregationStrategy,
|
|
getMonthKey,
|
|
getPeriodText,
|
|
sanitizeChartData
|
|
} from '@src/utils/chart-helpers';
|
|
import {describe, expect, it} from 'vitest';
|
|
|
|
type ChartDataItem = {
|
|
date: string;
|
|
value: number;
|
|
_isOutlier?: boolean;
|
|
customField?: number;
|
|
extra?: string;
|
|
};
|
|
|
|
type ChartDataItemWithOutlier = ChartDataItem & {
|
|
_isOutlier: boolean;
|
|
};
|
|
|
|
describe('chart-helpers', () => {
|
|
describe('getPeriodText', () => {
|
|
it('returns correct text for known ranges', () => {
|
|
const ranges = [
|
|
{value: 7, name: 'Last 7 days', expected: 'in the last 7 days'},
|
|
{value: 31, name: 'Last 30 days', expected: 'in the last 30 days'},
|
|
{value: 91, name: 'Last 3 months', expected: 'in the last 3 months'},
|
|
{value: 372, name: 'Last 12 months', expected: 'in the last 12 months'},
|
|
{value: 1000, name: 'All time', expected: '(all time)'}
|
|
];
|
|
|
|
ranges.forEach(({value, expected}) => {
|
|
expect(getPeriodText(value)).toBe(expected);
|
|
});
|
|
});
|
|
|
|
it('returns empty string for unknown range', () => {
|
|
expect(getPeriodText(-99)).toBe('');
|
|
});
|
|
|
|
it('returns lowercase name for non-standard range', () => {
|
|
const customRange = {value: 999, name: 'Custom Range'};
|
|
STATS_RANGE_OPTIONS.push(customRange);
|
|
expect(getPeriodText(customRange.value)).toBe('custom range');
|
|
STATS_RANGE_OPTIONS.pop(); // Clean up
|
|
});
|
|
});
|
|
|
|
describe('sanitizeChartData', () => {
|
|
const createDateRange = (days: number, startDate = '2024-01-01'): ChartDataItem[] => {
|
|
const result: ChartDataItem[] = [];
|
|
const start = moment(startDate);
|
|
for (let i = 0; i < days; i++) {
|
|
result.push({
|
|
date: start.clone().add(i, 'days').format('YYYY-MM-DD'),
|
|
value: 10
|
|
});
|
|
}
|
|
return result;
|
|
};
|
|
|
|
it('handles empty data', () => {
|
|
expect(sanitizeChartData([], 30)).toEqual([]);
|
|
});
|
|
|
|
describe('bulk import detection', () => {
|
|
it('does not mark values as outliers when variation is normal', () => {
|
|
const data: ChartDataItem[] = [
|
|
{date: '2024-01-01', value: 10},
|
|
{date: '2024-01-02', value: 15},
|
|
{date: '2024-01-03', value: 20},
|
|
{date: '2024-01-04', value: 12}
|
|
];
|
|
|
|
const result = sanitizeChartData(data, 7);
|
|
expect(result.some(item => item._isOutlier)).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('weekly aggregation', () => {
|
|
it('aggregates data weekly for 91-356 day ranges', () => {
|
|
const data = createDateRange(100);
|
|
const result = sanitizeChartData(data, 100);
|
|
|
|
// Should have roughly 14-15 weeks of data
|
|
expect(result.length).toBeLessThan(data.length);
|
|
expect(result.length).toBeGreaterThan(13);
|
|
expect(result.length).toBeLessThan(16);
|
|
});
|
|
|
|
it('handles sum aggregation type', () => {
|
|
const data: ChartDataItem[] = [
|
|
{date: '2024-01-01', value: 10},
|
|
{date: '2024-01-02', value: 20},
|
|
{date: '2024-01-03', value: 30}
|
|
];
|
|
|
|
const result = sanitizeChartData(data, 100, 'value', 'sum');
|
|
expect(result[0].value).toBe(60); // Sum of all values in the week
|
|
});
|
|
|
|
it('handles average aggregation type', () => {
|
|
const data: ChartDataItem[] = [
|
|
{date: '2024-01-01', value: 10},
|
|
{date: '2024-01-02', value: 20},
|
|
{date: '2024-01-03', value: 30}
|
|
];
|
|
|
|
const result = sanitizeChartData(data, 100, 'value', 'avg');
|
|
expect(result[0].value).toBe(20); // Average of values in the week
|
|
});
|
|
|
|
it('handles exact aggregation type for weekly data', () => {
|
|
const data = [
|
|
{date: '2024-01-01', value: 10}, // Week 1
|
|
{date: '2024-01-02', value: 15},
|
|
{date: '2024-01-03', value: 20},
|
|
{date: '2024-01-08', value: 25}, // Week 2
|
|
{date: '2024-01-09', value: 30},
|
|
{date: '2024-01-10', value: 35}
|
|
];
|
|
|
|
const result = sanitizeChartData(data, 100, 'value', 'exact');
|
|
expect(result.length).toBe(2);
|
|
expect(result[0].value).toBe(20); // Last value of first week
|
|
expect(result[1].value).toBe(35); // Last value of second week
|
|
});
|
|
});
|
|
|
|
describe('monthly aggregation', () => {
|
|
it('aggregates data monthly for ranges > 356 days', () => {
|
|
const data = createDateRange(400);
|
|
const result = sanitizeChartData(data, 400);
|
|
|
|
// Should have roughly 13-14 months of data
|
|
expect(result.length).toBeLessThan(data.length);
|
|
expect(result.length).toBeGreaterThan(12);
|
|
expect(result.length).toBeLessThan(15);
|
|
});
|
|
|
|
it('handles exact aggregation type with significant changes', () => {
|
|
const data: ChartDataItem[] = [
|
|
{date: '2024-01-01', value: 100},
|
|
{date: '2024-01-15', value: 150}, // 50% increase
|
|
{date: '2024-01-31', value: 155},
|
|
{date: '2024-02-01', value: 160},
|
|
{date: '2024-02-15', value: 250}, // Significant increase
|
|
{date: '2024-02-28', value: 255}
|
|
];
|
|
|
|
const result = sanitizeChartData(data, 400, 'value', 'exact');
|
|
|
|
// Should keep only end-of-month values
|
|
expect(result.length).toBe(2);
|
|
expect(result[0].date).toBe('2024-01-31');
|
|
expect(result[0].value).toBe(155);
|
|
expect(result[1].date).toBe('2024-02-28');
|
|
expect(result[1].value).toBe(255);
|
|
});
|
|
|
|
it('handles exact aggregation type for monthly data', () => {
|
|
const data = [
|
|
{date: '2024-01-01', value: 10}, // January start
|
|
{date: '2024-01-15', value: 15},
|
|
{date: '2024-01-31', value: 20}, // January end
|
|
{date: '2024-02-01', value: 25}, // February start
|
|
{date: '2024-02-15', value: 30},
|
|
{date: '2024-02-28', value: 35} // February end
|
|
];
|
|
|
|
const result = sanitizeChartData(data, 400, 'value', 'exact');
|
|
|
|
// Should keep only end-of-month values
|
|
expect(result.length).toBe(2);
|
|
expect(result[0].date).toBe('2024-01-31');
|
|
expect(result[0].value).toBe(20);
|
|
expect(result[1].date).toBe('2024-02-28');
|
|
expect(result[1].value).toBe(35);
|
|
});
|
|
|
|
it('handles simple month-end aggregation', () => {
|
|
const data = [
|
|
{date: '2024-01-01', value: 100}, // First day of Jan
|
|
{date: '2024-01-15', value: 110}, // Mid Jan
|
|
{date: '2024-01-31', value: 120}, // Last day of Jan
|
|
{date: '2024-02-01', value: 120}, // First day of Feb
|
|
{date: '2024-02-15', value: 130}, // Mid Feb
|
|
{date: '2024-02-28', value: 140}, // Last day of Feb
|
|
{date: '2024-03-01', value: 140}, // First day of Mar
|
|
{date: '2024-03-15', value: 150}, // Mid Mar
|
|
{date: '2024-03-31', value: 160} // Last day of Mar
|
|
];
|
|
|
|
const result = sanitizeChartData(data, 400, 'value', 'exact');
|
|
|
|
// Should keep only the last day of each month
|
|
expect(result.length).toBe(3);
|
|
expect(result[0].date).toBe('2024-01-31');
|
|
expect(result[0].value).toBe(120);
|
|
expect(result[1].date).toBe('2024-02-28');
|
|
expect(result[1].value).toBe(140);
|
|
expect(result[2].date).toBe('2024-03-31');
|
|
expect(result[2].value).toBe(160);
|
|
});
|
|
|
|
it('handles data with gaps between months', () => {
|
|
const data = [
|
|
{date: '2024-01-31', value: 100}, // Last day of Jan
|
|
{date: '2024-03-31', value: 120}, // Last day of Mar (Feb missing)
|
|
{date: '2024-05-31', value: 140} // Last day of May (Apr missing)
|
|
];
|
|
|
|
const result = sanitizeChartData(data, 400, 'value', 'exact');
|
|
|
|
// Should preserve the data as is since they're already month-end values
|
|
expect(result.length).toBe(3);
|
|
expect(result[0].date).toBe('2024-01-31');
|
|
expect(result[0].value).toBe(100);
|
|
expect(result[1].date).toBe('2024-03-31');
|
|
expect(result[1].value).toBe(120);
|
|
expect(result[2].date).toBe('2024-05-31');
|
|
expect(result[2].value).toBe(140);
|
|
});
|
|
|
|
it('preserves additional fields in data objects', () => {
|
|
const data = [
|
|
{date: '2024-01-31', value: 100, extra: 'info1'},
|
|
{date: '2024-02-28', value: 110, extra: 'info2'},
|
|
{date: '2024-03-31', value: 120, extra: 'info3'}
|
|
];
|
|
|
|
const result = sanitizeChartData(data, 400, 'value', 'exact');
|
|
|
|
expect(result.length).toBe(3);
|
|
expect(result[0].extra).toBe('info1');
|
|
expect(result[1].extra).toBe('info2');
|
|
expect(result[2].extra).toBe('info3');
|
|
});
|
|
|
|
it('integrates correctly with sanitizeChartData', () => {
|
|
const data = [
|
|
{date: '2024-01-01', value: 100},
|
|
{date: '2024-01-15', value: 150}, // 50% increase
|
|
{date: '2024-01-31', value: 155},
|
|
{date: '2024-02-15', value: 200}, // ~29% increase
|
|
{date: '2024-02-28', value: 205},
|
|
{date: '2024-03-15', value: 250}, // ~22% increase
|
|
{date: '2024-03-31', value: 255}
|
|
];
|
|
|
|
// First verify the strategy is correct
|
|
const strategy = determineAggregationStrategy(400, 90, 'exact');
|
|
expect(strategy).toBe('monthly');
|
|
|
|
// Then verify the full sanitization
|
|
const result = sanitizeChartData(data, 400, 'value', 'exact');
|
|
|
|
// Verify only end-of-month values are included
|
|
const points = new Map(result.map(item => [item.date, item.value]));
|
|
|
|
// Check month boundaries
|
|
expect(points.get('2024-01-31')).toBe(155);
|
|
expect(points.get('2024-02-28')).toBe(205);
|
|
expect(points.get('2024-03-31')).toBe(255);
|
|
|
|
// Mid-month significant changes should not be included
|
|
expect(points.has('2024-01-15')).toBe(false);
|
|
expect(points.has('2024-02-15')).toBe(false);
|
|
expect(points.has('2024-03-15')).toBe(false);
|
|
|
|
// Total points should be just the end-of-month values
|
|
expect(points.size).toBe(3);
|
|
});
|
|
|
|
it('integrates correctly with sanitizeChartData for non-exact aggregation', () => {
|
|
const data = [
|
|
{date: '2024-01-01', value: 100},
|
|
{date: '2024-01-15', value: 150},
|
|
{date: '2024-01-31', value: 200},
|
|
{date: '2024-02-15', value: 250},
|
|
{date: '2024-02-28', value: 300}
|
|
];
|
|
|
|
// First verify the strategy is correct
|
|
const strategy = determineAggregationStrategy(400, 60, 'avg');
|
|
expect(strategy).toBe('monthly');
|
|
|
|
// Then verify the full sanitization
|
|
const result = sanitizeChartData(data, 400, 'value', 'avg');
|
|
|
|
// Should have one point per month with average values
|
|
expect(result.length).toBe(2);
|
|
expect(result[0].date.startsWith('2024-01')).toBe(true);
|
|
expect(result[0].value).toBe(150); // Average of 100, 150, 200
|
|
expect(result[1].date.startsWith('2024-02')).toBe(true);
|
|
expect(result[1].value).toBe(275); // Average of 250, 300
|
|
});
|
|
|
|
it('handles sum aggregation with outliers', () => {
|
|
const data = [
|
|
{date: '2024-01-01', value: 100},
|
|
{date: '2024-01-15', value: 15000}, // Outlier - excluded from sum
|
|
{date: '2024-01-31', value: 200},
|
|
{date: '2024-02-15', value: 20000}, // Outlier - excluded from sum
|
|
{date: '2024-02-28', value: 300}
|
|
];
|
|
|
|
// First verify the strategy is correct
|
|
const strategy = determineAggregationStrategy(400, 60, 'sum');
|
|
expect(strategy).toBe('monthly');
|
|
|
|
// Then verify the full sanitization
|
|
const result = sanitizeChartData(data, 400, 'value', 'sum') as (ChartDataItem & {_isOutlier: boolean})[];
|
|
|
|
// Should have one point per month with sums (excluding outliers)
|
|
expect(result.length).toBe(2);
|
|
expect(result[0].date.startsWith('2024-01')).toBe(true);
|
|
expect(result[0].value).toBe(300); // Sum of 100, 200 (15000 excluded)
|
|
expect(result[1].date.startsWith('2024-02')).toBe(true);
|
|
expect(result[1].value).toBe(300); // Just 300 (20000 excluded)
|
|
|
|
// The final points aren't marked as outliers since the outliers were excluded from sums
|
|
expect(result[0]._isOutlier).toBe(false);
|
|
expect(result[1]._isOutlier).toBe(false);
|
|
});
|
|
|
|
it('uses aggregateByMonthSimple for exact monthly aggregation', () => {
|
|
const data = [
|
|
{date: '2024-01-01', value: 100},
|
|
{date: '2024-01-15', value: 150},
|
|
{date: '2024-01-31', value: 200},
|
|
{date: '2024-02-15', value: 250},
|
|
{date: '2024-02-28', value: 300}
|
|
];
|
|
|
|
// First verify the strategy is correct
|
|
const strategy = determineAggregationStrategy(200, 150, 'exact');
|
|
expect(strategy).toBe('weekly'); // Range 91-356 uses weekly
|
|
|
|
// Then verify the full sanitization with monthly range
|
|
const result = sanitizeChartData(data, 200, 'value', 'exact');
|
|
|
|
// Should have weekly points aligned to start of week
|
|
expect(result.length).toBe(5); // One point per week
|
|
expect(result[0].date).toBe('2023-12-31'); // Week containing Jan 1
|
|
expect(result[0].value).toBe(100);
|
|
expect(result[1].date).toBe('2024-01-14'); // Week containing Jan 15
|
|
expect(result[1].value).toBe(150);
|
|
expect(result[2].date).toBe('2024-01-28'); // Week containing Jan 31
|
|
expect(result[2].value).toBe(200);
|
|
expect(result[3].date).toBe('2024-02-11'); // Week containing Feb 15
|
|
expect(result[3].value).toBe(250);
|
|
expect(result[4].date).toBe('2024-02-25'); // Week containing Feb 28
|
|
expect(result[4].value).toBe(300);
|
|
});
|
|
|
|
it('handles significant changes in monthly exact aggregation', () => {
|
|
const data = [
|
|
{date: '2024-01-01', value: 100}, // Start of Jan
|
|
{date: '2024-01-15', value: 103}, // Mid Jan (3% increase - not significant)
|
|
{date: '2024-01-20', value: 110}, // Mid Jan (6.8% increase - significant)
|
|
{date: '2024-01-31', value: 112}, // End of Jan
|
|
{date: '2024-02-01', value: 112}, // Start of Feb
|
|
{date: '2024-02-15', value: 115}, // Mid Feb (2.7% increase - not significant)
|
|
{date: '2024-02-28', value: 118} // End of Feb
|
|
];
|
|
|
|
const result = sanitizeChartData(data, 400, 'value', 'exact');
|
|
|
|
// Should include start/end of months
|
|
expect(result.length).toBe(2);
|
|
expect(result[0].date).toBe('2024-01-31'); // End of Jan
|
|
expect(result[0].value).toBe(112);
|
|
expect(result[1].date).toBe('2024-02-28'); // End of Feb
|
|
expect(result[1].value).toBe(118);
|
|
});
|
|
|
|
it('handles monthly exact aggregation with significant changes', () => {
|
|
const data = [
|
|
{date: '2024-01-01', value: 100}, // Start of Jan
|
|
{date: '2024-01-15', value: 103}, // Mid Jan (3% increase - not significant)
|
|
{date: '2024-01-20', value: 110}, // Mid Jan (6.8% increase - significant)
|
|
{date: '2024-01-31', value: 112}, // End of Jan
|
|
{date: '2024-02-01', value: 112}, // Start of Feb
|
|
{date: '2024-02-15', value: 115}, // Mid Feb (2.7% increase - not significant)
|
|
{date: '2024-02-28', value: 118} // End of Feb
|
|
];
|
|
|
|
// Force monthly strategy by using a range that triggers it
|
|
const result = sanitizeChartData(data, 400, 'value', 'exact');
|
|
|
|
// Should include only end-of-month values
|
|
expect(result.length).toBe(2);
|
|
expect(result[0].date).toBe('2024-01-31'); // End of Jan
|
|
expect(result[0].value).toBe(112);
|
|
expect(result[1].date).toBe('2024-02-28'); // End of Feb
|
|
expect(result[1].value).toBe(118);
|
|
});
|
|
|
|
it('calculates date span correctly for single data point', () => {
|
|
const data = [{date: '2024-01-01', value: 100}];
|
|
const result = sanitizeChartData(data, 400, 'value', 'exact');
|
|
|
|
// Should return the single point as is
|
|
expect(result.length).toBe(1);
|
|
expect(result[0].date).toBe('2024-01-01');
|
|
expect(result[0].value).toBe(100);
|
|
});
|
|
|
|
it('uses getMonthKey for consistent month formatting', () => {
|
|
// Test the getMonthKey function directly
|
|
expect(getMonthKey('2024-01-01')).toBe('2024-01');
|
|
expect(getMonthKey('2024-01-15')).toBe('2024-01');
|
|
expect(getMonthKey('2024-01-31')).toBe('2024-01');
|
|
});
|
|
|
|
it('handles empty data array', () => {
|
|
const result = sanitizeChartData([], 400, 'value', 'exact');
|
|
expect(result).toEqual([]);
|
|
});
|
|
|
|
it('handles single data point with monthly exact aggregation', () => {
|
|
const data = [{date: '2024-01-01', value: 100}];
|
|
const result = sanitizeChartData(data, 400, 'value', 'exact');
|
|
expect(result.length).toBe(1);
|
|
expect(result[0].date).toBe('2024-01-01');
|
|
expect(result[0].value).toBe(100);
|
|
});
|
|
|
|
it('aggregates by month exact with significant changes', () => {
|
|
const data = [
|
|
{date: '2024-01-01', value: 100}, // Start of Jan
|
|
{date: '2024-01-15', value: 103}, // Mid Jan (3% increase - not significant)
|
|
{date: '2024-01-20', value: 110}, // Mid Jan (6.8% increase - significant)
|
|
{date: '2024-01-31', value: 112}, // End of Jan
|
|
{date: '2024-02-01', value: 112}, // Start of Feb
|
|
{date: '2024-02-15', value: 115}, // Mid Feb (2.7% increase - not significant)
|
|
{date: '2024-02-28', value: 118} // End of Feb
|
|
];
|
|
|
|
const result = aggregateByMonthExact(data, 'value');
|
|
|
|
// Should include first/last points, month boundaries, and significant changes
|
|
expect(result.length).toBe(7);
|
|
expect(result[0].date).toBe('2024-01-01'); // First point
|
|
expect(result[1].date).toBe('2024-01-15'); // Mid Jan
|
|
expect(result[2].date).toBe('2024-01-20'); // Mid Jan (significant change)
|
|
expect(result[3].date).toBe('2024-01-31'); // End of Jan
|
|
expect(result[4].date).toBe('2024-02-01'); // Start of Feb
|
|
expect(result[5].date).toBe('2024-02-15'); // Mid Feb
|
|
expect(result[6].date).toBe('2024-02-28'); // End of Feb/Last point
|
|
});
|
|
|
|
it('handles single data point in aggregateByMonthExact', () => {
|
|
const data = [{date: '2024-01-01', value: 100}];
|
|
const result = aggregateByMonthExact(data, 'value');
|
|
expect(result.length).toBe(1);
|
|
expect(result[0].date).toBe('2024-01-01');
|
|
expect(result[0].value).toBe(100);
|
|
});
|
|
|
|
it('handles single data point in detectBulkImports', () => {
|
|
const data = [{date: '2024-01-01', value: 100}];
|
|
const result = detectBulkImports(data, 'value');
|
|
expect(result).toEqual(data);
|
|
});
|
|
|
|
it('handles non-outlier values in detectBulkImports', () => {
|
|
const data = [
|
|
{date: '2024-01-01', value: 100},
|
|
{date: '2024-01-02', value: 110},
|
|
{date: '2024-01-03', value: 120}
|
|
];
|
|
const result = detectBulkImports(data, 'value') as ChartDataItemWithOutlier[];
|
|
expect(result.every(item => !item._isOutlier)).toBe(true);
|
|
});
|
|
|
|
it('handles single data point in aggregateByWeek', () => {
|
|
const data = [{date: '2024-01-01', value: 100}];
|
|
const result = aggregateByWeek(data, 'value', 'avg');
|
|
expect(result.length).toBe(1);
|
|
expect(result[0].date).toBe('2023-12-31'); // Week start
|
|
expect(result[0].value).toBe(100);
|
|
});
|
|
|
|
it('handles YTD range with long date span', () => {
|
|
const strategy = determineAggregationStrategy(-1, 180, 'exact');
|
|
expect(strategy).toBe('monthly');
|
|
});
|
|
|
|
it('handles YTD range with medium date span', () => {
|
|
const strategy = determineAggregationStrategy(-1, 100, 'exact');
|
|
expect(strategy).toBe('weekly');
|
|
});
|
|
|
|
it('handles YTD range with short date span', () => {
|
|
const strategy = determineAggregationStrategy(-1, 30, 'exact');
|
|
expect(strategy).toBe('none');
|
|
});
|
|
|
|
it('handles YTD range edge case with exact aggregation', () => {
|
|
const strategy = determineAggregationStrategy(-1, 151, 'exact');
|
|
expect(strategy).toBe('monthly');
|
|
});
|
|
|
|
it('handles YTD range with long span and non-exact aggregation', () => {
|
|
const strategy = determineAggregationStrategy(-1, 151, 'avg');
|
|
expect(strategy).toBe('monthly');
|
|
});
|
|
|
|
it('handles extreme outliers in bulk import detection', () => {
|
|
const data = [
|
|
{date: '2024-01-01', value: 100},
|
|
{date: '2024-01-02', value: 1000000},
|
|
{date: '2024-01-03', value: 100}
|
|
];
|
|
const result = detectBulkImports(data, 'value') as ChartDataItemWithOutlier[];
|
|
expect(result[1]._isOutlier).toBe(true);
|
|
expect(result[0]._isOutlier).toBe(false);
|
|
expect(result[2]._isOutlier).toBe(false);
|
|
});
|
|
});
|
|
|
|
describe('year to date handling', () => {
|
|
it('uses appropriate aggregation based on date span', () => {
|
|
// Test YTD with < 60 days
|
|
const shortData = createDateRange(30);
|
|
const shortResult = sanitizeChartData(shortData, -1);
|
|
expect(shortResult.length).toBe(shortData.length); // Should keep original data
|
|
|
|
// Test YTD with 61-150 days (weekly)
|
|
const mediumData = createDateRange(100);
|
|
const mediumResult = sanitizeChartData(mediumData, -1);
|
|
expect(mediumResult.length).toBeLessThan(mediumData.length); // Should aggregate weekly
|
|
|
|
// Test YTD with > 150 days (monthly)
|
|
const longData = createDateRange(200);
|
|
const longResult = sanitizeChartData(longData, -1);
|
|
expect(longResult.length).toBeLessThan(longData.length); // Should aggregate monthly
|
|
});
|
|
});
|
|
|
|
describe('edge cases', () => {
|
|
it('handles single data point', () => {
|
|
const data: ChartDataItem[] = [{date: '2024-01-01', value: 10}];
|
|
const result = sanitizeChartData(data, 30);
|
|
expect(result).toEqual(data);
|
|
});
|
|
|
|
it('handles custom field names', () => {
|
|
const data = [
|
|
{date: '2024-01-01', customField: 10},
|
|
{date: '2024-01-02', customField: 20}
|
|
];
|
|
const result = sanitizeChartData(data, 30, 'customField');
|
|
expect(result[0].customField).toBeDefined();
|
|
});
|
|
|
|
it('preserves additional fields in data objects', () => {
|
|
const data: ChartDataItem[] = [
|
|
{date: '2024-01-01', value: 10, extra: 'info'},
|
|
{date: '2024-01-02', value: 20, extra: 'info'}
|
|
];
|
|
const result = sanitizeChartData(data, 30);
|
|
expect(result[0].extra).toBe('info');
|
|
});
|
|
});
|
|
});
|
|
});
|