Skip to content

fix(frontend): guard stream progress bar against BigInt divide-by-zero (#550)#607

Merged
ogazboiz merged 4 commits into
LabsCrypt:mainfrom
dmystical-coder:fix/stream-progress-divzero-550
Jun 1, 2026
Merged

fix(frontend): guard stream progress bar against BigInt divide-by-zero (#550)#607
ogazboiz merged 4 commits into
LabsCrypt:mainfrom
dmystical-coder:fix/stream-progress-divzero-550

Conversation

@dmystical-coder
Copy link
Copy Markdown
Contributor

@dmystical-coder dmystical-coder commented Jun 1, 2026

Description

The stream-detail progress bar crashed when a stream's depositedAmount was "0". It computed (withdrawn * 100n) / deposited with BigInt operands, and BigInt division by zero throws RangeError, crashing the page render. This guards that division.

Type of Change

  • 🐛 Bug fix (non-breaking change which fixes an issue)
  • ✨ New feature (non-breaking change which adds functionality)
  • 💥 Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • 📚 Documentation update
  • 🔧 Refactoring (no functional changes)
  • ⚡ Performance improvement
  • 🧪 Test addition or update

Related Issues

Closes #550

Changes Made

  • frontend/src/utils/amount.ts: add a pure, exported streamProgressPercent(withdrawn, deposited) helper. Returns 0 when nothing is deposited (100 if anything was withdrawn) and clamps the result to [0, 100].
  • frontend/src/app/streams/[id]/page.tsx: use the helper instead of the inline (withdrawn * 100n) / deposited expression that threw.
  • frontend/src/__tests__/utils.test.ts: add tests for the helper, including a regression test asserting the zero-deposit case does not throw.
  • package-lock.json: reconcile the root lockfile with package.json (rollup platform deps 4.59.0 → 4.60.2; @rollup/rollup-linux-x64-gnu@4.60.2 was missing). This unblocks npm ci for all CI jobs — it was failing repo-wide on main, not just on this branch.
  • frontend/package.json + lockfile: add the missing @testing-library/dom peer dependency required by @testing-library/react@16. Without it the component/hook test suites could not load (Cannot find module '@testing-library/dom') once npm ci was unblocked. (Also clears 4 pre-existing tsc errors for screen/fireEvent.)
  • frontend/src/hooks/useModalDialog.ts: bind the modal Escape/focus-trap keydown handler to window instead of document so it also catches window-level keydown events. Fixes the previously-failing CancelConfirmModal Escape-to-close test.

Note: the lockfile, missing peer dep, and modal-handler items above were all pre-existing breakage unrelated to issue #550 — CI was red across the board on main. They are bundled here (at the maintainer-assignee's direction) so this PR's CI goes fully green and the #550 fix is actually validated end-to-end.

Testing

  • npx vitest run src/__tests__/utils.test.ts → 49 passed (45 existing + 4 new)
  • npm run lint → 0 errors (no new warnings in changed files)
  • npm run build → could not be completed in my local sandbox because app/layout.tsx fetches Google Fonts (IBM Plex Mono, Sora) at build time and outbound network is blocked here; this is unrelated to the change and is covered by CI.
  • npm ci --include=optional --dry-run → passes after the lockfile reconcile (previously failed; this is what was breaking CI on main).
  • npm test (full vitest suite) → 74/74 pass after adding @testing-library/dom and the modal-handler fix (previously 2 suites failed to load).
  • npx tsc --noEmit → 0 errors (the 4 pre-existing screen/fireEvent errors are resolved by the peer dep).
  • npm run lint → 0 errors (5 pre-existing warnings in untouched files).

Test Coverage

  • Unit tests added/updated
  • Integration tests added/updated
  • Manual testing performed (verified the exact arithmetic that threw via unit tests; the page is a heavy client component and the repo's @testing-library/react render harness is currently broken, so a full render test was not viable)

Test Steps

  1. Open a stream-detail page for a stream with depositedAmount: "0".
  2. Before: the page crashed with RangeError: Division by zero.
  3. After: the page renders; the progress bar shows 0% (or 100% if anything was withdrawn).

Screenshots/Demo

No screenshot attached: the change is a one-line guard with no visual restyling, and the app cannot be built/run in my sandbox (Google Fonts fetch is network-blocked, see Testing). The bar fills ${progressPercent}% exactly as before for normal streams; the only behavioral change is that a zero-deposit stream now renders 0% instead of crashing.

Checklist

  • My code follows the project's style guidelines
  • I have performed a self-review of my own code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation (not applicable)
  • My changes generate no new warnings
  • I have added tests that prove my fix is effective
  • New and existing unit tests pass locally with my changes
  • I have checked for breaking changes (none)

Additional Notes

Commit follows the conventional type(scope): description format and the branch follows the fix/short-description convention per CONTRIBUTING.md.


CI note: pre-existing backend failures (tracked separately)

Repairing the root lockfile unblocked npm ci, which surfaced 22 pre-existing backend integration-test failures (all blanket 401) in the Backend CI / Backend npm test jobs. These are unrelated to this PR — it changes no backend code or backend dependencies — and they were red on main already (just masked by the earlier npm ci failure). Tracked in #608. All frontend and #550-related checks on this PR are green.

The stream-detail progress bar computed (withdrawn * 100n) / deposited,
which throws RangeError when deposited is 0n (e.g. a freshly indexed
stream or a fee that consumed the full deposit), crashing the page.

Extract a pure streamProgressPercent helper that returns 0% when nothing
is deposited (100% if anything was withdrawn) and clamps to [0, 100],
and add regression tests for the zero-deposit case.

Closes LabsCrypt#550
CI's npm ci failed across all npm jobs because package-lock.json was out
of sync with package.json: rollup's platform optional-deps had drifted to
4.59.0 and @rollup/rollup-linux-x64-gnu@4.60.2 was missing from the lock.
Regenerate the lockfile so npm ci --include=optional succeeds.
@testing-library/react@16 requires @testing-library/dom as an explicit
peer dependency, but it was absent from package.json. Without it the
component and hook test suites fail to load (Cannot find module
'@testing-library/dom'), so npm test failed once npm ci was unblocked.
The modal Escape/focus-trap handler listened on document, so a keydown
dispatched at the window level was not caught. Listen on window instead:
real key presses bubble up to window unchanged, and the global Escape
handler now also catches window-level events. Fixes the Escape-to-close
test for CancelConfirmModal.
@ogazboiz ogazboiz merged commit 6207c70 into LabsCrypt:main Jun 1, 2026
7 of 9 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

Development

Successfully merging this pull request may close these issues.

[Frontend] Stream-detail progress bar throws on deposited === 0 (BigInt division by zero)

2 participants