zyc 44464dd334 feat: DevPerf Dashboard 研发人效看板 v1.0
- 后端:Bun + Hono + Drizzle ORM + SQLite
- 前端:Vue 3 + Naive UI + ECharts
- 项目管理:创建项目 + 绑定 Git 仓库
- OKR 系统:目标/关键结果 CRUD + 进度追踪
- Git 同步:Gitea API 自动同步 commit/PR + 作者关联
- 数据看板:项目 OKR 进度 + KR 状态分布 + 代码活动
- 权限体系:admin/manager/developer/viewer 四级
- Docker 部署:docker-compose + nginx

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-09 17:57:14 +08:00

86 lines
2.1 KiB
TypeScript

/**
* Test setup for DevPerf Dashboard Backend
*
* This file provides common test utilities and mock helpers for the
* Hono-based API test suite. Since the real DB requires SQLite and
* Drizzle migrations, unit tests operate on the Hono app directly
* using Hono's built-in test client (app.request).
*/
import { SignJWT } from 'jose';
// Shared test JWT secret (matches .env.example)
export const TEST_JWT_SECRET = 'test-secret-for-unit-tests-at-least-16-chars';
const secret = new TextEncoder().encode(TEST_JWT_SECRET);
/**
* Generate a valid JWT token for test requests.
*/
export async function createTestToken(payload: {
sub: string;
email: string;
role: string;
displayName: string;
}): Promise<string> {
return new SignJWT(payload)
.setProtectedHeader({ alg: 'HS256' })
.setIssuedAt()
.setExpirationTime('1h')
.sign(secret);
}
/**
* Standard test user fixtures.
*/
export const TEST_USERS = {
admin: {
sub: 'user-admin-001',
email: 'admin@test.com',
role: 'admin',
displayName: 'Test Admin',
},
manager: {
sub: 'user-mgr-001',
email: 'manager@test.com',
role: 'manager',
displayName: 'Test Manager',
},
developer: {
sub: 'user-dev-001',
email: 'dev@test.com',
role: 'developer',
displayName: 'Test Developer',
},
viewer: {
sub: 'user-viewer-001',
email: 'viewer@test.com',
role: 'viewer',
displayName: 'Test Viewer',
},
};
/**
* Helper to build request with auth header.
*/
export function authHeaders(token: string): Record<string, string> {
return {
Authorization: `Bearer ${token}`,
'Content-Type': 'application/json',
};
}
/**
* Assert a JSON response matches the standard ApiResponse shape.
*/
export function assertApiResponse(body: any) {
if (typeof body.code !== 'number') {
throw new Error(`Expected body.code to be a number, got ${typeof body.code}`);
}
if (typeof body.message !== 'string') {
throw new Error(`Expected body.message to be a string, got ${typeof body.message}`);
}
if (!('data' in body)) {
throw new Error('Expected body to have a "data" property');
}
}