Files
spotlightcam/backend/src/__tests__/middleware/auth.test.js

189 lines
4.7 KiB
JavaScript
Raw Normal View History

/**
* 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);
});
});
});