import { expect, test, type Page, type Route } from "@playwright/test"; import { createAuthenticationStack } from "./fixtures/auth-stack.mjs"; test.describe.configure({ mode: "serial" }); test.use({ viewport: { width: 1660, height: 822 } }); let stack: Awaited>; function json(route: Route, body: unknown) { return route.fulfill({ status: 200, contentType: "application/json", body: JSON.stringify(body), }); } async function signInAsAdmin(page: Page) { const account = stack.localAccount("admin"); await page.getByLabel("Username").fill(account.username); await page.locator('input[name="password"]').fill(account.password); await page.getByRole("button", { name: "Sign in", exact: true }).click(); await expect(page.getByTestId("app-shell")).toBeVisible({ timeout: 30_000 }); } test.beforeAll(async () => { stack = await createAuthenticationStack({ withF1Workspace: true }); await stack.useLocalMode(); }); test.afterAll(async () => { await stack?.close(); }); test("Administration stays within its rail when hosted by the Omics portal", async ({ page }) => { await page.route("**/api/settings", (route) => json(route, { workspace: "fixture-workspace", provider: "zai", model: "glm-5.2", thinking: "medium", })); await page.route("**/api/workspaces", (route) => json(route, [{ id: "fixture-workspace", name: "fixture-workspace", file: "fixture-workspace/workspace.yaml", displayName: "Fixture workspace", configurationState: "ready", revision: { id: "fixture-workspace", commit: "a".repeat(40), blob: "b".repeat(40), snapshotPath: `/snapshots/${"a".repeat(40)}/fixture-workspace.yaml`, }, }])); await page.route("**/api/workspaces/fixture-workspace/preprocessing", (route) => json(route, { schemaVersion: 1, workspaceId: "fixture-workspace", state: "running", actionable: false, clearable: false, detail: "Building schema and LSH.", progress: { stage: "schema_index", step: 2, totalSteps: 4, }, })); await page.goto(stack.publicUrl); await signInAsAdmin(page); await expect(page.getByRole("combobox", { name: "Workspace" })).toHaveValue("fixture-workspace"); // Hyper/Bootstrap and Thoth currently share the portal document. These // utility names are therefore resolved with the portal's !important values. await page.addStyleTag({ content: ` .px-2 { padding-right: 0.75rem !important; padding-left: 0.75rem !important; } .px-3 { padding-right: 1.5rem !important; padding-left: 1.5rem !important; } .px-4 { padding-right: 2.25rem !important; padding-left: 2.25rem !important; } ` }); const rail = page.getByRole("complementary", { name: "Session navigation" }); await rail.getByRole("button", { name: "Administration", exact: true }).click(); const administration = rail.getByRole("region", { name: "Administration" }); const boundary = rail.getByTestId("administration-boundary"); await expect(administration).toBeVisible(); await expect(rail.getByText("2 / 4", { exact: true })).toBeVisible(); const containment = await administration.evaluate((panel) => { const elements = Array.from(panel.querySelectorAll('button, [role="progressbar"], span')) .filter((element) => element.matches('button, [role="progressbar"]') || element.textContent?.trim() === "2 / 4"); return elements.map((element) => { const box = element.getBoundingClientRect(); return { label: element.textContent?.trim() || element.getAttribute("aria-label") || element.tagName, left: box.left, right: box.right, }; }); }); const boundaryBox = await boundary.boundingBox(); expect(boundaryBox).not.toBeNull(); if (!boundaryBox) return; for (const item of containment) { expect.soft(item.left, `${item.label} crosses the Administration left edge`).toBeGreaterThanOrEqual(boundaryBox.x - 1); expect.soft(item.right, `${item.label} crosses the Administration right edge`).toBeLessThanOrEqual(boundaryBox.x + boundaryBox.width + 1); } });