Repository navigation
test(frontend): cover stream-creation amount, schedule, token and tx-lifecycle paths - #1802
Open
Purity-Euphemia wants to merge 1 commit into
Open
Purity-Euphemia wants to merge 1 commit into
Purity-Euphemia wants to merge 1 commit into
Conversation
…lifecycle paths Closes LabsCrypt#1794, Closes LabsCrypt#1795, Closes LabsCrypt#1797, Closes LabsCrypt#1798 Adds deterministic regression tests for the four modules flagged by the testing sweep, plus a small fix to the flat create-stream form so the first validation error is actually surfaced as a toast. LabsCrypt#1794 — create-wizard transaction lifecycle - frontend/src/lib/soroban.polling.test.ts: the confirmation polling loop (success, on-chain failure, 20-attempt timeout, wallet cancellation, broadcast error, simulation error, multisig routing). - frontend/src/app/streams/create/__tests__/create-stream-content.tx-lifecycle.test.tsx: the page-level states (signing -> confirming -> redirect, timeout, failed transaction, cancellation, validation and dependency failures). LabsCrypt#1795 — frontend/src/components/stream-creation/__tests__/AmountStep.test.tsx 7-decimal token precision boundaries, zero/invalid amounts, over-balance detection, XLM base reserve, the Max button and balance lookup failures. LabsCrypt#1797 — frontend/src/components/stream-creation/__tests__/ScheduleStep.test.tsx duration unit conversion to fixed seconds, timezone/DST invariant durations, duration validation and the 28-byte UTF-8 memo limit. LabsCrypt#1798 — frontend/src/components/stream-creation/__tests__/TokenStep.test.tsx token selection and error contract, missing token metadata (avatar fallback), failed token lookup, and unsupported/failed decimals lookups. Fix: useStreamForm.validateAll() now returns the freshly computed errors instead of a boolean, so create-stream-content can report the first validation error as a toast (the previous code read the hook state before the state update had been applied, so the toast was never shown).
This branch has not been deployed
This file contains hidden or 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
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
This PR closes the four open testing gaps raised by the Stellar Wave sweep on the
stream-creation flow. It adds 83 deterministic tests across five new test files that
cover the success, failure, boundary and dependency-failure paths of the four modules
flagged in the issues, and it fixes one real bug that the new tests uncovered (the
flat create-stream form never showed the first validation error as a toast).
Closes #1794
Closes #1795
Closes #1797
Closes #1798
What was missing
frontend/src/app/streams/create/create-stream-content.tsxfrontend/src/components/stream-creation/AmountStep.tsxfrontend/src/components/stream-creation/ScheduleStep.tsxfrontend/src/components/stream-creation/TokenStep.tsxChanges
1.
#1794— Create-stream transaction lifecyclefrontend/src/lib/soroban.polling.test.ts(new, 7 tests)Exercises the real confirmation-polling loop in
lib/soroban.ts(freighterCall) with adeterministic fake RPC and fake wallet:
{ success, txHash }isreturned (asserts the poll count and the polled tx hash);
FAILEDstatus raisesSorobanCallError("Transaction failed on-chain.", "NetworkError");second apart, and then raises
SorobanCallError("Transaction confirmation timed out.");SorobanCallError("Transaction was rejected in wallet.", "WalletRejected")and no pollis performed;
additional dependency-failure paths.
Fake timers (
vi.advanceTimersByTimeAsync) keep the polling tests deterministic and fast(26 ms instead of 24 s of wall-clock waiting).
frontend/src/app/streams/create/__tests__/create-stream-content.tx-lifecycle.test.tsx(new, 14 tests)
Covers the page-level lifecycle the user actually sees:
100 → 1_000_000_000nstroops) and duration (
30 days → 2_592_000n);Confirm in Wallet...while the transaction is pending andFinalizing Stream...once it is confirmed;redirected to
/dashboardafter the 2 s grace period, with the form enabled again;surface the exact user-facing message produced by
toSorobanErrorMessage, neverredirect, log the failure and re-enable the form;
dependency failures (balance lookup error) are asserted: nothing is submitted to the
network and the user gets actionable feedback.
2.
#1795— Amount step validationfrontend/src/components/stream-creation/__tests__/AmountStep.test.tsx(new, 22 tests)Amount exceeds maximum precision (7 decimal places); the boundary (6 vs. 8 decimals)and negative amounts are pinned down;
"0","0.0"and""are rejected (Amount must be a positive number/Amount is required) and the step does not render the “You will stream …”summary for a zero amount;
role="alert", the input is markedaria-invalidand wired toaria-describedby="amount-error";base-reserve subtraction (and the “never negative” case), and the unknown-balance case
where no bogus error may be shown;
enabled and wired to
onSetMaxotherwise;role="status"message instead of a validation error.3.
#1797— Schedule step, timezones and DSTfrontend/src/components/stream-creation/__tests__/ScheduleStep.test.tsx(new, 21 tests)days,weeks,months) are rendered, changesare reported to the parent, and each unit converts to a fixed number of seconds
(86 400 / 604 800 / 2 592 000). A month is explicitly 30 days, never a calendar
month, so the on-chain duration is deterministic;
2026 US spring-forward (local day = 23 h) and fall-back (local day = 25 h) transitions,
and identical in
UTC,America/New_York,Europe/BerlinandAsia/Tokyo. The testderives the local-day length from
Intl.DateTimeFormat(with a timezone-offsetcorrection) so it stays correct on any machine, with or without full ICU;
documented message and the inline error contract is rendered;
€is 3 bytes), the “approaching the limit” warning appears at 23 bytes, exactly 28bytes is accepted, 29 bytes and a 10-character/30-byte multi-byte memo are rejected.
4.
#1798— Token step and token metadatafrontend/src/components/stream-creation/__tests__/TokenStep.test.tsx(new, 19 tests)radiogroupwith one radio per supported token, correctaria-checkedstate,onChangereporting the symbol, and the error contract(
role="alert"+aria-describedby="token-error");(initials) is rendered, and a token whose contract address is missing from the
registry still renders its option instead of crashing;
getTokenAddress("DOGE")throwsSorobanCallError(
Unsupported token: DOGE, codeUnknown), and supported symbols resolvecase-insensitively;
fetchTokenDecimalsreturns the contract value, caches it (oneRPC call), and falls back to Stellar’s 7 decimals when the lookup fails, when the
contract returns no value, when the returned decimals are of an unsupported type and
when the RPC throws.
getTokenDecimalsSyncreturns the cached/default valuesynchronously and reports the fetched value through its callback.
5. Bug fix found by the new tests
frontend/src/hooks/useStreamForm.ts—validateAll()now returns the freshly computederror object instead of a boolean, and
frontend/src/app/streams/create/create-stream-content.tsxreads the first error from that result:
Before this change the component read
errorsfrom the hook state in the same tickas the validation, but the state update is asynchronous — so
Object.values(errors)[0]was always
undefinedand the “first error as a toast” UX described in the code commentnever happened. The inline error was still rendered; now the toast is shown as intended.
validateAllhad exactly one caller, and no test or hook consumer relied on the booleanreturn value, so the change is contained.
Files changed
No production behaviour changes other than the toast fix described above.
Testing
All new tests live in the existing Vitest suite (
frontend/vitest.config.tscollectssrc/**/*.{test,spec}.{ts,tsx}), so they run automatically in the Frontend CI job(
npm run test:coverage).CI pre-checks run locally
npm run lint(frontend)npx tsc --noEmitnpm run test:coveragenpm run buildbash ./scripts/check-bundle-size.shcargo fmt --all -- --check(contracts)cargo clippy --all-targets -- -D warnings(contracts)cargo test(contracts)npx tsc --noEmit(backend)backend/**does not change)Determinism notes: no test depends on wall-clock time, network access, randomness or the
machine’s timezone. Time-related assertions use fake timers
(
vi.useFakeTimers/vi.advanceTimersByTimeAsync) or explicit IANA timezones.Reviewer notes
messages, ARIA wiring, callbacks, toasts, redirects) rather than implementation details.
Intl.DateTimeFormatand an explicittimezone-offset correction, so it asserts the real 23 h/25 h local days instead of
hard-coding a calendar assumption.
TokenStep.test.tsxoverrides the token address registry through a module mock with agetter, which keeps the “missing metadata” path testable without touching the real
registry.
useStreamForm.validateAllsignature change is the only API change; it isdocumented in the hook and covered by the new lifecycle tests.
Checklist
main(test/issues-1794-1795-1797-1798)and dependency failures
npm run test:coverage)Closes #1794,Closes #1795,Closes #1797,Closes #1798)