Skip to content

test(api): cover exact pagination-limit boundaries for sponsored transactions - #199

Open
phalap1 wants to merge 1 commit into
Octo-Protocol-org:mainfrom
phalap1:test/api/sponsored-tx-pagination-limits
Open

test(api): cover exact pagination-limit boundaries for sponsored transactions#199
phalap1 wants to merge 1 commit into
Octo-Protocol-org:mainfrom
phalap1:test/api/sponsored-tx-pagination-limits

Conversation

@phalap1

@phalap1 phalap1 commented Jul 30, 2026

Copy link
Copy Markdown

Closes #67

GET /v1/wallets/:id/sponsored-transactions (crates/api/src/routes/sponsor.rs::list_sponsored_transactions) validates limit against > 200 and < 1, and constrains status to pending|confirmed|failed. None of that was covered: list_sponsored_transactions_pagination only ever sends in-range values, so the two 400 paths never fired in a test, the exact accept/reject boundary was never pinned, and the status-filter rejection path had no coverage at all.

This adds direct coverage for each, in crates/api/tests/api_tests.rs alongside the existing list_sponsored_transactions_* tests, reusing the existing get_auth helper.

What's covered

Test Case Expected
sponsored_tx_limit_zero_and_negative_are_rejected limit=0, limit=-1 400 — limit must be at least 1
sponsored_tx_limit_201_is_rejected limit=201 400 — limit must not exceed 200
sponsored_tx_limit_boundaries_1_and_200_succeed limit=1, limit=200 200 — both accepted
sponsored_tx_invalid_status_filter_is_rejected status=bogus 400 — status must be one of: pending, confirmed, failed

Notes on the approach

Exact message assertions, not containment. Per the issue's guideline, each rejection asserts the precise string the handler returns, so a wording change fails the test rather than silently passing a substring check. This matches the existing convention in this file.

Ownership is validated before the query string. list_sponsored_transactions calls require_login, loads the wallet, and checks wallet.user_id before it looks at limit or status. Every case therefore creates a real wallet owned by the caller — without one, a 404 would mask the 400 actually under test and the tests would pass for the wrong reason.

limit is Option<i64>, so -1 is a real test. A negative value deserializes cleanly and reaches the handler's own < 1 branch, rather than being rejected earlier by the query extractor as malformed. That is what makes limit=-1 distinct from limit=0 and worth covering separately.

The boundary test proves the limit is applied, not just accepted. It inserts three sponsored transactions, so limit=1 must return exactly one row and emit a next_cursor, while limit=200 must return all three with a null cursor. Asserting only the status code would let a handler that ignores limit entirely still pass.

Empty status is pinned as valid. The handler does q.status.filter(|s| !s.is_empty()), so ?status= means "unfiltered", not "invalid". The invalid-status test asserts that ?status= still returns 200, which keeps that .filter() from being dropped as dead code later.

Verification

Run against a local Postgres:

running 4 tests
test sponsored_tx_invalid_status_filter_is_rejected ... ok
test sponsored_tx_limit_201_is_rejected ... ok
test sponsored_tx_limit_zero_and_negative_are_rejected ... ok
test sponsored_tx_limit_boundaries_1_and_200_succeed ... ok

test result: ok. 4 passed; 0 failed

The off-by-one check was confirmed to be meaningful rather than vacuous: temporarily changing the handler's guard from limit > 200 to limit > 199 fails sponsored_tx_limit_boundaries_1_and_200_succeed with left: 400, right: 200, and it passes again once the guard is restored.

No production code is changed — this PR is additive test coverage only.

…sactions

The limit validation in list_sponsored_transactions was implemented but
never tested at its exact boundaries (0, 1, 200, 201, negative), nor was the
status-filter validation error path. Adds direct coverage for each.

Asserts the exact error message the handler returns, not just the status
code, so a wording regression fails too. The boundary test inserts three
rows so limit=1 has to truncate and emit a cursor, proving the limit is
applied rather than merely accepted.
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.

test(api): Pagination boundary coverage for sponsored-transactions listing (limit=0, limit=201, negative)

1 participant