feat(core): Wave 1 part1 — 浮层进场动画/ESC + Toast 归正 + 账户表横线
S4 浮层: overlays.tsx 新增共享 useOverlayTransition(挂载→下一帧上 .show 触发 scale(.96→1)/translateX 进场过渡;关闭先撤 .show 播退场再卸载)+ 统一 ESC 关闭, 应用 TeamModal/ConfirmModal/SuccessModal/Drawer;EmptyPanel 补 .ic-empty 灰 icon S3 Toast: ToastLike 改用设计系统 .toast(右下/单橙 ic-t/shadow-floating/滑入), 不再随 success/error 变绿红边;auth login-toast → .toast S9 表格: account-page.css 删 tbody td border-bottom(对照 V1 account.html 确认应无行线) 验证: tsc 0 · 交互走查 toast出现+ESC关弹窗 · 14 路由回归 boot 0 报错 · 登录 643ms Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
8a0ae6a19d
commit
74e3c818c5
@@ -0,0 +1,61 @@
|
||||
// Wave 1 part-1 interaction smoke (scratch): S3 toast归正 + S4 modal ESC/进场动画.
|
||||
import { chromium } from "playwright";
|
||||
import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
|
||||
const BASE = process.env.BASE || "http://localhost:5173";
|
||||
const TOKEN = process.env.TOKEN || "";
|
||||
const OUT = path.resolve(process.env.OUT || "../../../_qa_shots/wave1");
|
||||
fs.mkdirSync(OUT, { recursive: true });
|
||||
|
||||
const browser = await chromium.launch({ headless: true });
|
||||
const result = {};
|
||||
|
||||
// 1) S3 — 登录页「忘记密码」应弹设计系统 .toast(右下),不再是旧 .login-toast
|
||||
{
|
||||
const ctx = await browser.newContext({ viewport: { width: 1440, height: 900 } });
|
||||
const p = await ctx.newPage();
|
||||
await p.goto(BASE + "/login", { waitUntil: "load" });
|
||||
await p.waitForTimeout(400);
|
||||
await p.locator("a", { hasText: "忘记密码" }).first().click();
|
||||
await p.waitForTimeout(500);
|
||||
result.authToast = {
|
||||
toastShown: await p.locator(".toast.show").count(),
|
||||
toastText: await p.locator(".toast .txt").innerText().catch(() => ""),
|
||||
legacyLoginToast: await p.locator(".login-toast").count(),
|
||||
};
|
||||
await p.screenshot({ path: path.join(OUT, "auth-toast.png") });
|
||||
await ctx.close();
|
||||
}
|
||||
|
||||
// 2) S4 — 团队页「创建账户」弹窗:打开有 .show / ESC 能关
|
||||
{
|
||||
const ctx = await browser.newContext({ viewport: { width: 1440, height: 900 } });
|
||||
const seed = await ctx.newPage();
|
||||
await seed.goto(BASE + "/", { waitUntil: "domcontentloaded" });
|
||||
await seed.evaluate((t) => localStorage.setItem("airshelf_token", t), TOKEN);
|
||||
await seed.close();
|
||||
const p = await ctx.newPage();
|
||||
await p.goto(BASE + "/team", { waitUntil: "load" });
|
||||
await p.waitForTimeout(1200);
|
||||
if (await p.locator("#open-invite").count()) {
|
||||
await p.click("#open-invite");
|
||||
await p.waitForTimeout(450); // 让进场动画跑完
|
||||
const shownOnOpen = await p.locator(".modal-bg.show").count();
|
||||
const modalTransform = await p.locator(".modal-bg.show .modal").first()
|
||||
.evaluate((el) => getComputedStyle(el).transform).catch(() => "n/a");
|
||||
await p.screenshot({ path: path.join(OUT, "team-modal-open.png") });
|
||||
await p.keyboard.press("Escape");
|
||||
await p.waitForTimeout(500); // 退场动画 + 卸载
|
||||
const modalGone = (await p.locator(".modal-bg").count()) === 0;
|
||||
await p.screenshot({ path: path.join(OUT, "team-modal-after-esc.png") });
|
||||
result.teamModal = { opened: true, shownOnOpen, modalTransform, closedByEsc: modalGone };
|
||||
} else {
|
||||
result.teamModal = { opened: false, note: "#open-invite not found" };
|
||||
}
|
||||
await ctx.close();
|
||||
}
|
||||
|
||||
await browser.close();
|
||||
console.log(JSON.stringify(result, null, 2));
|
||||
fs.writeFileSync(path.join(OUT, "summary.json"), JSON.stringify(result, null, 2));
|
||||
Reference in New Issue
Block a user