B-214: keep desktop header commands visible instead of behind ellipsis

Co-authored-by: Cursor <cursoragent@cursor.com>
Co-authored-by: multica-agent <github@multica.ai>
This commit is contained in:
MS-01-Codex
2026-08-20 12:39:22 +08:00
co-authored by Cursor multica-agent
parent f311580d02
commit 6ae0f5f862
8 changed files with 238 additions and 70 deletions
+119 -3
View File
@@ -3198,10 +3198,10 @@ test("merged header keeps date, detail fields and 13 pool columns after dual-rev
dashboard.limits = previousLimits;
await page.waitForTimeout(400);
await expect(page.locator("#currentPageSubtitle")).toContainText("市场复盘 ·");
await expect(page.locator("#headerMenuButton")).toBeVisible();
await expect(page.locator("#headerCommandGroup")).toBeHidden();
await expect(page.locator("#headerMenuButton")).toBeHidden();
await expect(page.locator("#headerCommandGroup")).toBeVisible();
await expect(page.locator("#themeToggle")).toBeVisible();
await expect(page.locator("#refreshButton")).toBeHidden();
await expect(page.locator("#refreshButton")).toBeVisible();
await page.locator('[data-view="limitPool"]').first().click();
await expect(page.locator("#currentPageSubtitle")).toContainText("市场复盘 ·");
@@ -3377,3 +3377,119 @@ test("B-199 screener review and account surfaces fit day night viewports", async
expect(pageErrors).toEqual([]);
});
test("desktop header keeps refresh, admin commands and account identity visible", async ({ page }) => {
const fs = require("node:fs");
const path = require("node:path");
const shotDir = path.join(__dirname, "../../runtime/b214-shots");
fs.mkdirSync(shotDir, { recursive: true });
const pageErrors = [];
page.on("pageerror", (error) => pageErrors.push(String(error)));
await mockApplication(page, session("admin", true));
await page.goto("/index.html");
const shot = (name) => page.locator(".app-header").screenshot({ path: path.join(shotDir, `${name}.png`) });
const shotPage = (name) => page.screenshot({ path: path.join(shotDir, `${name}.png`) });
const measureHeader = () => page.evaluate(() => {
const header = document.querySelector(".app-header");
const tape = document.querySelector(".market-tape");
const actions = document.querySelector(".header-actions");
const refresh = document.querySelector("#refreshButton");
const account = document.querySelector("#accountButton");
const name = document.querySelector("#accountName");
const box = (node) => node ? node.getBoundingClientRect() : null;
const visible = (node) => {
if (!node || node.hidden) return false;
const style = getComputedStyle(node);
if (style.display === "none" || style.visibility === "hidden") return false;
const rect = node.getBoundingClientRect();
return rect.width > 0 && rect.height > 0;
};
const tapeBox = box(tape);
const actionsBox = box(actions);
return {
headerOverflow: header ? header.scrollWidth - header.clientWidth : 0,
documentOverflow: document.documentElement.scrollWidth - window.innerWidth,
tapeHeight: tapeBox ? tapeBox.height : 0,
overlap: tapeBox && actionsBox
? Math.max(0, Math.min(tapeBox.right, actionsBox.right) - Math.max(tapeBox.left, actionsBox.left))
* Math.max(0, Math.min(tapeBox.bottom, actionsBox.bottom) - Math.max(tapeBox.top, actionsBox.top))
: 0,
refreshVisible: visible(refresh),
accountVisible: visible(account),
nameVisible: visible(name),
};
});
for (const viewport of [
{ width: 1600, height: 1000 },
{ width: 1440, height: 900 },
{ width: 1280, height: 800 },
]) {
await page.setViewportSize(viewport);
await expect(page.locator("#headerMenuButton")).toBeHidden();
await expect(page.locator("#headerCommandGroup")).toBeVisible();
await expect(page.locator("#refreshButton")).toBeVisible();
await expect(page.locator("#syncButton")).toBeVisible();
await expect(page.locator("#settingsButton")).toBeVisible();
await expect(page.locator("#accountAdminBadge")).toBeVisible();
await expect(page.locator("#accountVipBadge")).toBeVisible();
await expect(page.locator("#accountButton")).toBeVisible();
await expect(page.locator("#accountName")).toBeVisible();
const geometry = await measureHeader();
expect(geometry.headerOverflow, `${viewport.width} header overflow`).toBeLessThanOrEqual(1);
expect(geometry.documentOverflow, `${viewport.width} document overflow`).toBeLessThanOrEqual(1);
expect(geometry.overlap, `${viewport.width} tape overlap`).toBe(0);
expect(geometry.tapeHeight, `${viewport.width} tape height`).toBeGreaterThan(20);
await page.locator("#refreshButton").click();
await expect(page.locator("#loadingOverlay")).toBeHidden();
await page.locator("#settingsButton").click();
await expect(page.locator("#adminDialog")).toBeVisible();
await page.locator("#closeAdminDialog").click();
await page.locator("#accountButton").click();
await expect(page.locator("#accountDropdown")).toBeVisible();
await page.keyboard.press("Escape");
await shot(`${viewport.width}-day`);
}
await page.locator("#themeToggle").click();
await expect(page.locator("html")).toHaveAttribute("data-theme", "dark");
await page.setViewportSize({ width: 1600, height: 1000 });
await shot("1600-night");
await page.locator("#themeToggle").click();
await page.locator('[data-view="heavenView"]').first().click();
await expect(page.locator("#heavenView")).toHaveClass(/active-view/);
await expect(page.locator("#refreshButton")).toBeVisible();
await expect(page.locator("#accountButton")).toBeVisible();
await expect(page.locator("#headerMenuButton")).toBeHidden();
await shot("heaven-1600-day");
await page.setViewportSize({ width: 390, height: 844 });
await expect(page.locator("#headerMenuButton")).toBeVisible();
await expect(page.locator("#refreshButton")).toBeHidden();
await page.locator("#headerMenuButton").click();
await expect(page.locator("#headerCommandGroup")).toBeVisible();
await expect(page.locator("#refreshButton")).toBeVisible();
await expect(page.locator("#syncButton")).toBeVisible();
await expect(page.locator("#settingsButton")).toBeVisible();
await expect(page.locator("#accountAdminBadge")).toBeVisible();
await expect(page.locator("#accountVipBadge")).toBeVisible();
await expect(page.locator("#accountButton")).toBeVisible();
await expect(page.locator('[data-mobile-command-target="themeToggle"]')).toBeVisible();
await shotPage("390-menu-open");
await page.keyboard.press("Escape");
await expect(page.locator("#headerCommandGroup")).toBeHidden();
await mockApplication(page, session("user", false));
await page.setViewportSize({ width: 1600, height: 1000 });
await page.goto("/index.html");
await expect(page.locator("#refreshButton")).toBeVisible();
await expect(page.locator("#syncButton")).toBeHidden();
await expect(page.locator("#settingsButton")).toBeHidden();
await expect(page.locator("#accountAdminBadge")).toBeHidden();
await expect(page.locator("#accountVipBadge")).toBeVisible();
await expect(page.locator("#accountName")).toHaveText("normal_user");
await shot("1600-user-day");
expect(pageErrors).toEqual([]);
});