feat(core): Wave 3.5 团队邀请入口 — 生成邀请码弹窗 + 复制码/邀请链接
team.tsx 加「邀请成员」按钮 → gen-invite 弹窗:角色(成员/团管)+ 月限额 → api.createInvitation 生成邀请码,cred-card 展示码 + 邀请链接(/register?invite=)+ 一键复制;复用 batch1 的 cred-card 类,无新 CSS。 验证: tsc 0 · build 0 · 走查 邀请按钮/弹窗打开/角色select/生成按钮/ESC关 全过 · 0 console error ⚠️ 生成码 + 凭码注册的 e2e 需先把 Invitation 迁移 apply 到远程 MySQL(逻辑已被后端 5/5 测试证)。 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
c0a8582f3b
commit
b82c4d3234
@@ -0,0 +1,24 @@
|
||||
import { chromium } from "playwright";
|
||||
import fs from "node:fs"; import path from "node:path";
|
||||
const BASE = process.env.BASE, TOKEN = process.env.TOKEN;
|
||||
const OUT = path.resolve("../../../_qa_shots/wave35"); fs.mkdirSync(OUT, { recursive: true });
|
||||
const b = await chromium.launch({ headless: true });
|
||||
const ctx = await b.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(); const errs = [];
|
||||
p.on("console", m => { if (m.type()==="error") errs.push(m.text()); });
|
||||
p.on("pageerror", e => errs.push("PAGEERR:"+e.message));
|
||||
await p.goto(BASE + "/team", { waitUntil: "load" }); await p.waitForTimeout(1500);
|
||||
const r = { inviteBtn: await p.locator("#open-gen-invite").count() };
|
||||
if (r.inviteBtn) {
|
||||
await p.click("#open-gen-invite"); await p.waitForTimeout(450);
|
||||
r.modalShown = await p.locator(".modal-bg.show").count();
|
||||
r.roleSelect = await p.locator(".invite-gen-modal select").count();
|
||||
r.genBtnText = await p.locator(".modal-f .btn-primary").innerText().catch(()=>"");
|
||||
await p.screenshot({ path: path.join(OUT, "team-gen-invite.png") });
|
||||
await p.keyboard.press("Escape"); await p.waitForTimeout(350);
|
||||
r.closedByEsc = (await p.locator(".modal-bg").count()) === 0;
|
||||
}
|
||||
r.consoleErrors = errs.filter(e => !/Invitation|invitations|500|Failed to load resource/i.test(e));
|
||||
await b.close(); console.log(JSON.stringify(r, null, 2));
|
||||
Reference in New Issue
Block a user