import { chromium } from "playwright-core"; const API = "http://127.0.0.1:8100/api/v1"; const WEB = "http://127.0.0.1:5180"; const phone = "1370000" + String(Date.now()).slice(-4); async function call(path, body, token, method = "POST") { const res = await fetch(API + path, { method, headers: { "content-type": "application/json", ...(token ? { authorization: "Bearer " + token } : {}), }, body: body ? JSON.stringify(body) : undefined, }); const json = await res.json(); if (json.code !== 0) throw new Error(path + " -> " + JSON.stringify(json).slice(0, 200)); return json.data; } const sent = await call("/auth/sms/send", { phone }); const login = await call("/auth/login", { phone, code: sent.dev_code ?? "123456" }); const token = login.tokens.access_token; const ws = await call("/workspaces", { name: "海图工作室", slug: "haitu-" + Date.now().toString(36) }, token); const wsId = ws.id; const tasks = [ ["整理发票原件并寄给财务", "todo", 2, "#报销 财务"], ["给客户出第三季度复盘报告", "doing", 3, "#客户 周报"], ["把采集端的日志级别改回 info", "doing", 1, ""], ["和供应商确认二次报价", "blocked", 2, "#采购"], ["入职物料清单更新", "done", 0, ""], ["评审新版落地页文案", "inbox", 1, "#设计"], ]; for (const [title, status, priority, tags] of tasks) { const item = await call(`/workspaces/${wsId}/items`, { title, status, priority }, token); if (tags) { const names = tags.split(" ").filter((t) => t.startsWith("#")).map((t) => t.slice(1)); if (names.length) await call(`/workspaces/${wsId}/items/${item.id}`, { version: item.version, tag_names: names }, token, "PATCH"); } } const shop = await call(`/workspaces/${wsId}/items`, { title: "官网改版:首页轮播要换成新版素材", status: "todo", priority: 2 }, token); await call(`/workspaces/${wsId}/items/${shop.id}/knowledge?doc_type=howto`, {}, token); await call(`/workspaces/${wsId}/knowledge`, { title: "报销单必须贴发票原件,打印件不算", doc_type: "note" }, token); const me = await call("/workspaces/" + wsId + "/members", null, token, "GET").catch(() => null); // 视口可覆盖,用来核对宽屏布局:VIEWPORT=2560x1400 SUFFIX=-wide node e2e/shots.mjs const [VW, VH] = (process.env.VIEWPORT ?? "1440x960").split("x").map(Number); const SUFFIX = process.env.SUFFIX ?? ""; const browser = await chromium.launch({ executablePath: "C:\\Users\\Steven\\AppData\\Local\\ms-playwright\\chromium-1223\\chrome-win64\\chrome.exe", }); const page = await browser.newPage({ viewport: { width: VW, height: VH }, deviceScaleFactor: 1 }); await page.goto(WEB + "/login"); await page.evaluate(([t, r]) => { localStorage.setItem("dadao.access", t); localStorage.setItem("dadao.refresh", r); }, [login.tokens.access_token, login.tokens.refresh_token]); const shots = []; async function shot(url, name, prep) { await page.goto(WEB + url, { waitUntil: "networkidle" }); if (prep) await prep(); await page.waitForTimeout(600); const file = `e2e/artifacts/ui-${name}${SUFFIX}.png`; await page.screenshot({ path: file, fullPage: false }); shots.push(file); } await shot("/", "home"); await shot(`/w/${wsId}`, "tasks"); await shot(`/w/${wsId}`, "tasks-all", async () => { await page.getByRole("button", { name: "全部", exact: true }).click(); await page.waitForTimeout(500); }); await shot(`/w/${wsId}/board`, "board"); await shot(`/w/${wsId}/tickets`, "tickets"); await shot(`/w/${wsId}/knowledge`, "knowledge"); await shot(`/w/${wsId}/members`, "members"); await shot(`/w/${wsId}`, "detail", async () => { await page.getByRole("button", { name: "全部", exact: true }).click(); await page.waitForTimeout(500); await page.getByRole("button", { name: "把采集端的日志级别改回 info" }).first().click(); await page.waitForTimeout(800); }); await shot("/login", "login"); console.log(shots.join("\n")); await browser.close();