email-allowlist.guard.spec.tsβ’3.84 kB
import { describe, it, expect, beforeEach, vi } from 'vitest'
import { Test, TestingModule } from '@nestjs/testing'
import { ExecutionContext, UnauthorizedException } from '@nestjs/common'
import { EmailAllowlistGuard } from './email-allowlist.guard'
import { AllowlistService } from './allowlist.service'
describe('EmailAllowlistGuard', () => {
let guard: EmailAllowlistGuard
let allowlistService: AllowlistService
beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
providers: [
{
provide: AllowlistService,
useValue: {
isEmailAllowed: vi.fn(),
},
},
],
}).compile()
allowlistService = module.get<AllowlistService>(AllowlistService)
guard = new EmailAllowlistGuard(allowlistService)
})
describe('canActivate', () => {
let mockContext: ExecutionContext
let mockRequest: { user?: { email?: string; id?: string } | null }
beforeEach(() => {
mockRequest = {
user: {
email: 'user@example.com',
},
}
// Mock ExecutionContext for guard testing
const getRequestMock = <T = unknown>(): T => mockRequest as T
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const getResponseMock = <T = unknown>(): T => ({}) as T
// eslint-disable-next-line @typescript-eslint/consistent-type-assertions
const getNextMock = <T = unknown>(): T => ({}) as T
const httpArgumentsHost = {
getRequest: getRequestMock,
getResponse: getResponseMock,
getNext: getNextMock,
}
const context: Partial<ExecutionContext> = {
switchToHttp: () => httpArgumentsHost,
}
mockContext = context as ExecutionContext
})
it('should allow access for users with allowed email', async () => {
vi.spyOn(allowlistService, 'isEmailAllowed').mockReturnValue(true)
const result = await guard.canActivate(mockContext)
expect(result).toBe(true)
expect(allowlistService.isEmailAllowed).toHaveBeenCalledWith('user@example.com')
})
it('should deny access for users with non-allowed email', async () => {
vi.spyOn(allowlistService, 'isEmailAllowed').mockReturnValue(false)
await expect(guard.canActivate(mockContext)).rejects.toThrow(UnauthorizedException)
await expect(guard.canActivate(mockContext)).rejects.toThrow(
'Email user@example.com is not authorized to access this resource',
)
})
it('should throw UnauthorizedException when user object is missing', async () => {
mockRequest.user = null
await expect(guard.canActivate(mockContext)).rejects.toThrow(UnauthorizedException)
await expect(guard.canActivate(mockContext)).rejects.toThrow('User email not found in token')
})
it('should throw UnauthorizedException when user object is undefined', async () => {
mockRequest.user = undefined
await expect(guard.canActivate(mockContext)).rejects.toThrow(UnauthorizedException)
await expect(guard.canActivate(mockContext)).rejects.toThrow('User email not found in token')
})
it('should throw UnauthorizedException when email is missing from user object', async () => {
mockRequest.user = { id: '123' } // No email
await expect(guard.canActivate(mockContext)).rejects.toThrow(UnauthorizedException)
await expect(guard.canActivate(mockContext)).rejects.toThrow('User email not found in token')
})
it('should throw UnauthorizedException when email is empty string', async () => {
mockRequest.user = { email: '' }
await expect(guard.canActivate(mockContext)).rejects.toThrow(UnauthorizedException)
await expect(guard.canActivate(mockContext)).rejects.toThrow('User email not found in token')
})
})
})