Files
kandev/apps/web/e2e/tests/layout/topbar-alignment.spec.ts
T
José Almeida 9c16d337a2 feat(web): add global app status surface (#1869)
* feat(web): add app status bar

* feat(web): add app status bar visibility toggle

* feat(web): persist status bar item order

* fix(web): refine app status bar behavior

* fix(web): polish app status bar presentation

* test(web): split plugin slot coverage groups

* fix(web): address status surface review feedback

* fix(web): stabilize status bar overlay tests
2026-07-23 12:28:54 +01:00

119 lines
4.2 KiB
TypeScript

import { type Page } from "@playwright/test";
import { test, expect } from "../../fixtures/test-base";
import type { SeedData } from "../../fixtures/test-base";
import type { ApiClient } from "../../helpers/api-client";
import { KanbanPage } from "../../pages/kanban-page";
import { SessionPage } from "../../pages/session-page";
/**
* The sidebar header (h-10) must line up exactly with the surface top bar so the
* bottom border reads as one continuous line across the sidebar/content seam.
* On a task page that surface bar is the TaskTopBar — which previously had no
* explicit height and so sat a couple of px off from the 40px sidebar header.
*/
async function bottomOf(page: Page, testId: string): Promise<number> {
const box = await page.getByTestId(testId).boundingBox();
if (!box) throw new Error(`no bounding box for ${testId}`);
return box.y + box.height;
}
async function heightOf(page: Page, testId: string): Promise<number> {
const box = await page.getByTestId(testId).boundingBox();
if (!box) throw new Error(`no bounding box for ${testId}`);
return box.height;
}
async function enableStatusMetrics(apiClient: ApiClient): Promise<void> {
await apiClient.rawRequest("PATCH", "/api/v1/user/settings", {
system_metrics_display: { show_in_topbar: true },
});
}
test.describe("Sidebar header / top bar alignment", () => {
test.describe.configure({ retries: 1 });
test.afterEach(async ({ apiClient }) => {
await apiClient.rawRequest("PATCH", "/api/v1/user/settings", {
system_metrics_display: { show_in_topbar: false },
});
});
test("task top bar bottom edge aligns with the sidebar header", async ({
testPage,
apiClient,
seedData,
}: {
testPage: Page;
apiClient: ApiClient;
seedData: SeedData;
}) => {
const task = await apiClient.createTaskWithAgent(
seedData.workspaceId,
"Alignment Task",
seedData.agentProfileId,
{
description: "/e2e:simple-message",
workflow_id: seedData.workflowId,
workflow_step_id: seedData.startStepId,
repository_ids: [seedData.repositoryId],
},
);
if (!task.session_id) throw new Error("createTaskWithAgent did not return a session_id");
await testPage.goto(`/t/${task.id}`);
const session = new SessionPage(testPage);
await session.waitForLoad();
const topbar = testPage.getByTestId("task-topbar");
await expect(topbar).toBeVisible({ timeout: 30_000 });
// Read the named header directly so layout wrappers can change without
// weakening the alignment check (both top bars are 40px high).
await expect(testPage.getByTestId("app-sidebar-header")).toBeVisible();
const headerBottom = await bottomOf(testPage, "app-sidebar-header");
const topbarBottom = await bottomOf(testPage, "task-topbar");
// Allow 1px for sub-pixel rounding of the shared border line.
expect(Math.abs(headerBottom - topbarBottom)).toBeLessThanOrEqual(1);
});
test("task metrics render inside the fixed-height app status bar", async ({
testPage,
apiClient,
seedData,
}) => {
await enableStatusMetrics(apiClient);
const task = await apiClient.createTaskWithAgent(
seedData.workspaceId,
"Metrics Alignment Task",
seedData.agentProfileId,
{
description: "/e2e:simple-message",
workflow_id: seedData.workflowId,
workflow_step_id: seedData.startStepId,
repository_ids: [seedData.repositoryId],
},
);
if (!task.session_id) throw new Error("createTaskWithAgent did not return a session_id");
await testPage.goto(`/t/${task.id}`);
const session = new SessionPage(testPage);
await session.waitForLoad();
await expect(testPage.getByTestId("app-status-metrics")).toBeVisible();
expect(await heightOf(testPage, "app-status-bar")).toBe(24);
});
test("Kanban metrics render inside the fixed-height app status bar", async ({
testPage,
apiClient,
}) => {
await enableStatusMetrics(apiClient);
const kanban = new KanbanPage(testPage);
await kanban.goto();
await expect(testPage.getByTestId("app-status-metrics")).toBeVisible();
expect(await heightOf(testPage, "app-status-bar")).toBe(24);
});
});