补齐企微历史验收模拟接口隔离(09-06-release-gate-integrity / 09-17-company-loan-principal-repayment)
N3 第三轮候选 98bab397:浏览器 371 通过、1 失败;报销付款与 PWA 升级通过。 桌面企微历史测试整页导航后等待标题超时,快照退回登录页。 确认默认桌面 context 漏掉已有的 Service Worker 隔离;原运行没有请求来源证据,历史唯一根因未证实。 补文件级隔离,验证原导航实际获得该 fixture 的 refresh/profile 响应:200、非 Worker、requestId 对应。 原三项用例、登录/会话、桌面只读、手机布局及截图保持。受管定向 3 项通过,无失败/跳过/重试,环境和清理通过。 应用、资金规则、迁移、门禁范围、预算和全局并发未改。前三轮失败回执保留。 第四轮完整候选结果以新回执为准;独立代码复核及真实还款待验。 仅本地提交,不推送、不部署,不访问生产或真实 OCR。
这个提交包含在:
@@ -265,6 +265,7 @@ and verification contracts. Do not copy broad aesthetic guidance from
|
|||||||
- A spec that depends on Playwright route mocks must block Service Workers when
|
- A spec that depends on Playwright route mocks must block Service Workers when
|
||||||
it can run a PWA build. Do not rely on Service Worker installation or takeover
|
it can run a PWA build. Do not rely on Service Worker installation or takeover
|
||||||
timing to keep requests visible to `page.route`.
|
timing to keep requests visible to `page.route`.
|
||||||
|
- Cover both default `{ page }` fixtures and manually created contexts. A mobile `browser.newContext({ serviceWorkers: "block" })` does not protect the default desktop fixture; register full-navigation refresh/profile response witnesses before navigating and verify their synthetic source when diagnosing session loss.
|
||||||
- Vite dev success is not equivalent evidence: the generated PWA worker is a
|
- Vite dev success is not equivalent evidence: the generated PWA worker is a
|
||||||
production-build behavior and may be absent in dev.
|
production-build behavior and may be absent in dev.
|
||||||
- Blocking the worker is a fixture boundary, not an authentication bypass. The
|
- Blocking the worker is a fixture boundary, not an authentication bypass. The
|
||||||
|
|||||||
@@ -1,3 +1,14 @@
|
|||||||
|
## 2026-10-09 桌面模拟接口隔离补齐(N3 第三轮后)
|
||||||
|
|
||||||
|
原回执 `artifacts/release-gate/loan-receipt-n3-20261009-r3/`:候选 `98bab397`,82 迁移、服务端 4558 通过/1 项既有可选跳过,浏览器 371 通过/1 失败。PWA 升级和报销付款主链路通过;唯一失败位于桌面企微历史标题等待,失败快照为登录页。环境、源码一致性及自有资源清理通过。
|
||||||
|
|
||||||
|
- [x] 读取最终错误栈和快照,确认 `page.route` 文件缺默认 context 的 Worker 隔离;手机 helper 已有 `serviceWorkers: block`,不代表默认桌面 fixture 也生效。原请求来源未采集,历史唯一成因仍未证实。
|
||||||
|
- [x] 文件级补既有隔离设置;在桌面原导航前同时等待 refresh 与 `/api/me`,断言 200、非 Worker、匹配该 fixture 的 requestId。保持原登录、三项用例、页面/只读/布局断言、截图和预算。
|
||||||
|
- [x] 受管 `retained-local` 全文件三项通过、零失败/跳过/重试,浏览器用例总耗时 9.1 秒;生产构建、两种 context 的全导航及桌面响应来源检查通过,环境、源码一致性及清理通过。原第三轮 `login-portal-ux` 16 项及 R101 3 项按未变输入保留,不计入此次三项结果;不据单次通过追认历史唯一根因或真实银行/生产验收。
|
||||||
|
- [ ] 主会话检查和任务/治理通过后形成新的本地提交;N3 对干净新候选执行原完整门禁。此次是已有模拟隔离合同补漏,不修改产品认证或 PWA,也不提高预算/重试到绿。
|
||||||
|
|
||||||
|
准备目录中的 `internal-readiness-focused/`、`internal-readiness-focused.log` 记录定向结果,下一轮完整回执为 `artifacts/release-gate/loan-receipt-n3-20261009-r4/`。测试时冻结受测输入,结果写 ignored 回执。独立代码复核待完成;未推送、部署、查询生产或使用真实材料。
|
||||||
|
|
||||||
## 2026-10-09 PWA 跨导航版本等待修正(N3 候选验证接续)
|
## 2026-10-09 PWA 跨导航版本等待修正(N3 候选验证接续)
|
||||||
|
|
||||||
来源为借款任务 N3 的 `18315d11` 完整回执:服务端 4558 通过/1 项既有可选跳过,浏览器 371 通过/1 失败、零跳过/重试。栈明确位于 `expect.poll` 回调中的 `documentBuildSha`:页面自动更新销毁旧执行环境后,直接 `page.evaluate` 抛错,未等完原定 45 秒。冻结诊断已观察到文档 B、B 控制器摘要匹配、旧资源缓存归零、B 资源加载、会话保留及零静态 404;这些事后观察不改写原失败。
|
来源为借款任务 N3 的 `18315d11` 完整回执:服务端 4558 通过/1 项既有可选跳过,浏览器 371 通过/1 失败、零跳过/重试。栈明确位于 `expect.poll` 回调中的 `documentBuildSha`:页面自动更新销毁旧执行环境后,直接 `page.evaluate` 抛错,未等完原定 45 秒。冻结诊断已观察到文档 B、B 控制器摘要匹配、旧资源缓存归零、B 资源加载、会话保留及零静态 404;这些事后观察不改写原失败。
|
||||||
|
|||||||
@@ -1,3 +1,11 @@
|
|||||||
|
## 2026-10-09 桌面模拟接口隔离补齐(N3 第三轮接续)
|
||||||
|
|
||||||
|
候选 `98bab397` 第三轮完整门禁为 FAIL:浏览器 371 通过/1 失败、零跳过/重试;报销付款与 PWA 升级已通过。唯一失败是 `internal-readiness-ui.spec.ts` 的桌面企微历史页在整页导航后未出现标题,失败快照为登录页。该文件的手机手动 context 已屏蔽 Service Worker,使用 `page.route` 的桌面默认 context 却遗漏了既有隔离合同。原运行没有请求来源证据,不能宣称历史唯一根因已证明。
|
||||||
|
|
||||||
|
本次只补测试边界:默认 context 在首次导航前屏蔽 Service Worker;桌面整页导航必须观察到 refresh 与 `/api/me` 的 200 响应、来自预设模拟接口而非 Worker。保留真实页面登录操作、会话提示、全部三项用例、桌面只读和手机空态/详情/布局断言及截图,不改产品认证、PWA、权限、资金、预算或全局并发。先受管定向全文件,再固定本地候选并由 N3 完整复验;保留第三轮 FAIL,不用定向结果拼接资格。
|
||||||
|
|
||||||
|
修正后受管定向 3 项通过、无失败/跳过/重试,原页面断言、截图及新增响应来源检查通过,环境/源码一致性/自有资源清理通过。新候选完整门禁仍待第四轮回执;独立代码复核未完成。
|
||||||
|
|
||||||
## 2026-10-09 借款候选验证中的 PWA 导航观测修正
|
## 2026-10-09 借款候选验证中的 PWA 导航观测修正
|
||||||
|
|
||||||
`09-17-company-loan-principal-repayment` 的 N3 接续已获本地提交、验证及必要测试修正授权。其候选 `18315d11` 第二轮完整门禁为 FAIL:浏览器 371 通过/1 失败、零跳过/重试;唯一失败为 PWA 跨版本测试的版本读取在应用自动导航时抛出 `Execution context was destroyed`。报销付款主链路已通过,受管环境、源码一致性及清理通过。原回执保留在 `artifacts/release-gate/loan-receipt-n3-20261009-r2/`。
|
`09-17-company-loan-principal-repayment` 的 N3 接续已获本地提交、验证及必要测试修正授权。其候选 `18315d11` 第二轮完整门禁为 FAIL:浏览器 371 通过/1 失败、零跳过/重试;唯一失败为 PWA 跨版本测试的版本读取在应用自动导航时抛出 `Execution context was destroyed`。报销付款主链路已通过,受管环境、源码一致性及清理通过。原回执保留在 `artifacts/release-gate/loan-receipt-n3-20261009-r2/`。
|
||||||
|
|||||||
@@ -1,3 +1,15 @@
|
|||||||
|
## 2026-10-09 N3 第三轮结果及第四轮候选验证
|
||||||
|
|
||||||
|
第三轮候选 `98bab397` 的完整门禁为 **FAIL**:82 个迁移、服务端 4558 通过/1 项既有可选跳过、静态/构建及业务回归通过;浏览器 371 通过/1 失败、零跳过/重试。报销付款主链路和 PWA 跨版本升级通过。原回执及准确失败边界见 `artifacts/release-gate/loan-receipt-n3-20261009-r3/`;环境、源码一致性及自有资源清理通过。
|
||||||
|
|
||||||
|
- 唯一失败是 `internal-readiness-ui.spec.ts` 桌面企微历史页整页导航后等待标题超时,截图为登录页。确认该文件的模拟接口只在手机手动 context 屏蔽 Worker,默认桌面 fixture 遗漏既有合同;原运行没有请求来源证据,历史唯一成因仍未证实。
|
||||||
|
- 已由 `09-06-release-gate-integrity` 补文件级 Worker 隔离,并在原桌面导航中验证 refresh 与 `/api/me` 的 200、非 Worker 和预设 requestId。保留全部原三项用例、登录/会话、桌面只读、手机布局和截图,不改认证/PWA/借款资金代码、迁移、预算或全局并发。
|
||||||
|
- 修正后的完整文件受管定向 3 项通过、无失败/跳过/重试;新增响应来源检查、生产构建、环境/源码一致性/清理通过。证据为准备目录的 `internal-readiness-focused/`、`internal-readiness-focused.log`、`internal-focused-process.json`。原第三轮登录体验 16 项和 R101 3 项按未变输入保留,不累加成此次定向总数。
|
||||||
|
- 经主会话差异及任务/治理检查后按 N3 既有授权本地提交,再对干净新候选执行原 `bash scripts/qa/run-release-gate.sh verify-candidate`。第四轮回执为 `artifacts/release-gate/loan-receipt-n3-20261009-r4/`;前三轮失败不覆盖、不与定向拼接,不预填 PASS。
|
||||||
|
- 验证期间冻结源码、测试和任务文档,实际提交、完整结果、复核交接及专用浏览器清理写入 ignored 回执。独立代码复核、真实还款及公网仍待;未推送、部署、查询生产或调用真实 OCR。
|
||||||
|
|
||||||
|
最终候选及实际结果以第四轮回执和 `local-followup.json` 为准。以下保留前三轮历史记录,整体任务尚未完成。
|
||||||
|
|
||||||
## 2026-10-09 N3 第二轮结果及第三轮候选验证
|
## 2026-10-09 N3 第二轮结果及第三轮候选验证
|
||||||
|
|
||||||
第二轮候选为 `18315d11`,完整 `verify-candidate` 为 **FAIL**。82 个迁移、服务端 4558 通过/1 项既有可选跳过、静态/构建和业务回归通过;浏览器 371 通过/1 失败、无跳过或重试。修正后的报销付款主链路实际走到执行及下游收口并通过。原始回执、失败定位及环境清理见 `artifacts/release-gate/loan-receipt-n3-20261009-r2/`,不可由定向结果抵扣。
|
第二轮候选为 `18315d11`,完整 `verify-candidate` 为 **FAIL**。82 个迁移、服务端 4558 通过/1 项既有可选跳过、静态/构建和业务回归通过;浏览器 371 通过/1 失败、无跳过或重试。修正后的报销付款主链路实际走到执行及下游收口并通过。原始回执、失败定位及环境清理见 `artifacts/release-gate/loan-receipt-n3-20261009-r2/`,不可由定向结果抵扣。
|
||||||
|
|||||||
@@ -1,5 +1,13 @@
|
|||||||
# 公司借款台账与本金归还
|
# 公司借款台账与本金归还
|
||||||
|
|
||||||
|
## 2026-10-09 N3 第三轮结果及桌面测试隔离修正
|
||||||
|
|
||||||
|
候选 `98bab397` 第三轮为 FAIL:82 迁移、服务端 4558 通过/1 项既有可选跳过、静态/构建和业务回归通过;浏览器 371 通过/1 失败、无跳过或重试。报销付款主链路和 PWA 升级本轮均通过。唯一失败为桌面企微历史测试在整页导航后等待标题超时,快照已回登录页;现有测试使用模拟接口,却只在手机 context 屏蔽 Service Worker。原请求来源未记录,不将该漏项写成已证实的历史唯一根因。
|
||||||
|
|
||||||
|
`09-06-release-gate-integrity` 已补默认桌面 context 的隔离,并要求原导航实际获得该 fixture 的 refresh/profile 响应。原三项用例、登录、会话、桌面只读、手机布局和截图全部保留;受管定向 3 项通过,环境和清理通过。资金及产品代码、迁移、正式门禁范围和预算未变。按 N3 既有授权形成新的本地提交,第四轮完整回执固定为 `artifacts/release-gate/loan-receipt-n3-20261009-r4/`,以其 `release-result.json` 和 `local-followup.json` 记录实际候选及结论。
|
||||||
|
|
||||||
|
前三轮 FAIL 完整保留,定向通过不能拼接完整资格。独立代码复核和真实还款验收仍开放;没有推送、部署、生产查询或真实材料外发。以下为各历史时点,整体任务继续 `in_progress`。
|
||||||
|
|
||||||
## 2026-10-09 N3 第二轮结果及 PWA 测试等待修正
|
## 2026-10-09 N3 第二轮结果及 PWA 测试等待修正
|
||||||
|
|
||||||
修复候选 `18315d11` 的完整第二轮仍为 FAIL:82 个迁移、服务端 4558 通过/1 项既有可选跳过、静态/构建及业务回归通过;浏览器 371 通过/1 失败、无跳过或重试。本轮报销付款主链路完整通过;唯一失败为 PWA 自动升级时,测试读取版本号的 `page.evaluate` 遇到正常导航而失去执行环境。错误栈和原回执保留,不把定向通过或事后 B 版本见证替换为整轮 PASS。
|
修复候选 `18315d11` 的完整第二轮仍为 FAIL:82 个迁移、服务端 4558 通过/1 项既有可选跳过、静态/构建及业务回归通过;浏览器 371 通过/1 失败、无跳过或重试。本轮报销付款主链路完整通过;唯一失败为 PWA 自动升级时,测试读取版本号的 `page.evaluate` 遇到正常导航而失去执行环境。错误栈和原回执保留,不把定向通过或事后 B 版本见证替换为整轮 PASS。
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ import { mkdirSync, mkdtempSync } from "node:fs";
|
|||||||
import path from "node:path";
|
import path from "node:path";
|
||||||
import { expect, test, type Browser, type Page, type Route } from "@playwright/test";
|
import { expect, test, type Browser, type Page, type Route } from "@playwright/test";
|
||||||
|
|
||||||
|
test.use({ serviceWorkers: "block" });
|
||||||
|
|
||||||
const visualRoot = path.resolve(process.env.QA_VISUAL_OUTPUT_DIR?.trim() || path.join(process.cwd(), "../output/playwright"));
|
const visualRoot = path.resolve(process.env.QA_VISUAL_OUTPUT_DIR?.trim() || path.join(process.cwd(), "../output/playwright"));
|
||||||
mkdirSync(visualRoot, { recursive: true });
|
mkdirSync(visualRoot, { recursive: true });
|
||||||
const SCREENSHOT_DIR = mkdtempSync(path.join(visualRoot, "internal-readiness-ui-"));
|
const SCREENSHOT_DIR = mkdtempSync(path.join(visualRoot, "internal-readiness-ui-"));
|
||||||
@@ -397,7 +399,16 @@ test.describe("五人团队本地候选移动证据", () => {
|
|||||||
await mockApis(page, state);
|
await mockApis(page, state);
|
||||||
await login(page);
|
await login(page);
|
||||||
await page.setViewportSize({ width: 1024, height: 768 });
|
await page.setViewportSize({ width: 1024, height: 768 });
|
||||||
await page.goto("/wecom-approval-archive");
|
const [refreshResponse, meResponse] = await Promise.all([
|
||||||
|
page.waitForResponse((response) => new URL(response.url()).pathname === "/api/auth/refresh"),
|
||||||
|
page.waitForResponse((response) => new URL(response.url()).pathname === "/api/me"),
|
||||||
|
page.goto("/wecom-approval-archive"),
|
||||||
|
]);
|
||||||
|
for (const response of [refreshResponse, meResponse]) {
|
||||||
|
expect(response.status()).toBe(200);
|
||||||
|
expect(response.fromServiceWorker()).toBe(false);
|
||||||
|
expect((await response.json()).requestId).toBe("mock-internal-readiness-ui");
|
||||||
|
}
|
||||||
await expect(page).toHaveURL(/\/wecom-approval-archive$/);
|
await expect(page).toHaveURL(/\/wecom-approval-archive$/);
|
||||||
await expect(page.getByRole("heading", { level: 1, name: "企微审批历史" })).toBeVisible();
|
await expect(page.getByRole("heading", { level: 1, name: "企微审批历史" })).toBeVisible();
|
||||||
await expect(page.getByRole("button", { name: "查看历史" })).toBeVisible();
|
await expect(page.getByRole("button", { name: "查看历史" })).toBeVisible();
|
||||||
|
|||||||
在新工单中引用
屏蔽一个用户