test: 修复 e2e + 补单元测试

- e2e 改为登录链路(成功返回 token / 密码错误 401)
- 补 maskSensitive、resolveDataScope 单测

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
liuyun 2026-10-11 17:01:30 +08:00
parent ebc0797424
commit 6937f9ece0
3 changed files with 65 additions and 9 deletions

View File

@ -0,0 +1,16 @@
import { describe, expect, it } from 'vitest';
import { resolveDataScope } from './data-scope.js';
import type { DataScope } from './enums.js';
describe('resolveDataScope', () => {
it('空角色默认 self(仅本人)', () => {
expect(resolveDataScope([])).toBe('self');
});
it('多角色取最高数据权限档', () => {
expect(resolveDataScope(['self', 'all'] as DataScope[])).toBe('all');
expect(resolveDataScope(['self', 'dept'] as DataScope[])).toBe('dept');
expect(resolveDataScope(['dept', 'dept_and_child'] as DataScope[])).toBe('dept_and_child');
expect(resolveDataScope(['custom', 'dept'] as DataScope[])).toBe('dept');
});
});

24
src/common/mask.spec.ts Normal file
View File

@ -0,0 +1,24 @@
import { describe, expect, it } from 'vitest';
import { maskSensitive } from './mask.js';
describe('maskSensitive', () => {
it('脱敏密码/令牌类字段', () => {
expect(maskSensitive({ password: 'secret', token: 'abc' })).toEqual({ password: '***', token: '***' });
});
it('脱敏手机号与邮箱', () => {
expect(maskSensitive({ phone: '13800138000', email: 'a@b.com' })).toEqual({ phone: '***', email: '***' });
});
it('递归脱敏嵌套对象与数组', () => {
expect(maskSensitive({ user: { password: 'x' }, list: [{ phone: '1' }] })).toEqual({
user: { password: '***' },
list: [{ phone: '***' }],
});
});
it('原样返回基本类型', () => {
expect(maskSensitive('hello')).toBe('hello');
expect(maskSensitive(null)).toBeNull();
});
});

View File

@ -1,29 +1,45 @@
import { Test, TestingModule } from '@nestjs/testing'; import { Test, TestingModule } from '@nestjs/testing';
import { INestApplication } from '@nestjs/common'; import { INestApplication, ValidationPipe } from '@nestjs/common';
import request from 'supertest'; import request from 'supertest';
import { App } from 'supertest/types.js'; import { App } from 'supertest/types.js';
import { AppModule } from './../src/app.module.js'; import { AppModule } from './../src/app.module.js';
describe('AppController (e2e)', () => { /**
* 登录链路 e2e:需要已启动的 MySQL/Redis 且已执行 pnpm seed(默认账号 touyun / Touyun@123)。
*/
describe('Auth (e2e)', () => {
let app: INestApplication<App>; let app: INestApplication<App>;
beforeEach(async () => { beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({ const moduleFixture: TestingModule = await Test.createTestingModule({
imports: [AppModule], imports: [AppModule],
}).compile(); }).compile();
app = moduleFixture.createNestApplication(); app = moduleFixture.createNestApplication();
app.setGlobalPrefix('api/v1');
app.useGlobalPipes(new ValidationPipe({ whitelist: true, transform: true }));
await app.init(); await app.init();
}); });
it('/ (GET)', () => { it('登录成功返回 token(按用户名自动探测租户)', async () => {
return request(app.getHttpServer()) const res = await request(app.getHttpServer())
.get('/') .post('/api/v1/auth/login')
.expect(200) .send({ username: 'touyun', password: 'Touyun@123' })
.expect('Hello World!'); .expect(201);
expect(res.body.code).toBe(0);
expect(res.body.data.accessToken).toBeDefined();
expect(res.body.data.refreshToken).toBeDefined();
}); });
afterEach(async () => { it('密码错误返回 401', async () => {
const res = await request(app.getHttpServer())
.post('/api/v1/auth/login')
.send({ username: 'touyun', password: 'wrong-password' })
.expect(401);
expect(res.body.code).toBe(40100);
});
afterAll(async () => {
await app.close(); await app.close();
}); });
}); });