Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 44 additions & 0 deletions src/utils/__tests__/visualizationUtils.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,6 +152,50 @@ describe('visualizationUtils', () => {
expect(result.direction).toBe('neutral');
expect(result.percentage).toBe(0);
});

it('should handle zero baseline with positive growth without Infinity', () => {
const data = [0, 10, 250];
const result = calculateTrend(data);

expect(result.direction).toBe('up');
expect(result.percentage).toBe(100);
expect(Number.isFinite(result.percentage)).toBe(true);
});

it('should handle zero baseline with negative movement without Infinity', () => {
const data = [0, 2, -5];
const result = calculateTrend(data);

expect(result.direction).toBe('down');
expect(result.percentage).toBe(100);
expect(Number.isFinite(result.percentage)).toBe(true);
});

it('should handle zero baseline with no movement without NaN', () => {
const data = [0, 0, 0];
const result = calculateTrend(data);

expect(result.direction).toBe('neutral');
expect(result.percentage).toBe(0);
expect(Number.isNaN(result.percentage)).toBe(false);
});

it('should handle near-zero baseline without absurd percentages', () => {
const data = [Number.EPSILON / 2, 3, 5];
const result = calculateTrend(data);

expect(result.direction).toBe('up');
expect(result.percentage).toBe(100);
expect(Number.isFinite(result.percentage)).toBe(true);
});

it('should treat near-zero values at both endpoints as neutral', () => {
const data = [Number.EPSILON / 2, 0, Number.EPSILON / 4];
const result = calculateTrend(data);

expect(result.direction).toBe('neutral');
expect(result.percentage).toBe(0);
});
});

describe('calculateStatistics', () => {
Expand Down
18 changes: 18 additions & 0 deletions src/utils/visualizationUtils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,6 +247,24 @@ export const calculateTrend = (

const first = data[0];
const last = data[data.length - 1];

// Guard against a zero/near-zero baseline before dividing, otherwise the
// percentage change becomes Infinity or NaN (common for new metrics whose
// first data point is 0) and dashboards render a nonsensical trend.
// A percentage change from a zero baseline is undefined, so report the
// direction of movement with a full 100% change as a finite, sane fallback.
if (Math.abs(first) < Number.EPSILON) {
if (Math.abs(last) < Number.EPSILON) {
// Both endpoints are effectively zero: nothing changed.
return { direction: 'neutral', percentage: 0 };
}

return {
direction: last > first ? 'up' : 'down',
percentage: 100,
};
}

const change = ((last - first) / first) * 100;

if (Math.abs(change) < 1) {
Expand Down
Loading