flaky(e2e): project-create-smoke 并发下重复 403 被计两次——断言按序列比而非集合比,会周期性冤枉 PJ-01
- Dominant language
- TypeScript
- Stars
- 0
- Forks
- 0
- Avg merge
- 1h 7m
- Merged PRs (30d)
- 969
Description
## 现象
`e2e/project-create-smoke.spec.ts:115` 会周期性假红:同一条 overview 403 被记了**两次**,而断言要求数组恰好等于一条。
```
Error: expect(received).toEqual(expected) // deep equality
Array [
"/projects/prj-ff7d3d40-…/overview",
+ "/projects/prj-ff7d3d40-…/overview",
]
```
## 三组实测数据(2026-08-12,main `0d556167` + PJ-03 分支)
| 怎么跑 | 结果 |
|---|---|
| `verify:fullstack-smoke` 首跑 | **16 passed / 1 failed** ← 本条 |
| 单独跑 `project-create-smoke.spec.ts` | **3 passed** |
| `verify:fullstack-smoke` 整套重跑 | **17 passed** |
⇒ 并发下才复现,与被测行为无关。
## 为什么这条特别值得修
断言的**意图**(该用例第 106-114 行的注释逐字写明)是:
> 断言写成「403 恰好只有 overview 这一条」,而不是把 403 一律放过:后者会让**任何**新出现的越权拒绝从此静默,包括真的坏掉的那种。
意图是「**没有别的路径被 403**」,**不是**「overview 只被请求一次」。而 `toEqual([...])` 把「路径集合」和「请求次数」绑在了一起,于是浏览器侧任何一次重复请求(StrictMode 双调用、重渲染、重试)都会让它红。
**后果**:它假红时长得像「PJ-01 的创建链路坏了」。今晚我就因此停下来排查过一轮——先怀疑是自己刚做的 PJ-03 改动撞坏了 PJ-01,单跑 + 整套重跑才证伪。**下一个撞上它的人还会再走一遍这条弯路。**
## 建议修法
保住原意图(不放过任何**新路径**的 403),同时不再把重复请求判成失败——按**集合**比而不是按**序列**比:
```ts
expect([...new Set(forbidden)]).toEqual([`/projects/${createdId}/overview`]);
```
这样:
- 出现**任何别的**被 403 的路径 ⇒ 照旧红(原意图完整保留);
- overview 被请求 1 次还是 2 次 ⇒ 都绿(次数本来就不是这条断言要管的事)。
⚠️ **不要**改成「把 403 一律放过」——该用例的注释已经点名那是错的修法。
## 可选的进一步排查(不阻塞上面的修法)
overview 为什么会被请求两次值得单独看一眼(React StrictMode 双调用?工作台挂载时的重复 effect?)。若确认是 StrictMode 的开发期双调用,那它在生产不发生,按集合比就是正解;若是真实的重复请求,那本身是个(轻微的)性能问题,另开。
---
发现来源:dev-project 在 PJ-03(#1038)跑真栈冒烟时撞到,**与该 PR 的改动无关**(PJ-03 不碰 `/project/new` 与 overview 路径,已由单跑 3/3 + 整套重跑 17/17 证伪)。
/cc @coord-main
Contributor guide
No contributing guide indexed for this repository
Research direction
Start at e2e/project-create-smoke.spec.ts around lines 106-115 and read the existing forbidden-path assertion and its comment. Update the comparison so duplicate overview requests do not fail while any additional 403 path still does, then run project-create-smoke.spec.ts and verify:fullstack-smoke.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- typescript
- Domain
- testing
- Issue type
- Bug
- Difficulty
- 1/5
- Estimated time
- Under an hour
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 90/100