Files
buzz/desktop/tests/e2e/top-chrome-zoom-clearance.spec.ts
cls 9dfa06ffee
Docker image / Build (linux/amd64) (push) Has been cancelled
Docker image / Build (linux/arm64) (push) Has been cancelled
Docker image / Merge release multi-arch manifest (push) Has been cancelled
Docker image / Merge debug multi-arch manifest (push) Has been cancelled
Docker image / Build public push gateway (linux/amd64) (push) Has been cancelled
Docker image / Build public push gateway (linux/arm64) (push) Has been cancelled
Docker image / Publish public push gateway image (push) Has been cancelled
Sprig image / Build (linux/amd64) (push) Has been cancelled
Sprig image / Build (linux/arm64) (push) Has been cancelled
Sprig image / Merge multi-arch manifest (push) Has been cancelled
Harbor Buzz Orchestra / Python tests and lint (push) Has been cancelled
CI / Detect Changed Paths (push) Has been cancelled
CI / Rust Lint (push) Has been cancelled
CI / Unit Tests (push) Has been cancelled
CI / Desktop Core (push) Has been cancelled
CI / Desktop Smoke E2E (1) (push) Has been cancelled
CI / Desktop Smoke E2E (2) (push) Has been cancelled
CI / Desktop Smoke E2E (3) (push) Has been cancelled
CI / Desktop Smoke E2E (4) (push) Has been cancelled
CI / Desktop (push) Has been cancelled
CI / Desktop E2E Relay (push) Has been cancelled
CI / Desktop E2E Integration (1/2) (push) Has been cancelled
CI / Desktop E2E Integration (2/2) (push) Has been cancelled
CI / Desktop E2E Integration (push) Has been cancelled
CI / Backend Integration (relay e2e) (push) Has been cancelled
CI / Relay E2E (push) Has been cancelled
CI / Web (push) Has been cancelled
CI / Mobile (push) Has been cancelled
CI / Security (push) Has been cancelled
CI / Dead Token Reference Guard (push) Has been cancelled
CI / Server Cross-Compile (aarch64-unknown-linux-musl) (push) Has been cancelled
CI / Server Cross-Compile (x86_64-unknown-linux-musl) (push) Has been cancelled
CI / Windows Rust (x86_64-pc-windows-msvc) (push) Has been cancelled
CI / Desktop Build (macOS) (push) Has been cancelled
helm chart / lint + unittest + render matrix (push) Has been cancelled
helm chart / install on kind (gated) (push) Has been cancelled
helm chart / publish chart to GHCR (push) Has been cancelled
Mesh Lifecycle / Relay-Driven Mesh Lifecycle Smoke (push) Has been cancelled
Sprig / Build (aarch64-unknown-linux-musl) (push) Has been cancelled
Sprig / Build (x86_64-unknown-linux-musl) (push) Has been cancelled
Sprig / Publish rolling release (push) Has been cancelled
Sprig / Publish tagged release (push) Has been cancelled
feat: import Chinese-localized Buzz source snapshot
Signed-off-by: cls_宁波本机 <908705107@qq.com>
2026-08-13 18:34:25 +08:00

173 lines
5.7 KiB
TypeScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { expect, test } from "@playwright/test";
import { readFileSync } from "node:fs";
import { installMockBridge } from "../helpers/bridge";
type TauriConfig = {
app: {
windows: Array<{
trafficLightPosition?: { x: number; y: number };
}>;
};
};
const tauriConfig = JSON.parse(
readFileSync(
new URL("../../src-tauri/tauri.conf.json", import.meta.url),
"utf8",
),
) as TauriConfig;
const EXPECTED_TRAFFIC_LIGHT_POSITION = { x: 16, y: 25 };
const EXPECTED_NAV_CENTER_Y = 23;
// The macOS traffic lights are native chrome: with `trafficLightPosition`
// x:16 they occupy roughly x 1668 regardless of the app's Cmd +/- text
// zoom. The top-chrome nav row must clear that band in fixed px, so the
// clearance cannot shrink when the root font size scales down.
const TRAFFIC_LIGHT_RIGHT_EDGE = 72;
async function spoofMacPlatform(page: import("@playwright/test").Page) {
await page.addInitScript(() => {
Object.defineProperty(navigator, "platform", { get: () => "MacIntel" });
});
}
async function firstNavButtonX(page: import("@playwright/test").Page) {
const toggle = page.locator('[data-testid="app-top-chrome"] button').first();
await expect(toggle).toBeVisible();
const box = await toggle.boundingBox();
expect(box).not.toBeNull();
return box?.x ?? 0;
}
// The chrome buttons are styled to visually match the fixed-size native
// controls, so their box must not follow the rem text scale either. The
// sidebar toggle is 28px square; the back/forward history buttons share the
// height but are deliberately narrower (24px).
const NAV_BUTTON_SIZE = 28;
const HISTORY_BUTTON_WIDTH = 24;
// The grabber/drag strip hosting the buttons must hold its height too —
// otherwise Cmd+ balloons the bar around the fixed-size buttons and Cmd-
// collapses it.
const TOP_CHROME_BAR_HEIGHT = 40;
async function expectTopChromeFixedHeight(
page: import("@playwright/test").Page,
) {
const bar = page.getByTestId("app-top-chrome");
await expect(bar).toBeVisible();
const box = await bar.boundingBox();
expect(box).not.toBeNull();
expect(box?.height ?? 0).toBe(TOP_CHROME_BAR_HEIGHT);
}
async function expectNavButtonsFixedSize(
page: import("@playwright/test").Page,
) {
const buttons = page.locator('[data-testid="app-top-chrome"] button');
const count = await buttons.count();
expect(count).toBeGreaterThan(0);
for (let i = 0; i < count; i += 1) {
const button = buttons.nth(i);
const label = await button.getAttribute("aria-label");
const isHistoryButton = label === "Go back" || label === "Go forward";
const box = await button.boundingBox();
expect(box).not.toBeNull();
expect(box?.width ?? 0).toBe(
isHistoryButton ? HISTORY_BUTTON_WIDTH : NAV_BUTTON_SIZE,
);
expect(box?.height ?? 0).toBe(NAV_BUTTON_SIZE);
}
}
async function seedTextScale(
page: import("@playwright/test").Page,
scale: number,
) {
await page.addInitScript((value) => {
window.localStorage.setItem("buzz:text-scale", String(value));
}, scale);
}
async function expectRootFontSize(
page: import("@playwright/test").Page,
fontSize: string,
) {
await expect
.poll(() =>
page.evaluate(() => getComputedStyle(document.documentElement).fontSize),
)
.toBe(fontSize);
}
test.describe("top chrome macOS traffic-light clearance under text zoom", () => {
test("nav buttons clear the traffic lights at default zoom", async ({
page,
}) => {
await spoofMacPlatform(page);
await installMockBridge(page);
await page.goto("/");
// Lock the native and webview placements together: removing this explicit
// Tauri inset or shifting the nav row regresses the macOS chrome alignment.
expect(tauriConfig.app.windows[0]?.trafficLightPosition).toEqual(
EXPECTED_TRAFFIC_LIGHT_POSITION,
);
const toggleBox = await page
.getByRole("button", { name: "Toggle Sidebar", exact: true })
.boundingBox();
expect(toggleBox).not.toBeNull();
// Tauri interprets y:25 as a native titlebar inset, not the literal
// traffic-light center. The native controls use a small optical correction
// while the adjacent web controls remain centered at y:23.
expect((toggleBox?.y ?? 0) + (toggleBox?.height ?? 0) / 2).toBe(
EXPECTED_NAV_CENTER_Y,
);
expect(await firstNavButtonX(page)).toBeGreaterThanOrEqual(
TRAFFIC_LIGHT_RIGHT_EDGE,
);
await expectNavButtonsFixedSize(page);
await expectTopChromeFixedHeight(page);
});
test("nav buttons still clear the traffic lights when zoomed out", async ({
page,
}) => {
await spoofMacPlatform(page);
// Seed the minimum Cmd- text scale (0.75). The old rem-based clearance
// (pl-20 = 5rem) shrank to 60px here, sliding the buttons under the
// fixed-position native controls.
await seedTextScale(page, 0.75);
await installMockBridge(page);
await page.goto("/");
// Confirm the zoomed-out scale actually applied to the root font size.
await expectRootFontSize(page, "12px");
expect(await firstNavButtonX(page)).toBeGreaterThanOrEqual(
TRAFFIC_LIGHT_RIGHT_EDGE,
);
await expectNavButtonsFixedSize(page);
await expectTopChromeFixedHeight(page);
});
test("nav buttons keep their fixed size when zoomed in", async ({ page }) => {
await spoofMacPlatform(page);
// Seed the maximum Cmd+ text scale (1.5). Rem-sized buttons (h-7 = 42px
// here) grew visibly taller than the fixed-size traffic lights.
await seedTextScale(page, 1.5);
await installMockBridge(page);
await page.goto("/");
await expectRootFontSize(page, "24px");
expect(await firstNavButtonX(page)).toBeGreaterThanOrEqual(
TRAFFIC_LIGHT_RIGHT_EDGE,
);
await expectNavButtonsFixedSize(page);
await expectTopChromeFixedHeight(page);
});
});