Files
registry/test/unit/services/auth.service.test.ts
Juergen Kunz 44e92d48f2 Add unit tests for models and services
- Implemented unit tests for the Package model, covering methods such as generateId, findById, findByName, and version management.
- Created unit tests for the Repository model, including repository creation, name validation, and retrieval methods.
- Added tests for the Session model, focusing on session creation, validation, and invalidation.
- Developed unit tests for the User model, ensuring user creation, password hashing, and retrieval methods function correctly.
- Implemented AuthService tests, validating login, token refresh, and session management.
- Added TokenService tests, covering token creation, validation, and revocation processes.
2025-11-28 15:27:04 +00:00

225 lines
7.6 KiB
TypeScript

/**
* AuthService unit tests
*/
import { assertEquals, assertExists } from 'jsr:@std/assert';
import { describe, it, beforeAll, afterAll, beforeEach } from 'jsr:@std/testing/bdd';
import { setupTestDb, teardownTestDb, cleanupTestDb, createTestUser } from '../../helpers/index.ts';
import { AuthService } from '../../../ts/services/auth.service.ts';
import { Session } from '../../../ts/models/session.ts';
import { testConfig } from '../../test.config.ts';
describe('AuthService', () => {
let authService: AuthService;
beforeAll(async () => {
await setupTestDb();
authService = new AuthService({
jwtSecret: testConfig.jwt.secret,
accessTokenExpiresIn: 60, // 1 minute for tests
refreshTokenExpiresIn: 300, // 5 minutes for tests
});
});
afterAll(async () => {
await teardownTestDb();
});
beforeEach(async () => {
await cleanupTestDb();
});
describe('login', () => {
it('should successfully login with valid credentials', async () => {
const { user, password } = await createTestUser({
email: 'login@example.com',
status: 'active',
});
const result = await authService.login(user.email, password, {
userAgent: 'TestAgent/1.0',
ipAddress: '127.0.0.1',
});
assertEquals(result.success, true);
assertExists(result.user);
assertEquals(result.user.id, user.id);
assertExists(result.accessToken);
assertExists(result.refreshToken);
assertExists(result.sessionId);
});
it('should fail with invalid email', async () => {
const result = await authService.login('nonexistent@example.com', 'password');
assertEquals(result.success, false);
assertEquals(result.errorCode, 'INVALID_CREDENTIALS');
});
it('should fail with invalid password', async () => {
const { user } = await createTestUser({ email: 'wrongpass@example.com' });
const result = await authService.login(user.email, 'wrongpassword');
assertEquals(result.success, false);
assertEquals(result.errorCode, 'INVALID_CREDENTIALS');
});
it('should fail for inactive user', async () => {
const { user, password } = await createTestUser({
email: 'inactive@example.com',
status: 'suspended',
});
const result = await authService.login(user.email, password);
assertEquals(result.success, false);
assertEquals(result.errorCode, 'ACCOUNT_INACTIVE');
});
it('should create a session on successful login', async () => {
const { user, password } = await createTestUser({ email: 'session@example.com' });
const result = await authService.login(user.email, password);
assertEquals(result.success, true);
assertExists(result.sessionId);
const session = await Session.findValidSession(result.sessionId!);
assertExists(session);
assertEquals(session.userId, user.id);
});
});
describe('refresh', () => {
it('should refresh access token with valid refresh token', async () => {
const { user, password } = await createTestUser({ email: 'refresh@example.com' });
const loginResult = await authService.login(user.email, password);
assertEquals(loginResult.success, true);
const refreshResult = await authService.refresh(loginResult.refreshToken!);
assertEquals(refreshResult.success, true);
assertExists(refreshResult.accessToken);
assertEquals(refreshResult.sessionId, loginResult.sessionId);
});
it('should fail with invalid refresh token', async () => {
const result = await authService.refresh('invalid-token');
assertEquals(result.success, false);
assertEquals(result.errorCode, 'INVALID_TOKEN');
});
it('should fail when session is invalidated', async () => {
const { user, password } = await createTestUser({ email: 'invalidsession@example.com' });
const loginResult = await authService.login(user.email, password);
// Invalidate session
const session = await Session.findValidSession(loginResult.sessionId!);
await session!.invalidate('test');
const refreshResult = await authService.refresh(loginResult.refreshToken!);
assertEquals(refreshResult.success, false);
assertEquals(refreshResult.errorCode, 'SESSION_INVALID');
});
});
describe('validateAccessToken', () => {
it('should validate valid access token', async () => {
const { user, password } = await createTestUser({ email: 'validate@example.com' });
const loginResult = await authService.login(user.email, password);
const validation = await authService.validateAccessToken(loginResult.accessToken!);
assertExists(validation);
assertEquals(validation.user.id, user.id);
assertEquals(validation.sessionId, loginResult.sessionId);
});
it('should reject invalid access token', async () => {
const validation = await authService.validateAccessToken('invalid-token');
assertEquals(validation, null);
});
it('should reject when session is invalidated', async () => {
const { user, password } = await createTestUser({ email: 'invalidated@example.com' });
const loginResult = await authService.login(user.email, password);
// Invalidate session
const session = await Session.findValidSession(loginResult.sessionId!);
await session!.invalidate('test');
const validation = await authService.validateAccessToken(loginResult.accessToken!);
assertEquals(validation, null);
});
});
describe('logout', () => {
it('should invalidate session', async () => {
const { user, password } = await createTestUser({ email: 'logout@example.com' });
const loginResult = await authService.login(user.email, password);
const success = await authService.logout(loginResult.sessionId!);
assertEquals(success, true);
const session = await Session.findValidSession(loginResult.sessionId!);
assertEquals(session, null);
});
it('should return false for non-existent session', async () => {
const success = await authService.logout('non-existent-session-id');
assertEquals(success, false);
});
});
describe('logoutAll', () => {
it('should invalidate all user sessions', async () => {
const { user, password } = await createTestUser({ email: 'logoutall@example.com' });
// Create multiple sessions
await authService.login(user.email, password);
await authService.login(user.email, password);
await authService.login(user.email, password);
const count = await authService.logoutAll(user.id);
assertEquals(count, 3);
const sessions = await Session.getUserSessions(user.id);
assertEquals(sessions.length, 0);
});
});
describe('static password methods', () => {
it('should hash and verify password', async () => {
const password = 'MySecurePassword123!';
const hash = await AuthService.hashPassword(password);
const isValid = await AuthService.verifyPassword(password, hash);
assertEquals(isValid, true);
const isInvalid = await AuthService.verifyPassword('WrongPassword', hash);
assertEquals(isInvalid, false);
});
it('should generate different hashes for same password', async () => {
const password = 'SamePassword';
const hash1 = await AuthService.hashPassword(password);
const hash2 = await AuthService.hashPassword(password);
assertEquals(hash1 !== hash2, true);
// But both should verify
assertEquals(await AuthService.verifyPassword(password, hash1), true);
assertEquals(await AuthService.verifyPassword(password, hash2), true);
});
});
});