fix : added max length guards to question add-to-session validator (issue #1403) - #1408
Conversation
📝 WalkthroughWalkthroughThe PR adds maximum-length validation to flashcard, question, and session schemas. New Vitest suites verify accepted boundaries, rejected oversized values, required fields, and flashcard category defaults. ChangesInput validation limits
Estimated code review effort: 3 (Moderate) | ~20 minutes Possibly related issues
Possibly related PRs
🚥 Pre-merge checks | ✅ 3 | ❌ 2❌ Failed checks (2 warnings)
✅ Passed checks (3 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
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/tests/flashcardValidator.maxLength.unit.test.js`:
- Around line 18-100: Update the validator tests to use a vi.fn() next callback
and verify middleware continuation: in
backend/tests/flashcardValidator.maxLength.unit.test.js lines 18-100,
backend/tests/questionValidator.maxLength.unit.test.js lines 18-88, and
backend/tests/sessionValidator.maxLength.unit.test.js lines 18-110, assert next
is called once for every valid-input test and is not called for every
invalid-input test, while preserving the existing response assertions.
🪄 Autofix
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: Repository UI
Review profile: CHILL
Plan: Pro Plus
Run ID: a90b2407-2f12-405e-bafa-c7bfca79b265
📒 Files selected for processing (6)
backend/Input_validators/ValidateFlashcard.jsbackend/Input_validators/ValidateQuestions.jsbackend/Input_validators/ValidateSession.jsbackend/tests/flashcardValidator.maxLength.unit.test.jsbackend/tests/questionValidator.maxLength.unit.test.jsbackend/tests/sessionValidator.maxLength.unit.test.js
| it("accepts question and answer within max length", () => { | ||
| const req = makeReq({ | ||
| question: "What is polymorphism?", | ||
| answer: "Polymorphism allows objects of different types to be treated as instances of the same type.", | ||
| category: "OOP", | ||
| }); | ||
| const res = makeRes(); | ||
| validateCreateFlashcard(req, res, () => {}); | ||
| // If validation passes, res.status is not called | ||
| expect(res.status).not.toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it("rejects question exceeding 5000 characters", () => { | ||
| const req = makeReq({ | ||
| question: "A".repeat(5001), | ||
| answer: "Short answer", | ||
| }); | ||
| const res = makeRes(); | ||
| validateCreateFlashcard(req, res, () => {}); | ||
| expect(res.status).toHaveBeenCalledWith(400); | ||
| expect(res.json).toHaveBeenCalledWith( | ||
| expect.objectContaining({ success: false, message: "Validation failed" }) | ||
| ); | ||
| }); | ||
|
|
||
| it("rejects answer exceeding 5000 characters", () => { | ||
| const req = makeReq({ | ||
| question: "Short question", | ||
| answer: "B".repeat(5001), | ||
| }); | ||
| const res = makeRes(); | ||
| validateCreateFlashcard(req, res, () => {}); | ||
| expect(res.status).toHaveBeenCalledWith(400); | ||
| expect(res.json).toHaveBeenCalledWith( | ||
| expect.objectContaining({ success: false, message: "Validation failed" }) | ||
| ); | ||
| }); | ||
|
|
||
| it("rejects category exceeding 100 characters", () => { | ||
| const req = makeReq({ | ||
| question: "Q", | ||
| answer: "A", | ||
| category: "C".repeat(101), | ||
| }); | ||
| const res = makeRes(); | ||
| validateCreateFlashcard(req, res, () => {}); | ||
| expect(res.status).toHaveBeenCalledWith(400); | ||
| expect(res.json).toHaveBeenCalledWith( | ||
| expect.objectContaining({ success: false, message: "Validation failed" }) | ||
| ); | ||
| }); | ||
|
|
||
| it("accepts question and answer at exact boundary (5000 chars)", () => { | ||
| const req = makeReq({ | ||
| question: "Q".repeat(5000), | ||
| answer: "A".repeat(5000), | ||
| }); | ||
| const res = makeRes(); | ||
| validateCreateFlashcard(req, res, () => {}); | ||
| expect(res.status).not.toHaveBeenCalled(); | ||
| }); | ||
|
|
||
| it("rejects empty question", () => { | ||
| const req = makeReq({ question: "", answer: "A" }); | ||
| const res = makeRes(); | ||
| validateCreateFlashcard(req, res, () => {}); | ||
| expect(res.status).toHaveBeenCalledWith(400); | ||
| }); | ||
|
|
||
| it("rejects empty answer", () => { | ||
| const req = makeReq({ question: "Q", answer: "" }); | ||
| const res = makeRes(); | ||
| validateCreateFlashcard(req, res, () => {}); | ||
| expect(res.status).toHaveBeenCalledWith(400); | ||
| }); | ||
|
|
||
| it("defaults category to 'General' when omitted", () => { | ||
| const req = makeReq({ question: "Q", answer: "A" }); | ||
| const res = makeRes(); | ||
| validateCreateFlashcard(req, res, () => {}); | ||
| expect(res.status).not.toHaveBeenCalled(); | ||
| expect(req.body.category).toBe("General"); | ||
| }); |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Assert middleware continuation behavior.
Each test passes an anonymous next callback. The tests cannot detect a valid request that does not call next(). They also cannot detect an invalid request that calls next() after it sends the 400 response.
backend/tests/flashcardValidator.maxLength.unit.test.js#L18-L100: useconst next = vi.fn()and assertnextis called once for valid input and not called for invalid input.backend/tests/questionValidator.maxLength.unit.test.js#L18-L88: useconst next = vi.fn()and assertnextis called once for valid input and not called for invalid input.backend/tests/sessionValidator.maxLength.unit.test.js#L18-L110: useconst next = vi.fn()and assertnextis called once for valid input and not called for invalid input.
📍 Affects 3 files
backend/tests/flashcardValidator.maxLength.unit.test.js#L18-L100(this comment)backend/tests/questionValidator.maxLength.unit.test.js#L18-L88backend/tests/sessionValidator.maxLength.unit.test.js#L18-L110
🤖 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/tests/flashcardValidator.maxLength.unit.test.js` around lines 18 -
100, Update the validator tests to use a vi.fn() next callback and verify
middleware continuation: in
backend/tests/flashcardValidator.maxLength.unit.test.js lines 18-100,
backend/tests/questionValidator.maxLength.unit.test.js lines 18-88, and
backend/tests/sessionValidator.maxLength.unit.test.js lines 18-110, assert next
is called once for every valid-input test and is not called for every
invalid-input test, while preserving the existing response assertions.
Summary of What Has Been Done
Added
.max()guards to thequestionsarray items inaddQuestionToSessionSchemainbackend/Input_validators/ValidateQuestions.js:questions[].question: max 5000 charactersquestions[].answer: max 10000 charactersChanges Made
backend/Input_validators/ValidateQuestions.js: Added.max()Zod validators to question and answer fieldsbackend/tests/questionValidator.maxLength.unit.test.js: 7 unit tests covering max-length boundary casesImpact it Made
Closes #1403
Note: Please assign this PR to the
tmdeveloper007account.Adds maximum-length validation for flashcard, session, and session-question fields. Adds unit tests for boundary and rejection cases.
Ready to merge.