Skip to content

Harden swap, governance and balance components with tests - #1001

Merged
k-deejah merged 2 commits into
Sorokit:mainfrom
ussyalfaks:handsoff/issues-919-920-921-935-3fb809
Oct 26, 2026
Merged

k-deejah merged 2 commits into
Sorokit:mainfrom
ussyalfaks:handsoff/issues-919-920-921-935-3fb809

Conversation

@ussyalfaks

Copy link
Copy Markdown
Contributor

Closes #919, closes #920, closes #921, closes #935

#919: BalanceList fiat conversion, zero-state and issuer tooltip tests

Component change (small): AssetBadge now puts the full issuer key in a title tooltip on the truncated issuer line and on the (GA5Z...KZVN) duplicate-code suffix. Before this, the badge showed only the shortened key, so there was no tooltip to test.

Tests (BalanceList.test.tsx):

  • The AssetBadge mock can now hand off to the real component, using a hoisted flag and importOriginal. The issuer tests check the real truncation and tooltip markup, while all existing tests keep the lightweight stub.
  • Fiat conversion: symbol formatting for USD/EUR/GBP, the USD default, switching USD → EUR on rerender (symbol and value both update), falling back to the code for unknown currencies (JPY 200), rounding to two decimals, only native XLM counted, and no fiat figure when xlmPrice is missing.
  • Empty account: no balances (empty state, 0 assets, ~0 XLM (~€0), no search box). Zero XLM plus zero trustlines (dimmed "No balance" rows). "Hide zero" on an all-zero account (empty state and no Friendbot link). A malformed balance string is treated as 0 and never shows NaN.
  • Issuer tooltip: the truncated key carries the full key as title. Native XLM has no issuer tooltip. Same-code assets get tooltipped suffixes.

#920: ClaimableBalanceCard optimistic removal, clipboard and badge tests

Component change (small): BalanceRow (and its props type) is now exported, so onClaimed can be checked directly with a mock. The card's behaviour is unchanged.

Tests (ClaimableBalanceCard.test.tsx):

  • onClaimed: called once with the balance id when the claim succeeds, and only after the claim promise settles. It is not called when the claim returns an error, returns an empty result, or rejects. With confirmThreshold, it is only called after the dialog is confirmed. When used standalone, the row shows a "Claimed" badge.
  • Clipboard: navigator.clipboard.writeText is mocked. The full, untruncated id is copied even though only the truncated id is shown. The ✓ indicator goes back to ⎘ after 1.6s (fake timers). A missing clipboard API does not throw, and copying never starts a claim.
  • Status badges: an expired balance shows an error-styled "Expired" badge and a disabled, dimmed Claim button. A valid balance shows no badge and an enabled button. A table-driven test covers timeBound start/end, endTime, unconditional, and, or and not predicates. A rerender with a later currentTime switches the row to Expired.

#921: SwapSimulator slippage enforcement, flip and chart resizing

  • Minimum received: a new "Minimum Received" row shows amountOut * (1 - slippage / 100), or "—" when the slippage value is invalid. It is enforced at execution: once the simulated confirmation delay ends, the output is re-quoted against the pool as it is then. If it falls below the minimum, the swap is reverted with an inline alert and onSwap is not called. onSwap now also receives minAmountOut.
  • Direction inversion: flipping keeps the entered amount and re-quotes against the inverted pool reserves. It also clears any old success or error message, which no longer applies to the new direction.
  • Chart resizing: a ResizeObserver on the price-impact chart container drives the SVG's width/height/viewBox. The curve is still plotted on a 0–100 grid inside a scaled <g>, with vector-effect: non-scaling-stroke. The trade marker is drawn in viewport coordinates, so it stays circular after resizes and orientation changes. Zero-size entries are ignored, the observer disconnects on unmount, and environments without ResizeObserver are skipped. The marker also no longer calls reduce on an empty point list.
  • Tests (SwapSimulator.test.tsx): the minimum-received value and how it changes with slippage, the invalid-slippage placeholder, minAmountOut passed to onSwap, a revert when liquidity drains mid-swap, the flip keeping the amount and re-quoting (plus a double flip), and resize handling using a stubbed ResizeObserver (viewBox updates, rounding, ignoring zero sizes, marker coordinates, disconnect).

#935: GovernanceDashboard zero votes, prior votes and delegate validation

  • Zero votes: the vote bar's percentage helper guards against dividing by zero and non-finite results, so a proposal with no votes renders a clean 0% bar. A new approval label shows N% for, or "No votes yet" when there are no votes.
  • Prior votes: proposals accept an optional userVote from the contract payload (validated as yes/no/abstain). Successful votes are also recorded for the current session, keyed by account. Cards show "You voted: Yes/No/Abstain" and disable all vote buttons. The confirm dialog shows the prior vote and disables Confirm, and confirmVote refuses to submit a repeat vote.
  • Delegate validation: the delegation input is now a <form>, so pressing Enter goes through the same validation as clicking the button. An empty submit, or clearing a typed value, shows "Enter a delegate address." inline. Malformed addresses keep the validateStellarAddress error, and submitDelegation re-checks the address before calling the contract.
  • Tests (GovernanceDashboard.test.tsx): zero and malformed vote counts (no NaN, 0% widths), the approval percentage, the recorded userVote disabling voting, unknown userVote values being ignored, a duplicate vote blocked after a successful vote, and the empty, cleared, malformed-via-Enter and valid-via-Enter delegate cases.

Testing

Per the task rules, nothing was built, linted or run. The tests were written by reading the components and are untested.

Closes #919
Closes #920
Closes #921
Closes #935

@drips-wave

drips-wave Bot commented Oct 17, 2026

Copy link
Copy Markdown

@ussyalfaks Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits.

You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀

Learn more about application limits

@k-deejah
k-deejah merged commit c8c16d8 into Sorokit:main Oct 26, 2026
1 of 3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

2 participants