From 391419e1ce2c581224449dbd92a82406d6555c20 Mon Sep 17 00:00:00 2001 From: "waldenyan20+test2026.7.21" Date: Wed, 22 Jul 2026 06:07:35 +0000 Subject: [PATCH] test: add unit tests for frontend bignumber and utilities helpers Co-Authored-By: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- frontend/src/helpers/bignumber.test.ts | 203 +++++++++++++++++++++++++ frontend/src/helpers/utilities.test.ts | 99 ++++++++++++ 2 files changed, 302 insertions(+) create mode 100644 frontend/src/helpers/bignumber.test.ts create mode 100644 frontend/src/helpers/utilities.test.ts diff --git a/frontend/src/helpers/bignumber.test.ts b/frontend/src/helpers/bignumber.test.ts new file mode 100644 index 0000000..2776117 --- /dev/null +++ b/frontend/src/helpers/bignumber.test.ts @@ -0,0 +1,203 @@ +import { + isNaN, + isNumber, + isInteger, + isPositive, + isNegative, + isZero, + countDecimalPlaces, + convertNumberToString, + convertStringToNumber, + convertHexToString, + convertStringToHex, + greaterThan, + greaterThanOrEqual, + smallerThan, + smallerThanOrEqual, + multiply, + divide, + floorDivide, + mod, + add, + subtract, + convertAmountToRawNumber, + convertAmountFromRawNumber, + handleSignificantDecimals, + formatFixedDecimals, + formatInputDecimals, +} from './bignumber'; + +describe('bignumber helpers', () => { + describe('isNaN', () => { + it('returns true for non-numeric input', () => { + expect(isNaN('abc')).toBe(true); + expect(isNaN(undefined)).toBe(true); + }); + + it('returns false for numeric input', () => { + expect(isNaN('123')).toBe(false); + expect(isNaN(0)).toBe(false); + }); + }); + + describe('isNumber', () => { + it('is the inverse of isNaN', () => { + expect(isNumber('42')).toBe(true); + expect(isNumber('not a number')).toBe(false); + }); + }); + + describe('isInteger', () => { + it('detects integers', () => { + expect(isInteger('10')).toBe(true); + expect(isInteger(-3)).toBe(true); + }); + + it('rejects non-integers', () => { + expect(isInteger('10.5')).toBe(false); + }); + }); + + describe('sign predicates', () => { + it('isPositive', () => { + expect(isPositive('1')).toBe(true); + expect(isPositive('-1')).toBe(false); + }); + + it('isNegative', () => { + expect(isNegative('-1')).toBe(true); + expect(isNegative('1')).toBe(false); + }); + + it('isZero', () => { + expect(isZero('0')).toBe(true); + expect(isZero('0.0')).toBe(true); + expect(isZero('1')).toBe(false); + }); + }); + + describe('countDecimalPlaces', () => { + it('counts decimal digits', () => { + expect(countDecimalPlaces('1.234')).toBe(3); + expect(countDecimalPlaces('5')).toBe(0); + }); + }); + + describe('conversions', () => { + it('convertNumberToString', () => { + expect(convertNumberToString(1000)).toBe('1000'); + }); + + it('convertStringToNumber', () => { + expect(convertStringToNumber('42')).toBe(42); + }); + + it('convertHexToString parses decimal-string input', () => { + expect(convertHexToString('255')).toBe('255'); + }); + + it('convertStringToHex returns base-16 representation', () => { + expect(convertStringToHex('255')).toBe('ff'); + expect(convertStringToHex(16)).toBe('10'); + }); + }); + + describe('comparisons', () => { + it('greaterThan', () => { + expect(greaterThan('2', '1')).toBe(true); + expect(greaterThan('1', '1')).toBe(false); + expect(greaterThan('1', '2')).toBe(false); + }); + + it('greaterThanOrEqual', () => { + expect(greaterThanOrEqual('2', '1')).toBe(true); + expect(greaterThanOrEqual('1', '1')).toBe(true); + expect(greaterThanOrEqual('0', '1')).toBe(false); + }); + + it('smallerThan', () => { + expect(smallerThan('1', '2')).toBe(true); + expect(smallerThan('1', '1')).toBe(false); + expect(smallerThan('2', '1')).toBe(false); + }); + + it('smallerThanOrEqual', () => { + expect(smallerThanOrEqual('1', '2')).toBe(true); + expect(smallerThanOrEqual('1', '1')).toBe(true); + expect(smallerThanOrEqual('2', '1')).toBe(false); + }); + }); + + describe('arithmetic', () => { + it('multiply', () => { + expect(multiply('3', '4')).toBe('12'); + }); + + it('divide', () => { + expect(divide('10', '4')).toBe('2.5'); + }); + + it('floorDivide', () => { + expect(floorDivide('10', '4')).toBe('2'); + }); + + it('mod', () => { + expect(mod('10', '3')).toBe('1'); + }); + + it('add', () => { + expect(add('1', '2')).toBe('3'); + }); + + it('subtract', () => { + expect(subtract('5', '2')).toBe('3'); + }); + + it('handles large integers without precision loss', () => { + expect(add('1000000000000000000', '1')).toBe('1000000000000000001'); + }); + }); + + describe('raw number conversion', () => { + it('convertAmountToRawNumber uses 18 decimals by default', () => { + expect(convertAmountToRawNumber('1')).toBe('1000000000000000000'); + expect(convertAmountToRawNumber('1.5')).toBe('1500000000000000000'); + }); + + it('convertAmountToRawNumber honours a custom decimal count', () => { + expect(convertAmountToRawNumber('1', 9)).toBe('1000000000'); + }); + + it('convertAmountFromRawNumber is the inverse', () => { + expect(convertAmountFromRawNumber('1000000000000000000')).toBe('1'); + expect(convertAmountFromRawNumber('1000000000', 9)).toBe('1'); + }); + }); + + describe('handleSignificantDecimals', () => { + it('returns null when decimals is not an integer', () => { + expect(handleSignificantDecimals('1', 2.5, 0)).toBeNull(); + }); + + it('formats a value that is >= 1', () => { + expect(handleSignificantDecimals('123.456', 4, 0)).toBe('123.456'); + }); + + it('formats a value smaller than 1 using significant digits', () => { + expect(handleSignificantDecimals('0.00012345', 8, 0)).toBe('0.000123'); + }); + }); + + describe('formatFixedDecimals', () => { + it('rounds to the requested number of decimals', () => { + expect(formatFixedDecimals('1.23456', 2)).toBe('1.23'); + expect(formatFixedDecimals('1.5', 0)).toBe('2'); + }); + }); + + describe('formatInputDecimals', () => { + it('formats based on the decimal places of the second input', () => { + expect(formatInputDecimals('1.23456789', '0.1')).toBe('1.23456789'); + }); + }); +}); diff --git a/frontend/src/helpers/utilities.test.ts b/frontend/src/helpers/utilities.test.ts new file mode 100644 index 0000000..0a64421 --- /dev/null +++ b/frontend/src/helpers/utilities.test.ts @@ -0,0 +1,99 @@ +import { + isObject, + sanitizeHex, + convertStringToHex, + convertNumberToString, + getChainData, + hashPersonalMessage, +} from './utilities'; + +describe('utilities helpers', () => { + describe('isObject', () => { + it('returns true for non-empty objects', () => { + expect(isObject({ a: 1 })).toBe(true); + }); + + it('returns false for empty objects', () => { + expect(isObject({})).toBe(false); + }); + + it('returns false for non-objects', () => { + expect(isObject('string')).toBe(false); + expect(isObject(42)).toBe(false); + }); + }); + + describe('sanitizeHex', () => { + it('adds the 0x prefix when missing', () => { + expect(sanitizeHex('ff')).toBe('0xff'); + }); + + it('keeps an existing 0x prefix', () => { + expect(sanitizeHex('0xff')).toBe('0xff'); + }); + + it('left-pads odd-length hex to an even number of characters', () => { + expect(sanitizeHex('f')).toBe('0x0f'); + expect(sanitizeHex('0xf')).toBe('0x0f'); + }); + + it('returns an empty string for empty input', () => { + expect(sanitizeHex('')).toBe(''); + expect(sanitizeHex('0x')).toBe(''); + }); + }); + + describe('convertStringToHex', () => { + it('converts a decimal string to hex', () => { + expect(convertStringToHex('255')).toBe('ff'); + expect(convertStringToHex(16)).toBe('10'); + }); + }); + + describe('convertNumberToString', () => { + it('stringifies numbers', () => { + expect(convertNumberToString(123)).toBe('123'); + }); + }); + + describe('getChainData', () => { + it('returns the matching chain for a known chainId', () => { + const data = getChainData(1); + expect(data.name).toBe('Ethereum Mainnet'); + expect(data.chain).toBe('ETH'); + }); + + it('returns Binance Smart Chain data for chainId 56', () => { + const data = getChainData(56); + expect(data.chain).toBe('smartchain'); + expect(data.native_currency.symbol).toBe('BNB'); + }); + + it('returns an "Unknown" fallback for an unsupported chainId', () => { + const data = getChainData(999999); + expect(data.name).toBe('Unknown'); + expect(data.chain).toBe('unknown'); + expect(data.chain_id).toBe(0); + }); + + it('injects the Infura API key into an infura rpc url', () => { + const previous = process.env.REACT_APP_INFURA_ID; + process.env.REACT_APP_INFURA_ID = 'test-infura-id'; + try { + const data = getChainData(1); + expect(data.rpc_url).toBe('https://mainnet.infura.io/v3/test-infura-id'); + expect(data.rpc_url).not.toContain('%API_KEY%'); + } finally { + process.env.REACT_APP_INFURA_ID = previous; + } + }); + }); + + describe('hashPersonalMessage', () => { + it('produces a deterministic EIP-191 hash', () => { + expect(hashPersonalMessage('hello world')).toBe( + '0xd9eba16ed0ecae432b71fe008c98cc872bb4cc214d3220a36f365326cf807d68' + ); + }); + }); +});