152 lines
5.7 KiB
TypeScript
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();
|
|
});
|
|
});
|