123 lines
4.0 KiB
TypeScript
123 lines
4.0 KiB
TypeScript
|
|
/**
|
|||
|
|
* Password Service Unit Tests
|
|||
|
|
* TDD: Test-Driven Development
|
|||
|
|
*/
|
|||
|
|
|
|||
|
|
import { describe, it, expect } from '@jest/globals';
|
|||
|
|
import { PasswordService } from '../../../src/services/password.service';
|
|||
|
|
|
|||
|
|
describe('PasswordService', () => {
|
|||
|
|
describe('hash', () => {
|
|||
|
|
it('should hash password with bcrypt', async () => {
|
|||
|
|
// @ralph 这个测试是否清晰描述了期望行为?
|
|||
|
|
const plainPassword = 'MySecurePassword123!';
|
|||
|
|
const hash = await PasswordService.hash(plainPassword);
|
|||
|
|
|
|||
|
|
expect(hash).toBeDefined();
|
|||
|
|
expect(hash).not.toBe(plainPassword);
|
|||
|
|
expect(hash.length).toBe(60); // bcrypt hash length
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('should generate different hashes for same password (salt)', async () => {
|
|||
|
|
// @ralph 这是否验证了salt的正确性?
|
|||
|
|
const password = 'test123';
|
|||
|
|
const hash1 = await PasswordService.hash(password);
|
|||
|
|
const hash2 = await PasswordService.hash(password);
|
|||
|
|
|
|||
|
|
expect(hash1).not.toBe(hash2);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('should handle empty string', async () => {
|
|||
|
|
// @ralph 边界条件是否考虑充分?
|
|||
|
|
const hash = await PasswordService.hash('');
|
|||
|
|
expect(hash).toBeDefined();
|
|||
|
|
expect(hash.length).toBe(60);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('should handle special characters', async () => {
|
|||
|
|
// @ralph 特殊字符是否正确处理?
|
|||
|
|
const password = '!@#$%^&*()_+-=[]{}|;:\'",.<>?/~`';
|
|||
|
|
const hash = await PasswordService.hash(password);
|
|||
|
|
expect(hash).toBeDefined();
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('should handle very long passwords', async () => {
|
|||
|
|
// @ralph 是否考虑了长度限制?
|
|||
|
|
const password = 'a'.repeat(1000);
|
|||
|
|
const hash = await PasswordService.hash(password);
|
|||
|
|
expect(hash).toBeDefined();
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
describe('verify', () => {
|
|||
|
|
it('should verify correct password', async () => {
|
|||
|
|
// @ralph 基本功能是否正确?
|
|||
|
|
const password = 'test123';
|
|||
|
|
const hash = await PasswordService.hash(password);
|
|||
|
|
const isValid = await PasswordService.verify(password, hash);
|
|||
|
|
|
|||
|
|
expect(isValid).toBe(true);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('should reject wrong password', async () => {
|
|||
|
|
// @ralph 错误密码是否被正确拒绝?
|
|||
|
|
const hash = await PasswordService.hash('test123');
|
|||
|
|
const isValid = await PasswordService.verify('wrong', hash);
|
|||
|
|
|
|||
|
|
expect(isValid).toBe(false);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('should be case sensitive', async () => {
|
|||
|
|
// @ralph 大小写敏感性是否正确?
|
|||
|
|
const hash = await PasswordService.hash('Password123');
|
|||
|
|
const isValid = await PasswordService.verify('password123', hash);
|
|||
|
|
|
|||
|
|
expect(isValid).toBe(false);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('should reject invalid hash format', async () => {
|
|||
|
|
// @ralph 错误处理是否完善?
|
|||
|
|
await expect(
|
|||
|
|
PasswordService.verify('test', 'invalid-hash')
|
|||
|
|
).rejects.toThrow();
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('should reject empty hash', async () => {
|
|||
|
|
// @ralph 空值处理是否正确?
|
|||
|
|
await expect(
|
|||
|
|
PasswordService.verify('test', '')
|
|||
|
|
).rejects.toThrow();
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('should handle unicode characters', async () => {
|
|||
|
|
// @ralph Unicode是否正确处理?
|
|||
|
|
const password = '密码123🔐';
|
|||
|
|
const hash = await PasswordService.hash(password);
|
|||
|
|
const isValid = await PasswordService.verify(password, hash);
|
|||
|
|
|
|||
|
|
expect(isValid).toBe(true);
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
describe('strength validation', () => {
|
|||
|
|
it('should validate strong password', () => {
|
|||
|
|
// @ralph 强度规则是否合理?
|
|||
|
|
const strong = PasswordService.checkStrength('Str0ng!Pass');
|
|||
|
|
expect(strong.isStrong).toBe(true);
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('should reject weak password (too short)', () => {
|
|||
|
|
// @ralph 弱密码是否被正确识别?
|
|||
|
|
const weak = PasswordService.checkStrength('12345');
|
|||
|
|
expect(weak.isStrong).toBe(false);
|
|||
|
|
expect(weak.reason).toContain('长度');
|
|||
|
|
});
|
|||
|
|
|
|||
|
|
it('should reject weak password (no numbers)', () => {
|
|||
|
|
// @ralph 规则是否全面?
|
|||
|
|
const weak = PasswordService.checkStrength('abcdefgh');
|
|||
|
|
expect(weak.isStrong).toBe(false);
|
|||
|
|
});
|
|||
|
|
});
|
|||
|
|
});
|