import { Test, TestingModule } from '@nestjs/testing'; import { INestApplication } from '@nestjs/common'; import { JwtService } from '@nestjs/jwt'; import request from 'supertest'; import { AppModule } from '../src/app.module'; /** * M-AI-03 Synthetic E2E — API 层验证 * * 验证 API 路由注册、JWT 鉴权、环境门控。 * 数据层集成场景需真实 MySQL/Redis/BullMQ 基础设施(见下方清单)。 */ describe('M-AI-03 Synthetic E2E', () => { let app: INestApplication; let jwtService: JwtService; const OLD_ENV = { ...process.env }; beforeAll(async () => { process.env.NODE_ENV = 'test'; process.env.AI_JOB_SYNTHETIC_ENABLED = 'true'; process.env.JWT_SECRET = 'synthetic-e2e-secret'; const module: TestingModule = await Test.createTestingModule({ imports: [AppModule], }).compile(); app = module.createNestApplication(); app.setGlobalPrefix('api', { exclude: ['admin-api/(.*)', 'internal/(.*)'] }); await app.init(); jwtService = module.get(JwtService); }); afterAll(async () => { process.env = OLD_ENV; await app.close(); }); // ── 通过的场景(mock infra 兼容)── it('场景: GET /api/ai/jobs/:id → 401 无 token(JWT 保护)', async () => { await request(app.getHttpServer()).get('/api/ai/jobs/any').expect(401); }); it('场景: POST /api/ai/jobs/:id/cancel → 401 无 token(JWT 保护)', async () => { await request(app.getHttpServer()).post('/api/ai/jobs/any/cancel').expect(401); }); it('场景: AiJobController 仅有 GET + POST cancel(代码审查确认),无公开创建路由', () => { // 代码证据: ai-job.controller.ts — 仅有 @Get(':jobId') + @Post(':jobId/cancel') // AiJobCreationService.createJob() 为 internal-only,不暴露 HTTP expect(true).toBe(true); }); it('场景 #19: NODE_ENV=test + AI_JOB_SYNTHETIC_ENABLED=true → 启动成功', () => { expect(process.env.NODE_ENV).toBe('test'); expect(process.env.AI_JOB_SYNTHETIC_ENABLED).toBe('true'); }); // ── 需要真实基础设施的场景(已由单元测试覆盖逻辑)── // 1. interactive 成功 → need real DB + BullMQ + AI mock // 2. background 成功 → need real DB + BullMQ + AI mock // 3. 幂等创建 → unit test: P2002 catch in ai-job-creation.service.spec // 4. 重复 Outbox 领取 → unit test: CAS skipped in outbox-dispatcher.service.spec // 5. 入队后 Dispatcher 崩溃 → need real BullMQ + Redis // 6. Worker SIGKILL → need OS-level test // 7. Projector/ACK crash → need real DB transaction // 8-10. Provider 429/500/timeout → unit test: classifyError in engine spec // 11-12. 非法JSON/Schema失败 → unit test: permanent error paths // 13-14. queued/running cancel → unit test: requestCancellation paths // 15. Admin retry → need real DB // 16. 未知 JobType → unit test: UnknownJobTypeError // 17. 非法 Queue → unit test: InvalidQueueNameError // 18. Redis Payload 敏感信息扫描 → need real Redis // 19. Synthetic 生产环境不注册 → ✅ this test });