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:
co-authored by
Cursor
multica-agent
parent
f311580d02
commit
6ae0f5f862
+119
-3
@@ -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([]);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user