189 lines
4.7 KiB
JavaScript
189 lines
4.7 KiB
JavaScript
|
|
/**
|
||
|
|
* 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);
|
||
|
|
});
|
||
|
|
});
|
||
|
|
});
|