feat: test coverage for utils
Some checks failed
Lint / Lint Code (push) Failing after 7m20s
Test / Svelte Checks (push) Failing after 7m20s

This commit is contained in:
Ilia Mashkov
2026-01-07 17:26:59 +03:00
parent f4c2a38873
commit 36a326817d
3 changed files with 634 additions and 0 deletions

View File

@@ -0,0 +1,270 @@
/**
* Tests for roundToStepPrecision utility
*/
import {
describe,
expect,
test,
} from 'vitest';
import { roundToStepPrecision } from './roundToStepPrecision';
describe('roundToStepPrecision', () => {
describe('basic functionality', () => {
test('should return value unchanged for step=1', () => {
// step=1 has 0 decimal places, so it rounds to integers
expect(roundToStepPrecision(5, 1)).toBe(5);
expect(roundToStepPrecision(5.5, 1)).toBe(6); // rounds to nearest integer
expect(roundToStepPrecision(5.999, 1)).toBe(6);
});
test('should round to 1 decimal place for step=0.1', () => {
expect(roundToStepPrecision(1.23, 0.1)).toBeCloseTo(1.2);
expect(roundToStepPrecision(1.25, 0.1)).toBeCloseTo(1.3);
expect(roundToStepPrecision(1.29, 0.1)).toBeCloseTo(1.3);
});
test('should round to 2 decimal places for step=0.01', () => {
expect(roundToStepPrecision(1.234, 0.01)).toBeCloseTo(1.23);
expect(roundToStepPrecision(1.235, 0.01)).toBeCloseTo(1.24);
expect(roundToStepPrecision(1.239, 0.01)).toBeCloseTo(1.24);
});
test('should round to 3 decimal places for step=0.001', () => {
expect(roundToStepPrecision(1.2345, 0.001)).toBeCloseTo(1.235);
expect(roundToStepPrecision(1.2344, 0.001)).toBeCloseTo(1.234);
});
});
describe('floating-point precision issues', () => {
test('should fix floating-point precision errors with step=0.05', () => {
// Known floating-point issue: 0.1 + 0.05 = 0.15000000000000002
const value = 0.1 + 0.05;
const result = roundToStepPrecision(value, 0.05);
expect(result).toBeCloseTo(0.15, 2);
});
test('should fix floating-point errors with repeated additions', () => {
// Simulate adding 0.05 multiple times
let value = 1;
for (let i = 0; i < 10; i++) {
value += 0.05;
}
// value should be 1.5 but might be 1.4999999999999998
const result = roundToStepPrecision(value, 0.05);
expect(result).toBeCloseTo(1.5, 2);
});
test('should fix floating-point errors with step=0.1', () => {
// Known floating-point issue: 0.1 + 0.2 = 0.30000000000000004
const value = 0.1 + 0.2;
const result = roundToStepPrecision(value, 0.1);
expect(result).toBeCloseTo(0.3, 1);
});
test('should fix floating-point errors with step=0.01', () => {
// Known floating-point issue: 0.01 + 0.02 = 0.029999999999999999
const value = 0.01 + 0.02;
const result = roundToStepPrecision(value, 0.01);
expect(result).toBeCloseTo(0.03, 2);
});
test('should fix floating-point errors with step=0.25', () => {
const value = 0.5 + 0.25;
const result = roundToStepPrecision(value, 0.25);
expect(result).toBeCloseTo(0.75, 2);
});
test('should handle classic 0.1 + 0.2 problem', () => {
// Classic JavaScript floating-point issue
const value = 0.1 + 0.2;
// Without rounding: 0.30000000000000004
const result = roundToStepPrecision(value, 0.1);
expect(result).toBe(0.3);
});
});
describe('edge cases', () => {
test('should return value unchanged when step <= 0', () => {
expect(roundToStepPrecision(5, 0)).toBe(5);
expect(roundToStepPrecision(5, -1)).toBe(5);
expect(roundToStepPrecision(5, -0.5)).toBe(5);
});
test('should handle zero value', () => {
expect(roundToStepPrecision(0, 0.1)).toBe(0);
expect(roundToStepPrecision(0, 0.01)).toBe(0);
});
test('should handle negative values', () => {
expect(roundToStepPrecision(-1.234, 0.01)).toBeCloseTo(-1.23);
expect(roundToStepPrecision(-0.15, 0.05)).toBeCloseTo(-0.15);
expect(roundToStepPrecision(-5.5, 0.5)).toBeCloseTo(-5.5);
});
test('should handle very small step values', () => {
expect(roundToStepPrecision(1.1234, 0.0001)).toBeCloseTo(1.1234);
expect(roundToStepPrecision(1.12345, 0.0001)).toBeCloseTo(1.1235);
});
test('should handle very large values', () => {
expect(roundToStepPrecision(12345.6789, 0.01)).toBeCloseTo(12345.68);
expect(roundToStepPrecision(99999.9999, 0.001)).toBeCloseTo(100000);
});
});
describe('special number values', () => {
test('should handle Infinity', () => {
expect(roundToStepPrecision(Infinity, 0.1)).toBe(Infinity);
expect(roundToStepPrecision(-Infinity, 0.1)).toBe(-Infinity);
});
test('should handle NaN', () => {
expect(roundToStepPrecision(NaN, 0.1)).toBeNaN();
});
test('should handle step=Infinity', () => {
// getDecimalPlaces(Infinity) returns 0, so this rounds to 0 decimal places (integer)
const result = roundToStepPrecision(1.234, Infinity);
expect(result).toBeCloseTo(1);
});
});
describe('real-world scenarios', () => {
test('should handle currency calculations with step=0.01', () => {
// Add items with tax that might have floating-point errors
const subtotal = 10.99 + 5.99 + 2.99;
const rounded = roundToStepPrecision(subtotal, 0.01);
expect(rounded).toBeCloseTo(19.97, 2);
});
test('should handle slider values with step=0.1', () => {
// Slider value after multiple increments
let sliderValue = 0;
for (let i = 0; i < 15; i++) {
sliderValue += 0.1;
}
const rounded = roundToStepPrecision(sliderValue, 0.1);
expect(rounded).toBeCloseTo(1.5, 1);
});
test('should handle font size adjustments with step=0.5', () => {
// Font size adjustments
let fontSize = 12;
fontSize += 0.5; // 12.5
fontSize += 0.5; // 13.0
const rounded = roundToStepPrecision(fontSize, 0.5);
expect(rounded).toBeCloseTo(13, 1);
});
test('should handle opacity values with step=0.05', () => {
// Opacity from 0 to 1 in 5% increments
let opacity = 0;
for (let i = 0; i < 10; i++) {
opacity += 0.05;
}
const rounded = roundToStepPrecision(opacity, 0.05);
expect(rounded).toBeCloseTo(0.5, 2);
});
test('should handle percentage calculations with step=0.01', () => {
// Calculate percentage with floating-point issues
const percentage = (1 / 3) * 100;
const rounded = roundToStepPrecision(percentage, 0.01);
expect(rounded).toBeCloseTo(33.33, 2);
});
test('should handle coordinate rounding with step=0.000001', () => {
// GPS coordinates with micro-degree precision
const lat = 40.7128 + 0.000001;
const rounded = roundToStepPrecision(lat, 0.000001);
expect(rounded).toBeCloseTo(40.712801, 6);
});
test('should handle time values with step=0.001', () => {
// Millisecond precision timing
const time = 123.456 + 0.001 + 0.001;
const rounded = roundToStepPrecision(time, 0.001);
expect(rounded).toBeCloseTo(123.458, 3);
});
});
describe('common step values', () => {
test('should correctly round for step=0.05', () => {
// step=0.05 has 2 decimal places, so it rounds to 2 decimal places
// Note: This rounds to the DECIMAL PRECISION, not to the step increment
expect(roundToStepPrecision(1.34, 0.05)).toBeCloseTo(1.34);
expect(roundToStepPrecision(1.36, 0.05)).toBeCloseTo(1.36);
expect(roundToStepPrecision(1.37, 0.05)).toBeCloseTo(1.37);
expect(roundToStepPrecision(1.38, 0.05)).toBeCloseTo(1.38);
});
test('should correctly round for step=0.25', () => {
// step=0.25 has 2 decimal places, so it rounds to 2 decimal places
// Note: This rounds to the DECIMAL PRECISION, not to the step increment
expect(roundToStepPrecision(1.24, 0.25)).toBeCloseTo(1.24);
expect(roundToStepPrecision(1.26, 0.25)).toBeCloseTo(1.26);
expect(roundToStepPrecision(1.37, 0.25)).toBeCloseTo(1.37);
expect(roundToStepPrecision(1.38, 0.25)).toBeCloseTo(1.38);
});
test('should correctly round for step=0.1', () => {
// step=0.1 has 1 decimal place, so it rounds to 1 decimal place
expect(roundToStepPrecision(1.04, 0.1)).toBeCloseTo(1.0);
expect(roundToStepPrecision(1.05, 0.1)).toBeCloseTo(1.1);
expect(roundToStepPrecision(1.14, 0.1)).toBeCloseTo(1.1);
expect(roundToStepPrecision(1.15, 0.1)).toBeCloseTo(1.1); // standard banker's rounding
});
test('should correctly round for step=0.01', () => {
expect(roundToStepPrecision(1.234, 0.01)).toBeCloseTo(1.23);
expect(roundToStepPrecision(1.235, 0.01)).toBeCloseTo(1.24);
expect(roundToStepPrecision(1.236, 0.01)).toBeCloseTo(1.24);
});
});
describe('integration with getDecimalPlaces', () => {
test('should use correct decimal places from step parameter', () => {
// step=0.1 has 1 decimal place
expect(roundToStepPrecision(1.234, 0.1)).toBeCloseTo(1.2);
// step=0.01 has 2 decimal places
expect(roundToStepPrecision(1.234, 0.01)).toBeCloseTo(1.23);
// step=0.001 has 3 decimal places
expect(roundToStepPrecision(1.2345, 0.001)).toBeCloseTo(1.235);
});
test('should handle steps with different precisions correctly', () => {
const value = 1.123456789;
expect(roundToStepPrecision(value, 0.1)).toBeCloseTo(1.1);
expect(roundToStepPrecision(value, 0.01)).toBeCloseTo(1.12);
expect(roundToStepPrecision(value, 0.001)).toBeCloseTo(1.123);
expect(roundToStepPrecision(value, 0.0001)).toBeCloseTo(1.1235);
});
});
describe('return type behavior', () => {
test('should return finite number for valid inputs', () => {
expect(Number.isFinite(roundToStepPrecision(1.23, 0.01))).toBe(true);
});
});
describe('precision edge cases', () => {
test('should round 0.9999 correctly with step=0.01', () => {
expect(roundToStepPrecision(0.9999, 0.01)).toBeCloseTo(1);
});
test('should round 0.99999 correctly with step=0.001', () => {
expect(roundToStepPrecision(0.99999, 0.001)).toBeCloseTo(1);
});
test('should handle rounding up to next integer', () => {
expect(roundToStepPrecision(0.999, 0.001)).toBeCloseTo(0.999);
});
test('should handle values just below step boundary', () => {
expect(roundToStepPrecision(1.4999, 0.01)).toBeCloseTo(1.5);
expect(roundToStepPrecision(1.499, 0.01)).toBeCloseTo(1.5);
});
});
});