Files
NixMsg/web/e2e/admin-main.spec.ts
T

152 lines
5.7 KiB
TypeScript

import { expect, test, type APIRequestContext, type Page } from "@playwright/test";
import { readFile } from "node:fs/promises";
import path from "node:path";
import { fileURLToPath } from "node:url";
import { spawn } from "node:child_process";
type RuntimeInfo = {
httpBase: string;
adminPassword: string;
dataDir: string;
binPath: string;
vitePort: number;
};
const webRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
const repoRoot = path.resolve(webRoot, "..");
const runtimePath = path.join(webRoot, "e2e", ".runtime.json");
async function loadRuntime(): Promise<RuntimeInfo> {
return JSON.parse(await readFile(runtimePath, "utf8")) as RuntimeInfo;
}
async function login(page: Page, password: string) {
await page.goto("/login");
await page.getByPlaceholder("admin").fill("admin");
await page.getByPlaceholder("请输入密码").fill(password);
await page.getByTestId("login-submit").click();
await expect(page).toHaveURL(/\/overview/);
}
function nav(page: Page, label: string) {
return page.locator(".n-menu").getByText(label, { exact: true }).click();
}
async function createPeerViaAdmin(
request: APIRequestContext,
httpBase: string,
password: string,
id: string,
loginPassword: string,
) {
const loginRes = await request.post(`${httpBase}/api/admin/login`, {
data: { username: "admin", password },
});
expect(loginRes.ok()).toBeTruthy();
const res = await request.post(`${httpBase}/api/admin/endpoints`, {
headers: { "X-Nixmsg-Request": "1" },
data: { id, name: id, login_password: loginPassword },
});
const body = await res.json();
expect(res.ok(), JSON.stringify(body)).toBeTruthy();
expect(body.ok).toBe(true);
}
function seedPending(httpBase: string, from: string, fromPass: string, to: string): Promise<void> {
return new Promise((resolve, reject) => {
const child = spawn(
"go",
[
"run",
"./web/e2e/seedpending",
"-base",
httpBase,
"-from",
from,
"-from-pass",
fromPass,
"-to",
to,
],
{ cwd: repoRoot, shell: process.platform === "win32" },
);
let out = "";
child.stdout.on("data", (d) => {
out += String(d);
});
child.stderr.on("data", (d) => {
out += String(d);
});
child.on("error", reject);
child.on("close", (code) => {
if (code === 0) resolve();
else reject(new Error(`seedpending failed: ${out}`));
});
});
}
test.describe("后台主路径 W4", () => {
test("登录、开通、注册、建群、未完成投递、令牌创建停用", async ({ page, request }) => {
const rt = await loadRuntime();
await login(page, rt.adminPassword);
await nav(page, "端");
await expect(page).toHaveURL(/\/endpoints/);
await page.getByRole("button", { name: "开通", exact: true }).click();
await page.getByTestId("create-id").locator("input").fill("w4ep001");
await page.getByTestId("create-name").locator("input").fill("W4端一");
await page.getByTestId("create-submit").click();
await expect(page.getByText("只显示一次")).toBeVisible();
await page.getByRole("button", { name: "我已保存" }).click();
await expect(page.getByText("只显示一次")).toHaveCount(0);
await expect(page.getByText("w4ep001")).toBeVisible();
// 管理接口开通第二端(已知密码),供 MQTT 造未完成投递;管理 messages 只读
await createPeerViaAdmin(request, rt.httpBase, rt.adminPassword, "w4ep002", "password12ab");
await nav(page, "注册设置");
await expect(page).toHaveURL(/\/registration/);
await page.getByTestId("reg-enabled").click();
await expect(page.getByText("已开启自助注册")).toBeVisible();
await page.getByTestId("reg-code").locator("input").fill("w4-reg-code-01");
await page.getByTestId("reg-save-code").click();
await expect(page.getByText("安全码已更新")).toBeVisible();
await nav(page, "群");
await expect(page).toHaveURL(/\/groups/);
await page.getByTestId("group-create-open").click();
await page.getByTestId("group-name").locator("input").fill("W4测试群");
await page.getByTestId("group-owner").locator("input").fill("w4ep001");
await page.getByTestId("group-members").locator("textarea").fill("w4ep002");
await page.getByTestId("group-create-submit").click();
await expect(page.getByText("W4测试群")).toBeVisible();
await seedPending(rt.httpBase, "w4ep002", "password12ab", "w4ep001");
await nav(page, "投递记录");
await expect(page).toHaveURL(/\/messages/);
await expect(page.getByText("w4-e2e-scheduled")).toBeVisible();
await expect(page.getByRole("cell", { name: "scheduled", exact: true })).toBeVisible();
await nav(page, "API 令牌");
await expect(page).toHaveURL(/\/tokens/);
await page.getByTestId("token-create-open").click();
await page.getByTestId("token-name").locator("input").fill("w4-e2e-token");
await page.getByTestId("token-create-submit").click();
await expect(page.getByText("令牌只显示一次")).toBeVisible();
const bodyText = await page.locator("body").innerText();
const tokenMatch = bodyText.match(/nxm_[A-Za-z0-9_-]+/);
expect(tokenMatch).toBeTruthy();
const shown = tokenMatch![0];
await page.getByRole("button", { name: "我已保存" }).click();
await expect(page.getByText("令牌只显示一次")).toHaveCount(0);
await expect(page.getByText(shown)).toHaveCount(0);
await expect(page.getByText("w4-e2e-token")).toBeVisible();
const row = page.locator("tr", { hasText: "w4-e2e-token" });
await expect(row.getByText("是")).toBeVisible();
await row.getByRole("button", { name: "停用" }).click();
await expect(row.getByText("否")).toBeVisible();
});
});