afab4e7cba
- 新增 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)均通过
106 lines
3.8 KiB
TypeScript
106 lines
3.8 KiB
TypeScript
import { test, expect } from "./fixtures";
|
|
import { E2E_ADMIN } from "./global-setup";
|
|
import { freshAccount, loginViaUi, smsAndLogin, pickBottle } from "./helpers";
|
|
|
|
test.describe("admin governance", () => {
|
|
test("admin login is guarded, reports are resolved with audit, sanction applies", async ({
|
|
browser,
|
|
request,
|
|
}) => {
|
|
// 预置管理员账号(global-setup),用 demo 登录拿到 accessToken
|
|
const adminSession = await smsAndLogin(request, E2E_ADMIN);
|
|
expect(adminSession.accessToken).toBeTruthy();
|
|
const adminHeaders = {
|
|
authorization: `Bearer ${adminSession.accessToken}`,
|
|
"content-type": "application/json",
|
|
};
|
|
|
|
// 制造举报:Alice 投瓶,Bob 捞瓶回复后举报会话
|
|
const aliceAccount = freshAccount("147");
|
|
const ctxAlice = await browser.newContext();
|
|
const alicePage = await ctxAlice.newPage();
|
|
await loginViaUi(alicePage, aliceAccount);
|
|
await alicePage.goto("/throw");
|
|
await alicePage
|
|
.getByPlaceholder("写下你想让陌生人看到的话…")
|
|
.fill(`治理测试会话 ${Date.now()}`);
|
|
await alicePage.getByRole("button", { name: /扔进海里/ }).click();
|
|
await expect(alicePage.getByText(/瓶子已进入审核/)).toBeVisible();
|
|
|
|
const bobAccount = freshAccount("145");
|
|
const ctxBob = await browser.newContext();
|
|
const bobPage = await ctxBob.newPage();
|
|
await loginViaUi(bobPage, bobAccount);
|
|
await bobPage.goto("/pick");
|
|
await pickBottle(bobPage);
|
|
await bobPage.locator(".bottle-card textarea").fill("这条消息将被举报");
|
|
await bobPage.getByRole("button", { name: /回复并建立会话/ }).click();
|
|
await expect(bobPage).toHaveURL(/\/conversations\//, { timeout: 15_000 });
|
|
|
|
// Bob 举报该会话
|
|
await bobPage.getByRole("button", { name: /举报会话/ }).click();
|
|
await bobPage.getByRole("button", { name: "提交举报" }).click();
|
|
await expect(bobPage.getByText(/举报已提交审核/)).toBeVisible();
|
|
|
|
// 管理员查看待审举报并处置
|
|
const after = await request.get(
|
|
"/api/v1/admin/reports?status=PENDING&limit=5",
|
|
{ headers: adminHeaders },
|
|
);
|
|
expect(after.ok()).toBeTruthy();
|
|
const afterBody = (await after.json()) as {
|
|
data?: { items?: Array<{ id: string }> };
|
|
};
|
|
const pending = afterBody.data?.items ?? [];
|
|
expect(pending.length).toBeGreaterThan(0);
|
|
const report = pending[0]!;
|
|
|
|
const resolve = await request.post(
|
|
`/api/v1/admin/reports/${report.id}/resolve`,
|
|
{
|
|
headers: adminHeaders,
|
|
data: { decision: "DISMISSED", resolution: "E2E 无违规" },
|
|
},
|
|
);
|
|
expect(resolve.ok()).toBeTruthy();
|
|
|
|
// 独立处罚:为 Bob 的公开 ID 施加警告
|
|
const aliceMe = await request.get("/api/v1/me", {
|
|
headers: {
|
|
authorization: `Bearer ${
|
|
(await smsAndLogin(request, aliceAccount)).accessToken
|
|
}`,
|
|
},
|
|
});
|
|
const aliceBody = (await aliceMe.json()) as {
|
|
data?: { publicId?: string };
|
|
};
|
|
const publicId = aliceBody.data?.publicId;
|
|
if (publicId) {
|
|
const sanction = await request.post(
|
|
`/api/v1/admin/accounts/${publicId}/sanctions`,
|
|
{
|
|
headers: adminHeaders,
|
|
data: { type: "WARNING", reason: "E2E 处罚验证" },
|
|
},
|
|
);
|
|
expect(sanction.ok()).toBeTruthy();
|
|
}
|
|
|
|
await ctxBob.close();
|
|
await ctxAlice.close();
|
|
});
|
|
|
|
test("non-admin user is forbidden from the admin workbench", async ({
|
|
page,
|
|
}) => {
|
|
const account = freshAccount("152");
|
|
await loginViaUi(page, account);
|
|
|
|
await page.goto("/admin");
|
|
// 非管理员应被引导回独立管理员登录页并显示无权限
|
|
await expect(page).toHaveURL(/\/admin\/login/, { timeout: 15_000 });
|
|
await expect(page.getByText(/没有管理员权限/).first()).toBeVisible();
|
|
});
|
|
});
|