rebuild(stage-4): deliver shared shell and account interfaces
This commit is contained in:
@@ -0,0 +1,132 @@
|
||||
const fs = require("node:fs");
|
||||
const path = require("node:path");
|
||||
|
||||
const { expect, test } = require("@playwright/test");
|
||||
|
||||
const evidence = path.resolve(__dirname, "../../docs/evidence/stage-4");
|
||||
|
||||
test.beforeAll(() => fs.mkdirSync(evidence, { recursive: true }));
|
||||
|
||||
async function authenticate(page, username, password) {
|
||||
await page.goto("/");
|
||||
await expect(page.getByRole("heading", { name: "小白复盘" })).toBeVisible();
|
||||
await page.getByLabel("账号名").fill(username);
|
||||
await page.getByLabel("密码").fill(password);
|
||||
await page.getByRole("button", { name: "登录", exact: true }).click();
|
||||
await expect(page.locator(".sidebar, .field-error")).toBeVisible();
|
||||
if (!(await page.locator(".sidebar").isVisible())) {
|
||||
await page.getByRole("tab", { name: "注册" }).click();
|
||||
await page.getByRole("button", { name: "注册并登录" }).click();
|
||||
}
|
||||
await expect(page.getByRole("navigation", { name: "主导航", exact: true })).toBeVisible();
|
||||
}
|
||||
|
||||
test("authentication, shell, dialogs, theme and responsive structure", async ({ page }) => {
|
||||
const consoleErrors = [];
|
||||
const unexpectedResponses = [];
|
||||
page.on("console", (message) => {
|
||||
if (message.type() === "error" && !message.text().includes("401 (Unauthorized)")) {
|
||||
consoleErrors.push(message.text());
|
||||
}
|
||||
});
|
||||
page.on("response", (response) => {
|
||||
const expectedAnonymousProbe = response.status() === 401 && response.url().endsWith("/api/auth/session");
|
||||
if (response.status() >= 400 && !expectedAnonymousProbe) {
|
||||
unexpectedResponses.push(`${response.status()} ${response.url()}`);
|
||||
}
|
||||
});
|
||||
|
||||
await authenticate(page, "stage4admin", "Stage4-pass-123!");
|
||||
await expect(page.getByText("管理员", { exact: true })).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: "系统管理" })).toBeVisible();
|
||||
await expect(page.locator(".nav-item")).toHaveCount(16);
|
||||
|
||||
await page.getByRole("button", { name: /stage4admin/ }).click();
|
||||
const accountMenu = page.locator(".account-menu");
|
||||
await expect(accountMenu.getByRole("button")).toHaveCount(5);
|
||||
await accountMenu.getByRole("button", { name: "个人资料" }).click();
|
||||
const profileDialog = page.getByRole("dialog", { name: "个人资料" });
|
||||
await expect(profileDialog).toBeVisible();
|
||||
await profileDialog.getByLabel("出生日期").fill("1990-03-08");
|
||||
await profileDialog.getByLabel("出生时间").fill("08:30");
|
||||
await profileDialog.getByLabel("性别").selectOption("male");
|
||||
await profileDialog.getByRole("button", { name: "保存", exact: true }).click();
|
||||
await expect(page.getByRole("status")).toContainText("个人资料已保存");
|
||||
await page.getByLabel("关闭").click();
|
||||
|
||||
await page.getByRole("button", { name: "普通用户" }).click();
|
||||
await expect(page.getByRole("dialog", { name: "会员状态" })).toContainText("智能选股、问师、问天、复盘助手");
|
||||
await page.getByLabel("关闭").click();
|
||||
|
||||
await page.getByRole("button", { name: /stage4admin/ }).click();
|
||||
await page.locator(".account-menu").getByRole("button", { name: "修改密码" }).click();
|
||||
const passwordDialog = page.getByRole("dialog", { name: "修改密码" });
|
||||
await expect(passwordDialog.getByLabel("当前密码")).toBeVisible();
|
||||
await expect(passwordDialog.getByLabel("确认新密码")).toBeVisible();
|
||||
await page.getByLabel("关闭").click();
|
||||
|
||||
await page.keyboard.press("Control+K");
|
||||
const searchDialog = page.getByRole("dialog", { name: "全局搜索" });
|
||||
await expect(searchDialog).toBeVisible();
|
||||
const dialogBox = await searchDialog.boundingBox();
|
||||
expect(dialogBox).not.toBeNull();
|
||||
expect(Math.abs(dialogBox.x + dialogBox.width / 2 - 960)).toBeLessThan(2);
|
||||
await page.keyboard.press("Escape");
|
||||
|
||||
const desktopMetrics = await page.evaluate(() => ({
|
||||
topbar: document.querySelector(".topbar")?.getBoundingClientRect().height,
|
||||
sidebar: document.querySelector(".sidebar")?.getBoundingClientRect().width,
|
||||
paddingTop: getComputedStyle(document.querySelector(".page-frame")).paddingTop,
|
||||
paddingLeft: getComputedStyle(document.querySelector(".page-frame")).paddingLeft,
|
||||
overflow: document.documentElement.scrollWidth - window.innerWidth,
|
||||
}));
|
||||
expect(desktopMetrics).toEqual({ topbar: 46, sidebar: 200, paddingTop: "14px", paddingLeft: "16px", overflow: 0 });
|
||||
await page.screenshot({ path: path.join(evidence, "shell-light-1920x1080.jpg"), type: "jpeg", quality: 82 });
|
||||
|
||||
await page.getByRole("button", { name: "夜间" }).click();
|
||||
await expect(page.locator("html")).toHaveAttribute("data-theme", "dark");
|
||||
await page.reload();
|
||||
await expect(page.locator("html")).toHaveAttribute("data-theme", "dark");
|
||||
await expect(page.getByRole("button", { name: "日间" })).toBeVisible();
|
||||
await page.screenshot({ path: path.join(evidence, "shell-dark-1920x1080.jpg"), type: "jpeg", quality: 82 });
|
||||
|
||||
await page.getByRole("button", { name: "系统管理" }).click();
|
||||
await expect(page.getByRole("heading", { name: "系统管理" })).toBeVisible();
|
||||
await expect(page.getByRole("tab")).toHaveCount(0);
|
||||
await expect(page.getByRole("button", { name: "行情管理" })).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: "模型池" })).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: "会员管理" })).toBeVisible();
|
||||
await page.getByRole("button", { name: "模型池" }).click();
|
||||
await expect(page.getByRole("heading", { name: "添加模型" })).toBeVisible();
|
||||
await page.getByRole("button", { name: "会员管理" }).click();
|
||||
await expect(page.getByRole("heading", { name: "账号会员状态" })).toBeVisible();
|
||||
await page.getByRole("button", { name: "行情管理" }).click();
|
||||
|
||||
await page.setViewportSize({ width: 3840, height: 2160 });
|
||||
expect(await page.evaluate(() => document.documentElement.scrollWidth - window.innerWidth)).toBe(0);
|
||||
await page.screenshot({ path: path.join(evidence, "system-dark-3840x2160.jpg"), type: "jpeg", quality: 72 });
|
||||
|
||||
await page.goto("/workspace/emotion");
|
||||
await page.setViewportSize({ width: 390, height: 844 });
|
||||
await expect(page.getByRole("navigation", { name: "移动端主导航" })).toBeVisible();
|
||||
await expect(page.getByRole("navigation", { name: "主导航", exact: true })).toBeHidden();
|
||||
expect(await page.evaluate(() => document.documentElement.scrollWidth - window.innerWidth)).toBe(0);
|
||||
await page.screenshot({ path: path.join(evidence, "shell-dark-390x844.jpg"), type: "jpeg", quality: 82 });
|
||||
|
||||
expect(consoleErrors).toEqual([]);
|
||||
expect(unexpectedResponses).toEqual([]);
|
||||
});
|
||||
|
||||
test("regular users do not receive administrator controls and see intelligent locks", async ({ page }) => {
|
||||
await authenticate(page, "stage4user", "Stage4-user-123!");
|
||||
await expect(page.getByText("管理员", { exact: true })).toHaveCount(0);
|
||||
await expect(page.getByRole("button", { name: "系统管理" })).toHaveCount(0);
|
||||
await expect(page.getByRole("button", { name: "后台刷新" })).toHaveCount(0);
|
||||
|
||||
await page.goto("/system");
|
||||
await expect(page).toHaveURL(/\/workspace\/emotion$/);
|
||||
|
||||
await page.goto("/workspace/screener");
|
||||
await expect(page.getByText("智能选股仅对会员开放")).toBeVisible();
|
||||
await expect(page.getByRole("button", { name: "查看会员状态" })).toBeVisible();
|
||||
});
|
||||
Reference in New Issue
Block a user