/** * Auth Middleware Tests (Phase 1.5) * Tests for authentication and email verification middleware */ const { requireEmailVerification } = require('../../middleware/auth'); describe('Auth Middleware Tests (Phase 1.5)', () => { let req, res, next; beforeEach(() => { req = { user: null }; res = { status: jest.fn().mockReturnThis(), json: jest.fn() }; next = jest.fn(); }); describe('requireEmailVerification', () => { it('should pass through if email is verified', async () => { req.user = { id: 1, email: 'user@example.com', emailVerified: true }; await requireEmailVerification(req, res, next); expect(next).toHaveBeenCalled(); expect(res.status).not.toHaveBeenCalled(); }); it('should return 401 if user is not attached to request', async () => { req.user = null; await requireEmailVerification(req, res, next); expect(res.status).toHaveBeenCalledWith(401); expect(res.json).toHaveBeenCalledWith( expect.objectContaining({ success: false, error: 'Unauthorized' }) ); expect(next).not.toHaveBeenCalled(); }); it('should return 403 if email is not verified', async () => { req.user = { id: 1, email: 'user@example.com', emailVerified: false }; await requireEmailVerification(req, res, next); expect(res.status).toHaveBeenCalledWith(403); expect(res.json).toHaveBeenCalledWith( expect.objectContaining({ success: false, error: 'Email Not Verified', requiresVerification: true }) ); expect(next).not.toHaveBeenCalled(); }); it('should include helpful message for unverified email', async () => { req.user = { id: 1, email: 'user@example.com', emailVerified: false }; await requireEmailVerification(req, res, next); expect(res.json).toHaveBeenCalledWith( expect.objectContaining({ message: expect.stringContaining('verify your email') }) ); }); it('should handle undefined emailVerified as false', async () => { req.user = { id: 1, email: 'user@example.com' // emailVerified is undefined }; await requireEmailVerification(req, res, next); expect(res.status).toHaveBeenCalledWith(403); expect(next).not.toHaveBeenCalled(); }); it('should handle errors gracefully', async () => { const consoleSpy = jest.spyOn(console, 'error').mockImplementation(); // Force an error by making req.user a getter that throws Object.defineProperty(req, 'user', { get: () => { throw new Error('Test error'); } }); await requireEmailVerification(req, res, next); expect(res.status).toHaveBeenCalledWith(500); expect(res.json).toHaveBeenCalledWith( expect.objectContaining({ success: false, error: 'Internal Server Error' }) ); consoleSpy.mockRestore(); }); it('should not call next if verification fails', async () => { req.user = { id: 1, email: 'user@example.com', emailVerified: false }; await requireEmailVerification(req, res, next); expect(next).not.toHaveBeenCalled(); }); it('should work with verified users multiple times', async () => { req.user = { id: 1, email: 'user@example.com', emailVerified: true }; await requireEmailVerification(req, res, next); await requireEmailVerification(req, res, next); await requireEmailVerification(req, res, next); expect(next).toHaveBeenCalledTimes(3); }); it('should handle boolean true emailVerified', async () => { req.user = { id: 1, email: 'user@example.com', emailVerified: true }; await requireEmailVerification(req, res, next); expect(next).toHaveBeenCalled(); expect(res.status).not.toHaveBeenCalled(); }); it('should handle boolean false emailVerified', async () => { req.user = { id: 1, email: 'user@example.com', emailVerified: false }; await requireEmailVerification(req, res, next); expect(res.status).toHaveBeenCalledWith(403); expect(next).not.toHaveBeenCalled(); }); it('should include requiresVerification flag in response', async () => { req.user = { id: 1, email: 'user@example.com', emailVerified: false }; await requireEmailVerification(req, res, next); const jsonCall = res.json.mock.calls[0][0]; expect(jsonCall.requiresVerification).toBe(true); }); }); });