cursor-init/.test-rules.md
expressgy 5b0b37ef78 chore: 项目初始化相关配置与文档归档优化
- Prettier 配置迁移为 .prettierrc.cjs,解决 ESM/CJS 兼容问题
- 优化 package.json,补全元信息、整理依赖、完善 Bun 热更新脚本
- 归档项目初始化 PRD 与任务清单到 tasks/archive,并加日期前缀
- 同步代码风格与格式化配置,提升团队协作一致性

归档文件:tasks/archive/20240610-prd-项目初始化.md, tasks/archive/20240610-tasks-prd-项目初始化.md
2025-06-28 02:03:40 +08:00

100 lines
3.4 KiB
Markdown
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.

# Elysia + Vitest 测试用例编写规范
## 1. 文件结构与命名
- 每个被测模块应有对应的 `xxx.test.ts` 文件,放在同目录或 `tests/` 下。
- 测试文件需有文件头注释,说明作者、日期、描述等。
## 2. 测试用例基本格式
- 使用 `describe` 分组,`it`(或 `test`)描述单个场景。
- 每个 `it` 需有明确的行为描述。
## 3. 参数传递与类型
- 明确传递参数类型,推荐用 TypeBox schema 自动推导类型。
- 测试用例中参数应覆盖正常、异常、边界值。
## 4. 响应结构与 code 校验
- 断言 HTTP 状态码(如 200、400、401
- 断言响应体结构(如 code、message、data类型可用 `as any` 或 schema 类型断言。
## 5. 边界与异常测试
- 必须覆盖参数边界(如最短/最长用户名、最短密码等)。
- 必须覆盖异常分支如缺少参数、token 错误、未授权等)。
## 6. 类型安全
- 推荐用 TypeBox 的 `Static<typeof schema>` 推导类型,或在测试用例中用 `as any` 简化断言。
- 对于复杂响应,可定义类型辅助断言。
## 7. 断言范围
- 断言应覆盖HTTP 状态码、响应 code、message、data 字段、关键数据类型。
- 对于 token、id 等动态值,用 `typeof` 或正则断言。
## 8. 其他建议
-`it.only`/`describe.only` 聚焦调试,提交前移除。
-`console.log` 输出实际响应,便于排查失败。
- 每个接口的正常、异常、边界场景都应有测试覆盖。
## 9. 示例
```typescript
/**
* @file 用户登录接口测试
* @author hotok
* @date 2025-06-28
* @lastEditor hotok
* @lastEditTime 2025-06-28
* @description 覆盖登录接口的正常、异常、边界场景
*/
describe('POST /api/login', () => {
it('应登录成功并返回token', async () => {
const res = await app.fetch(
new Request('http://localhost/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username: 'admin', password: '123456' }),
}),
);
const body = (await res.json()) as any;
expect(res.status).toBe(200);
expect(body.code).toBe(0);
expect(typeof body.data.token).toBe('string');
});
it('用户名过短应返回400', async () => {
const res = await app.fetch(
new Request('http://localhost/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username: 'a', password: '123456' }),
}),
);
const body = (await res.json()) as any;
expect(res.status).toBe(400);
expect(body.code).toBe(400);
expect(body.message).toMatch(/用户名长度/);
});
it('密码错误应返回400', async () => {
const res = await app.fetch(
new Request('http://localhost/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ username: 'admin', password: 'wrong' }),
}),
);
const body = (await res.json()) as any;
expect(res.status).toBe(400);
expect(body.code).toBe(400);
expect(body.message).toBe('用户名或密码错误');
});
});
```