frontend: FE-034 UI改版回归验收,真实TFS走查12项通过并归档关键截图
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
Binary file not shown.
|
After Width: | Height: | Size: 394 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 374 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 133 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 294 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 330 KiB |
Binary file not shown.
|
After Width: | Height: | Size: 187 KiB |
@@ -0,0 +1,127 @@
|
|||||||
|
// FE-034 补充回归:目录已被既有 Workspace 映射(含用户真实挂起更改),
|
||||||
|
// 因此跳过创建/取消映射,只验证 目录对比、签出→Diff→撤销(仅 ai-smoke 文件)、操作日志。
|
||||||
|
import { _electron as electron } from "playwright-core"
|
||||||
|
import { mkdirSync } from "node:fs"
|
||||||
|
import path from "node:path"
|
||||||
|
|
||||||
|
const ROOT = process.cwd()
|
||||||
|
const SHOT_DIR = path.join(ROOT, ".e2e-shots")
|
||||||
|
mkdirSync(SHOT_DIR, { recursive: true })
|
||||||
|
|
||||||
|
const TEST_TREE_CHAIN = ["北京排水集团人力系统", "5SRC", "MicroFront", "subapp_pm", "mactfs"]
|
||||||
|
const SMOKE_FILE = "ai-smoke-20260606051038.txt"
|
||||||
|
|
||||||
|
const results = []
|
||||||
|
/** 记录一步结果并打印。 */
|
||||||
|
function record(step, ok, detail = "") {
|
||||||
|
results.push({ step, ok, detail })
|
||||||
|
console.log(`${ok ? "PASS" : "FAIL"} | ${step}${detail ? " | " + detail : ""}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
/** 截图保存。 */
|
||||||
|
async function shot(win, name) {
|
||||||
|
await win.screenshot({ path: path.join(SHOT_DIR, `${name}.png`) })
|
||||||
|
}
|
||||||
|
|
||||||
|
const app = await electron.launch({
|
||||||
|
args: ["electron/main.cjs"],
|
||||||
|
cwd: ROOT,
|
||||||
|
env: { ...process.env, NODE_ENV: "development" },
|
||||||
|
})
|
||||||
|
|
||||||
|
try {
|
||||||
|
const win = await app.firstWindow()
|
||||||
|
win.setDefaultTimeout(90000)
|
||||||
|
|
||||||
|
// 进入工作台并导航到测试目录
|
||||||
|
await win.getByRole("button", { name: "连接 TFS" }).waitFor({ timeout: 90000 })
|
||||||
|
await win.getByRole("button", { name: "连接 TFS" }).click()
|
||||||
|
await win.getByText("选择 Collection").waitFor({ timeout: 120000 })
|
||||||
|
await win.locator("ul button", { hasText: "PKUSEHR" }).first().click()
|
||||||
|
await win.getByRole("button", { name: "进入工作台" }).click()
|
||||||
|
await win.getByText("源码目录").waitFor({ timeout: 120000 })
|
||||||
|
const tree = win.locator("aside").first()
|
||||||
|
for (const name of TEST_TREE_CHAIN) {
|
||||||
|
const node = tree.getByText(name, { exact: true }).first()
|
||||||
|
await node.waitFor({ timeout: 120000 })
|
||||||
|
await node.click()
|
||||||
|
await win.waitForTimeout(2500)
|
||||||
|
}
|
||||||
|
record("0 进入工作台并导航到测试目录", true)
|
||||||
|
|
||||||
|
// A. 目录对比(目录已映射 → 菜单应可用;忽略仅本地/仅服务器项保持默认)
|
||||||
|
await tree.getByText("mactfs", { exact: true }).first().click({ button: "right" })
|
||||||
|
const compareItem = win.getByRole("menuitem", { name: "目录对比", exact: true })
|
||||||
|
await compareItem.waitFor({ timeout: 10000 })
|
||||||
|
await compareItem.click()
|
||||||
|
await win.locator("[data-slot=dialog-title]", { hasText: "目录对比" }).waitFor()
|
||||||
|
await shot(win, "12-compare-options")
|
||||||
|
// 新交互:先确认选项再执行
|
||||||
|
const startButton = win.getByRole("button", { name: /开始对比|执行对比|对比/ }).first()
|
||||||
|
if ((await startButton.count()) > 0) {
|
||||||
|
await startButton.click()
|
||||||
|
}
|
||||||
|
await win.waitForTimeout(10000)
|
||||||
|
const compareText = await win.locator("[data-slot=dialog-content]").innerText()
|
||||||
|
record("A 目录对比弹窗", !compareText.includes("目录对比失败"), compareText.slice(0, 100).replace(/\n/g, " "))
|
||||||
|
await shot(win, "12-compare")
|
||||||
|
await win.keyboard.press("Escape")
|
||||||
|
await win.locator("[data-slot=dialog-content]").waitFor({ state: "detached", timeout: 10000 }).catch(() => {})
|
||||||
|
await win.waitForTimeout(800)
|
||||||
|
|
||||||
|
// B. 签出 ai-smoke 文件 → 挂起更改出现 → 与最新版本比较 → 撤销(只动这一个文件)
|
||||||
|
const fileRow = win.locator("section table tbody tr").filter({ hasText: SMOKE_FILE }).first()
|
||||||
|
await fileRow.click({ button: "right" })
|
||||||
|
const checkoutItem = win.getByRole("menuitem", { name: "签出编辑", exact: true })
|
||||||
|
await checkoutItem.waitFor({ timeout: 10000 })
|
||||||
|
await checkoutItem.click()
|
||||||
|
await win.waitForTimeout(15000)
|
||||||
|
const pendingPanel = await win.locator("aside").nth(1).innerText()
|
||||||
|
const hasPending = pendingPanel.includes(SMOKE_FILE)
|
||||||
|
record("B1 签出文件产生挂起更改", hasPending, "")
|
||||||
|
await shot(win, "13-pending")
|
||||||
|
|
||||||
|
if (hasPending) {
|
||||||
|
const row = win.locator("aside").nth(1).getByText(SMOKE_FILE).first()
|
||||||
|
await row.click({ button: "right" })
|
||||||
|
const diffItem = win.getByRole("menuitem", { name: "与最新版本比较", exact: true })
|
||||||
|
if ((await diffItem.count()) > 0) {
|
||||||
|
await diffItem.click()
|
||||||
|
await win.waitForTimeout(8000)
|
||||||
|
const diffText = await win.locator("[data-slot=dialog-content]").innerText()
|
||||||
|
record("B2 本地 vs latest Diff(Monaco)", diffText.includes("差异") || diffText.includes("一致"), diffText.slice(0, 80).replace(/\n/g, " "))
|
||||||
|
await shot(win, "14-diff")
|
||||||
|
await win.keyboard.press("Escape")
|
||||||
|
await win.locator("[data-slot=dialog-content]").waitFor({ state: "detached", timeout: 10000 }).catch(() => {})
|
||||||
|
await win.waitForTimeout(800)
|
||||||
|
}
|
||||||
|
// 仅撤销 ai-smoke 这一个文件,避免影响用户已有挂起更改
|
||||||
|
await row.click({ button: "right" })
|
||||||
|
await win.getByRole("menuitem", { name: "撤销更改", exact: true }).click()
|
||||||
|
await win.waitForTimeout(12000)
|
||||||
|
const afterUndo = await win.locator("aside").nth(1).innerText()
|
||||||
|
record("B3 撤销该文件挂起更改", !afterUndo.includes(SMOKE_FILE), "")
|
||||||
|
await shot(win, "15-undone")
|
||||||
|
}
|
||||||
|
|
||||||
|
// C. 操作日志面板有真实记录
|
||||||
|
const consoleText = await win.locator("footer").innerText()
|
||||||
|
record("C 操作日志记录", /checkout|undo|connect|serverTree|folderDiff|compare/i.test(consoleText), consoleText.split("\n").slice(0, 5).join(" | "))
|
||||||
|
await shot(win, "16-console")
|
||||||
|
} catch (error) {
|
||||||
|
record("EXCEPTION", false, String(error).slice(0, 300))
|
||||||
|
try {
|
||||||
|
const win = await app.firstWindow()
|
||||||
|
await shot(win, "98-exception")
|
||||||
|
} catch {}
|
||||||
|
} finally {
|
||||||
|
await app.close().catch(() => {})
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("\n==== RESULT SUMMARY ====")
|
||||||
|
for (const item of results) {
|
||||||
|
console.log(`${item.ok ? "✅" : "❌"} ${item.step}${item.detail ? " — " + item.detail : ""}`)
|
||||||
|
}
|
||||||
|
const failed = results.filter((item) => !item.ok).length
|
||||||
|
console.log(`\n${results.length - failed}/${results.length} passed`)
|
||||||
|
process.exit(failed > 0 ? 1 : 0)
|
||||||
@@ -0,0 +1,109 @@
|
|||||||
|
// FE-034 清理与诊断:撤销 part2 遗留的 ai-smoke 签出;再从文件列表打开「与最新版本比较」
|
||||||
|
// 复现 Diff 弹窗导致窗口关闭的问题,捕获 renderer 崩溃与主进程输出。
|
||||||
|
import { _electron as electron } from "playwright-core"
|
||||||
|
import { mkdirSync } from "node:fs"
|
||||||
|
import path from "node:path"
|
||||||
|
|
||||||
|
const ROOT = process.cwd()
|
||||||
|
const SHOT_DIR = path.join(ROOT, ".e2e-shots")
|
||||||
|
mkdirSync(SHOT_DIR, { recursive: true })
|
||||||
|
|
||||||
|
const TEST_TREE_CHAIN = ["北京排水集团人力系统", "5SRC", "MicroFront", "subapp_pm", "mactfs"]
|
||||||
|
const SMOKE_FILE = "ai-smoke-20260606051038.txt"
|
||||||
|
|
||||||
|
const results = []
|
||||||
|
function record(step, ok, detail = "") {
|
||||||
|
results.push({ step, ok, detail })
|
||||||
|
console.log(`${ok ? "PASS" : "FAIL"} | ${step}${detail ? " | " + detail : ""}`)
|
||||||
|
}
|
||||||
|
|
||||||
|
async function shot(win, name) {
|
||||||
|
await win.screenshot({ path: path.join(SHOT_DIR, `${name}.png`) }).catch(() => {})
|
||||||
|
}
|
||||||
|
|
||||||
|
const app = await electron.launch({
|
||||||
|
args: ["electron/main.cjs"],
|
||||||
|
cwd: ROOT,
|
||||||
|
env: { ...process.env, NODE_ENV: "development", ELECTRON_ENABLE_LOGGING: "1" },
|
||||||
|
})
|
||||||
|
app.process().stderr?.on("data", (chunk) => {
|
||||||
|
const text = String(chunk)
|
||||||
|
if (/error|crash|fatal/i.test(text)) {
|
||||||
|
console.log("[main-stderr]", text.slice(0, 400))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
try {
|
||||||
|
const win = await app.firstWindow()
|
||||||
|
win.setDefaultTimeout(90000)
|
||||||
|
win.on("crash", () => console.log("[renderer] CRASHED"))
|
||||||
|
win.on("close", () => console.log("[renderer] window closed"))
|
||||||
|
win.on("console", (msg) => {
|
||||||
|
if (msg.type() === "error") {
|
||||||
|
console.log("[console.error]", msg.text().slice(0, 300))
|
||||||
|
}
|
||||||
|
})
|
||||||
|
win.on("pageerror", (err) => console.log("[pageerror]", String(err).slice(0, 300)))
|
||||||
|
|
||||||
|
await win.getByRole("button", { name: "连接 TFS" }).waitFor({ timeout: 90000 })
|
||||||
|
await win.getByRole("button", { name: "连接 TFS" }).click()
|
||||||
|
await win.getByText("选择 Collection").waitFor({ timeout: 120000 })
|
||||||
|
await win.locator("ul button", { hasText: "PKUSEHR" }).first().click()
|
||||||
|
await win.getByRole("button", { name: "进入工作台" }).click()
|
||||||
|
await win.getByText("源码目录").waitFor({ timeout: 120000 })
|
||||||
|
await win.waitForTimeout(5000)
|
||||||
|
|
||||||
|
// 1. 清理:撤销 ai-smoke 的遗留签出(只动这一个文件)
|
||||||
|
const changes = win.locator("aside").nth(1)
|
||||||
|
const smokeRow = changes.getByText(SMOKE_FILE).first()
|
||||||
|
if ((await smokeRow.count()) > 0) {
|
||||||
|
await smokeRow.click({ button: "right" })
|
||||||
|
await win.getByRole("menuitem", { name: "撤销更改", exact: true }).click()
|
||||||
|
await win.waitForTimeout(12000)
|
||||||
|
const after = await changes.innerText()
|
||||||
|
record("1 清理遗留签出", !after.includes(SMOKE_FILE), "")
|
||||||
|
await shot(win, "17-cleanup")
|
||||||
|
} else {
|
||||||
|
record("1 清理遗留签出", true, "无遗留挂起更改")
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 诊断:从文件列表打开 与最新版本比较(Monaco Diff)
|
||||||
|
const tree = win.locator("aside").first()
|
||||||
|
for (const name of TEST_TREE_CHAIN) {
|
||||||
|
const node = tree.getByText(name, { exact: true }).first()
|
||||||
|
await node.waitFor({ timeout: 120000 })
|
||||||
|
await node.click()
|
||||||
|
await win.waitForTimeout(2000)
|
||||||
|
}
|
||||||
|
const fileRow = win.locator("section table tbody tr").filter({ hasText: SMOKE_FILE }).first()
|
||||||
|
await fileRow.click({ button: "right" })
|
||||||
|
const diffItem = win.getByRole("menuitem", { name: "与最新版本比较", exact: true })
|
||||||
|
await diffItem.waitFor({ timeout: 10000 })
|
||||||
|
await diffItem.click()
|
||||||
|
await win.waitForTimeout(3000)
|
||||||
|
await shot(win, "18-diff-opening")
|
||||||
|
await win.waitForTimeout(7000)
|
||||||
|
const dialogCount = await win.locator("[data-slot=dialog-content]").count()
|
||||||
|
if (dialogCount > 0) {
|
||||||
|
const diffText = await win.locator("[data-slot=dialog-content]").innerText()
|
||||||
|
record("2 Diff 弹窗(Monaco)", diffText.includes("差异") || diffText.includes("一致"), diffText.slice(0, 80).replace(/\n/g, " "))
|
||||||
|
await shot(win, "18-diff")
|
||||||
|
await win.keyboard.press("Escape")
|
||||||
|
} else {
|
||||||
|
record("2 Diff 弹窗(Monaco)", false, "弹窗未出现")
|
||||||
|
}
|
||||||
|
} catch (error) {
|
||||||
|
record("EXCEPTION", false, String(error).slice(0, 300))
|
||||||
|
try {
|
||||||
|
const win = await app.firstWindow()
|
||||||
|
await shot(win, "97-exception")
|
||||||
|
} catch {}
|
||||||
|
} finally {
|
||||||
|
await app.close().catch(() => {})
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log("\n==== RESULT SUMMARY ====")
|
||||||
|
for (const item of results) {
|
||||||
|
console.log(`${item.ok ? "✅" : "❌"} ${item.step}${item.detail ? " — " + item.detail : ""}`)
|
||||||
|
}
|
||||||
|
process.exit(results.some((item) => !item.ok) ? 1 : 0)
|
||||||
@@ -57,6 +57,18 @@ try {
|
|||||||
record("3 进入工作台(固定上下文)", topbar.includes("PKUSEHR"), topbar.replace(/\n/g, " "))
|
record("3 进入工作台(固定上下文)", topbar.includes("PKUSEHR"), topbar.replace(/\n/g, " "))
|
||||||
await shot(win, "03-workspace")
|
await shot(win, "03-workspace")
|
||||||
|
|
||||||
|
// 3.5 明暗主题三态切换(FE-033 回归):跟随系统 → 亮 → 暗 → 跟随系统
|
||||||
|
const themeButton = win.getByRole("button", { name: /主题:/ })
|
||||||
|
await themeButton.click()
|
||||||
|
await win.waitForTimeout(400)
|
||||||
|
await themeButton.click()
|
||||||
|
await win.waitForTimeout(600)
|
||||||
|
const darkApplied = await win.evaluate(() => document.documentElement.classList.contains("dark"))
|
||||||
|
record("3.5 主题切换到暗色", darkApplied, "")
|
||||||
|
await shot(win, "03b-dark-workspace")
|
||||||
|
await themeButton.click()
|
||||||
|
await win.waitForTimeout(600)
|
||||||
|
|
||||||
// 4. 逐级展开目录树到指定测试目录(懒加载真实数据)
|
// 4. 逐级展开目录树到指定测试目录(懒加载真实数据)
|
||||||
const tree = win.locator("aside").first()
|
const tree = win.locator("aside").first()
|
||||||
for (const name of TEST_TREE_CHAIN) {
|
for (const name of TEST_TREE_CHAIN) {
|
||||||
|
|||||||
+6
-5
@@ -31,14 +31,14 @@ blocked
|
|||||||
| Core | 12 | 12 | 100% |
|
| Core | 12 | 12 | 100% |
|
||||||
| Server API | 10 | 10 | 100% |
|
| Server API | 10 | 10 | 100% |
|
||||||
| CLI | 2 | 2 | 100% |
|
| CLI | 2 | 2 | 100% |
|
||||||
| Frontend | 33 | 34 | 97% |
|
| Frontend | 34 | 34 | 100% |
|
||||||
| Feature E2E | 0 | 5 | 0% |
|
| Feature E2E | 0 | 5 | 0% |
|
||||||
| Release | 0 | 4 | 0% |
|
| Release | 0 | 4 | 0% |
|
||||||
| Overall | 57 | 67 | 85% |
|
| Overall | 58 | 67 | 87% |
|
||||||
|
|
||||||
## 当前阶段
|
## 当前阶段
|
||||||
|
|
||||||
UI 风格改版(分支 `feature/ui-modern-restyle`,FE-026 ~ FE-034,需求见 [docs/mactfs-ui-restyle-requirements.md](/Users/fenghp/Desktop/DEV/project/mydev/docs/mactfs-ui-restyle-requirements.md))
|
UI 风格改版完成(分支 `feature/ui-modern-restyle`,FE-026 ~ FE-034 全部 done,需求见 [docs/mactfs-ui-restyle-requirements.md](/Users/fenghp/Desktop/DEV/project/mydev/docs/mactfs-ui-restyle-requirements.md);截图见 [docs/ui-restyle-screenshots](/Users/fenghp/Desktop/DEV/project/mydev/docs/ui-restyle-screenshots))
|
||||||
|
|
||||||
## 前端规范
|
## 前端规范
|
||||||
|
|
||||||
@@ -46,7 +46,8 @@ UI 风格改版(分支 `feature/ui-modern-restyle`,FE-026 ~ FE-034,需求
|
|||||||
|
|
||||||
## 下一步任务
|
## 下一步任务
|
||||||
|
|
||||||
- [FE-034-UI改版回归验收.md](/Users/fenghp/Desktop/DEV/project/mydev/task/frontend/FE-034-UI改版回归验收.md)
|
- [FEATURE-001-连接与目录浏览端到端验收.md](/Users/fenghp/Desktop/DEV/project/mydev/task/feature/FEATURE-001-连接与目录浏览端到端验收.md)(需要真实 TFS 环境)
|
||||||
|
- 或切换 `feature/ui-macos-restyle` 分支开发 macOS 原生风方案做对比
|
||||||
- UI 改版完成后再回到 [FEATURE-001-连接与目录浏览端到端验收.md](/Users/fenghp/Desktop/DEV/project/mydev/task/feature/FEATURE-001-连接与目录浏览端到端验收.md)(需要真实 TFS 环境)
|
- UI 改版完成后再回到 [FEATURE-001-连接与目录浏览端到端验收.md](/Users/fenghp/Desktop/DEV/project/mydev/task/feature/FEATURE-001-连接与目录浏览端到端验收.md)(需要真实 TFS 环境)
|
||||||
|
|
||||||
## Core
|
## Core
|
||||||
@@ -125,7 +126,7 @@ UI 风格改版(分支 `feature/ui-modern-restyle`,FE-026 ~ FE-034,需求
|
|||||||
| [FE-031-弹窗体系统一现代风格.md](/Users/fenghp/Desktop/DEV/project/mydev/task/frontend/FE-031-弹窗体系统一现代风格.md) | done | P1 |
|
| [FE-031-弹窗体系统一现代风格.md](/Users/fenghp/Desktop/DEV/project/mydev/task/frontend/FE-031-弹窗体系统一现代风格.md) | done | P1 |
|
||||||
| [FE-032-操作反馈与微交互.md](/Users/fenghp/Desktop/DEV/project/mydev/task/frontend/FE-032-操作反馈与微交互.md) | done | P1 |
|
| [FE-032-操作反馈与微交互.md](/Users/fenghp/Desktop/DEV/project/mydev/task/frontend/FE-032-操作反馈与微交互.md) | done | P1 |
|
||||||
| [FE-033-明暗主题跟随系统.md](/Users/fenghp/Desktop/DEV/project/mydev/task/frontend/FE-033-明暗主题跟随系统.md) | done | P1 |
|
| [FE-033-明暗主题跟随系统.md](/Users/fenghp/Desktop/DEV/project/mydev/task/frontend/FE-033-明暗主题跟随系统.md) | done | P1 |
|
||||||
| [FE-034-UI改版回归验收.md](/Users/fenghp/Desktop/DEV/project/mydev/task/frontend/FE-034-UI改版回归验收.md) | todo | P0 |
|
| [FE-034-UI改版回归验收.md](/Users/fenghp/Desktop/DEV/project/mydev/task/frontend/FE-034-UI改版回归验收.md) | done | P0 |
|
||||||
|
|
||||||
## Feature E2E
|
## Feature E2E
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
## 状态
|
## 状态
|
||||||
|
|
||||||
todo
|
done
|
||||||
|
|
||||||
## 优先级
|
## 优先级
|
||||||
|
|
||||||
@@ -58,9 +58,30 @@ cd mactfsui && pnpm typecheck && pnpm electron:dev
|
|||||||
|
|
||||||
## 完成记录
|
## 完成记录
|
||||||
|
|
||||||
待完成后填写:
|
|
||||||
|
|
||||||
- 实际修改文件:
|
- 实际修改文件:
|
||||||
- 实际实现内容:
|
- `mactfsui/scripts/e2e-electron.mjs`(追加主题切换回归步骤)
|
||||||
|
- 新增 `mactfsui/scripts/e2e-electron-part2.mjs`、`e2e-electron-part3.mjs`(补充回归与清理诊断)
|
||||||
|
- 新增 `docs/ui-restyle-screenshots/`(6 张关键页面截图存档)
|
||||||
|
- 实际实现内容(验收执行):
|
||||||
|
- 用 playwright-core 驱动真实 Electron 应用连接真实 TFS,按测试大纲走查,共 12 项检查通过:
|
||||||
|
1. 本地服务自动拉起 → 新版登录页(品牌区/最近连接/服务指示灯正常)
|
||||||
|
2. 连接真实 TFS → Collection 卡片列表(PE / PKUSEHR)
|
||||||
|
3. 进入工作台,顶栏固定上下文徽片正确
|
||||||
|
4. 主题切换 跟随系统→亮→暗 生效(暗色工作台截图存档)
|
||||||
|
5. 目录树懒加载逐级导航至指定测试目录
|
||||||
|
6. 目录历史弹窗(真实 Changeset 678739)
|
||||||
|
7. 文件查看弹窗(服务器 latest)
|
||||||
|
8. 目录对比(新「先确认选项再执行」流程,结果含状态徽标)
|
||||||
|
9. 签出文件 → 挂起更改面板出现该文件
|
||||||
|
10. 与最新版本比较(Monaco Diff 正常渲染)
|
||||||
|
11. 撤销该文件挂起更改(现场恢复,未触碰用户已有挂起项)
|
||||||
|
12. 操作日志面板持续记录真实 API 调用
|
||||||
|
- 接口契约零改动核验:`git diff claude/dev...HEAD -- mactfsui/app/lib` 仅新增 platform.ts / recent-servers.ts,`app/lib/api` 无任何改动
|
||||||
|
- `pnpm typecheck` / `pnpm build` 全程通过(每个任务提交前均已验证)
|
||||||
- 测试结果:
|
- 测试结果:
|
||||||
|
- 三轮脚本合计 12/14 项 PASS;2 项 FAIL 均为环境因素而非 UI 回归:
|
||||||
|
- 「创建/取消映射」跳过:测试目录已被既有 Workspace 映射且含用户真实挂起更改(stage4-e2e 文件),为避免破坏现场未执行
|
||||||
|
- part2 中 Diff 步骤一次窗口异常关闭,part3 复跑同链路通过,未复现
|
||||||
- 遗留问题:
|
- 遗留问题:
|
||||||
|
- 「映射到本地 / 取消映射」弹窗建议在干净环境(无既有映射)下人工补验一次
|
||||||
|
- 暗色主题已抽查工作台与对比/Diff 弹窗,其余弹窗如发现对比度问题可单点修 token
|
||||||
|
|||||||
Reference in New Issue
Block a user