Skip to content

fix(tests): repair failing component tests, add interaction and error-state coverage for critical flows - #211

Merged
JamesEjembi merged 1 commit into
VeriNode-Labs:mainfrom
Cyber-Mitch:fix/188-failing-component-tests
Aug 29, 2026
Merged

fix(tests): repair failing component tests, add interaction and error-state coverage for critical flows#211
JamesEjembi merged 1 commit into
VeriNode-Labs:mainfrom
Cyber-Mitch:fix/188-failing-component-tests

Conversation

@Cyber-Mitch

@Cyber-Mitch Cyber-Mitch commented Aug 28, 2026

Copy link
Copy Markdown
Contributor

closes #188

8 component tests were failing across three distinct root causes, plus a set of assertions that only surfaced once the crashing tests were fixed. All 8 diagnosed and fixed at their actual cause — none skipped, none deleted, none weakened to pass.

The dead-modal regression — a real bug found while investigating a stale test, not a test bug itself

Two buttons in the Delegate Hub — "Delegate to Custom Address" and "Revoke Delegation" — did nothing when clicked. Git-bisected to three separate commits:

  1. 1b214d0 built full confirmation modals for both flows.
  2. 14ef38b ("chore: resolve strict typescript and eslint errors") deleted the modal JSX.
  3. 7ebaecd, an accessibility PR, reintroduced the state and click handlers that open those modals — without restoring what they opened.

Net effect: the handlers fired, open flipped to true, and nothing rendered. Fixed by restoring both modals (adapted to current field names/styling), and while in there, added the <label> elements the a11y PR's own stated goal (WCAG labelling) had missed on the search and custom-address inputs — both had placeholders only.

Two genuine production bugs, not test-authoring mistakes

#7useSorobanStaking.ts: a failed on-chain stake showed "Successfully staked." runAction's catch block called fail()/onToast() but never re-threw, so the returned promise always resolved — even on failure. StakeForm.tsx/UnstakeForm.tsx already await stake(...) inside try/catch, expecting rejection; the swallow silently broke that contract. Fixed by re-throwing after handling. New StakeForm.test.tsx proves the real-world impact directly: pre-fix, a failed stake still cleared the form and showed success. Also patched StakingPendingIndicator.tsx's unguarded retry() click handler, since the promise can now genuinely reject and that path needed handling to avoid an unhandled-rejection warning.

#8governanceProposalService.ts: the delegate count shown to users never updated. Delegate carried two near-duplicate fields — delegatorsCount (what the UI reads, matching the sibling governanceStore.ts) and delegatorCount (what the service actually mutated on delegation). Standardized on delegatorsCount (7 occurrences) and removed the duplicate from governance.ts's Delegate interface only — UserGovernanceProfile.delegatorCount and the unrelated validator-delegation domain (delegation.ts, liquidStakingService.ts) were left untouched, since they're a different field on a different type.

Everything else, by root cause

# Test Cause Fix
1–4 governanceComponents.test.tsx › DelegateManager Missing QueryClientProvideruseDelegates/useGovernanceMetrics use react-query, test rendered with plain render() Test fix: renderWithQueryClient() helper, matching the existing VotePanel.test.tsx convention
5 GovernancePage Integration Same cause Same fix
6 hexDecoder.test.ts perf test No warm-up pass — the timed loop paid one-time JIT cost; passed in isolation (60–101ms), failed under full-suite CPU contention (108–180ms observed) Untimed warm-up pass added; budget raised 100ms → 250ms — ~1.4× headroom over the worst observed contention, ~2.5× regression from isolated baseline needed to trip it

Surfaced only after fixing #1–5, since the provider crash had been masking them:

  • Three stale assertions (Self-Voting Mode / Total Proposals / Delegate Hub labels) that never matched any version of the component's text, back to its original PR — corrected.
  • DelegateManager was missing data-testid="delegate-manager-container", the convention every sibling governance component already follows (ProposalList, ProposalDetail, ProposalCreator, VoteHistoryTable) — added.
  • The test asserted delegate names (Stellar Foundation Guild, etc.) from governanceStore.ts's dataset, but DelegateManager actually renders governanceProposalService.ts's dataset (Soroban Whale Node, etc.) via useDelegates(). This is a real architectural gap, not a test bug — flagged separately below, not fixed here. Test corrected to assert the dataset the component actually renders, plus localStorage.clear() added to beforeEach for determinism.

Architectural finding, not fixed here — flagging for the maintainer

The Delegate Hub reads from a dataset that no other governance surface reads. governanceStore (Zustand) — consumed by ProposalList/ProposalDetail/ProposalCreator/VoteHistoryTable — and governanceProposalService (localStorage-backed, via react-query) — consumed by DelegateManager/GovernanceDashboard — are two independent delegate datasets with different names. A user delegating via the Delegate Hub tab updates a dataset nothing else in the governance UI reads; the delegation has no visible effect anywhere except the tab it was performed in. Unifying which store is authoritative is a real architectural decision with unknown blast radius on other react-query consumers — larger and riskier than this issue's scope of fixing test reliability.

CI relationship — revised from initial recon, not just confirmed

npm audit / OSV scan: confirmed independent workflows with no job dependency on the test job, exactly as expected — untouched, git diff --stat shows zero changes to package.json/package-lock.json/.github/. Root causes (a security:audit script referenced in CI but never wired into package.json; a real, pre-existing 16-vulnerability dependency backlog led by next/axios/postcss/sharp) are unrelated to #188 and untouched.

"Frontend Build Check / build" — fixing the 8 tests was necessary but not sufficient. npm run test:coverage (CI's actual command) still exits 1 with all 655 tests green, because of a pre-existing, repo-wide coverage floor: overall statement/line coverage is 27% against a 70% threshold (branches 78%, functions 76% — both already pass). Dozens of files unrelated to #188 — web workers, QR/crypto utilities, risk-scoring, sanitize — sit at 0% coverage, dragging the average down. Confirmed pre-existing and unaffected by this PR: the same 27% figure holds regardless of the 8-test fix, and none of the zero-coverage files were touched. Closing this gap means writing tests across many unrelated domains — a materially different, much larger task than "fix failing tests." Flagging clearly rather than attempting it here.

Critical-flow coverage added

  • Staking (new StakeForm.test.tsx): happy path (amount → confirm modal → confirm → success toast → form clears) and error state (same flow ending in an on-chain failure → error toast, no false success message, amount retained) — this test exercises the Offline-First Local Data Storage Model via IndexedDB for Field Auditing #7 fix at the component level, which the hook-only test couldn't catch on its own.
  • Governance delegation: new error-state test — delegateVotingPower mocked to reject, asserting the modal stays open and no false "Transaction confirmed" message appears.
  • Bridge-transaction interaction/error-state coverage was already solid; untouched.

Flakiness check

5 consecutive vitest run executions: 56/56 files, 655/655 tests, clean every time. Plus 3 additional runs under vitest run --coverage (CI's actual instrumented command, heavier overhead) specifically watching the previously-flaky hexDecoder perf test under that load: 127ms, 160ms, 176ms — all comfortably under the new 250ms budget. No flaky test found under either condition.

Changed files

src/tests/governanceComponents.test.tsx | 132 +++++++++--
src/tests/hexDecoder.test.ts | 28 ++-
src/components/StakingPendingIndicator.tsx | 9 +-
src/components/governance/DelegateManager.tsx | 103 ++++++++-
src/hooks/tests/useSorobanStaking.test.tsx | 8 +
src/hooks/useSorobanStaking.ts | 12 +-
src/services/governanceProposalService.ts | 14 +-
src/types/governance.ts | 1 -

src/components/staking/tests/StakeForm.test.tsx (new)
9 files changed, 397 insertions(+), 40 deletions(-)
All test/component/hook/service/type files — nothing touching build config or dependencies.

Verification

npm run test:unit: 56/56 files, 655/655 tests, 0 failed. npm run build: exit 0, all 24 routes generated.

Acceptance criteria

  • All tests pass — 655/655, 5 consecutive clean runs
  • Critical flows tested — staking (happy + error) and governance delegation (happy + error) added; bridge already covered
  • No flaky tests — 5 plain + 3 coverage-instrumented runs, all clean; the one flaky test found fixed at its root cause and re-verified under contention

Skipped or deleted tests

None. Every originally-failing test diagnosed and fixed at its actual cause.

@Cyber-Mitch

Copy link
Copy Markdown
Contributor Author

The 4 failing checks are all pre-existing and unrelated to this PR — documented in detail under "CI relationship" in the description above:

  • Frontend Build Check / build: blocked by a pre-existing repo-wide coverage floor (27% actual vs. 70% required), unaffected by this PR — git diff --stat shows zero test-config or dependency changes, and the 27% figure is identical before and after.
  • Dependency Vulnerability Scan (all 3 jobs): a pre-existing 16-vulnerability dependency backlog and a security:audit script referenced in CI but never wired into package.json — confirmed via git diff main -- package.json package-lock.json showing no changes in this PR.

Happy to file both as separate issues if that's useful — neither is something #188 asked for or should quietly absorb.

@Cyber-Mitch

Copy link
Copy Markdown
Contributor Author

@JamesEjembi Please review

@JamesEjembi
JamesEjembi merged commit 2b041b3 into VeriNode-Labs:main Aug 29, 2026
4 of 8 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.

Fix Failing Component Tests

2 participants