From 368672f001bb88f7fb2f012604986d7f8ce2820a Mon Sep 17 00:00:00 2001 From: Citrons <909229731@qq.com> Date: Mon, 24 Aug 2026 17:53:09 +0800 Subject: [PATCH] =?UTF-8?q?fix(FEAT-QA-001):=20=E9=9A=94=E7=A6=BB=E5=B8=82?= =?UTF-8?q?=E5=9C=BA=E6=A6=82=E8=A7=88=20E2E=20=E6=B5=8B=E8=AF=95=E6=97=B6?= =?UTF-8?q?=E9=92=9F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../FEAT-QA-001-e2e-clock-isolation/design.md | 25 ++++++ .../development-summary.md | 35 ++++++++ .../gitnexus/after.md | 13 +++ .../gitnexus/before.md | 34 ++++++++ .../gitnexus/comparison.md | 13 +++ .../gitnexus/detected-changes.md | 5 ++ .../gitnexus/impact-plan.md | 27 ++++++ .../implementation-plan.md | 9 ++ .../manifest.yaml | 12 +++ .../FEAT-QA-001-e2e-clock-isolation/prd.md | 84 +++++++++++++++++++ .../qa/test-results.md | 14 ++++ .../qa/visual-qa.md | 3 + .../release-notes.md | 3 + .../requirements.md | 8 ++ .../review/code-review.md | 50 +++++++++++ .../review/standards-review.md | 33 ++++++++ .../rollback.md | 3 + .../test-plan.md | 24 ++++++ .../apps/api/test/market-overview.e2e-spec.ts | 16 +++- 19 files changed, 408 insertions(+), 3 deletions(-) create mode 100644 docs/features/FEAT-QA-001-e2e-clock-isolation/design.md create mode 100644 docs/features/FEAT-QA-001-e2e-clock-isolation/development-summary.md create mode 100644 docs/features/FEAT-QA-001-e2e-clock-isolation/gitnexus/after.md create mode 100644 docs/features/FEAT-QA-001-e2e-clock-isolation/gitnexus/before.md create mode 100644 docs/features/FEAT-QA-001-e2e-clock-isolation/gitnexus/comparison.md create mode 100644 docs/features/FEAT-QA-001-e2e-clock-isolation/gitnexus/detected-changes.md create mode 100644 docs/features/FEAT-QA-001-e2e-clock-isolation/gitnexus/impact-plan.md create mode 100644 docs/features/FEAT-QA-001-e2e-clock-isolation/implementation-plan.md create mode 100644 docs/features/FEAT-QA-001-e2e-clock-isolation/manifest.yaml create mode 100644 docs/features/FEAT-QA-001-e2e-clock-isolation/prd.md create mode 100644 docs/features/FEAT-QA-001-e2e-clock-isolation/qa/test-results.md create mode 100644 docs/features/FEAT-QA-001-e2e-clock-isolation/qa/visual-qa.md create mode 100644 docs/features/FEAT-QA-001-e2e-clock-isolation/release-notes.md create mode 100644 docs/features/FEAT-QA-001-e2e-clock-isolation/requirements.md create mode 100644 docs/features/FEAT-QA-001-e2e-clock-isolation/review/code-review.md create mode 100644 docs/features/FEAT-QA-001-e2e-clock-isolation/review/standards-review.md create mode 100644 docs/features/FEAT-QA-001-e2e-clock-isolation/rollback.md create mode 100644 docs/features/FEAT-QA-001-e2e-clock-isolation/test-plan.md diff --git a/docs/features/FEAT-QA-001-e2e-clock-isolation/design.md b/docs/features/FEAT-QA-001-e2e-clock-isolation/design.md new file mode 100644 index 0000000..396da25 --- /dev/null +++ b/docs/features/FEAT-QA-001-e2e-clock-isolation/design.md @@ -0,0 +1,25 @@ +# 市场概览 E2E 测试时钟隔离设计 + +## 根因与方案 + +`MarketOverviewService` 使用 `new Date()` 生成 `asOf`,再按上海日期判断行情是否延迟。服务单测已经在 suite 级固定时钟,HTTP E2E 没有采用同一模式。设计在 E2E 的 `beforeEach/afterEach` 建立请求级测试时钟边界,不向生产服务注入测试专用接口。 + +## 数据流 + +固定系统时间 → 启动 Nest 测试应用 → Controller 调用真实 Service → Service 将固定夹具识别为当日行情 → HTTP 断言 → 关闭应用 → 恢复系统时间。 + +## 错误与恢复 + +应用引用保持可选,`afterEach` 无论断言是否成功都关闭应用并恢复真实时钟。不得吞掉 HTTP 或关闭错误。 + +## 安全策略与评估 + +测试客户端完全使用内存 mock,不连接 TDX;生产时间和数据状态逻辑保持原样。功能档案只记录相对路径和脱敏统计,无凭据、本机用户目录、网络身份或 PID。 + +## 性能目标与评估 + +fake timers 是进程内操作,不增加 I/O、网络或依赖。定向测试应保持 2 秒内完成,完整门禁不增加外部负载。 + +## 架构与同步边界 + +变更限定在 `server/apps/api/test/market-overview.e2e-spec.ts`。HTTP/OpenAPI、Web、消息契约、MySQL、Redis、Scheduler、Worker 和部署均无需同步;功能档案和 Review 证据同步更新。 diff --git a/docs/features/FEAT-QA-001-e2e-clock-isolation/development-summary.md b/docs/features/FEAT-QA-001-e2e-clock-isolation/development-summary.md new file mode 100644 index 0000000..b8dc023 --- /dev/null +++ b/docs/features/FEAT-QA-001-e2e-clock-isolation/development-summary.md @@ -0,0 +1,35 @@ +# 市场概览 E2E 测试时钟隔离开发总结 + +- 功能编号:FEAT-QA-001 +- 总结版本:0.1 +- 日期:2026-08-24 + +## 原始开发需求 + +在 FEAT-MO-002/003 收尾的完整门禁中,修复市场概览 HTTP E2E 随自然日期变化而失败的问题,并保持生产行情逻辑不变。 + +## 需求与范围变化 + +最初只计划收尾端口和 README;完整门禁暴露测试夹具时钟缺陷后,经用户确认新增独立 `FEAT-QA-001`,避免把缺陷混入端口提交。 + +## 实际完成需求 + +- E2E suite 固定到夹具交易日,并在每个用例后恢复真实时钟。 +- 生产 Service、Controller、DTO、TDX 和 OpenAPI 未修改。 +- 根因、影响、安全、性能与回退边界建立独立档案。 + +## 修复缺陷 + +修复固定交易日夹具依赖真实系统日期导致 `fresh` 断言跨日变为 `delayed` 的非确定性缺陷。RED 为 Server 65/67、2 个状态断言失败;GREEN 为定向 E2E 2/2 通过。 + +## 未完成与延期项 + +权威交易日历仍不在本功能范围;本功能只保证测试确定性,不改变休市日保守标记 `delayed` 的既有生产策略。 + +## 关键提交 + +等待独立 Review、中文提交和远程 SHA 核对后补充。 + +## 验证证据 + +定向 E2E 2/2 和完整 `pnpm verify` 已通过:Web 21/21、Server 67/67、启动器 2/2、Playwright 4/4。GitNexus 刷新为 3,122 nodes、4,343 edges、85 flows;detect changes 为 LOW、0 受影响执行流。独立 Review 和推送结果等待收尾。 diff --git a/docs/features/FEAT-QA-001-e2e-clock-isolation/gitnexus/after.md b/docs/features/FEAT-QA-001-e2e-clock-isolation/gitnexus/after.md new file mode 100644 index 0000000..88403fe --- /dev/null +++ b/docs/features/FEAT-QA-001-e2e-clock-isolation/gitnexus/after.md @@ -0,0 +1,13 @@ +# GitNexus 开发后基线 + +## GitNexus 状态 + +索引已刷新为 3,122 nodes、4,343 edges、68 clusters、85 flows;当前提交索引状态 `up-to-date`。 + +## Git 已跟踪变更摘要 + +本功能只修改市场概览 HTTP E2E 的时钟生命周期并新增功能档案;生产 Service、Controller、DTO、TDX 和 OpenAPI 无变化。 + +## Git 工作区摘要 + +工作区还包含已批准收尾的 FEAT-MO-002/003;无关未跟踪文件明确排除。最终提交使用逐路径 staging,不使用 `git add -A`。 diff --git a/docs/features/FEAT-QA-001-e2e-clock-isolation/gitnexus/before.md b/docs/features/FEAT-QA-001-e2e-clock-isolation/gitnexus/before.md new file mode 100644 index 0000000..004c7f9 --- /dev/null +++ b/docs/features/FEAT-QA-001-e2e-clock-isolation/gitnexus/before.md @@ -0,0 +1,34 @@ +# GitNexus 开发前基线 + +- 功能编号:FEAT-QA-001 +- 记录时间:2026年8月24日 GMT+8 17:26:04 +- 分支:main +- 基线提交:1f6ed00e6fbb + +## 工作区 + +```text +M AGENTS.md + M README.md + M docs/deployment/local-development.md + M web/playwright.config.ts + M web/src/vite-config.test.ts + M web/vite.config.ts +?? <计划外未跟踪文件,明确排除且未读取> +?? docs/features/FEAT-MO-002-web-port-8888/ +?? docs/features/FEAT-MO-003-readme-refresh/ +``` + +## GitNexus 状态 + +```text +Repository: +Indexed: 8/24/2026, 5:26:03 PM +Indexed commit: 1f6ed00 +Current commit: 1f6ed00 +Status: ✅ up-to-date +``` + +## 后续人工分析 + +在修改代码前,将 GitNexus query、context、impact 的结论写入 `gitnexus/impact-plan.md`。高风险结果必须先获得用户确认。 diff --git a/docs/features/FEAT-QA-001-e2e-clock-isolation/gitnexus/comparison.md b/docs/features/FEAT-QA-001-e2e-clock-isolation/gitnexus/comparison.md new file mode 100644 index 0000000..c6b0874 --- /dev/null +++ b/docs/features/FEAT-QA-001-e2e-clock-isolation/gitnexus/comparison.md @@ -0,0 +1,13 @@ +# GitNexus 前后对比 + +## 开发前 + +生产时钟函数 upstream 风险 CRITICAL,影响五个市场概览接口;E2E 文件 upstream 风险 LOW、0 执行流。自然日期下完整门禁出现 2 个状态断言失败。 + +## 开发后 + +生产调用图和业务执行流不变;E2E suite 在夹具日期下运行并恢复真实时钟。开发后 detect changes 为 LOW、0 受影响执行流,完整门禁通过。 + +## 差异处置 + +没有修改 CRITICAL 生产符号,也没有同步 HTTP/OpenAPI、Web API、消息、数据库、Redis、Scheduler、Worker 或部署。 diff --git a/docs/features/FEAT-QA-001-e2e-clock-isolation/gitnexus/detected-changes.md b/docs/features/FEAT-QA-001-e2e-clock-isolation/gitnexus/detected-changes.md new file mode 100644 index 0000000..3835122 --- /dev/null +++ b/docs/features/FEAT-QA-001-e2e-clock-isolation/gitnexus/detected-changes.md @@ -0,0 +1,5 @@ +# GitNexus 变更检测 + +执行 `gitnexus_detect_changes({scope: "all", repo: "a-share-analysis"})`:changed_count=10、changed_files=7、affected_count=0、risk_level=low、受影响执行流 0。 + +当前工作区同时包含已批准收尾的 FEAT-MO-002/003。GitNexus 识别到 README、本地开发文档和 AGENTS 索引统计;测试生命周期变化没有映射为生产执行流。实际提交将显式列出路径并排除计划外未跟踪文件。 diff --git a/docs/features/FEAT-QA-001-e2e-clock-isolation/gitnexus/impact-plan.md b/docs/features/FEAT-QA-001-e2e-clock-isolation/gitnexus/impact-plan.md new file mode 100644 index 0000000..03cb7dd --- /dev/null +++ b/docs/features/FEAT-QA-001-e2e-clock-isolation/gitnexus/impact-plan.md @@ -0,0 +1,27 @@ +# GitNexus 开发前影响计划 + +- 功能编号:FEAT-QA-001 +- 总体风险:LOW(实际修改范围);生产关联符号若修改为 CRITICAL,因此明确排除 + +## 直接与间接影响 + +- `gitnexus_query` 定位到市场概览 Service、TDX 日期映射和 HTTP E2E。 +- `gitnexus_context(getShanghaiCalendarDate)` 确认生产函数由 `createTradeDateWarning` 调用。 +- `gitnexus_impact(getShanghaiCalendarDate, upstream, includeTests=true)` 返回 CRITICAL:直接消费者 1、影响五个市场概览接口和 5 条流程。该结果用于约束本次不修改生产函数。 +- `gitnexus_impact(market-overview.e2e-spec.ts, upstream, includeTests=true)` 返回 LOW:上游 0、执行流 0。 +- 根因由 2026-08-24 完整门禁稳定复现:夹具日期为 `20260818`,真实系统日期导致生产服务正确返回 `delayed`,E2E 错误断言 `fresh`。 + +## 跨模块同步修改 + +| 维度 | 判断 | 同步修改 | +|---|---|---| +| HTTP/OpenAPI | 响应和契约不变 | 无 | +| Web API | 不涉及 | 无 | +| 消息契约 | 不涉及 RocketMQ | 无 | +| 数据库 | 不涉及 MySQL 或 Schema | 无 | +| Redis | 不涉及 | 无 | +| API | 生产模块不变,仅 HTTP E2E 生命周期 | 修改测试 | +| Scheduler/Worker | 不涉及 | 无 | +| 配置部署 | 不涉及 | 无 | +| 测试 | 固定夹具时钟并恢复真实时钟 | 修改 E2E | +| 文档 | 建立缺陷追溯和验证证据 | 新增功能档案 | diff --git a/docs/features/FEAT-QA-001-e2e-clock-isolation/implementation-plan.md b/docs/features/FEAT-QA-001-e2e-clock-isolation/implementation-plan.md new file mode 100644 index 0000000..6ca4b65 --- /dev/null +++ b/docs/features/FEAT-QA-001-e2e-clock-isolation/implementation-plan.md @@ -0,0 +1,9 @@ +# 市场概览 E2E 测试时钟隔离实施计划 + +1. 运行完整门禁复现自然日期下 2 个 `fresh`/`delayed` 失败。 +2. 使用 GitNexus 查询时钟判断链路,并对生产时钟函数和测试文件执行 upstream impact。 +3. 在 E2E suite 的 `beforeEach` 固定到 `2026-08-18T03:00:00.000Z`。 +4. 在 `afterEach` 关闭应用后恢复 real timers。 +5. 运行定向测试确认 2/2 通过,再执行完整 `pnpm verify`。 +6. 更新 GitNexus 前后对比、安全、性能、Review、发布和回退证据。 +7. 使用中文 Conventional Commit 提交并立即推送当前分支。 diff --git a/docs/features/FEAT-QA-001-e2e-clock-isolation/manifest.yaml b/docs/features/FEAT-QA-001-e2e-clock-isolation/manifest.yaml new file mode 100644 index 0000000..36e973d --- /dev/null +++ b/docs/features/FEAT-QA-001-e2e-clock-isolation/manifest.yaml @@ -0,0 +1,12 @@ +id: FEAT-QA-001 +name: 市场概览 E2E 测试时钟隔离 +slug: e2e-clock-isolation +status: ready_for_release +owner: project +created_at: 2026-08-24 +requirements: requirements.md +prd: prd.md +design: design.md +implementation_plan: implementation-plan.md +traceability_note: 修复固定交易日夹具依赖真实系统日期导致的跨日失败,不修改生产行情和新鲜度逻辑 +release: unreleased diff --git a/docs/features/FEAT-QA-001-e2e-clock-isolation/prd.md b/docs/features/FEAT-QA-001-e2e-clock-isolation/prd.md new file mode 100644 index 0000000..c820f6e --- /dev/null +++ b/docs/features/FEAT-QA-001-e2e-clock-isolation/prd.md @@ -0,0 +1,84 @@ +# 市场概览 E2E 测试时钟隔离 PRD + +- 功能编号:FEAT-QA-001 +- PRD 版本:0.1 +- 状态:in_review +- 日期:2026-08-24 + +## 背景与问题 + +市场概览 HTTP E2E 使用 `20260818` 固定行情夹具,却读取真实系统日期判断 `fresh/delayed`。日期跨过 2026-08-18 后,生产代码正确返回 `delayed`,测试仍固定要求 `fresh`,导致完整门禁出现 2 个稳定失败。 + +## 目标用户与使用场景 + +开发者在任意自然日期执行完整验证,都应得到与固定夹具语义一致、可重复的测试结果。 + +## 产品目标 + +隔离 E2E 测试时钟,使测试日期与夹具交易日一致,并在用例结束后恢复真实时钟。 + +## 非目标 + +不修改生产新鲜度规则、不引入交易日历、不改变 HTTP/OpenAPI、不修改 TDX 数据映射。 + +## 用户流程 + +开发者执行 Server 测试,E2E 在隔离时钟下启动 Nest 应用、验证响应,随后关闭应用并恢复真实时钟。 + +## 功能需求 + +| 编号 | 优先级 | 需求 | 可观察结果 | +|---|---|---|---| +| QA-001 | P0 | 每个市场概览 HTTP E2E 用例固定到夹具交易日 | `fresh` 断言不随自然日期漂移 | +| QA-002 | P0 | 每个用例后关闭应用并恢复真实时钟 | 不污染同进程其他测试 | +| QA-003 | P1 | 记录根因、影响和完整回归证据 | 功能档案可追溯 | + +## 数据与口径 + +测试系统时间固定为 `2026-08-18T03:00:00.000Z`,对应上海日期 `20260818`;夹具数据及生产新鲜度口径不变。 + +## 状态与异常 + +若用例中断,`afterEach` 仍负责关闭 Nest 应用并调用 `vi.useRealTimers()`;测试失败必须保留真实断言差异。 + +## 权限、合规与安全 + +测试不访问真实 TDX、数据库或公网服务,不读取 `.env.local`,不输出凭据、本机绝对路径或临时进程标识。 + +## 安全需求与信任边界 + +只修改测试运行时;禁止通过修改生产时间判断或把 `delayed` 强行改成 `fresh` 来通过测试。 + +## 性能目标与容量假设 + +不增加外部请求;定向 E2E 保持秒级完成,完整门禁耗时不应产生可感知增长。 + +## 关联模块与同步修改 + +只同步 Server E2E 测试和功能档案;HTTP/OpenAPI、Web API、消息、数据库、Redis、API 生产代码、Scheduler、Worker 和部署均不修改。 + +## 新增依赖评估 + +不新增依赖,使用现有 Vitest fake timers。 + +## 成功指标 + +定向 E2E 2/2 通过;完整 `pnpm verify` 通过;测试结束后无 fake timer 泄漏。 + +## 验收标准 + +- 当前自然日期下可复现的 2 个失败消失。 +- 生产文件没有差异。 +- GitNexus 仅识别预期测试和文档变化。 + +## 风险与依赖 + +残余风险是未来修改固定行情日期时必须同步测试时钟;代码注释明确该关联。 + +## 发布范围与回退触发条件 + +仅测试和文档。若测试时钟污染其他套件或隐藏真实延迟语义,回退本功能提交。 + +## 变更记录 + +- 0.1:建立跨日 E2E 时钟隔离需求。 diff --git a/docs/features/FEAT-QA-001-e2e-clock-isolation/qa/test-results.md b/docs/features/FEAT-QA-001-e2e-clock-isolation/qa/test-results.md new file mode 100644 index 0000000..b652136 --- /dev/null +++ b/docs/features/FEAT-QA-001-e2e-clock-isolation/qa/test-results.md @@ -0,0 +1,14 @@ +# 测试结果 + +- RED:`pnpm verify` 的 Server 测试为 65/67,通过值实际为 `delayed`,2 个 E2E 固定要求 `fresh` 而失败。 +- GREEN:`pnpm --filter @a-share-analysis/server exec vitest run apps/api/test/market-overview.e2e-spec.ts` 为 2/2 通过。 +- 完整门禁:`pnpm verify` 通过;Web 21/21、Server 67/67、启动器 2/2、Playwright 4/4,契约、边界、Schema、类型检查和前后端构建均通过。 +- Lint:0 error;35 条市场概览组件既有格式 warning 未因本功能增加。 + +## 安全验证 + +生产市场概览代码没有变化;测试使用内存 mock,未访问真实行情、数据库、Redis 或 RocketMQ;无关 CSV 明确排除。 + +## 性能验证 + +定向 E2E 在 1 秒内完成;完整门禁成功结束,fake timers 不增加网络或持久化负载。 diff --git a/docs/features/FEAT-QA-001-e2e-clock-isolation/qa/visual-qa.md b/docs/features/FEAT-QA-001-e2e-clock-isolation/qa/visual-qa.md new file mode 100644 index 0000000..550049c --- /dev/null +++ b/docs/features/FEAT-QA-001-e2e-clock-isolation/qa/visual-qa.md @@ -0,0 +1,3 @@ +# 视觉 QA + +本功能不改变 DOM、CSS、组件或浏览器交互,视觉变化不适用。完整 Playwright 桌面/移动端 4/4 通过,确认测试基础设施调整没有影响现有页面。 diff --git a/docs/features/FEAT-QA-001-e2e-clock-isolation/release-notes.md b/docs/features/FEAT-QA-001-e2e-clock-isolation/release-notes.md new file mode 100644 index 0000000..17ff2a1 --- /dev/null +++ b/docs/features/FEAT-QA-001-e2e-clock-isolation/release-notes.md @@ -0,0 +1,3 @@ +# 发布说明 + +修复市场概览 HTTP E2E 随自然日期变化出现 `fresh/delayed` 误失败的问题。仅影响测试确定性,不改变用户界面、HTTP 契约、TDX 数据或生产新鲜度判断。 diff --git a/docs/features/FEAT-QA-001-e2e-clock-isolation/requirements.md b/docs/features/FEAT-QA-001-e2e-clock-isolation/requirements.md new file mode 100644 index 0000000..da9ca8e --- /dev/null +++ b/docs/features/FEAT-QA-001-e2e-clock-isolation/requirements.md @@ -0,0 +1,8 @@ +# 市场概览 E2E 测试时钟隔离需求 + +- `beforeEach` 必须启用 fake timers,并固定到夹具交易日对应的上海日期。 +- `afterEach` 必须在关闭 Nest 应用后恢复 real timers。 +- 必须先保存自然日期下 2 个 `fresh`/`delayed` 失败作为 RED 证据,再验证修复后的 GREEN。 +- 不得修改 `MarketOverviewService`、Controller、DTO、TDX Client/Mapper 或 OpenAPI。 +- 不得读取真实外部服务或把无关 CSV 纳入任何提交。 +- 必须完成安全、性能、完整测试、构建、GitNexus 和独立 Review。 diff --git a/docs/features/FEAT-QA-001-e2e-clock-isolation/review/code-review.md b/docs/features/FEAT-QA-001-e2e-clock-isolation/review/code-review.md new file mode 100644 index 0000000..dff36ec --- /dev/null +++ b/docs/features/FEAT-QA-001-e2e-clock-isolation/review/code-review.md @@ -0,0 +1,50 @@ +# 代码 Review + +- 功能编号:FEAT-QA-001 +- reviewer_type:independent +- reviewer:Codex 独立审查代理 +- 基线提交:1f6ed00 +- 审查提交:working-tree +- 日期:2026-08-24 + +## 审查范围 + +市场概览 HTTP E2E 的测试时钟生命周期和对应功能档案。 + +## PRD 与设计符合性 + +实现符合 PRD:测试时钟固定到夹具交易日,生产行情和新鲜度逻辑不变;完整门禁已通过,等待关闭本轮独立 Review 发现项。 + +## 发现 + +| 严重程度 | 位置 | 问题 | 影响 | 处理 | +|---|---|---|---|---| +| Important | E2E cleanup | `app.close()` 抛错可能跳过时钟恢复 | 污染同进程后续测试 | 使用 `try/finally` 保证恢复 real timers,定向与完整门禁通过 | +| Important | README | 将尚不存在的强势个股入口描述为已预留 | 项目状态说明失真 | 明确标记强势个股模块尚未开发 | +| Minor | Review 文档 | 部分证据仍写成等待执行 | 治理记录与实际状态矛盾 | 同步完整门禁和 GitNexus 实际结果 | + +## 测试缺口 + +完整 `pnpm verify` 已通过;Lint 为 0 error,35 条既有格式 warning 未增加。 + +## 安全与残余风险 + +生产逻辑保持不变;`finally` 保证测试结束后恢复 real timers。安全扫描未发现环境信息,无关 CSV 保持未跟踪并由逐路径 staging 排除。 + +## 性能与资源影响 + +仅进程内 fake timers,无运行时资源影响;定向 E2E 在 1 秒内完成,完整门禁通过且未增加外部调用。 + +## GitNexus 与同步修改 + +生产时钟函数 upstream 风险 CRITICAL、关联五个接口,因此明确不修改;测试文件 upstream 风险 LOW、0 执行流。开发后 detect changes 为 LOW、0 受影响执行流。 + +## 修复与复审 + +定向 GREEN 和完整门禁已完成。独立 Review 发现 `app.close()` 抛错时可能跳过时钟恢复,已将 `vi.useRealTimers()` 移入 `finally`;README 的强势个股入口夸大属于 FEAT-MO-003 范围,已同步纠正。复审未发现新的代码阻断项,最后一轮仅要求同步上述证据文字。 + +## 最终结论 + +最终复审确认 `try/finally` 清理、README 纠偏和证据同步均已关闭;无 Critical、Important 或 Minor 问题,`Ready to commit: Yes`。 + +最终结论:passed diff --git a/docs/features/FEAT-QA-001-e2e-clock-isolation/review/standards-review.md b/docs/features/FEAT-QA-001-e2e-clock-isolation/review/standards-review.md new file mode 100644 index 0000000..03ca822 --- /dev/null +++ b/docs/features/FEAT-QA-001-e2e-clock-isolation/review/standards-review.md @@ -0,0 +1,33 @@ +# 开发规范符合性 Review + +- 功能编号:FEAT-QA-001 +- reviewer_type:independent +- reviewer:Codex 独立审查代理 +- 审查提交:working-tree +- 日期:2026-08-24 + +## 检查结果 + +- [x] 缺陷有稳定复现和 RED/GREEN 证据。 +- [x] 生产逻辑没有为测试让步。 +- [x] GitNexus 已执行 query、context 和 upstream impact。 +- [x] 完整测试、构建、E2E 和开发后分析已完成。 +- [x] 独立 Review 最终无 Critical、Important 或 Minor 问题。 + +## 不符合项与处置 + +完整门禁、开发后 GitNexus 和独立 Review 均已完成;`finally` 清理和文档纠偏通过复审。 + +## 安全、性能与架构检查 + +测试时钟限定在 suite 生命周期,不进入生产依赖注入或外部系统;无新增依赖和 I/O。 + +## GitNexus 与开发总结检查 + +功能档案已记录根因、生产符号 CRITICAL 风险和测试文件 LOW 风险;开发后变更检测为 LOW、0 执行流,提交与远程证据将在复审后补充。 + +## 最终结论 + +最终独立复审结论为 `Ready to commit: Yes`,无未关闭问题。 + +最终结论:passed diff --git a/docs/features/FEAT-QA-001-e2e-clock-isolation/rollback.md b/docs/features/FEAT-QA-001-e2e-clock-isolation/rollback.md new file mode 100644 index 0000000..284e71b --- /dev/null +++ b/docs/features/FEAT-QA-001-e2e-clock-isolation/rollback.md @@ -0,0 +1,3 @@ +# 回退说明 + +若 fake timers 污染同进程其他测试或掩盖真实状态缺陷,回退本功能提交即可。回退只移除 E2E suite 的 `beforeEach` 时钟固定和 `afterEach` 时钟恢复;不需要数据库、缓存、消息、配置或生产服务回滚。 diff --git a/docs/features/FEAT-QA-001-e2e-clock-isolation/test-plan.md b/docs/features/FEAT-QA-001-e2e-clock-isolation/test-plan.md new file mode 100644 index 0000000..0d6aeb6 --- /dev/null +++ b/docs/features/FEAT-QA-001-e2e-clock-isolation/test-plan.md @@ -0,0 +1,24 @@ +# 市场概览 E2E 测试时钟隔离测试计划 + +## RED/GREEN + +- RED:在 2026-08-24 运行完整门禁,固定 `20260818` 夹具被生产逻辑标记为 `delayed`,2 个 E2E 断言失败。 +- GREEN:加入 suite 级时钟隔离后,定向 E2E 2/2 通过。 + +## 回归范围 + +- Server 全部 Vitest 和启动器测试。 +- Web 测试、类型、构建和 Playwright E2E。 +- 契约、边界、治理、Schema 和源码部署门禁。 + +## 安全验证 + +确认测试不访问真实 TDX、数据库或公网;`git diff` 不含凭据、本机绝对路径、PID 或无关 CSV;生产市场概览文件无变化。 + +## 性能验证 + +记录定向测试和完整门禁耗时;确认无新增网络、数据库或消息调用。 + +## 残余风险 + +未来夹具交易日变化但固定时钟未同步会重新出现语义不一致,应由明确注释和失败断言暴露。 diff --git a/server/apps/api/test/market-overview.e2e-spec.ts b/server/apps/api/test/market-overview.e2e-spec.ts index c98d0ed..452189b 100644 --- a/server/apps/api/test/market-overview.e2e-spec.ts +++ b/server/apps/api/test/market-overview.e2e-spec.ts @@ -1,7 +1,7 @@ import type { INestApplication } from '@nestjs/common'; import { Test } from '@nestjs/testing'; import request from 'supertest'; -import { afterEach, describe, expect, it, vi } from 'vitest'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; import { MarketOverviewController } from '../src/market-overview/market-overview.controller'; import { @@ -12,9 +12,19 @@ import { describe('市场概览 HTTP API', () => { let app: INestApplication | undefined; + beforeEach(() => { + // 固定到夹具交易日,避免测试随自然日期变化把正确的 delayed 响应误判为失败。 + vi.useFakeTimers(); + vi.setSystemTime(new Date('2026-08-18T03:00:00.000Z')); + }); + afterEach(async () => { - await app?.close(); - app = undefined; + try { + await app?.close(); + } finally { + app = undefined; + vi.useRealTimers(); + } }); it('按模块返回指数和 TDX 来源元数据', async () => {