Files
plp/tests/e2e/global-setup.ts
T
root afab4e7cba test(web): 补充 Web MVP 端到端测试与本地测试编排
- 新增 Playwright E2E(治理、登录、投瓶捞瓶回复与实时聊天、举报拉黑与断线恢复)共 9 条用例
- 每个用例前重置数据库、用例后关闭全部 browser context,消除跨用例污染与资源泄漏
- 前端改由 Playwright 托管构建与 preview(关闭 SW);Vite 代理注入 Origin 头以通过接口 Origin 校验
- 根级 vitest 排除 Playwright 用例与需专用配置的 web 用例,避免误收集导致的假失败
- 测试手机号按实测校验结果收敛白名单,避免用例传入会被后端拒绝的号段

验证结果:
- Web E2E 9/9 连续两轮通过(含运行前后服务健康检查)
- API E2E 146/146 连续两轮通过
- 单测:根级 14 文件/119 用例、web 包 8 文件/31 用例通过
- typecheck、lint、build、依赖审计(audit)均通过
2026-09-18 11:23:20 +08:00

92 lines
2.6 KiB
TypeScript

import { createHmac } from "node:crypto";
import { PrismaClient } from "@prisma/client";
const DATABASE_URL =
process.env.DATABASE_URL ??
"postgresql://drift:drift_test_only@127.0.0.1:55432/drift_bottle_test?schema=public";
const ADMIN_PHONE = "13900000001";
const ADMIN_DEVICE = "e2e-admin-device";
// 与测试/开发环境一致的演示密钥(auth.e2e-spec.ts 同款)
const PHONE_HMAC_KEY = "test-phone-hmac-key-with-at-least-32-bytes";
function phoneHmac(phone: string): string {
return createHmac("sha256", PHONE_HMAC_KEY).update(phone).digest("hex");
}
function normalizePhone(raw: string): string {
const compact = raw.replace(/[\s()-]/g, "");
const local = compact.startsWith("+86")
? compact.slice(3)
: compact.startsWith("86") && compact.length === 13
? compact.slice(2)
: compact;
if (!/^1[3-9]\d{9}$/.test(local))
throw new Error(`invalid admin phone: ${raw}`);
return `+86${local}`;
}
export const E2E_ADMIN = { phone: ADMIN_PHONE, deviceId: ADMIN_DEVICE };
const TABLES = [
"outbox_events",
"moderation_tasks",
"bottle_pick_leases",
"bottle_pick_requests",
"bottle_pick_history",
"messages",
"conversation_members",
"conversations",
"notifications",
"reports",
"sanctions",
"audit_logs",
"refresh_tokens",
"sessions",
"daily_usage",
"bottles",
"anonymous_profiles",
"accounts",
];
/**
* 清空所有业务表(保留 schema)并重建管理员账号。
* 既用于 globalSetup,也被各 spec 的 beforeEach 调用,避免用例间数据污染
*(残留瓶子会让「捞取」捞到别的用例的瓶子,导致会话归属错乱)。
*/
export async function resetDatabase(): Promise<void> {
const prisma = new PrismaClient({
datasources: { db: { url: DATABASE_URL } },
});
try {
for (const table of TABLES) {
await prisma.$executeRawUnsafe(`TRUNCATE TABLE "${table}" CASCADE`);
}
const digest = phoneHmac(normalizePhone(ADMIN_PHONE));
await prisma.account.upsert({
where: { phoneHmac: digest },
update: { role: "ADMIN", status: "ACTIVE" },
create: {
role: "ADMIN",
status: "ACTIVE",
phoneHmac: digest,
// 测试库仅用于校验 phoneHmac 查找,明文备用
phoneCiphertext: Buffer.from("admin-e2e-placeholder", "utf8"),
anonymousProfile: {
create: {
nickname: "管理员",
avatarColor: "#66CCFF",
reviewStatus: "APPROVED",
},
},
},
});
} finally {
await prisma.$disconnect();
}
}
export default async function globalSetup(): Promise<void> {
await resetDatabase();
}