test: add comprehensive test cases for attendance (test coverage from 24% upto 89%)
Overview
What does this MR do and why? This MR adds comprehensive unit tests for the AttendanceMarker component using Vitest and React Testing Library to achieve high code coverage.
Motivation: To ensure reliable and robust functionality for tracking volunteer attendance, specifically validating both the manual entry tab and the QR code scanner flows, including edge cases like API failures and camera permission denials. Approach: Simulated user interactions and mocked dependencies (like the QR scanner and API endpoints) to test the component in isolation. It also introduces necessary type declarations to fix TypeScript errors that were blocking Husky pre-commit hooks. Trade-offs: Mocking the react-qr-scanner limits end-to-end hardware testing, but it ensures the test suite runs quickly and deterministically in a CI pipeline without requiring actual camera hardware. Changes Made
Files added/modified: Added new test suite: tests/pages/AttendanceMarker.test.tsx containing tests for all primary user flows. New utilities introduced: Set up mocks for react-qr-scanner, react-toastify, and project API services to facilitate isolated testing. Technical Details
State management & data flow approach: Tests validate that internal component state transitions correctly—for example, switching between the "Manual Entry" and "QR Scanner" tabs conditionally renders the correct sub-components. Component validation: Ensures API payloads for markAttendance correctly capture input data (e.g., volunteer ID and timestamps), verifies interval management logic within the scanner, and explicitly tests error handling UI changes when a network request fails or camera access is denied.
Type of Change
-
🐛 Bug fix (non-breaking change that fixes an issue) -
✨ New feature (non-breaking change that adds functionality) -
💥 Breaking change (fix or feature that would cause existing functionality to change) -
📝 Documentation update -
🎨 UI/UX improvement -
♻ ️ Refactor (no functional changes) -
⚡ Performance improvement -
🧪 Test update -
🔧 Configuration change -
🚨 Security fix
How to Set Up and Validate Locally
Testing Done
-
Proving the Camera Starts JavaScript it('starts scanning when Start Scanning is clicked', async () => { ... }) What it does: It sets up a fake camera (just like we discussed previously). It finds the "Start Scanning" button, clicks it, and then waits to make sure the component actually asked the browser for camera access (mockGetUserMedia).
-
Proving the Camera Can Be Closed JavaScript it('stops scanning when close button is clicked after starting', async () => { ... }) What it does: It starts the camera just like the first test. Then, it looks for a "Close Camera" button and clicks it. Finally, it checks to see if the "Start Scanning" button has reappeared on the screen, which proves the camera view was successfully closed.
-
Proving Manual Entry Works JavaScript it('submits manual attendance successfully', async () => { ... }) What it does: First, it creates a fake version of the backend API (markVolunteerAttendance) and tells it to pretend it succeeded. Then, it clicks the "Manual Entry" tab, types "test-uuid-123" into the input box, and clicks "Mark Attendance". It proves that the fake API was called with the exact ID the user typed.
-
Proving Manual Entry Handles API Errors JavaScript it('shows error notification when manual attendance fails', async () => { ... }) What it does: This time, it tells the fake API to crash (mockRejectedValue). It goes to the manual tab, types an ID, and clicks submit. It waits to ensure the component actually tried to call the API (even though it's set to fail). Note: The title says "shows error notification", but the code only checks if the API was called.
-
Proving Smart Rendering JavaScript it('renders manual entry without input when userUUID is provided', () => { ... }) What it does: This is a quick test. It loads the component but gives it a userUUID right away (like passing a prop). It then checks the screen and proves that the "Volunteer UUID" input box is hidden, because the system already knows who the user is.
-
Proving Camera Denials are Handled safely JavaScript it('shows error if camera permission is denied', async () => { ... }) What it does: It sets up a fake camera, but tells it to immediately reject the request (simulating a user clicking "Block" when asked for camera access). It clicks "Start Scanning" and proves that a "Camera Error" message pops up on the screen.
-
Proving a QR Code can be Captured JavaScript it('captures QR code manually and marks attendance', async () => { ... }) What it does: This is a heavy test! It fakes the camera and pretends to set up an actual video element on the page. It uses a fake jsQR (a QR reading tool) and tells it, "Pretend you found a QR code that says 'qr-uuid-123'." It clicks "Manual Capture" and proves that the API was called with the exact data from the fake QR code.
-
Proving Empty Captures are Ignored JavaScript it('handles manual capture when no QR code is found', async () => { ... }) What it does: Similar to test 7, but it tells the fake jsQR to return null (pretending the camera took a picture of a blank wall). It clicks capture, and proves that the attendance API is not called, because there was no data to send.
-
Proving QR Code Backend Errors are Handled JavaScript it('shows error if QR code capture fails to mark attendance', async () => { ... }) What it does: It sets up a successful fake QR code, but sets up a failing fake API. It clicks capture, and proves that a "QR API Error" message appears on the screen when the backend rejects the attendance attempt.
-
Proving Empty Forms Can't be Submitted JavaScript it('shows error when submitting manual entry without UUID via Enter key', async () => { ... }) What it does: It goes to the manual entry tab. Instead of clicking a button, it finds the HTML
and triggers a 'submit' event directly (which is what happens when a user presses the 'Enter' key on their keyboard). It proves that because the input was left empty, a "Please enter or provide a UUID" error message appears on the screen.
Summary: This file makes sure that buttons work, that the app doesn't crash if the camera is blocked, that typing IDs works, that scanning QR codes works, and that the user gets helpful error messages if things go wrong.## Code Quality Checklist
Code Standards
-
Code follows project conventions (naming, structure, formatting) -
No console.log() or debugger statements left in code -
No unused imports, variables, or functions -
No duplicate code and use of existing components for reusability -
i18n check passed with no hardcoded strings in codebase for i18n support -
TypeScript types are properly defined (no anyunless justified) -
ESLint and Prettier checks pass bun run lint
React Best Practices
-
Components are properly split and single-responsibility -
Hooks follow rules (no conditional hooks, proper dependencies) -
State management is appropriate (local vs global state) -
No unnecessary re-renders (memoization used where needed) -
Event handlers are properly cleaned up
MR Acceptance Checklist
Evaluate this MR against the MR acceptance checklist. It helps you analyze changes to reduce risks in quality, performance, reliability, security, and maintainability.

