tyt-api-nest/test/e2e/specs/auth.e2e-spec.ts
EL 6ec8891be5 修复 E2E 准备脚本:
package.json
test:e2e:prepare 现在是 migrate reset --force && prisma generate && seed
为 seed 运行时补充 JS Prisma client 生成器:
schema.prisma
修复 seed 在 ESM/CJS 下的 Prisma 导入兼容:
seed.mjs
修复 Jest 环境未加载 .env 导致连到 127.0.0.1 的问题:
e2e-app.helper.ts
修复夹具依赖“名称”导致被组织测试改名后失效的问题(改为按 seed openId 反查):
e2e-fixtures.helper.ts
修复组织测试的状态污染与清理逻辑,并收敛 afterAll 资源释放:
organization.e2e-spec.ts
e2e-context.helper.ts
2026-03-13 03:29:16 +08:00

130 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.

import request from 'supertest';
import { Role } from '../../../src/generated/prisma/enums.js';
import {
closeE2EContext,
createE2EContext,
type E2EContext,
} from '../helpers/e2e-context.helper.js';
import { assertRoleMatrix } from '../helpers/e2e-matrix.helper.js';
import {
expectErrorEnvelope,
expectSuccessEnvelope,
uniquePhone,
uniqueSeedValue,
} from '../helpers/e2e-http.helper.js';
describe('AuthController (e2e)', () => {
let ctx: E2EContext;
beforeAll(async () => {
ctx = await createE2EContext();
});
afterAll(async () => {
await closeE2EContext(ctx);
});
describe('POST /auth/register', () => {
it('成功:注册医生账号', async () => {
const response = await request(ctx.app.getHttpServer())
.post('/auth/register')
.send({
name: uniqueSeedValue('Auth 注册医生'),
phone: uniquePhone(),
password: 'Seed@1234',
role: Role.DOCTOR,
hospitalId: ctx.fixtures.hospitalAId,
departmentId: ctx.fixtures.departmentA1Id,
groupId: ctx.fixtures.groupA1Id,
openId: uniqueSeedValue('auth-register-openid'),
});
expectSuccessEnvelope(response, 201);
expect(response.body.data.role).toBe(Role.DOCTOR);
});
it('失败:参数不合法返回 400', async () => {
const response = await request(ctx.app.getHttpServer())
.post('/auth/register')
.send({
name: 'bad-register',
phone: '13800009999',
password: '123',
role: Role.DOCTOR,
hospitalId: ctx.fixtures.hospitalAId,
departmentId: ctx.fixtures.departmentA1Id,
groupId: ctx.fixtures.groupA1Id,
});
expectErrorEnvelope(response, 400, 'password 长度至少 8 位');
});
});
describe('POST /auth/login', () => {
it('成功seed 账号登录并拿到 token', async () => {
const response = await request(ctx.app.getHttpServer())
.post('/auth/login')
.send({
phone: '13800001004',
password: 'Seed@1234',
role: Role.DOCTOR,
hospitalId: ctx.fixtures.hospitalAId,
});
expectSuccessEnvelope(response, 201);
expect(response.body.data.accessToken).toEqual(expect.any(String));
expect(response.body.data.actor.role).toBe(Role.DOCTOR);
});
it('失败:密码错误返回 401', async () => {
const response = await request(ctx.app.getHttpServer())
.post('/auth/login')
.send({
phone: '13800001004',
password: 'Seed@12345',
role: Role.DOCTOR,
hospitalId: ctx.fixtures.hospitalAId,
});
expectErrorEnvelope(response, 401, '手机号、角色或密码错误');
});
});
describe('GET /auth/me', () => {
it('成功:已登录用户可读取当前信息', async () => {
const response = await request(ctx.app.getHttpServer())
.get('/auth/me')
.set('Authorization', `Bearer ${ctx.tokens[Role.DOCTOR]}`);
expectSuccessEnvelope(response, 200);
expect(response.body.data.role).toBe(Role.DOCTOR);
});
it('失败:未登录返回 401', async () => {
const response = await request(ctx.app.getHttpServer()).get('/auth/me');
expectErrorEnvelope(response, 401, '缺少 Bearer Token');
});
it('角色矩阵6 角色都可访问,未登录 401', async () => {
await assertRoleMatrix({
name: 'GET /auth/me role matrix',
tokens: ctx.tokens,
expectedStatusByRole: {
[Role.SYSTEM_ADMIN]: 200,
[Role.HOSPITAL_ADMIN]: 200,
[Role.DIRECTOR]: 200,
[Role.LEADER]: 200,
[Role.DOCTOR]: 200,
[Role.ENGINEER]: 200,
},
sendAsRole: async (_role, token) =>
request(ctx.app.getHttpServer())
.get('/auth/me')
.set('Authorization', `Bearer ${token}`),
sendWithoutToken: async () =>
request(ctx.app.getHttpServer()).get('/auth/me'),
});
});
});
});