B-217: show full header username without 108px truncation
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
6ae0f5f862
commit
f3a1f1adc2
@@ -517,6 +517,49 @@ async function openHeaderCommandMenu(page) {
|
||||
await expect(menu).toBeVisible();
|
||||
}
|
||||
|
||||
function namedSession(username, role = "admin", subscribed = true) {
|
||||
const auth = session(role, subscribed);
|
||||
auth.user.username = username;
|
||||
return auth;
|
||||
}
|
||||
|
||||
async function setColorTheme(page, theme) {
|
||||
const wanted = theme === "night" ? "dark" : "light";
|
||||
const current = await page.locator("html").getAttribute("data-theme");
|
||||
if (current === wanted) return;
|
||||
await page.locator("#themeToggle").click();
|
||||
await expect(page.locator("html")).toHaveAttribute("data-theme", wanted);
|
||||
}
|
||||
|
||||
function measureAccountName() {
|
||||
const name = document.querySelector("#accountName");
|
||||
const button = document.querySelector("#accountButton");
|
||||
const badges = document.querySelector("#accountRoleBadges");
|
||||
const adminLabel = document.querySelector("#accountAdminBadge > span");
|
||||
const vipLabel = document.querySelector("#accountVipLabel");
|
||||
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 buttonBox = box(button);
|
||||
const badgeBox = box(badges);
|
||||
return {
|
||||
text: name ? String(name.textContent || "") : "",
|
||||
clientWidth: name ? name.clientWidth : 0,
|
||||
scrollWidth: name ? name.scrollWidth : 0,
|
||||
fits: name ? name.clientWidth >= name.scrollWidth : false,
|
||||
buttonFits: button ? button.clientWidth >= button.scrollWidth : false,
|
||||
stacked: Boolean(badgeBox && buttonBox && buttonBox.top >= badgeBox.bottom - 1),
|
||||
adminLabelVisible: visible(adminLabel),
|
||||
vipLabelVisible: visible(vipLabel),
|
||||
documentOverflow: document.documentElement.scrollWidth - window.innerWidth,
|
||||
};
|
||||
}
|
||||
|
||||
test("admin shell opens every primary workspace and global search", async ({ page }) => {
|
||||
await mockApplication(page);
|
||||
await page.goto("/index.html");
|
||||
@@ -3418,6 +3461,7 @@ test("desktop header keeps refresh, admin commands and account identity visible"
|
||||
refreshVisible: visible(refresh),
|
||||
accountVisible: visible(account),
|
||||
nameVisible: visible(name),
|
||||
nameFits: name ? name.clientWidth >= name.scrollWidth : false,
|
||||
};
|
||||
});
|
||||
|
||||
@@ -3441,6 +3485,7 @@ test("desktop header keeps refresh, admin commands and account identity visible"
|
||||
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);
|
||||
expect(geometry.nameFits, `${viewport.width} account name truncated`).toBe(true);
|
||||
await page.locator("#refreshButton").click();
|
||||
await expect(page.locator("#loadingOverlay")).toBeHidden();
|
||||
await page.locator("#settingsButton").click();
|
||||
@@ -3477,6 +3522,9 @@ test("desktop header keeps refresh, admin commands and account identity visible"
|
||||
await expect(page.locator("#accountVipBadge")).toBeVisible();
|
||||
await expect(page.locator("#accountButton")).toBeVisible();
|
||||
await expect(page.locator('[data-mobile-command-target="themeToggle"]')).toBeVisible();
|
||||
const mobileName = await page.evaluate(measureAccountName);
|
||||
expect(mobileName.fits, "390 account name truncated").toBe(true);
|
||||
expect(mobileName.stacked, "390 identity and account should stack").toBe(true);
|
||||
await shotPage("390-menu-open");
|
||||
await page.keyboard.press("Escape");
|
||||
await expect(page.locator("#headerCommandGroup")).toBeHidden();
|
||||
@@ -3493,3 +3541,72 @@ test("desktop header keeps refresh, admin commands and account identity visible"
|
||||
await shot("1600-user-day");
|
||||
expect(pageErrors).toEqual([]);
|
||||
});
|
||||
|
||||
test("header username stays untruncated on desktop and in the mobile menu", async ({ page }) => {
|
||||
test.setTimeout(120_000);
|
||||
const fs = require("node:fs");
|
||||
const path = require("node:path");
|
||||
const shotDir = path.join(__dirname, "../../runtime/b217-shots");
|
||||
fs.mkdirSync(shotDir, { recursive: true });
|
||||
const measurements = [];
|
||||
const viewports = [
|
||||
{ width: 1600, height: 1000 },
|
||||
{ width: 1440, height: 900 },
|
||||
{ width: 1280, height: 800 },
|
||||
{ width: 390, height: 844 },
|
||||
];
|
||||
const accounts = [
|
||||
{ label: "admin", username: "review_admin", auth: namedSession("review_admin", "admin", true) },
|
||||
{ label: "user", username: "normal_user", auth: namedSession("normal_user", "user", false) },
|
||||
];
|
||||
|
||||
for (const account of accounts) {
|
||||
await mockApplication(page, account.auth);
|
||||
await page.goto("/index.html");
|
||||
await expect(page.locator("#accountName")).toHaveText(account.username);
|
||||
|
||||
for (const theme of ["day", "night"]) {
|
||||
await page.setViewportSize({ width: 1600, height: 1000 });
|
||||
await setColorTheme(page, theme);
|
||||
for (const viewport of viewports) {
|
||||
await page.setViewportSize(viewport);
|
||||
if (viewport.width === 390) {
|
||||
await page.locator("#headerMenuButton").click();
|
||||
await expect(page.locator("#headerCommandGroup")).toBeVisible();
|
||||
} else {
|
||||
await expect(page.locator("#headerMenuButton")).toBeHidden();
|
||||
await expect(page.locator("#accountName")).toBeVisible();
|
||||
}
|
||||
const geometry = await page.evaluate(measureAccountName);
|
||||
const label = `${account.label}-${viewport.width}-${theme}`;
|
||||
expect(geometry.text, `${label} username`).toBe(account.username);
|
||||
expect(geometry.fits, `${label} accountName truncated ${geometry.clientWidth}<${geometry.scrollWidth}`).toBe(true);
|
||||
expect(geometry.documentOverflow, `${label} document overflow`).toBeLessThanOrEqual(1);
|
||||
if (viewport.width === 390) {
|
||||
expect(geometry.stacked, `${label} identity/account not stacked`).toBe(true);
|
||||
}
|
||||
if (viewport.width >= 1440 && account.label === "admin") {
|
||||
expect(geometry.adminLabelVisible, `${label} admin badge text hidden`).toBe(true);
|
||||
expect(geometry.vipLabelVisible, `${label} vip badge text hidden`).toBe(true);
|
||||
}
|
||||
measurements.push({
|
||||
account: account.username,
|
||||
theme,
|
||||
width: viewport.width,
|
||||
height: viewport.height,
|
||||
...geometry,
|
||||
});
|
||||
const shotName = `${account.label}-${viewport.width}-${theme}.png`;
|
||||
if (viewport.width === 390) {
|
||||
await page.screenshot({ path: path.join(shotDir, shotName) });
|
||||
await page.keyboard.press("Escape");
|
||||
await expect(page.locator("#headerCommandGroup")).toBeHidden();
|
||||
} else {
|
||||
await page.locator(".app-header").screenshot({ path: path.join(shotDir, shotName) });
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fs.writeFileSync(path.join(shotDir, "measurements.json"), `${JSON.stringify(measurements, null, 2)}\n`);
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user