-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update value view component w/ shortened amount
- Loading branch information
Showing
8 changed files
with
517 additions
and
27 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
import { describe, expect, it } from 'vitest'; | ||
import { round, RoundOptions } from './round.js'; | ||
|
||
describe('round function', () => { | ||
const testCases: { | ||
description: string; | ||
options: RoundOptions; | ||
expected: string; | ||
}[] = [ | ||
// Default rounding mode ('round') | ||
{ | ||
description: 'should round up using default rounding (round)', | ||
options: { value: 1.2345, decimals: 3 }, | ||
expected: '1.235', | ||
}, | ||
{ | ||
description: 'should round down using default rounding (round)', | ||
options: { value: 1.2341, decimals: 3 }, | ||
expected: '1.234', | ||
}, | ||
{ | ||
description: 'should round a negative number using default rounding (round)', | ||
options: { value: -1.2345, decimals: 2 }, | ||
expected: '-1.23', | ||
}, | ||
{ | ||
description: 'should round zero', | ||
options: { value: 0, decimals: 2 }, | ||
expected: '0.00', | ||
}, | ||
{ | ||
description: 'should round an integer with decimals', | ||
options: { value: 5, decimals: 2 }, | ||
expected: '5.00', | ||
}, | ||
// Rounding mode: 'ceil' | ||
{ | ||
description: 'should ceil to 2 decimals', | ||
options: { value: 1.2345, decimals: 2, roundingMode: 'ceil' }, | ||
expected: '1.24', | ||
}, | ||
{ | ||
description: 'should ceil a negative number', | ||
options: { value: -1.2345, decimals: 2, roundingMode: 'ceil' }, | ||
expected: '-1.23', | ||
}, | ||
{ | ||
description: 'should ceil with zero decimals', | ||
options: { value: 1.5, decimals: 0, roundingMode: 'ceil' }, | ||
expected: '2', | ||
}, | ||
// Rounding mode: 'floor' | ||
{ | ||
description: 'should floor to 2 decimals', | ||
options: { value: 1.2399, decimals: 2, roundingMode: 'floor' }, | ||
expected: '1.23', | ||
}, | ||
{ | ||
description: 'should floor a negative number', | ||
options: { value: -1.2345, decimals: 2, roundingMode: 'floor' }, | ||
expected: '-1.24', | ||
}, | ||
{ | ||
description: 'should floor with zero decimals', | ||
options: { value: 1.9, decimals: 0, roundingMode: 'floor' }, | ||
expected: '1', | ||
}, | ||
// Edge Cases | ||
{ | ||
description: 'should handle very large numbers', | ||
options: { value: 1.23456789e10, decimals: 2, roundingMode: 'round' }, | ||
expected: '12345678900.00', | ||
}, | ||
{ | ||
description: 'should handle very small numbers', | ||
options: { value: 0.000123456, decimals: 8, roundingMode: 'round' }, | ||
expected: '0.00012346', | ||
}, | ||
{ | ||
description: 'should handle Infinity', | ||
options: { value: Infinity, decimals: 2, roundingMode: 'round' }, | ||
expected: 'Infinity', | ||
}, | ||
{ | ||
description: 'should handle -Infinity', | ||
options: { value: -Infinity, decimals: 2, roundingMode: 'floor' }, | ||
expected: '-Infinity', | ||
}, | ||
{ | ||
description: 'should handle NaN', | ||
options: { value: NaN, decimals: 2, roundingMode: 'ceil' }, | ||
expected: 'NaN', | ||
}, | ||
{ | ||
description: 'should handle decimals greater than available decimal places', | ||
options: { value: 1.2, decimals: 5, roundingMode: 'floor' }, | ||
expected: '1.20000', | ||
}, | ||
// Rounding to integer | ||
{ | ||
description: 'should round to integer using round mode', | ||
options: { value: 2.5, decimals: 0, roundingMode: 'round' }, | ||
expected: '3', | ||
}, | ||
{ | ||
description: 'should ceil to integer', | ||
options: { value: 2.1, decimals: 0, roundingMode: 'ceil' }, | ||
expected: '3', | ||
}, | ||
{ | ||
description: 'should floor to integer', | ||
options: { value: 2.9, decimals: 0, roundingMode: 'floor' }, | ||
expected: '2', | ||
}, | ||
]; | ||
|
||
testCases.forEach(({ description, options, expected }) => { | ||
// eslint-disable-next-line vitest/valid-title | ||
it(description, () => { | ||
const result = round(options); | ||
expect(result).toBe(expected); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,39 @@ | ||
import { ceil as lodashCeil, floor as lodashFloor, round as lodashRound } from 'lodash'; | ||
|
||
export type RoundingMode = 'round' | 'ceil' | 'floor'; | ||
|
||
export interface RoundOptions { | ||
value: number; | ||
decimals: number; | ||
roundingMode?: RoundingMode; | ||
} | ||
|
||
const roundingStrategies = { | ||
ceil: lodashCeil, | ||
floor: lodashFloor, | ||
round: lodashRound, | ||
} as const; | ||
|
||
/** | ||
* Rounds a number based on the specified options. | ||
* | ||
* @param options - An object containing the properties: | ||
* - value: The number to round. | ||
* - decimals: The number of decimal places to round to. | ||
* - roundingMode: The mode of rounding ('round', 'ceil', 'floor'). Defaults to 'round'. | ||
* | ||
* @returns A string representation of the rounded number. | ||
* | ||
* @example | ||
* | ||
* ```typescript | ||
* round({ value: 1.2345, decimals: 2, roundingMode: 'ceil' }); // "1.24" | ||
* round({ value: 1.2345, decimals: 2, roundingMode: 'floor' }); // "1.23" | ||
* round({ value: 1.2345, decimals: 2 }); // "1.23" (default rounding) | ||
* ``` | ||
*/ | ||
export function round({ value, decimals, roundingMode = 'round' }: RoundOptions): string { | ||
const roundingFn = roundingStrategies[roundingMode]; | ||
const roundedNumber = roundingFn(value, decimals); | ||
return roundedNumber.toFixed(decimals); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,208 @@ | ||
import { describe, expect, it } from 'vitest'; | ||
import { removeTrailingZeros, shortify } from './shortify.js'; | ||
|
||
describe('shortify Function', () => { | ||
describe('No suffix needed (|value| < 1,000)', () => { | ||
it('should return the integer part for positive numbers', () => { | ||
expect(shortify(0)).toBe('0'); | ||
expect(shortify(999)).toBe('999'); | ||
expect(shortify(123.456)).toBe('123'); // floor rounding | ||
}); | ||
|
||
it('should return the integer part for negative numbers', () => { | ||
expect(shortify(-999)).toBe('-999'); | ||
expect(shortify(-123.456)).toBe('-123'); // ceil rounding | ||
}); | ||
}); | ||
|
||
describe('Thousands suffix (K)', () => { | ||
it('should format positive numbers correctly', () => { | ||
expect(shortify(1000)).toBe('1K'); | ||
expect(shortify(1500)).toBe('1.5K'); | ||
expect(shortify(999999)).toBe('999K'); | ||
expect(shortify(1234)).toBe('1.23K'); | ||
expect(shortify(12345)).toBe('12.3K'); | ||
expect(shortify(123456)).toBe('123K'); | ||
}); | ||
|
||
it('should format negative numbers correctly', () => { | ||
expect(shortify(-1000)).toBe('-1K'); | ||
expect(shortify(-1500)).toBe('-1.5K'); | ||
expect(shortify(-999999)).toBe('-999K'); | ||
expect(shortify(-1234)).toBe('-1.23K'); | ||
expect(shortify(-12345)).toBe('-12.3K'); | ||
expect(shortify(-123456)).toBe('-123K'); | ||
}); | ||
}); | ||
|
||
describe('Millions suffix (M)', () => { | ||
it('should format positive numbers correctly', () => { | ||
expect(shortify(1_000_000)).toBe('1M'); | ||
expect(shortify(1_500_000)).toBe('1.5M'); | ||
expect(shortify(999_999_999)).toBe('999M'); | ||
expect(shortify(1234567)).toBe('1.23M'); | ||
expect(shortify(12345678)).toBe('12.3M'); | ||
expect(shortify(123456789)).toBe('123M'); | ||
}); | ||
|
||
it('should format negative numbers correctly', () => { | ||
expect(shortify(-1_000_000)).toBe('-1M'); | ||
expect(shortify(-1_500_000)).toBe('-1.5M'); | ||
expect(shortify(-999_999_999)).toBe('-999M'); | ||
expect(shortify(-1234567)).toBe('-1.23M'); | ||
expect(shortify(-12345678)).toBe('-12.3M'); | ||
expect(shortify(-123456789)).toBe('-123M'); | ||
}); | ||
}); | ||
|
||
describe('Billions suffix (B)', () => { | ||
it('should format positive numbers correctly', () => { | ||
expect(shortify(1_000_000_000)).toBe('1B'); | ||
expect(shortify(1_500_000_000)).toBe('1.5B'); | ||
expect(shortify(999_999_999_999)).toBe('999B'); | ||
expect(shortify(1234567890)).toBe('1.23B'); | ||
expect(shortify(12345678901)).toBe('12.3B'); | ||
expect(shortify(123456789012)).toBe('123B'); | ||
}); | ||
|
||
it('should format negative numbers correctly', () => { | ||
expect(shortify(-1_000_000_000)).toBe('-1B'); | ||
expect(shortify(-1_500_000_000)).toBe('-1.5B'); | ||
expect(shortify(-999_999_999_999)).toBe('-999B'); | ||
expect(shortify(-1234567890)).toBe('-1.23B'); | ||
expect(shortify(-12345678901)).toBe('-12.3B'); | ||
expect(shortify(-123456789012)).toBe('-123B'); | ||
}); | ||
}); | ||
|
||
describe('Trillions suffix (T)', () => { | ||
it('should format positive numbers correctly', () => { | ||
expect(shortify(1_000_000_000_000)).toBe('1T'); | ||
expect(shortify(1_500_000_000_000)).toBe('1.5T'); | ||
expect(shortify(1234567890123)).toBe('1.23T'); | ||
expect(shortify(12345678901234)).toBe('12.3T'); | ||
expect(shortify(123456789012345)).toBe('123T'); | ||
expect(shortify(1e15)).toBe('1000T'); // Edge case: beyond trillion | ||
}); | ||
|
||
it('should format negative numbers correctly', () => { | ||
expect(shortify(-1_000_000_000_000)).toBe('-1T'); | ||
expect(shortify(-1_500_000_000_000)).toBe('-1.5T'); | ||
expect(shortify(-1234567890123)).toBe('-1.23T'); | ||
expect(shortify(-12345678901234)).toBe('-12.3T'); | ||
expect(shortify(-123456789012345)).toBe('-123T'); | ||
expect(shortify(-1e15)).toBe('-1000T'); // Edge case: beyond trillion | ||
}); | ||
}); | ||
|
||
describe('Trailing zeros removal', () => { | ||
it('should remove trailing zeros after decimal', () => { | ||
expect(shortify(1000)).toBe('1K'); | ||
expect(shortify(1200)).toBe('1.2K'); | ||
expect(shortify(1230)).toBe('1.23K'); | ||
expect(shortify(1000000)).toBe('1M'); | ||
expect(shortify(1200000)).toBe('1.2M'); | ||
expect(shortify(1230000)).toBe('1.23M'); | ||
expect(shortify(1000000000)).toBe('1B'); | ||
expect(shortify(1200000000)).toBe('1.2B'); | ||
expect(shortify(1230000000)).toBe('1.23B'); | ||
expect(shortify(1000000000000)).toBe('1T'); | ||
expect(shortify(1200000000000)).toBe('1.2T'); | ||
expect(shortify(1230000000000)).toBe('1.23T'); | ||
|
||
expect(shortify(-1000)).toBe('-1K'); | ||
expect(shortify(-1200)).toBe('-1.2K'); | ||
expect(shortify(-1230)).toBe('-1.23K'); | ||
expect(shortify(-1000000)).toBe('-1M'); | ||
expect(shortify(-1200000)).toBe('-1.2M'); | ||
expect(shortify(-1230000)).toBe('-1.23M'); | ||
expect(shortify(-1000000000)).toBe('-1B'); | ||
expect(shortify(-1200000000)).toBe('-1.2B'); | ||
expect(shortify(-1230000000)).toBe('-1.23B'); | ||
expect(shortify(-1000000000000)).toBe('-1T'); | ||
expect(shortify(-1200000000000)).toBe('-1.2T'); | ||
expect(shortify(-1230000000000)).toBe('-1.23T'); | ||
}); | ||
}); | ||
|
||
describe('Very large numbers beyond trillion', () => { | ||
it('should handle numbers larger than 1 trillion', () => { | ||
expect(shortify(1_500_000_000_000)).toBe('1.5T'); | ||
expect(shortify(12_345_678_901_234)).toBe('12.3T'); | ||
expect(shortify(123_456_789_012_345)).toBe('123T'); | ||
expect(shortify(999_999_999_999_999)).toBe('999T'); | ||
expect(shortify(1e15)).toBe('1000T'); | ||
expect(shortify(-1_500_000_000_000)).toBe('-1.5T'); | ||
expect(shortify(-12_345_678_901_234)).toBe('-12.3T'); | ||
expect(shortify(-123_456_789_012_345)).toBe('-123T'); | ||
expect(shortify(-999_999_999_999_999)).toBe('-999T'); | ||
expect(shortify(-1e15)).toBe('-1000T'); | ||
}); | ||
}); | ||
|
||
describe('Rounding behavior', () => { | ||
it('should floor positive numbers and ceil negative numbers', () => { | ||
// Positive numbers | ||
expect(shortify(1234)).toBe('1.23K'); // floor to 2 decimals | ||
expect(shortify(12345)).toBe('12.3K'); // floor to 1 decimal | ||
expect(shortify(123456)).toBe('123K'); // floor to 0 decimals | ||
|
||
// Negative numbers | ||
expect(shortify(-1234)).toBe('-1.23K'); // ceil to 2 decimals | ||
expect(shortify(-12345)).toBe('-12.3K'); // ceil to 1 decimal | ||
expect(shortify(-123456)).toBe('-123K'); // ceil to 0 decimals | ||
}); | ||
}); | ||
}); | ||
|
||
describe('removeTrailingZeros', () => { | ||
it('should remove trailing zeros after decimal point', () => { | ||
expect(removeTrailingZeros('123.45000')).toBe('123.45'); | ||
expect(removeTrailingZeros('0.5000')).toBe('0.5'); | ||
expect(removeTrailingZeros('3.14159000')).toBe('3.14159'); | ||
}); | ||
|
||
it('should remove decimal point if all decimal digits are zeros', () => { | ||
expect(removeTrailingZeros('123.000')).toBe('123'); | ||
expect(removeTrailingZeros('0.0000')).toBe('0'); | ||
expect(removeTrailingZeros('456.0')).toBe('456'); | ||
}); | ||
|
||
it('should handle numbers without decimal points', () => { | ||
expect(removeTrailingZeros('123')).toBe('123'); | ||
expect(removeTrailingZeros('0')).toBe('0'); | ||
expect(removeTrailingZeros('456789')).toBe('456789'); | ||
}); | ||
|
||
it('should handle numbers with no trailing zeros', () => { | ||
expect(removeTrailingZeros('123.45')).toBe('123.45'); | ||
expect(removeTrailingZeros('0.5')).toBe('0.5'); | ||
expect(removeTrailingZeros('789.123456')).toBe('789.123456'); | ||
}); | ||
|
||
it('should handle negative numbers', () => { | ||
expect(removeTrailingZeros('-123.45000')).toBe('-123.45'); | ||
expect(removeTrailingZeros('-0.000')).toBe('-0'); | ||
expect(removeTrailingZeros('-456')).toBe('-456'); | ||
}); | ||
|
||
it('should handle empty string gracefully', () => { | ||
expect(removeTrailingZeros('')).toBe(''); | ||
}); | ||
|
||
it('should handle very large numbers', () => { | ||
expect(removeTrailingZeros('12345678901234567890.000000')).toBe('12345678901234567890'); | ||
expect(removeTrailingZeros('9876543210.09876543210000')).toBe('9876543210.0987654321'); | ||
}); | ||
|
||
it('should handle numbers with leading zeros', () => { | ||
expect(removeTrailingZeros('000123.45000')).toBe('000123.45'); | ||
expect(removeTrailingZeros('000.000')).toBe('000'); | ||
expect(removeTrailingZeros('000456')).toBe('000456'); | ||
}); | ||
|
||
it('should handle numbers with no digits after decimal point', () => { | ||
expect(removeTrailingZeros('123.')).toBe('123.'); | ||
expect(removeTrailingZeros('-456.')).toBe('-456.'); | ||
}); | ||
}); |
Oops, something went wrong.