Adiciona testes para RefreshTokenService e TokenBlacklistService
- Cria testes completos para RefreshTokenService (14 testes) - Cria testes completos para TokenBlacklistService (11 testes) - Remove JSDoc do DebService - Adiciona testes para DebService (6 testes) - Corrige query SQL no DebRepository para usar SQL raw em vez de QueryBuilder - Adiciona documentação de cobertura de testes
This commit is contained in:
@@ -0,0 +1,64 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { RefreshTokenService } from '../refresh-token.service';
|
||||
import { IRedisClient } from '../../../core/configs/cache/IRedisClient';
|
||||
import { RedisClientToken } from '../../../core/configs/cache/redis-client.adapter.provider';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
|
||||
export const createMockRedisClient = () =>
|
||||
({
|
||||
get: jest.fn(),
|
||||
set: jest.fn(),
|
||||
del: jest.fn(),
|
||||
keys: jest.fn(),
|
||||
} as any);
|
||||
|
||||
export const createMockJwtService = () =>
|
||||
({
|
||||
sign: jest.fn(),
|
||||
verify: jest.fn(),
|
||||
decode: jest.fn(),
|
||||
} as any);
|
||||
|
||||
export interface RefreshTokenServiceTestContext {
|
||||
service: RefreshTokenService;
|
||||
mockRedisClient: jest.Mocked<IRedisClient>;
|
||||
mockJwtService: jest.Mocked<JwtService>;
|
||||
}
|
||||
|
||||
export async function createRefreshTokenServiceTestModule(
|
||||
redisClientMethods: Partial<IRedisClient> = {},
|
||||
jwtServiceMethods: Partial<JwtService> = {},
|
||||
): Promise<RefreshTokenServiceTestContext> {
|
||||
const mockRedisClient = {
|
||||
...createMockRedisClient(),
|
||||
...redisClientMethods,
|
||||
} as any;
|
||||
|
||||
const mockJwtService = {
|
||||
...createMockJwtService(),
|
||||
...jwtServiceMethods,
|
||||
} as any;
|
||||
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
RefreshTokenService,
|
||||
{
|
||||
provide: RedisClientToken,
|
||||
useValue: mockRedisClient,
|
||||
},
|
||||
{
|
||||
provide: JwtService,
|
||||
useValue: mockJwtService,
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
const service = module.get<RefreshTokenService>(RefreshTokenService);
|
||||
|
||||
return {
|
||||
service,
|
||||
mockRedisClient,
|
||||
mockJwtService,
|
||||
};
|
||||
}
|
||||
|
||||
392
src/auth/services/__tests__/refresh-token.service.spec.ts
Normal file
392
src/auth/services/__tests__/refresh-token.service.spec.ts
Normal file
@@ -0,0 +1,392 @@
|
||||
import { UnauthorizedException } from '@nestjs/common';
|
||||
import { createRefreshTokenServiceTestModule } from './refresh-token.service.spec.helper';
|
||||
import { RefreshTokenData } from '../refresh-token.service';
|
||||
|
||||
describe('RefreshTokenService', () => {
|
||||
describe('generateRefreshToken', () => {
|
||||
let context: Awaited<
|
||||
ReturnType<typeof createRefreshTokenServiceTestModule>
|
||||
>;
|
||||
|
||||
beforeEach(async () => {
|
||||
context = await createRefreshTokenServiceTestModule();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('deve gerar refresh token com sucesso', async () => {
|
||||
const userId = 123;
|
||||
const sessionId = 'session-123';
|
||||
const mockToken = 'mock.refresh.token';
|
||||
const mockTokenId = 'token-id-123';
|
||||
|
||||
jest.spyOn(require('crypto'), 'randomBytes').mockReturnValue({
|
||||
toString: () => mockTokenId,
|
||||
});
|
||||
|
||||
context.mockJwtService.sign.mockReturnValue(mockToken);
|
||||
context.mockRedisClient.set.mockResolvedValue(undefined);
|
||||
context.mockRedisClient.keys.mockResolvedValue([]);
|
||||
|
||||
const result = await context.service.generateRefreshToken(
|
||||
userId,
|
||||
sessionId,
|
||||
);
|
||||
|
||||
expect(result).toBe(mockToken);
|
||||
expect(context.mockJwtService.sign).toHaveBeenCalledWith(
|
||||
{
|
||||
userId,
|
||||
tokenId: mockTokenId,
|
||||
sessionId,
|
||||
type: 'refresh',
|
||||
},
|
||||
{ expiresIn: '7d' },
|
||||
);
|
||||
expect(context.mockRedisClient.set).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('deve gerar refresh token sem sessionId', async () => {
|
||||
const userId = 123;
|
||||
const mockToken = 'mock.refresh.token';
|
||||
const mockTokenId = 'token-id-123';
|
||||
|
||||
jest.spyOn(require('crypto'), 'randomBytes').mockReturnValue({
|
||||
toString: () => mockTokenId,
|
||||
});
|
||||
|
||||
context.mockJwtService.sign.mockReturnValue(mockToken);
|
||||
context.mockRedisClient.set.mockResolvedValue(undefined);
|
||||
context.mockRedisClient.keys.mockResolvedValue([]);
|
||||
|
||||
const result = await context.service.generateRefreshToken(userId);
|
||||
|
||||
expect(result).toBe(mockToken);
|
||||
expect(context.mockJwtService.sign).toHaveBeenCalledWith(
|
||||
{
|
||||
userId,
|
||||
tokenId: mockTokenId,
|
||||
sessionId: undefined,
|
||||
type: 'refresh',
|
||||
},
|
||||
{ expiresIn: '7d' },
|
||||
);
|
||||
});
|
||||
|
||||
it('deve limitar número de refresh tokens por usuário', async () => {
|
||||
const userId = 123;
|
||||
const mockToken = 'mock.refresh.token';
|
||||
const mockTokenId = 'token-id-123';
|
||||
|
||||
jest.spyOn(require('crypto'), 'randomBytes').mockReturnValue({
|
||||
toString: () => mockTokenId,
|
||||
});
|
||||
|
||||
context.mockJwtService.sign.mockReturnValue(mockToken);
|
||||
context.mockRedisClient.set.mockResolvedValue(undefined);
|
||||
|
||||
const existingTokens: RefreshTokenData[] = Array.from(
|
||||
{ length: 6 },
|
||||
(_, i) => ({
|
||||
userId,
|
||||
tokenId: `token-${i}`,
|
||||
expiresAt: Date.now() + 1000000,
|
||||
createdAt: Date.now(),
|
||||
}),
|
||||
);
|
||||
|
||||
context.mockRedisClient.keys.mockResolvedValue([
|
||||
'auth:refresh_tokens:123:token-0',
|
||||
'auth:refresh_tokens:123:token-1',
|
||||
'auth:refresh_tokens:123:token-2',
|
||||
'auth:refresh_tokens:123:token-3',
|
||||
'auth:refresh_tokens:123:token-4',
|
||||
'auth:refresh_tokens:123:token-5',
|
||||
]);
|
||||
|
||||
context.mockRedisClient.get
|
||||
.mockResolvedValueOnce(existingTokens[0])
|
||||
.mockResolvedValueOnce(existingTokens[1])
|
||||
.mockResolvedValueOnce(existingTokens[2])
|
||||
.mockResolvedValueOnce(existingTokens[3])
|
||||
.mockResolvedValueOnce(existingTokens[4])
|
||||
.mockResolvedValueOnce(existingTokens[5]);
|
||||
|
||||
await context.service.generateRefreshToken(userId);
|
||||
|
||||
expect(context.mockRedisClient.del).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('validateRefreshToken', () => {
|
||||
let context: Awaited<
|
||||
ReturnType<typeof createRefreshTokenServiceTestModule>
|
||||
>;
|
||||
|
||||
beforeEach(async () => {
|
||||
context = await createRefreshTokenServiceTestModule();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('deve validar refresh token com sucesso', async () => {
|
||||
const mockDecoded = {
|
||||
userId: 123,
|
||||
tokenId: 'token-id-123',
|
||||
sessionId: 'session-123',
|
||||
type: 'refresh',
|
||||
};
|
||||
|
||||
const mockTokenData: RefreshTokenData = {
|
||||
userId: 123,
|
||||
tokenId: 'token-id-123',
|
||||
sessionId: 'session-123',
|
||||
expiresAt: Date.now() + 1000000,
|
||||
createdAt: Date.now(),
|
||||
};
|
||||
|
||||
context.mockJwtService.verify.mockReturnValue(mockDecoded);
|
||||
context.mockRedisClient.get.mockResolvedValue(mockTokenData);
|
||||
|
||||
const result = await context.service.validateRefreshToken(
|
||||
'valid.refresh.token',
|
||||
);
|
||||
|
||||
expect(result.id).toBe(123);
|
||||
expect((result as any).tokenId).toBe('token-id-123');
|
||||
expect(result.sessionId).toBe('session-123');
|
||||
});
|
||||
|
||||
it('deve lançar exceção quando token não é do tipo refresh', async () => {
|
||||
const mockDecoded = {
|
||||
userId: 123,
|
||||
tokenId: 'token-id-123',
|
||||
type: 'access',
|
||||
};
|
||||
|
||||
context.mockJwtService.verify.mockReturnValue(mockDecoded);
|
||||
|
||||
await expect(
|
||||
context.service.validateRefreshToken('invalid.token'),
|
||||
).rejects.toThrow(UnauthorizedException);
|
||||
});
|
||||
|
||||
it('deve lançar exceção quando token não existe no Redis', async () => {
|
||||
const mockDecoded = {
|
||||
userId: 123,
|
||||
tokenId: 'token-id-123',
|
||||
sessionId: 'session-123',
|
||||
type: 'refresh',
|
||||
};
|
||||
|
||||
context.mockJwtService.verify.mockReturnValue(mockDecoded);
|
||||
context.mockRedisClient.get.mockResolvedValue(null);
|
||||
|
||||
await expect(
|
||||
context.service.validateRefreshToken('expired.token'),
|
||||
).rejects.toThrow(UnauthorizedException);
|
||||
});
|
||||
|
||||
it('deve lançar exceção quando token está expirado', async () => {
|
||||
const mockDecoded = {
|
||||
userId: 123,
|
||||
tokenId: 'token-id-123',
|
||||
sessionId: 'session-123',
|
||||
type: 'refresh',
|
||||
};
|
||||
|
||||
const mockTokenData: RefreshTokenData = {
|
||||
userId: 123,
|
||||
tokenId: 'token-id-123',
|
||||
sessionId: 'session-123',
|
||||
expiresAt: Date.now() - 1000,
|
||||
createdAt: Date.now() - 1000000,
|
||||
};
|
||||
|
||||
context.mockJwtService.verify.mockReturnValue(mockDecoded);
|
||||
context.mockRedisClient.get.mockResolvedValue(mockTokenData);
|
||||
context.mockRedisClient.del.mockResolvedValue(undefined);
|
||||
|
||||
await expect(
|
||||
context.service.validateRefreshToken('expired.token'),
|
||||
).rejects.toThrow(UnauthorizedException);
|
||||
expect(context.mockRedisClient.del).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('deve lançar exceção quando verificação do JWT falha', async () => {
|
||||
context.mockJwtService.verify.mockImplementation(() => {
|
||||
throw new Error('Token inválido');
|
||||
});
|
||||
|
||||
await expect(
|
||||
context.service.validateRefreshToken('invalid.token'),
|
||||
).rejects.toThrow(UnauthorizedException);
|
||||
});
|
||||
});
|
||||
|
||||
describe('revokeRefreshToken', () => {
|
||||
let context: Awaited<
|
||||
ReturnType<typeof createRefreshTokenServiceTestModule>
|
||||
>;
|
||||
|
||||
beforeEach(async () => {
|
||||
context = await createRefreshTokenServiceTestModule();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('deve revogar refresh token com sucesso', async () => {
|
||||
const userId = 123;
|
||||
const tokenId = 'token-id-123';
|
||||
|
||||
context.mockRedisClient.del.mockResolvedValue(undefined);
|
||||
|
||||
await context.service.revokeRefreshToken(userId, tokenId);
|
||||
|
||||
expect(context.mockRedisClient.del).toHaveBeenCalledWith(
|
||||
`auth:refresh_tokens:${userId}:${tokenId}`,
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe('revokeAllRefreshTokens', () => {
|
||||
let context: Awaited<
|
||||
ReturnType<typeof createRefreshTokenServiceTestModule>
|
||||
>;
|
||||
|
||||
beforeEach(async () => {
|
||||
context = await createRefreshTokenServiceTestModule();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('deve revogar todos os refresh tokens do usuário', async () => {
|
||||
const userId = 123;
|
||||
const mockKeys = [
|
||||
'auth:refresh_tokens:123:token-1',
|
||||
'auth:refresh_tokens:123:token-2',
|
||||
'auth:refresh_tokens:123:token-3',
|
||||
];
|
||||
|
||||
context.mockRedisClient.keys.mockResolvedValue(mockKeys);
|
||||
context.mockRedisClient.del.mockResolvedValue(undefined);
|
||||
|
||||
await context.service.revokeAllRefreshTokens(userId);
|
||||
|
||||
expect(context.mockRedisClient.keys).toHaveBeenCalledWith(
|
||||
`auth:refresh_tokens:${userId}:*`,
|
||||
);
|
||||
expect(context.mockRedisClient.del).toHaveBeenCalledWith(...mockKeys);
|
||||
});
|
||||
|
||||
it('deve retornar sem erro quando não há tokens para revogar', async () => {
|
||||
const userId = 123;
|
||||
|
||||
context.mockRedisClient.keys.mockResolvedValue([]);
|
||||
|
||||
await context.service.revokeAllRefreshTokens(userId);
|
||||
|
||||
expect(context.mockRedisClient.del).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('getActiveRefreshTokens', () => {
|
||||
let context: Awaited<
|
||||
ReturnType<typeof createRefreshTokenServiceTestModule>
|
||||
>;
|
||||
|
||||
beforeEach(async () => {
|
||||
context = await createRefreshTokenServiceTestModule();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('deve retornar tokens ativos ordenados por data de criação', async () => {
|
||||
const userId = 123;
|
||||
const mockKeys = [
|
||||
'auth:refresh_tokens:123:token-1',
|
||||
'auth:refresh_tokens:123:token-2',
|
||||
];
|
||||
|
||||
const now = Date.now();
|
||||
const token1: RefreshTokenData = {
|
||||
userId: 123,
|
||||
tokenId: 'token-1',
|
||||
expiresAt: now + 1000000,
|
||||
createdAt: now - 2000,
|
||||
};
|
||||
|
||||
const token2: RefreshTokenData = {
|
||||
userId: 123,
|
||||
tokenId: 'token-2',
|
||||
expiresAt: now + 1000000,
|
||||
createdAt: now - 1000,
|
||||
};
|
||||
|
||||
context.mockRedisClient.keys.mockResolvedValue(mockKeys);
|
||||
context.mockRedisClient.get
|
||||
.mockResolvedValueOnce(token1)
|
||||
.mockResolvedValueOnce(token2);
|
||||
|
||||
const result = await context.service.getActiveRefreshTokens(userId);
|
||||
|
||||
expect(result).toHaveLength(2);
|
||||
expect(result[0].tokenId).toBe('token-2');
|
||||
expect(result[1].tokenId).toBe('token-1');
|
||||
});
|
||||
|
||||
it('deve filtrar tokens expirados', async () => {
|
||||
const userId = 123;
|
||||
const mockKeys = [
|
||||
'auth:refresh_tokens:123:token-1',
|
||||
'auth:refresh_tokens:123:token-2',
|
||||
];
|
||||
|
||||
const now = Date.now();
|
||||
const token1: RefreshTokenData = {
|
||||
userId: 123,
|
||||
tokenId: 'token-1',
|
||||
expiresAt: now - 1000,
|
||||
createdAt: now - 2000,
|
||||
};
|
||||
|
||||
const token2: RefreshTokenData = {
|
||||
userId: 123,
|
||||
tokenId: 'token-2',
|
||||
expiresAt: now + 1000000,
|
||||
createdAt: now - 1000,
|
||||
};
|
||||
|
||||
context.mockRedisClient.keys.mockResolvedValue(mockKeys);
|
||||
context.mockRedisClient.get
|
||||
.mockResolvedValueOnce(token1)
|
||||
.mockResolvedValueOnce(token2);
|
||||
|
||||
const result = await context.service.getActiveRefreshTokens(userId);
|
||||
|
||||
expect(result).toHaveLength(1);
|
||||
expect(result[0].tokenId).toBe('token-2');
|
||||
});
|
||||
|
||||
it('deve retornar array vazio quando não há tokens', async () => {
|
||||
const userId = 123;
|
||||
|
||||
context.mockRedisClient.keys.mockResolvedValue([]);
|
||||
|
||||
const result = await context.service.getActiveRefreshTokens(userId);
|
||||
|
||||
expect(result).toHaveLength(0);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -0,0 +1,62 @@
|
||||
import { Test, TestingModule } from '@nestjs/testing';
|
||||
import { TokenBlacklistService } from '../token-blacklist.service';
|
||||
import { IRedisClient } from '../../../core/configs/cache/IRedisClient';
|
||||
import { RedisClientToken } from '../../../core/configs/cache/redis-client.adapter.provider';
|
||||
import { JwtService } from '@nestjs/jwt';
|
||||
|
||||
export const createMockRedisClient = () =>
|
||||
({
|
||||
get: jest.fn(),
|
||||
set: jest.fn(),
|
||||
del: jest.fn(),
|
||||
keys: jest.fn(),
|
||||
} as any);
|
||||
|
||||
export const createMockJwtService = () =>
|
||||
({
|
||||
decode: jest.fn(),
|
||||
} as any);
|
||||
|
||||
export interface TokenBlacklistServiceTestContext {
|
||||
service: TokenBlacklistService;
|
||||
mockRedisClient: jest.Mocked<IRedisClient>;
|
||||
mockJwtService: jest.Mocked<JwtService>;
|
||||
}
|
||||
|
||||
export async function createTokenBlacklistServiceTestModule(
|
||||
redisClientMethods: Partial<IRedisClient> = {},
|
||||
jwtServiceMethods: Partial<JwtService> = {},
|
||||
): Promise<TokenBlacklistServiceTestContext> {
|
||||
const mockRedisClient = {
|
||||
...createMockRedisClient(),
|
||||
...redisClientMethods,
|
||||
} as any;
|
||||
|
||||
const mockJwtService = {
|
||||
...createMockJwtService(),
|
||||
...jwtServiceMethods,
|
||||
} as any;
|
||||
|
||||
const module: TestingModule = await Test.createTestingModule({
|
||||
providers: [
|
||||
TokenBlacklistService,
|
||||
{
|
||||
provide: RedisClientToken,
|
||||
useValue: mockRedisClient,
|
||||
},
|
||||
{
|
||||
provide: JwtService,
|
||||
useValue: mockJwtService,
|
||||
},
|
||||
],
|
||||
}).compile();
|
||||
|
||||
const service = module.get<TokenBlacklistService>(TokenBlacklistService);
|
||||
|
||||
return {
|
||||
service,
|
||||
mockRedisClient,
|
||||
mockJwtService,
|
||||
};
|
||||
}
|
||||
|
||||
257
src/auth/services/__tests__/token-blacklist.service.spec.ts
Normal file
257
src/auth/services/__tests__/token-blacklist.service.spec.ts
Normal file
@@ -0,0 +1,257 @@
|
||||
import { createTokenBlacklistServiceTestModule } from './token-blacklist.service.spec.helper';
|
||||
import { JwtPayload } from '../../models/jwt-payload.model';
|
||||
|
||||
describe('TokenBlacklistService', () => {
|
||||
describe('addToBlacklist', () => {
|
||||
let context: Awaited<
|
||||
ReturnType<typeof createTokenBlacklistServiceTestModule>
|
||||
>;
|
||||
|
||||
beforeEach(async () => {
|
||||
context = await createTokenBlacklistServiceTestModule();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('deve adicionar token à blacklist com sucesso', async () => {
|
||||
const mockToken = 'valid.jwt.token';
|
||||
const mockPayload: JwtPayload = {
|
||||
id: 123,
|
||||
sellerId: 1,
|
||||
storeId: '1',
|
||||
username: 'user',
|
||||
email: 'user@example.com',
|
||||
exp: Math.floor(Date.now() / 1000) + 3600,
|
||||
};
|
||||
|
||||
context.mockJwtService.decode.mockReturnValue(mockPayload);
|
||||
context.mockRedisClient.set.mockResolvedValue(undefined);
|
||||
|
||||
await context.service.addToBlacklist(mockToken);
|
||||
|
||||
expect(context.mockJwtService.decode).toHaveBeenCalledWith(mockToken);
|
||||
expect(context.mockRedisClient.set).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('deve adicionar token à blacklist com TTL customizado', async () => {
|
||||
const mockToken = 'valid.jwt.token';
|
||||
const mockPayload: JwtPayload = {
|
||||
id: 123,
|
||||
sellerId: 1,
|
||||
storeId: '1',
|
||||
username: 'user',
|
||||
email: 'user@example.com',
|
||||
exp: Math.floor(Date.now() / 1000) + 3600,
|
||||
};
|
||||
|
||||
const customTTL = 7200;
|
||||
|
||||
context.mockJwtService.decode.mockReturnValue(mockPayload);
|
||||
context.mockRedisClient.set.mockResolvedValue(undefined);
|
||||
|
||||
await context.service.addToBlacklist(mockToken, customTTL);
|
||||
|
||||
expect(context.mockRedisClient.set).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
'blacklisted',
|
||||
customTTL,
|
||||
);
|
||||
});
|
||||
|
||||
it('deve calcular TTL automaticamente quando não informado', async () => {
|
||||
const mockToken = 'valid.jwt.token';
|
||||
const now = Math.floor(Date.now() / 1000);
|
||||
const exp = now + 3600;
|
||||
const mockPayload: JwtPayload = {
|
||||
id: 123,
|
||||
sellerId: 1,
|
||||
storeId: '1',
|
||||
username: 'user',
|
||||
email: 'user@example.com',
|
||||
exp,
|
||||
};
|
||||
|
||||
context.mockJwtService.decode.mockReturnValue(mockPayload);
|
||||
context.mockRedisClient.set.mockResolvedValue(undefined);
|
||||
|
||||
await context.service.addToBlacklist(mockToken);
|
||||
|
||||
expect(context.mockRedisClient.set).toHaveBeenCalledWith(
|
||||
expect.any(String),
|
||||
'blacklisted',
|
||||
expect.any(Number),
|
||||
);
|
||||
});
|
||||
|
||||
it('deve lançar erro quando token é inválido', async () => {
|
||||
const mockToken = 'invalid.token';
|
||||
|
||||
context.mockJwtService.decode.mockReturnValue(null);
|
||||
|
||||
await expect(
|
||||
context.service.addToBlacklist(mockToken),
|
||||
).rejects.toThrow('Token inválido');
|
||||
});
|
||||
|
||||
it('deve lançar erro quando decode falha', async () => {
|
||||
const mockToken = 'invalid.token';
|
||||
|
||||
context.mockJwtService.decode.mockImplementation(() => {
|
||||
throw new Error('Token malformado');
|
||||
});
|
||||
|
||||
await expect(
|
||||
context.service.addToBlacklist(mockToken),
|
||||
).rejects.toThrow('Erro ao adicionar token à blacklist');
|
||||
});
|
||||
});
|
||||
|
||||
describe('isBlacklisted', () => {
|
||||
let context: Awaited<
|
||||
ReturnType<typeof createTokenBlacklistServiceTestModule>
|
||||
>;
|
||||
|
||||
beforeEach(async () => {
|
||||
context = await createTokenBlacklistServiceTestModule();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('deve retornar true quando token está na blacklist', async () => {
|
||||
const mockToken = 'blacklisted.token';
|
||||
const mockPayload: JwtPayload = {
|
||||
id: 123,
|
||||
sellerId: 1,
|
||||
storeId: '1',
|
||||
username: 'user',
|
||||
email: 'user@example.com',
|
||||
};
|
||||
|
||||
context.mockJwtService.decode.mockReturnValue(mockPayload);
|
||||
context.mockRedisClient.get.mockResolvedValue('blacklisted');
|
||||
|
||||
const result = await context.service.isBlacklisted(mockToken);
|
||||
|
||||
expect(result).toBe(true);
|
||||
expect(context.mockRedisClient.get).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('deve retornar false quando token não está na blacklist', async () => {
|
||||
const mockToken = 'valid.token';
|
||||
const mockPayload: JwtPayload = {
|
||||
id: 123,
|
||||
sellerId: 1,
|
||||
storeId: '1',
|
||||
username: 'user',
|
||||
email: 'user@example.com',
|
||||
};
|
||||
|
||||
context.mockJwtService.decode.mockReturnValue(mockPayload);
|
||||
context.mockRedisClient.get.mockResolvedValue(null);
|
||||
|
||||
const result = await context.service.isBlacklisted(mockToken);
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
|
||||
it('deve retornar false quando ocorre erro', async () => {
|
||||
const mockToken = 'error.token';
|
||||
const mockPayload: JwtPayload = {
|
||||
id: 123,
|
||||
sellerId: 1,
|
||||
storeId: '1',
|
||||
username: 'user',
|
||||
email: 'user@example.com',
|
||||
};
|
||||
|
||||
context.mockJwtService.decode.mockReturnValue(mockPayload);
|
||||
context.mockRedisClient.get.mockRejectedValue(
|
||||
new Error('Redis error'),
|
||||
);
|
||||
|
||||
const result = await context.service.isBlacklisted(mockToken);
|
||||
|
||||
expect(result).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('removeFromBlacklist', () => {
|
||||
let context: Awaited<
|
||||
ReturnType<typeof createTokenBlacklistServiceTestModule>
|
||||
>;
|
||||
|
||||
beforeEach(async () => {
|
||||
context = await createTokenBlacklistServiceTestModule();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('deve remover token da blacklist com sucesso', async () => {
|
||||
const mockToken = 'token.to.remove';
|
||||
const mockPayload: JwtPayload = {
|
||||
id: 123,
|
||||
sellerId: 1,
|
||||
storeId: '1',
|
||||
username: 'user',
|
||||
email: 'user@example.com',
|
||||
};
|
||||
|
||||
context.mockJwtService.decode.mockReturnValue(mockPayload);
|
||||
context.mockRedisClient.del.mockResolvedValue(undefined);
|
||||
|
||||
await context.service.removeFromBlacklist(mockToken);
|
||||
|
||||
expect(context.mockRedisClient.del).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('clearUserBlacklist', () => {
|
||||
let context: Awaited<
|
||||
ReturnType<typeof createTokenBlacklistServiceTestModule>
|
||||
>;
|
||||
|
||||
beforeEach(async () => {
|
||||
context = await createTokenBlacklistServiceTestModule();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
jest.clearAllMocks();
|
||||
});
|
||||
|
||||
it('deve limpar todos os tokens do usuário da blacklist', async () => {
|
||||
const userId = 123;
|
||||
const mockKeys = [
|
||||
'auth:blacklist:123:hash1',
|
||||
'auth:blacklist:123:hash2',
|
||||
'auth:blacklist:123:hash3',
|
||||
];
|
||||
|
||||
context.mockRedisClient.keys.mockResolvedValue(mockKeys);
|
||||
context.mockRedisClient.del.mockResolvedValue(undefined);
|
||||
|
||||
await context.service.clearUserBlacklist(userId);
|
||||
|
||||
expect(context.mockRedisClient.keys).toHaveBeenCalledWith(
|
||||
`auth:blacklist:${userId}:*`,
|
||||
);
|
||||
expect(context.mockRedisClient.del).toHaveBeenCalledWith(...mockKeys);
|
||||
});
|
||||
|
||||
it('deve retornar sem erro quando não há tokens para limpar', async () => {
|
||||
const userId = 123;
|
||||
|
||||
context.mockRedisClient.keys.mockResolvedValue([]);
|
||||
|
||||
await context.service.clearUserBlacklist(userId);
|
||||
|
||||
expect(context.mockRedisClient.del).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user