# L1 集成测试被全局 ThrottlerGuard 误伤（5 req/30s）

**日期**: 2026-05-15
**模块**: 任何写 L1 集成测试 + 涉及 login / 多 HTTP 调用的新模块
**关键词**: throttler, 401-not-429, beforeEach, login, jest, integration-test

## 现象

跑 ai-usage L1 31 个 case：
- test 1+2 PASS
- test 3+ 全部 FAIL with `401 Unauthorized`

单独跑 test 3 时 PASS。说明是**测试之间的累积效应**而非代码 bug。

POST 创建 token 在 test 1 工作正常，DELETE 在 test 3 报 401（同一 user 同一 JWT，逻辑上不应该）。

## 根因

`backend/src/config/configuration.ts` 全局 `ThrottlerGuard`：

```ts
throttler: {
  ttlMs: process.env.AUTH_THROTTLER_TTL_MS || '30000',
  limit: process.env.AUTH_THROTTLER_LIMIT || '5',  // 5 req / 30s / IP
}
```

注释说"登录限流"，但 `APP_GUARD` 是**全局**的。supertest 所有请求都来自 `127.0.0.1`，IP 维度限流命中。

每个 `beforeEach` 调用 `setupAiUsageTestContext()`：
- 创建 org / users / roles
- **2 次 login**（admin + member）

跑到第 3 个 test 时，30 秒窗口内累计 6+ login → throttler 拦下 → 第 N 次 login 返回 429 →
`loginRes.body.data.accessToken` 是 `undefined` → 后续 `Bearer ${undefined}` → 服务端
看到 `Bearer undefined` 实际是 `Bearer ` 空 token → **401**（不是 429！这就是误导点）。

## 排错关键症状

- "POST 同 token 工作，DELETE 401" — JWT 验证应该是同一逻辑路径，不可能时好时坏
- 单测过 / 套件挂 — 经典 test interference
- 错误码是 401 **不是 429** — 因为 throttler 把 429 还给了 login 调用，但失败的是后续业务接口

## 修法

在 `_helpers.ts` 文件**最顶部**（早于 AppModule import 链解析时机）覆盖 env：

```ts
process.env.AUTH_THROTTLER_LIMIT = process.env.AUTH_THROTTLER_LIMIT || '10000';

import { PrismaClient } from '@prisma/client';
// ... 其他 imports
```

env 在 `ThrottlerModule.forRootAsync` 的 `useFactory: (cfg) => ...` 里读取，而该工厂在
`TestingModule.compile()` 时执行——也就是 `createTestApp()` 内部。只要在 `createTestApp()`
被 await 之前 set process.env 就有效。

**注意**：不要尝试在 `beforeAll` 内 set —— 那时 AppModule 已 imported，ConfigService 已实例化。
要在 file-top-level（早于 import chain 完成解析）。

## 检查清单（写新 L1 时）

- [ ] _helpers.ts 顶部 `process.env.AUTH_THROTTLER_LIMIT = '10000'`
- [ ] beforeEach 含 ≥ 2 个 HTTP 调用时尤其需要
- [ ] L1 失败首条线索是 401 时，**先怀疑 throttler 而非 JWT/权限**

## 复用范围

所有用 `createTestApp` 的 L1 集成测试场景。每加新模块都会再踩一次。
**值得加进 `createTestApp` helper 默认行为**（建议另开 PR：让 helper 自动给测试套件加大
throttler 上限或完全 disable）。
