- 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.
225 lines
7.6 KiB
TypeScript
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);
|
|
});
|
|
});
|
|
});
|