Files

119 lines
4.5 KiB
TypeScript

import { test, expect } from "./e2e-fixtures";
import Database from "better-sqlite3";
import { createHash } from "node:crypto";
test("managed relay UI, authenticated script, deployment state and subscription membership", async ({
page,
request,
}) => {
await page.goto("/login");
await page.getByLabel("用户名", { exact: true }).fill("ui-review");
await page.getByLabel("密码", { exact: true }).fill("ui-review-local-2026");
await page.getByRole("button", { name: "登录", exact: true }).click();
await expect(page).toHaveURL(/dashboard/);
await page.getByRole("link", { name: "节点管理", exact: true }).click();
const node = page
.locator("details")
.filter({
has: page.getByRole("heading", { name: "新增 HY2 节点", exact: true }),
});
await node.locator("summary").click();
await node.getByLabel("Slug", { exact: true }).fill("jp2");
await node.getByLabel("显示名", { exact: true }).fill("JP2 direct");
await node
.getByLabel("客户端地址", { exact: true })
.fill("jp2.p.xn--876a.net");
await node.getByRole("button", { name: "创建节点" }).click();
await expect(
page.getByText("JP2 direct", { exact: true }).first(),
).toBeVisible();
await page.getByRole("link", { name: "中转线路", exact: true }).click();
const host = page
.locator("details")
.filter({ has: page.getByRole("heading", { name: "新增中转主机" }) });
await host.getByLabel("主机名称").fill("HK2");
await host.getByLabel("公网域名 / IP").fill("hk2.p.xn--876a.net");
await host.getByRole("button", { name: "创建主机" }).click();
await expect(page.getByText("等待安装", { exact: true })).toBeVisible();
const row = page
.locator("details")
.filter({ has: page.locator("summary strong", { hasText: /^HK2$/ }) });
await row.locator("summary").click();
const href = await row
.getByRole("link", { name: "下载安装 SH" })
.getAttribute("href");
expect((await request.get(href!, { maxRedirects: 0 })).status()).toBe(307);
const script = await page.request.get(href!);
expect(script.status()).toBe(200);
expect(await script.text()).toContain("realm");
const create = page
.locator("details")
.filter({ has: page.getByRole("heading", { name: "新增中转线路" }) });
await create.getByLabel("线路名称").fill("JP2 via HK2");
await create
.getByLabel("中转主机", { exact: true })
.selectOption({ label: "HK2" });
await create
.getByLabel("目标节点")
.selectOption({ label: "JP2 direct · UDP" });
await create.getByLabel("公网端口").fill("51044");
await create.getByLabel("本机监听端口").fill("51044");
await create.getByRole("button", { name: "创建线路" }).click();
await expect(
page.locator("summary strong", { hasText: "JP2 via HK2" }),
).toBeVisible();
const db = new Database(process.env.HY2_E2E_DATABASE!);
const token = "a".repeat(64);
const id = (db.prepare("SELECT id FROM relay_hosts").get() as { id: string })
.id;
db.prepare("UPDATE relay_hosts SET token_hash=? WHERE id=?").run(
createHash("sha256").update(token).digest("hex"),
id,
);
db.close();
expect(
(
await request.post(`/api/relay/${id}/sync`, {
data: { appliedHash: "", active: false, error: "" },
})
).status(),
).toBe(403);
expect(
(
await request.post(`/api/relay/${id}/sync`, { data: "x".repeat(17000) })
).status(),
).toBe(413);
const sync = await request.post(`/api/relay/${id}/sync`, {
headers: { Authorization: `Bearer ${token}` },
data: { appliedHash: "", active: false, error: "" },
});
expect(sync.status()).toBe(200);
const desired = await sync.json();
expect(desired.config.endpoints[0].network.use_udp).toBe(true);
await request.post(`/api/relay/${id}/sync`, {
headers: { Authorization: `Bearer ${token}` },
data: { appliedHash: desired.hash, active: true, error: "" },
});
await page.reload();
await expect(
page.getByText("配置已应用", { exact: true }).first(),
).toBeVisible();
await page.screenshot({
path: "test-results/relays-desktop.png",
fullPage: true,
});
await page.setViewportSize({ width: 390, height: 844 });
await page.screenshot({
path: "test-results/relays-mobile.png",
fullPage: true,
});
expect(
await page.evaluate(
() => document.documentElement.scrollWidth <= innerWidth + 1,
),
).toBe(true);
await page.getByRole("link", { name: "订阅配置", exact: true }).click();
await expect(
page.getByRole("button", { name: "拖拽排序 JP2 via HK2" }),
).toBeVisible();
});