Skip to content

test(claim): cover the unprojected send-link payload that crashed the claim page - #2892

Closed
innolope-dev wants to merge 1 commit into
mainfrom
test/send-link-fixture-matches-api
Closed

test(claim): cover the unprojected send-link payload that crashed the claim page#2892
innolope-dev wants to merge 1 commit into
mainfrom
test/send-link-fixture-matches-api

Conversation

@innolope-dev

@innolope-dev innolope-dev commented Aug 31, 2026

Copy link
Copy Markdown
Collaborator

Follow-up to #2889 (already merged) — adds the regression coverage that fix lacked.

Why the existing test didn't catch it

claim-states.test.tsx already had the right test — "CANCELLED link shows ClaimedView", rendering the real Claim component with status: 'CANCELLED'. It passed anyway, because of one line in the fixture factory:

function makeSendLink(overrides = {}) {
    return {, claim: null, events: [], ...overrides }
}

[][0] is undefined and undefined?.timestamp is safe. Production sends no events key at all, and undefined[0] throws. The fixture modelled a shape the endpoint doesn't return.

Where the unprojected shape comes from

GET /send-links/:pubKey has two response paths:

  • DB pathreply.send(sanitizeSendLink(sendLink)) — projects intents into the legacy claim + events shape.
  • Cache path (send-links/index.ts:905, 30s TTL) → reply.send(cached.sendLink) — the raw Prisma row, with intents and no claim/events.

So the crash needed a cache hit on a cancelled link, which is why it was rare and intermittent rather than constant.

I've filed the backend half separately — that side also skips toWireUser, so the cache path is a data-exposure issue, not just a shape mismatch.

The test

Builds the payload by stripping claim and events, matching the cache-hit response.

It gates on the drawer effect rather than the rendered view. That matters: claimLinkData is populated by an async effect that awaits fetchTokenDetails, so the view settles before the transaction memo ever runs — asserting on claimed-view alone passes even against the crashing code. Gating on openTransactionDetails forces the wait until the memo has produced a value.

Verified

  • Against pre-fix Claim.tsx (c020f6b57^1): fails with TypeError: Cannot read properties of undefined (reading '0'), in isolation as well as in the full suite.
  • Against current main: 16/16 pass.

The default fixture keeps events: [] so the projected shape stays covered too — this adds the second shape rather than swapping one blind spot for another.

Summary by CodeRabbit

  • Bug Fixes

    • Improved handling of cancelled send links when transaction details are opened.
    • Ensured the claimed view renders successfully for cancelled links with limited cached data.
  • Tests

    • Added regression coverage for cancelled send link scenarios.

… claim page

GET /send-links/:pubKey answers a cache hit (30s TTL) with the raw Prisma
row, which carries `intents` instead of the `claim` + `events` shape
`sanitizeSendLink` projects on the DB path. The existing CANCELLED test
never caught PEANUT-UI-SJ0 because its fixture hard-codes `events: []`,
and `[][0]?.timestamp` is safe where `undefined[0]` throws.

Add a case built from the cache-hit shape. It gates on the drawer effect
rather than the rendered view: the view settles before the transaction
memo runs, so asserting on it alone passes even against the crashing code.
@vercel

vercel Bot commented Aug 31, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
peanut-wallet Ready Ready Preview Aug 31, 2026 4:39pm

Request Review

@coderabbitai

coderabbitai Bot commented Aug 31, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 5eb63694-3d7d-48db-aff3-42e8da966673

📥 Commits

Reviewing files that changed from the base of the PR and between c020f6b and 6192ca0.

📒 Files selected for processing (1)
  • src/components/Claim/__tests__/claim-states.test.tsx

Included review availability: 0 reviews are currently available. Your included PR review attempts over the past 7 days set your current allowance at 2 reviews per hour.


📝 Walkthrough

Walkthrough

Added a regression test for cancelled send links returned without claim or events. The test verifies that transaction details open and the claimed view renders successfully.

Changes

Cancelled claim link handling

Layer / File(s) Summary
Regression test for unprojected cancelled links
src/components/Claim/__tests__/claim-states.test.tsx
The test covers cancelled links returned without projected claim and events fields. It verifies transaction-detail handling and claimed-view rendering.

Estimated code review effort: 2 (Simple) | ~10 minutes

Merge Risk: ⚪ Minimal · up to 6192c

This PR adds localized regression coverage for the claim-page crash without changing production behavior. No actionable merge-blocking risk remains, and it is merge-ready after normal checks.

Suggested reviewers: hugo0

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the regression test for the unprojected send-link payload that caused the claim page crash.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 1…
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check. Docstring coverage is scoped to functions touched by this diff. Analyzed 0 functions across 1 files.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch test/send-link-fixture-matches-api

Comment @coderabbitai help to get the list of available commands.

@github-actions

Copy link
Copy Markdown
Contributor

Code-analysis diff

Painscore total: 7753.44 → 7753.44 (0)
Findings: 0 net (+0 new, -0 resolved)

@github-actions

Copy link
Copy Markdown
Contributor

🧪 UI test report — ✅ all green

Suites

  • unit: 4234 ran, 0 failed, 0 skipped, 1.2m

📊 Coverage (unit)

metric %
statements 71.5%
branches 56.4%
functions 62.5%
lines 72.5%
⏱ 10 slowest test cases
time test
3.7s src/components/Card/share-asset/__tests__/shareAssetLayout.test.ts › never places two stickers in heavy overlap (broad seed sweep)
1.0s src/hooks/query/__tests__/user.test.tsx › does NOT clear a token that rotated mid-request (stale 401 racing a fresh login)
0.6s src/utils/__tests__/crisp.test.ts › configures once across repeated support opens
0.6s src/utils/__tests__/crisp.test.ts › retries configuration on the next open after a failure
0.5s src/app/receipt/[entryId]/pdf/__tests__/receipt-pdf-render.test.ts › produces a real, non-trivial PDF document
0.5s src/utils/__tests__/sentry.utils.test.ts › defaults to the client budget under a browser global
0.4s src/utils/__tests__/crisp.test.ts › resets the native session on logout once support has been opened
0.4s src/components/Card/share-asset/__tests__/shareAssetLayout.test.ts › every sticker stays within canvas at any count
0.4s src/utils/__tests__/crisp.test.ts › settles, and hands back a usable plugin, against a real-shaped plugin proxy
0.4s src/app/[locale]/(marketing)/status/StatusBoard.test.tsx › renders one 72-hour bar row per service, in user-facing language
📍 Inline annotations are in the **Unit test report** check above. Coverage artifact: `coverage-unit`. Generated by `.github/workflows/tests.yml`.

@chip-peanut-bot chip-peanut-bot Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Chip review — no blocking findings — this is not an approval

Clean. The regression test models a send-link response without claim/events and waits for the transaction drawer effect, so it reaches the previously crashing memo path.

Checked clean

  • Pinned worktree HEAD and merge base matched the supplied head and base SHAs; PR metadata matched the trusted author and main base.
  • Reviewed the only diff, the Claim transaction memo, and the preceding fix: omitting events reaches the formerly unsafe index access, while the drawer assertion waits past asynchronous link processing.
  • Exact-head unit, typecheck, eslint, format, e2e, CodeQL, analysis, reporting, and preview checks completed successfully.
  • Correctness, security, adversarial, and slop passes found no runtime behavior change, trust-boundary change, or actionable test defect.
  • A targeted local Jest rerun was unavailable because dependencies are not installed in the detached worktree; the exact-head unit CI job passed.

Second opinion by moonshotai/kimi-k3: 0 finding(s), marked with the model name. It reads the diff only, so treat its findings as advice.

Exact head: 6192ca05f92c · Context: repo

@innolope-dev

Copy link
Copy Markdown
Collaborator Author

Superseded by #2893, which targets dev instead. dev never received the #2889 fix, so the re-targeted PR carries both the fix and this test; the test's gate also had to change (the transaction-details drawer this one hooks into doesn't exist on dev).

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.

1 participant