Add validation tests for create stream – duration minimum and amount … - #658
Add validation tests for create stream – duration minimum and amount …#658nanaabdul1172 wants to merge 2 commits into
Conversation
|
@nanaabdul1172 is attempting to deploy a commit to the ritik4ever's projects Team on Vercel. A member of the Team first needs to authorize it. |
|
@nanaabdul1172 Great news! 🎉 Based on an automated assessment of this PR, the linked Wave issue(s) no longer count against your application limits. You can now already apply to more issues while waiting for a review of this PR. Keep up the great work! 🚀 |
|
Important Review skippedReview was skipped due to path filters ⛔ Files ignored due to path filters (1)
CodeRabbit blocks several paths by default. You can override this behavior by explicitly including those paths in the path filters. For example, including ⚙️ Run configurationConfiguration used: defaults Review profile: CHILL Plan: Pro Plus Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
📝 WalkthroughWalkthroughThe PR adds boundary tests and documentation for ChangesStream validation coverage
Recipient stream filtering
Estimated code review effort: 2 (Simple) | ~10 minutes Possibly related PRs
Suggested reviewers: 🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@backend/src/index.test.ts`:
- Around line 663-742: The totalAmountSchema decimal-place check is bypassed by
scientific notation, allowing sub-stroop values such as 0.00000001. Replace the
string-based precision check with stroop-scale/decimal-safe validation, add a
rejection test in backend/src/index.test.ts for that sub-stroop value, and
update BOUNDARY_TESTS_SUMMARY.md at lines 36-40 to reflect coverage only after
the new case is included.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: defaults
Review profile: CHILL
Plan: Pro Plus
Run ID: a95ca4be-b2e7-4f49-bd75-3c1c0d4467a8
⛔ Files ignored due to path filters (2)
backend/package-lock.jsonis excluded by!**/package-lock.jsonpackage-lock.jsonis excluded by!**/package-lock.json
📒 Files selected for processing (3)
BOUNDARY_TESTS_SUMMARY.mdbackend/src/index.test.tsbackend/src/index.ts
| it("returns 201 when totalAmount is 0.0000001 (1 stroop - minimum valid)", async () => { | ||
| const response = await request(app) | ||
| .post("/api/streams") | ||
| .set("Authorization", "Bearer mock_token") | ||
| .send({ | ||
| sender: SENDER_A, | ||
| recipient: RECIPIENT_1, | ||
| assetCode: "USDC", | ||
| totalAmount: 0.0000001, | ||
| durationSeconds: 120, | ||
| }); | ||
|
|
||
| expect(response.status).toBe(201); | ||
| expect(response.body.data).toMatchObject({ | ||
| totalAmount: 0.0000001, | ||
| }); | ||
| }); | ||
|
|
||
| it("returns 400 when totalAmount is 0", async () => { | ||
| const response = await request(app) | ||
| .post("/api/streams") | ||
| .set("Authorization", "Bearer mock_token") | ||
| .send({ | ||
| sender: SENDER_A, | ||
| recipient: RECIPIENT_1, | ||
| assetCode: "USDC", | ||
| totalAmount: 0, | ||
| durationSeconds: 120, | ||
| }); | ||
|
|
||
| expect(response.status).toBe(400); | ||
| expect(response.body.code).toBe("VALIDATION_ERROR"); | ||
| expect(response.body.error).toContain("Amount must be greater than zero"); | ||
| expect(response.body.details).toEqual( | ||
| expect.arrayContaining([ | ||
| expect.objectContaining({ field: "totalAmount" }), | ||
| ]), | ||
| ); | ||
| }); | ||
|
|
||
| it("returns 400 when totalAmount has more than 7 decimal places", async () => { | ||
| const response = await request(app) | ||
| .post("/api/streams") | ||
| .set("Authorization", "Bearer mock_token") | ||
| .send({ | ||
| sender: SENDER_A, | ||
| recipient: RECIPIENT_1, | ||
| assetCode: "USDC", | ||
| totalAmount: 100.12345678, // 8 decimal places | ||
| durationSeconds: 120, | ||
| }); | ||
|
|
||
| expect(response.status).toBe(400); | ||
| expect(response.body.code).toBe("VALIDATION_ERROR"); | ||
| expect(response.body.error).toContain("Amount cannot have more than 7 decimal places"); | ||
| expect(response.body.details).toEqual( | ||
| expect.arrayContaining([ | ||
| expect.objectContaining({ field: "totalAmount" }), | ||
| ]), | ||
| ); | ||
| }); | ||
|
|
||
| it("returns 201 when totalAmount has exactly 7 decimal places", async () => { | ||
| const response = await request(app) | ||
| .post("/api/streams") | ||
| .set("Authorization", "Bearer mock_token") | ||
| .send({ | ||
| sender: SENDER_A, | ||
| recipient: RECIPIENT_1, | ||
| assetCode: "USDC", | ||
| totalAmount: 100.1234567, // exactly 7 decimal places | ||
| durationSeconds: 120, | ||
| }); | ||
|
|
||
| expect(response.status).toBe(201); | ||
| expect(response.body.data).toMatchObject({ | ||
| totalAmount: 100.1234567, | ||
| }); | ||
| }); | ||
| }); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🌐 Web query:
What does JavaScript Number.prototype.toString()return for0.00000001, and when does it use exponential notation?
💡 Result:
For the number 0.00000001 (which is 10⁻⁸), JavaScript's Number.prototype.toString returns the string "1e-8" [1][2]. Exponential (scientific) notation is used by Number.prototype.toString when the radix is 10 and the absolute value of the number is either greater than or equal to 10²¹ or strictly less than 10⁻⁶ [1][3]. Specifically, the ECMAScript specification defines this behavior based on the exponent n in the number's representation [4][5]. When formatting a number in base 10, if the number cannot be represented without exceeding the range -5 to 21 for the exponent n, the engine switches to exponential notation [4][5]. In summary: - Result for 0.00000001: "1e-8" [1][2] - Threshold for exponential notation: magnitude < 10⁻⁶ or ≥ 10²¹ [1][3]
Citations:
- 1: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Number/toString
- 2: https://exploringjs.com/js/book/ch_numbers.html
- 3: https://github.com/mdn/content/blob/main/files/en-us/web/javascript/reference/global_objects/number/tostring/index.md
- 4: https://tc39.es/ecma262/multipage/ecmascript-data-types-and-values.html
- 5: https://tc39.es/ecma262/2026/multipage/ecmascript-data-types-and-values.html
🏁 Script executed:
#!/bin/bash
set -euo pipefail
echo "Locate relevant files"
git ls-files | rg '(^|/)schemas\.ts$|(@|^|/)index\.test\.ts$|BOUNDARY_TESTS_SUMMARY\.md$|backend/src/validation' || true
echo
echo "Search decimal validation symbols"
rg -n "Amount cannot have more than 7 decimal places|decimal places|totalAmountSchema|totalAmount" backend/src validation BOUNDARY_TESTS_SUMMARY.md 2>/dev/null || true
echo
echo "Candidate schema/test summary"
for f in backend/src/validation/schemas.ts backend/src/index.test.ts BOUNDARY_TESTS_SUMMARY.md; do
if [ -f "$f" ]; then
echo "===== $f ====="
wc -l "$f"
if [ "$f" = "backend/src/validation/schemas.ts" ]; then
ast-grep outline "$f" --match totalAmountSchema --view expanded || true
sed -n '1,220p' "$f" | cat -n
elif [ "$f" = "backend/src/index.test.ts" ]; then
sed -n '620,760p' "$f" | cat -n
elif [ "$f" = "BOUNDARY_TESTS_SUMMARY.md" ]; then
sed -n '1,80p' "$f" | cat -n
fi
fi
doneRepository: ritik4ever/stellar-stream
Length of output: 34506
🏁 Script executed:
#!/bin/bash
set -euo pipefail
node - <<'JS'
const values = [0.00000001, 0.0000001, 100.12345678, 100.1234567, 0, 100];
for (const v of values) {
const parts = String(v).split(".");
const decimalStr = parts[1];
console.log(JSON.stringify({ value: v, string: String(v), decimalStr, passes: !decimalStr || decimalStr.length <= 7 }));
}
JS
echo
echo "Relevant schema/validation tests"
sed -n '34,44p' backend/src/validation/schemas.ts | cat -n
sed -n '236,248p' backend/src/validation/schemas.test.ts | cat -n
sed -n '296,312p' backend/src/validation/schemas.test.ts | cat -nRepository: ritik4ever/stellar-stream
Length of output: 2371
Cover the scientific-notation precision bypass.
totalAmountSchema counts decimal places with value.toString().split(".")[1]; 0.00000001 becomes 1e-8, which has no fractional substring and passes the “no more than 7 decimal places” check. Add a sub-stroop rejection case and switch the schema to stroop-scale/decimal-safe validation; update BOUNDARY_TESTS_SUMMARY.md where it claims >7 decimal precision is fully rejected until that case is covered.
📍 Affects 2 files
backend/src/index.test.ts#L663-L742(this comment)BOUNDARY_TESTS_SUMMARY.md#L36-L40
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@backend/src/index.test.ts` around lines 663 - 742, The totalAmountSchema
decimal-place check is bypassed by scientific notation, allowing sub-stroop
values such as 0.00000001. Replace the string-based precision check with
stroop-scale/decimal-safe validation, add a rejection test in
backend/src/index.test.ts for that sub-stroop value, and update
BOUNDARY_TESTS_SUMMARY.md at lines 36-40 to reflect coverage only after the new
case is included.
|
Hi @nanaabdul1172, This PR could not be merged because it has merge conflicts with the target branch. Please resolve the merge conflicts, push the updated changes, and the PR can be reviewed and merged. Thank you! |
closes #316
✅ Boundary Tests Added
Duration Validation (lines 621-660):
durationSeconds = 59 → Returns 400 with "durationSeconds must be at least 60 seconds"
durationSeconds = 60 → Returns 201 (boundary passes) ✓
Amount Precision Validation (lines 663-743):
totalAmount = 0.0000001 (1 stroop) → Returns 201 (valid minimum) ✓
totalAmount = 0 → Returns 400 with "Amount must be greater than zero"
totalAmount = 100.12345678 (8 decimals) → Returns 400 with "Amount cannot have more than 7 decimal places"
totalAmount = 100.1234567 (7 decimals) → Returns 201 (maximum precision accepted) ✓
✅ Acceptance Criteria Met
✅ Duration boundary (59 vs 60) is tested explicitly
✅ Stroop-level minimum amount (0.0000001) is accepted
✅ More than 7 decimal places is rejected with clear message
✅ Zero amount is rejected with appropriate error
Additional Work
Fixed a syntax error in
index.ts
where duplicate code was preventing compilation
Tests are well-organized under nested describe blocks for easy maintenance
All tests follow the existing pattern with proper assertions for status codes, error codes, and error messages
Summary by CodeRabbit
New Features
Bug Fixes
Documentation