Files
PicAnalysis/backend/tests/unit/services/password.service.test.ts
wjl 1a0ebde95d feat: 初始化 PicAnalysis 项目
完整的前后端图片分析应用,包含:
- 后端:Express + Prisma + SQLite,101个单元测试全部通过
- 前端:React + TypeScript + Vite,47个单元测试,89.73%覆盖率
- E2E测试:Playwright 测试套件
- MCP集成:Playwright MCP配置完成并测试通过

功能模块:
- 用户认证(JWT)
- 文档管理(CRUD)
- 待办管理(三态工作流)
- 图片管理(上传、截图、OCR)

测试覆盖:
- 后端单元测试:101/101 
- 前端单元测试:47/47 
- E2E测试:通过 
- MCP Playwright测试:通过 

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-02-22 20:10:11 +08:00

123 lines
4.0 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* 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);
});
});
});