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
18 changes: 18 additions & 0 deletions __tests__/reducers/amountFormat.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { describe, it, expect } from '@jest/globals';
import { reducer } from '../../src/reducers/reducer';
import { setAmountFormat } from '../../src/actions';
import { AMOUNT_FORMAT, AMOUNT_FORMAT_DEFAULT } from '../../src/constants';

// initialState is not exported; derive it by initializing the reducer.
const getInitialState = () => reducer(undefined, { type: '@@INIT' });

describe('amountFormat reducer', () => {
it('defaults to the expanded format', () => {
expect(getInitialState().amountFormat).toBe(AMOUNT_FORMAT_DEFAULT);
});

it('sets the amount format', () => {
const next = reducer(getInitialState(), setAmountFormat(AMOUNT_FORMAT.COMPRESSED));
expect(next.amountFormat).toBe(AMOUNT_FORMAT.COMPRESSED);
});
});
149 changes: 149 additions & 0 deletions __tests__/utils/amountFormat.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
import { describe, it, expect } from '@jest/globals';
Comment thread
tuliomir marked this conversation as resolved.
import {
compressAmountString, renderValue, getDisplayAmountFormat, normalizeAmountFormat,
capDecimalsByMagnitude, renderHomeValue,
} from '../../src/utils';
import { AMOUNT_FORMAT, AMOUNT_FORMAT_DEFAULT, AMOUNT_FORMAT_FEATURE_TOGGLE } from '../../src/constants';

const stateWith = (flagOn, amountFormat) => ({
featureToggles: { [AMOUNT_FORMAT_FEATURE_TOGGLE]: flagOn },
amountFormat,
});

describe('compressAmountString', () => {
// Compresses only the leading fractional zero run into subscript notation and
// keeps every later digit verbatim (including inner and trailing zeros), so the
// compressed form shows the same significant digits as the Expanded form.
it.each([
['0.0000005195', '0.0₆5195'],
['0.000000012345', '0.0₇12345'],
['0.00012', '0.0₃12'], // exactly 3 leading zeros (threshold)
['-0.0000005195', '-0.0₆5195'], // keeps the negative sign
['-0.00012', '-0.0₃12'],
['0.0000005000', '0.0₆5000'], // trailing zeros are kept, not trimmed
['0.00000000000050', '0.0₁₂50'], // deep run + trailing zero kept verbatim
['0.000000000012', '0.0₁₀12'], // multi-digit subscript (10 zeros)
['0.000000045600000123', '0.0₇45600000123'], // inner zeros kept verbatim
])('compresses %s -> %s', (input, expected) => {
expect(compressAmountString(input)).toBe(expected);
});

it.each([
['0.05'], // 1 leading zero, below threshold
['0.0012'], // 2 leading zeros, below threshold
['0.005195'], // 2 leading zeros, below threshold
['1.0000005195'], // non-zero integer part
['10.0000005'], // non-zero integer part
['1,234.00005'], // non-zero (grouped) integer part
['0.000000'], // effectively zero, nothing significant after the run
['1,234'], // no fractional part
['1234'], // no fractional part
])('leaves %s unchanged', (input) => {
expect(compressAmountString(input)).toBe(input);
});
});

describe('capDecimalsByMagnitude', () => {
// < 1 -> 8, 1-999 -> 4, 1000-9999 -> 3, >= 10000 -> 2; truncated, not padded.
it.each([
['0.12345678', '0.12345678'], // < 1, keeps up to 8
['0.123456789', '0.12345678'], // < 1, truncated to 8
['0.5', '0.5'], // < 1, no padding
['1.12345678', '1.1234'], // 1-999 -> 4
['999.98765', '999.9876'], // 999 -> 4
['1000.12345', '1000.123'], // 1000-9999 -> 3
['9999.9999', '9999.999'], // 9999 -> 3
['10000.98765', '10000.98'], // >= 10000 -> 2
['100000.12345678', '100000.12'],
['9223372036854775808.12345678', '9223372036854775808.12'],
['-0.123456789', '-0.12345678'], // sign preserved
['1,234.56789', '1,234.567'], // grouping preserved, magnitude 1234 -> 3
['1234', '1234'], // no fractional part unchanged
])('%s -> %s', (input, expected) => {
expect(capDecimalsByMagnitude(input)).toBe(expected);
});
});

describe('renderValue with amount format', () => {
it('renders with the network decimal places it is given', () => {
// 12 base units at 8 decimals => 0.00000012
expect(renderValue(12n, false, 8)).toBe('0.00000012');
});

it('falls back to the lib default decimals when unset', () => {
// 1234 base units at default 2 decimals => 12.34
expect(renderValue(1234n, false)).toBe('12.34');
});

it('defaults to expanded (unchanged behavior)', () => {
expect(renderValue(1234n, false, 8)).toBe(renderValue(1234n, false, 8, AMOUNT_FORMAT.EXPANDED));
});

it('routes COMPRESSED output through compressAmountString', () => {
const amount = 500000n;
expect(renderValue(amount, false, 8, AMOUNT_FORMAT.COMPRESSED))
.toBe(compressAmountString(renderValue(amount, false, 8, AMOUNT_FORMAT.EXPANDED)));
});

it('compresses sub-1 amounts once the network precision allows it', () => {
// 5195 base units at 8 decimals => 0.00005195 => 0.0₄5195. At the lib
// default of 2 decimals there is no zero run long enough to compress.
expect(renderValue(5195n, false, 8, AMOUNT_FORMAT.COMPRESSED)).toBe('0.0₄5195');
});

it('is a no-op for NFT amounts (no fractional part)', () => {
expect(renderValue(12345n, true, 8, AMOUNT_FORMAT.COMPRESSED)).toBe('12,345');
});
});

describe('renderHomeValue (magnitude rule + network decimals)', () => {
it('renders small amounts with up to 8 decimals from the network decimal places', () => {
// 12 base units at 8 decimals => 0.00000012 (< 1 => 8 dp)
expect(renderHomeValue(12n, false, 8, AMOUNT_FORMAT.EXPANDED)).toBe('0.00000012');
});

it('caps large amounts to 2 decimals by magnitude', () => {
// 10000012345678 at 8 decimals => 100,000.12345678 (>= 10000 => 2 dp)
expect(renderHomeValue(10000012345678n, false, 8, AMOUNT_FORMAT.EXPANDED)).toBe('100,000.12');
});

it('applies Compressed notation after the magnitude cap', () => {
expect(renderHomeValue(12n, false, 8, AMOUNT_FORMAT.COMPRESSED)).toBe('0.0₆12');
});

it('falls back to the lib default decimals when unset', () => {
// 1234 base units at default 2 decimals => 12.34
expect(renderHomeValue(1234n, false)).toBe('12.34');
});
});

describe('getDisplayAmountFormat (flag gating)', () => {
it('returns the stored preference while the flag is on', () => {
expect(getDisplayAmountFormat(stateWith(true, AMOUNT_FORMAT.COMPRESSED)))
.toBe(AMOUNT_FORMAT.COMPRESSED);
expect(getDisplayAmountFormat(stateWith(true, AMOUNT_FORMAT.EXPANDED)))
.toBe(AMOUNT_FORMAT.EXPANDED);
});

it('forces Expanded when the flag is off, ignoring the stored preference', () => {
expect(getDisplayAmountFormat(stateWith(false, AMOUNT_FORMAT.COMPRESSED)))
.toBe(AMOUNT_FORMAT.EXPANDED);
});

it('falls back to the default when nothing is stored', () => {
expect(getDisplayAmountFormat(stateWith(true, undefined))).toBe(AMOUNT_FORMAT.EXPANDED);
});
});

describe('normalizeAmountFormat', () => {
it('passes through known enum values', () => {
expect(normalizeAmountFormat(AMOUNT_FORMAT.EXPANDED)).toBe(AMOUNT_FORMAT.EXPANDED);
expect(normalizeAmountFormat(AMOUNT_FORMAT.COMPRESSED)).toBe(AMOUNT_FORMAT.COMPRESSED);
});

it('falls back to the default for unknown, null or undefined values', () => {
expect(normalizeAmountFormat('bogus')).toBe(AMOUNT_FORMAT_DEFAULT);
expect(normalizeAmountFormat(null)).toBe(AMOUNT_FORMAT_DEFAULT);
expect(normalizeAmountFormat(undefined)).toBe(AMOUNT_FORMAT_DEFAULT);
});
});
85 changes: 65 additions & 20 deletions locale/da/texts.po
Original file line number Diff line number Diff line change
Expand Up @@ -57,25 +57,25 @@ msgid "[Last] dddd [•] HH:mm"
msgstr "[Sidste] dddd [•] HH:mm"

#. See https://momentjs.com/docs/#/displaying/calendar-time/
#: src/models.js:107 src/utils.js:665
#: src/models.js:107 src/utils.js:752
msgid "DD MMM YYYY [•] HH:mm"
msgstr "DD MMM YYYY [•] HH:mm"

#: src/utils.js:271
msgid "Invalid address"
msgstr "Ugyldig adresse"

#: src/utils.js:650
#: src/utils.js:737
msgid "CREATE DEPOSIT TOKEN"
msgstr ""

#: src/utils.js:652
#: src/utils.js:739
msgid "CREATE FEE TOKEN"
msgstr ""

#: src/screens/CreateTokenAmount.js:36 src/screens/CreateTokenConfirm.js:87
#: src/screens/CreateTokenDepositNotice.js:42
#: src/screens/CreateTokenTypeNotice.js:94 src/utils.js:654
#: src/screens/CreateTokenTypeNotice.js:94 src/utils.js:741
msgid "CREATE TOKEN"
msgstr "OPRET TOKEN"

Expand Down Expand Up @@ -215,7 +215,7 @@ msgid ""
"wallet are already in use."
msgstr ""

#: src/screens/AddressMode.js:261
#: src/screens/AddressMode.js:261 src/screens/AmountFormat.js:145
msgid "SAVE PREFERENCES"
msgstr ""

Expand All @@ -225,6 +225,47 @@ msgid ""
"address mode..."
msgstr ""

#: src/screens/AmountFormat.js:83
msgid "Default"
msgstr ""

#: src/screens/AmountFormat.js:96
msgid "AMOUNT FORMAT"
msgstr ""

#: src/screens/AmountFormat.js:102
msgid ""
"Choose how amounts are displayed across your wallet. You can change your "
"default anytime."
msgstr ""

#: src/screens/AmountFormat.js:108
msgid "Expanded"
msgstr ""

#: src/screens/AmountFormat.js:109
msgid ""
"Standard notation. Leading zeros are written out in full (ex: 0.0000005195)."
msgstr ""

#: src/screens/AmountFormat.js:115
msgid "Compressed"
msgstr ""

#: src/screens/AmountFormat.js:116
msgid ""
"Compresses leading zeros into a subscript count for shorter, easier-to-read "
"small values (ex: 0.0₆5195)."
msgstr ""

#: src/screens/AmountFormat.js:121
msgid "PREVIEW"
msgstr ""

#: src/screens/AmountFormat.js:123
msgid "Full amount"
msgstr ""

#: src/screens/BackupWords.js:184
msgid "To make sure you saved,"
msgstr "For at sikre dig, at du har gemt,"
Expand Down Expand Up @@ -704,39 +745,39 @@ msgid "There's been an error connecting to the server."
msgstr ""

#: src/screens/LoadWalletErrorScreen.js:28 src/screens/PinScreen.js:318
#: src/screens/Settings.js:177
#: src/screens/Settings.js:181
msgid "Reset wallet"
msgstr "Nulstil wallet"

#: src/screens/LoadWalletErrorScreen.js:29
msgid "Connect to mainnet"
msgstr ""

#: src/screens/MainScreen.js:136
#: src/screens/MainScreen.js:138
msgid "No transactions"
msgstr "Ingen transaktioner"

#: src/screens/MainScreen.js:139
#: src/screens/MainScreen.js:141
msgid "|share:Share your address| with friends and start exchanging tokens"
msgstr "|share:Del din adresse| med venner og begynd at udveksle tokens"

#: src/screens/MainScreen.js:156
#: src/screens/MainScreen.js:158
msgid "Loading transactions"
msgstr "Indlæser dine transaktioner"

#: src/screens/MainScreen.js:165
#: src/screens/MainScreen.js:167
msgid "There was an error loading your transaction history"
msgstr ""

#: src/screens/MainScreen.js:168
#: src/screens/MainScreen.js:170
msgid "Please |tryAgain:try again|"
msgstr ""

#: src/screens/MainScreen.js:551 src/screens/MainScreen.js:580
#: src/screens/MainScreen.js:564 src/screens/MainScreen.js:597
msgid "Available Balance"
msgstr "Tilgængelig saldo"

#: src/screens/MainScreen.js:560
#: src/screens/MainScreen.js:573
msgid "Locked"
msgstr "Låst"

Expand Down Expand Up @@ -1114,15 +1155,19 @@ msgstr ""
msgid "Address Mode"
msgstr ""

#: src/screens/Settings.js:185
#: src/screens/Settings.js:177
msgid "Amount format"
msgstr ""

#: src/screens/Settings.js:189
msgid "About"
msgstr "Om"

#: src/screens/Settings.js:193
#: src/screens/Settings.js:197
msgid "Unique app identifier"
msgstr ""

#: src/screens/Settings.js:206
#: src/screens/Settings.js:210
msgid "Connected to"
msgstr "Forbundet til"

Expand Down Expand Up @@ -1620,21 +1665,21 @@ msgstr "Transaktion"
msgid "Open"
msgstr "Åben"

#: src/sagas/wallet.js:908
#: src/sagas/wallet.js:917
msgid "Wallet is not ready to load addresses."
msgstr ""

#. This will show the message in the feedback content at SelectAddressModal
#: src/sagas/wallet.js:922
#: src/sagas/wallet.js:931
msgid "There was an error while loading wallet addresses. Try again."
msgstr ""

#: src/sagas/wallet.js:932
#: src/sagas/wallet.js:941
msgid "Wallet is not ready to load the first address."
msgstr ""

#. This will show the message in the feedback content
#: src/sagas/wallet.js:948
#: src/sagas/wallet.js:957
msgid "There was an error while loading first wallet address. Try again."
msgstr ""

Expand Down
Loading
Loading